第五章 数据复制
概述
-
数据复制的目的
-
低延时
-
高可用
-
高吞吐
主从复制方式及故障恢复
-
主从复制过程
-
主节点:可读写
-
从节点:只读
-
日志从主节点同步到从节点
-
复制方式(各自优缺点)
-
同步复制
-
异步复制
-
半同步复制
-
链式复制(待深入)
-
增加从节点步骤:快照+append日志
-
节点故障恢复
-
主节点:选举
-
从节点:日志
-
问题
-
脑裂
-
选举的新主节点数据不全
-
复制日志形式
-
基于语句(缺点)
-
基于行(binlog)
复制滞后(延迟)带来的问题
-
写后(立即)读
-
写入主节点,立即从从节点读。似乎数据丢失
-
实际场景:用户编辑保存个人信息
-
强一致性场景
-
解决方案
-
强制读主节点
-
客户端记录更新时间戳,带入请求;从节点判断是否满足时间戳,否则转移给另一个节点处理
-
单调读
-
第一次读某节点有新数据,第二次读另一个节点没有新数据。似乎数据丢失
-
实际场景:评论列表获取刷新,有评论消失
-
一致性要求弱于写后读
-
解决方案
-
确保同一个用户固定读一个节点(基于userId哈希)
-
前缀一致读
-
实际场景:群聊消息顺序错乱
-
解决方案:见后
主从架构
-
单主节点(如上)
-
多主节点
-
优点
-
高性能
-
主节点切换方便
-
缺点:写冲突问题(单主节点不会存在这种问题),两个存在冲突的写请求访问不同的主节点,写入都成功。如何处理写冲突
-
避免冲突;同一个用户固定访问某个主节点(UserId哈希)(应用最多)
-
LWW:写请求时间戳,最后者获胜。会丢数据
-
逻辑合并;用户提示
-
自动冲突解决算法:CRDT、OT、MPD(待深入)
-
happen-before:
-
服务端下发最新版本号
-
客户端写请求前,必须先发送读请求
-
覆盖低版本写入
-
架构模式(各自缺陷)
-
环形
-
星形
-
全拓扑(常用)
-
日志覆盖顺序问题:版本向量
-
无主节点
-
quorum
-
原则:n个节点,写确认w个,读查询r个,则必有w+r>n
-
缺陷:
-
sloppy
-
时钟偏差
-
写入失败,但已经写入的节点无法回滚。脏数据
第六章 数据分区
-
分区和复制的结合图6-1:一个节点多个分区,其中有主副本分区和从副本分区
-
唯一主键分区策略
-
基于主键(关键字)
-
优点:有序性,区间查询
-
缺点:热点集中(如以时间戳为关键字)
-
基于主键哈希
-
特性和直接用主键相反
-
折中:id+timestamp(Cassandra)
-
二级索引分区
-
基于唯一主键分区(ES,MongoDB)
-
主键分片后,各自维护二级索引,广泛应用
-
优点:写快
-
缺点:读需要聚集,慢
-
基于二级索引分区
-
对二级索引值直接分片(直接法or哈希,类似主键分区)
-
特性和唯一主键分区相反
-
往往异步写操作
-
分区平衡
-
取模的问题:节点数变化,迁移量大
-
固定分区法:分区数远大于节点数
-
动态分区法
-
多节点多分区路由请求策略(需要感知节点和分区映射关系,可能是客户端、路由、节点)
-
客户端任意连节点,若该节点无目标分区则转发给下一个节点
-
引入路由,客户端连路由,路由转发
-
客户端感知分区和节点状态,直连目标节点
-
维护节点和分区映射关系
-
引入独立协调服务 zookeeper
-
分布式协议,集群节点自同步。gossip