主从复制
集群中有一个主节点,写操作都必须经过主节点完成,读操作主从节点都可以处理。
同步复制
数据在副本上落盘才返回。
优点:保证在副本上的数据是最新数据。
缺点:延迟高,响应慢。
异步复制
数据不保证在副本上落盘。
优点:延迟低
缺点:不能保证在副本上的数据最新。
不能把集群中所有节点设置为同步节点,因为这样的话任何一个节点的停滞都会导致整个集群的不可用。像Paxos、Raft算法,都要求集群中大多数节点返回就可以了。部分同步、部分异步的集群配置成为半同步(semi-sync)的集群配置。
新增从节点
主节点生成快照数据
主节点将快照数据发送到从节点。
从节点请求主节点快照数据之后的数据。
重复上面三步直到从节点追上主节点的进度。
处理节点失效
从节点失效
从节点崩溃恢复之后按照前面新增新的从节点的步骤来追上主节点的数据进度。
主节点失效
主节点失败时需要提升某个从节点为新的主节点,同时需要通知客户端新的主节点。
自动切换主节点的步骤通常如下:
确认主节点失效。大部分系统采用基于超时的机制,主从节点直接发送心跳消息,主节点在某个时间内都没有响应,则认为主节点已经失效。
选举新的主节点。通过选举的方式(超过半数以上的从节点达成共识)来选举新的主节点,新的主节点是与旧的主节点数据差异最小的一个,最小化数据丢失的风险。
重新配置使新的主节点上线。
除了以上步骤之外,还有以下问题需要考虑:
如果使用异步复制机制,而且在失效之前,新的主节点并没有收到旧的主节点的所有数据,那么在旧的主节点重新上线之后,未完成复制的数据将被丢弃。
可能会出现集群同时存在两个主节点的情况,也就是所谓的脑裂(split brain)现象,此时两个主节点都认为自己是主节点并且都能接收客户端的写数据请求,会导致数据丢失或者破坏。
如何设置合理的超时时间来判断主节点失效?如果太大意味着总体恢复时间长,如果太小意味着某些情况下可能主节点并未失效但是被误判为失效了,比如网络峰值导致延迟高等原因,这样会导致很多不必要的主节点切换。
上述的问题,包括节点失效、网络不可靠、副本一致性、持久性、可用性与延迟之间的各种细微的权衡,正是分布式系统核心的基本问题。
复制日志的实现
基于语句的复制
主节点记录所执行的每个写请求并将该语句做为日志发送给从节点。但是有些场景并不适合这么做,比如:
调用任何非确定函数的语句,比如NOW()获得当前时间,RAND()返回一个随机数。
语句中使用了自