当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”

刷脏页的时间

第一种是“redo log写满了,要flush脏页” 整个系统就不能再接受更新了,所有的更新都必须堵住。如果你从监控上看,这时候更新数会跌为0

第二种是“内存不够用了,要先将脏页写到磁盘” 这种情况是常态

InnoDB用缓冲池(buffer pool)管理内存,缓冲池中的内存页有三种状态:

  1. 还没有使用的;
  2. 使用了并且是干净页;
  3. 使用了并且是脏页。

InnoDB的策略是尽量使用内存,因此对于一个长时间运行的库来说,未被使用的页面很少。

当要读入的数据页没有在内存的时候,就必须到缓冲池中申请一个数据页。这时候只能把最久不使用的数据页从内存中淘汰掉:如果要淘汰的是一个干净页,就直接释放出来复用;但如果是脏页呢,就必须将脏页先刷到磁盘,变成干净页后才能复用

一个查询要淘汰的脏页个数太多,会导致查询的响应时间明显变长;

第三种是MySQL空闲时

第四种是MySQL正常关闭

刷脏页的控制策略

innodb_io_capacity 它会告诉InnoDB你的磁盘能力 设置成磁盘的IOPS

innodb_max_dirty_pages_pct脏页比例上限,默认值是75% 通过Innodb_buffer_pool_pages_dirty/Innodb_buffer_pool_pages_total得到的

InnoDB的刷盘速度就是要参考这两个因素:一个是脏页比例,一个是redo log写盘速度

刷脏页的连坐”机制

一旦一个查询请求需要在执行过程中先flush掉一个脏页时,这个查询就可能要比平时慢了。而MySQL中的一个机制,可能让你的查询会更慢:在准备刷一个脏页的时候,如果这个数据页旁边的数据页刚好是脏页,就会把这个“邻居”也带着一起刷掉;而且这个把“邻居”拖下水的逻辑还可以继续蔓延,也就是对于每个邻居数据页,如果跟它相邻的数据页也还是脏页的话,也会被放到一起刷

innodb_flush_neighbors 值为1的时候会有上述的“连坐”机制,值为0时表示不找邻居,自己刷自己的

找“邻居”这个优化在机械硬盘时代是很有意义的,可以减少很多随机IO。机械硬盘的随机IOPS一般只有几百,相同的逻辑操作减少随机IO就意味着系统性能的大幅度提升

使用的是SSD这类IOPS比较高的设备的话,建议把innodb_flush_neighbors的值设置成0

在MySQL 8.0中,innodb_flush_neighbors参数的默认值已经是0了

broker

ons 默认有两个brokerName组,分别有0-7共16个队列

还有两个死信队列 topic是 %RETRY%+tag

consumer15分钟消费超时,broker会重发消息

Producer

轮询发送到broker队列

如果发送失败会换个队列

defaultTopicQueueNums

自动创建topic时设置队列数量
ons不允许自动创建topic,也不允许修改队列数量

Consumer

AllocateMessageQueueAveragely

  • 默认 集群消费

平均分配可消费的 Broker 对应的消息队列 c1对应b1,b2,b3 c2对应d1,d2,d3

AllocateMessageQueueAveragelyByCircle

以环状轮流分Broker

广播消费

每个Consume都订阅每个Broker

注意点

  1. 刚启动时,broker分配还没有完成,会导致消息重复消费
  2. 但是可能会存在同样的消息有两个不同 msgId的情况(有多种原因),这种情况可能会使业务上重复消费,建议最好使用消息内容中的唯一标识字段去重

由filebeat导入的default template导致

检查

先创建个新的索引:

1
PUT /my_index

然后查下是否有default mapping

1
2
3
4
5
6
7
8
GET /my_index
//像这样
{
"mappings": {
"_default_": {}
}
}

比较下和之前数据的mapping有没有冲突

解决方案

首先查看es中存在的模板 /_template, 是否存在名为filebeat,存在就执行

1
DELETE /_template/filebeat

在日志系统中通常直接由es按天生成索引,这样就简单了,直接把使用错误索引的数据删掉重新导入就好了。

但在使用自己的索引时,就需要做重索引,可以尝试通过索引别名的方式切换

起因

在尝试新的日志格式时,启动了其他版本的filebeat并让它直接output到es,忘记设置 template.enabled: false 导致它导入default模板

在第二天生成新索引时发现kibana报warning shards failed,才发现mapping conflict

填完一坑,继续logstash挖坑

分布式

特征

  • 分布性 分布式系统中的计算机会依据业务或其他需求在空间中随意分布,并且可以灵活变动
  • 对等性 整个系统中的计算机节点都是对等的,没有物理上的主从之分
  • 并发性 系统中的多节计算机节点可能会并发操作共享资源
  • 没有全局时钟 因为多个节点在空间上的随意分布,没有办法设置全局的时钟序列
  • 故障率 在由大量计算机组成的分布式系统中,故障是无法避免的

CAP定理

在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼

  • 强一致性 分布式系统会存在多个数据副本,要求所有的用户都可以读到最新的数据
  • 可用性 系统对用户的每个操作都能在有限的时间内返回正常的结果
  • 分区容错性 组成分布式系统的子网由于网络故障不能通信,导致整个系统被分成若干孤立的子网,但仍要保证致性和可用性服务

BASE理论

对CAP中可用性和一致性权衡的结果,通过牺牲强一致性来获取可用性,核心思想是:每个应用可以根据自身的特点,采用适当的方式达到最终一致性

  • 基本可用(Basically Available)是当系统出现故障时,可以牺牲部分可用性,如响应时间、功能减少,从而保证系统运行
  • 软状态(Soft state)允许不同节点的数据副本在同步时存在延迟,并认为该状态不会影响系统整体的可用性;
  • 最终一致性(Eventually consistent)强调系统所有的数据副本最终能达到一致状态,但不需要实时保证数据一致性,而所有客户端能获取到最新的值

一致性协议

2PC 两段提交

将事务的提交过程分成了两个阶段来进行处理,它对每个事务使用先尝试后提交的方式来处理,是一种强一致性算法。它的优点是原理简单,实现方便,而缺点是同步阻塞,单点问题,数据不一致

Smaller icon

阶段一:提交事务请求

  1. 事务询问:向所有参与者发送事务内容,并询问事务提交是否可以执行,然后等待参与者响应
  2. 执行事务:参与者执行事务,并在日志中记录Undo和Redo信息
  3. 参与者反馈响应:如果参与者成功执行事务操作就反馈Yes,否则反馈No

执行事务提交

  1. 发送提交请求:向参与者发送Commit
  2. 事务提交:参与者收到Commit后,执行事务提交,并在完成之后释放占用的事务资源
  3. 反馈提交结果:参与者完成事务提交后,反馈Ack消息
  4. 完成事务:所有参与者反馈Ack消息,完成事务

Paxos算法

Paxos是一种基于消息传递且具有高度容错性的一致性算法,是解决分布式一致性问题最有效的算法之一,能避免2PC和3PC存在的问题。

Raft协议

  1. 将一致性协议划分为领导者选举,Log复制和安全性
  2. 将paxos的p2p模式改成Master-slave模式

三种常见的通信机制:序列化和远程过程调用,消息队列,多播通信

序列化和远程过程调用

网络中处于不同机器上的进程,通过远程过程调用(Remote Procedure Call,rpc)相互通信
Smaller icon

当机器A上的进程调用B上的进程时,A的调用进程被挂起,B上被调用的进程开始执行,执行完再将结果返回。通常RPC框架使用JSON或XML序列化数据,以提高数据存取和通信

采用Pub-Sub机制的分布式消息系统,具有极高的消息吞吐量,支持消息传递至少到达一次

整体架构

由三类角色组成:消息生产者(producer),代理服务器(Broker),消息消费者(Consumer)

当组件是被connect绑定redux后,可以使用getWrappedInstance()获取组件的原型,但需要给connect添加{ withRef: true }选项才能使用

  • connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

其中mergeProps(stateProps, dispatchProps, ownProps)是用于特定情况下,修改提供给组件的props

1
2
3
4
function mergeProps(stateProps, dispatchProps, ownProps) {
//默认情况下返回
return Object.assign({}, ownProps, stateProps, dispatchProps)
}

需要添加的{ withRef: true }选项要放在connect的第四个参数

###example

使用connect绑定redux的后test组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import {connect} from 'react-redux'
import {Component} from 'react'
export default class Test extends Component {
constructor(props) {
super(props);
}
testFunction =(test='1')=>{
alert(test)
}
render() {
return (
<div>test</div>
)
}
}
function mergeProps(stateProps, dispatchProps, ownProps) {
return Object.assign({}, ownProps, stateProps, dispatchProps)
}
export default connect({}, {},mergeProps,{withRef:true})(Test)

获取test组件的原型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import {Component} from 'react'
import Test from './Test'
export default class Test2 extends Component {
constructor(props) {
super(props);
}
componentWillMount(){
//使用connect提供的getWrappedInstance()
this.refs.test.getWrappedInstance().testFunction('test')
}
render() {
return (
<div><Test ref='test' /></div>
)
}
}

image概念

Smaller icon

Remote docker hub 集中存储镜像的web服务器地址

Namespace 命名空间,存放一类镜像

Repository 一个镜像仓库,使用tag区分

Tag 类似的git中的Tag,表示镜像版本

使用image

  • 列出本机镜像:
1
2
3
4
$ docker images
```
可以使用--filter过滤结果,例如--filter "dangling=true"选出悬挂镜像(没有对应名称和tag,其上层不会被任何镜像依赖,通常可删除)

//删除悬挂镜像
$ docker image –filter “dangling=true” -q|xargs docker rmi
```

创建镜像

使用DockerFile built: docker build -t nginx-node:6.9.2 .

将容器commit: 使用docker ps查看容器id,在docker commit id nginx:version

导入镜像

下载镜像: docker pull busybox

导出镜像: docker save nginx:version >nginx.tar

导入镜像: docker import(导入包含根文件系统的归档),docker load(一般导入由docker save导出的镜像)

find

1
2
3
4
5
db.c.find() 匹配集合所有文档
db.users.find({age:27}) 查找特定键值的文档
db.user.find({},{username:1,email:1}) 返回指定的键 默认有_id,加_id:0剔除
操作符 含义
$lt <
$lte <=
$gt >
$gte >=
$OR
$in
$not 元条件句,用在其他条件之上
$inc 自增 {$inc:{age:1}} 自增一
$all 使用多个元素匹配数组
$slice 返回指定位置的数据 {$slice:”10”}

查询内嵌文档

精确匹配 查询条件与子文档完全匹配

点表示法 进入内嵌文档内部查询 db.people.find({name.first:’joe’,name.last:something})

模糊查找 $elemMatch 对内嵌文档使用操作符查找 db.blog.find({comments:{$elemMatch:{author:joe,score:{$gte:5}}}})

skip

  • 当数据量大时,使用skip会很慢,mongo还不支持在索引中保存太多的元数据

利用上次结果来计算下次的查询条件

koa-csrf

Cross-Site Request Forgery 跨站请求伪造

koa-csrf

原理

它在session中保存一个secret字段,然后使用它生成token,其中salt是随机生成的字符串,长度可自定。每次请求时都会重新生成salt,于是每次token也会不同。

1
2
3
4
5
var hash = crypto
.createHash('sha1')
.update(salt + '-' + secret, 'ascii')
.digest('base64');
token = salt + '-' + hash;

验证的时候,只需要取出token头部的salt,再从session中取出secret,再生成expected,与token对比

默认不检查GET,HEAD,OPTIONS请求

使用

与session配合使用,在请求时附带字段_csrf:token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var koa = require('koa')
var csrf = require('koa-csrf')
var session = require('koa-session')
var Router = require('koa-router');
var bodyParser = require('koa-bodyparser');
var app = koa();
var router = Router();
app.use(bodyParser());
app.keys = ['session secret']
session(app)
app.use(csrf());
router.get('/', async ctx => {
ctx.body = ctx.csrf;
})
router.post('/', ctx => {
ctx.body = ctx.request.body
});