分布式数据库理论知识
前言
分布式数据库作为一个新兴基础软件,还没有一个相对的标准的来定义它,但我们可以从两个视角来观察。
外部视角
业务系统划分
- OLTP:面向交易的处理过程,需要在很短时间给出结果
- OLAP:基于大数据集的运算
分布式数据库特点
针对OLTP场景关系型数据库:
- 写多杜少,读操作复杂度较低,一般不涉及大数据集汇总
- 低延时,用户对于延时容忍度低,一般500ms内
- 高并发,伴随业务量增长,没有理论上限
- 高可靠,从恢复时间目标RTO(故障恢复所花费时间),恢复点目标RPO(服务恢复后丢失数据的数量)
- 海量数据存储能力
内部视角
- 客户端组件+单体数据库:shardingJdbc
- 代理中间件+单体数据库:MyCat
- 单元化架构+单体数据库:需要业务拆分
强一致性
分布式数据库一致性主要指数据一致性和事务一致性
数据一致性
主要关注点是单对象,单操作在多副本上的一致性
- 从状态一致性角度:数据所处的客观,实际状态体现的一致性;任何变更操作后,数据只有两种状态,副本一致或不一致。对应强一致和弱一致。永远不一致不会去讨论
- 从操作一致性角度:外部用户通过协议约定的操作,能够读取数据一致性。弱一致定义比较含糊,一段时间是不确定的值,从操作视角可分为常见5个一致性模型:
- 写后读一致性:从自己角度写入数据,下一刻一定读取到这个数据
- 单调读一致性:一个用户一旦读到某个值,不会读到比这个值更旧的值。常出现在多副本同步不一致,导致读取数据不一致
- 前缀一致性:因为网络等原因导致的副本节点对数据的存储发生顺序性问题。比如评论1和评论2顺序错误。这种考虑在原有评论数据上增加一种显式因果关系
- 线性一致性:建立在事件的先后顺序上,整个系统好像只有一个副本,所有操作在一条时间线上,而且被原子化。为了使集群中各个节点做到真正时钟同步,那么需要一个绝对时间全局时钟,现在大多数主流分布式数据库如:TiDB,OceanBase,Spanner等;多数使用单点授时TSO,获取服务时间。(只适用于经典物理场景,非时间相对论)
- 因果一致性:基于偏序关系,节点内部依靠节点本地时钟;节点间依靠数据接收先后顺序进行判断
事务一致性
事务一致性更多关注的是多对象,多操作在单副本上的一致性
BASE理论是一个很宽泛的定义,承诺很有限,放弃量一些ACID的特性从而简单地实现了高性能和可用性
广义的事务一致性被细化为ACID四个方面,原子性的实现依赖于隔离性并发控制技术和持久性日志技术
最早的隔离级别定义是ANSI SQL-92,也就是我们平时常说的未提交读,已提交读,可重复读,可串行化。主要基于锁的并发控制。而Critique是更严谨的隔离级别,定义了6种隔离级别,8种异常现象。其中幻读的处理还可以依靠快照隔离,但是无法解决写倾斜的问题
写倾斜
事务T1和事务T2对同一区间数据进行相反的修改,可能得到不是目标的结果
隔离性是事务的核心。降低隔离级别,其实就是在正确性上做妥协,将异常现象交由开发人员去解决,从而获取更好的性能。除了串行化,都有无法处理的异常现象
可提交读,可重复读,快照隔离,是大多数单体/分布式数据库普遍提供的,可串行化在少数产品才有提供
架构风格
分布式数据库大多分为两种架构
- NewSQL,比如Google Spanner
- 从单体数据库中间件基础演进而来,被称为Prxoy风格
数据库的架构
- 客户端通信管理器:负责客户端的连接管理
- 进程管理器:也可能是线程,负责客户端发送所有操作的处理
- 查询处理器:对sql进行解析,重写优化,算法优化,执行
- 事务存储管理器:四个部分,访问方式(数据在磁盘具体存储形式);锁管理(并发控制),日志管理(数据持久性),缓存管理(I/O相关缓存管理)
- 共享组件和工具
PGXC单体数据库自然演进
单体数据库面临高并发场景写入性能不足问题,简单直接使用分库分表来实现,在多个数据库前增加代理节点来路由数据
代理节点不仅仅是路由数据
- 代理节点增加分布式事务组件实现跨库事务
- 代理节点增强查询计算能力,支持多个单体对全局性查询需求
- 增加全局时钟最后一块,就形成了有协调能力的
NewSQL
放弃数据库事务处理能力,将重点放在存储和写入能力,高可靠上,这个能力基础是分片,实现更小粒度单元,使用LSM-Tree替换B+Tree模型,大幅提升存储引擎能力
全局时钟
授时机制需要抓住3个要素
- 时间源:单个/多个
- 使用时钟类型:物理时钟/混合逻辑时钟
- 授时点:一个/多个
常见授时方案
3要素可以产生8种可能性,但是真正能用到实践的方案,常见的有4种:
- TrueTime:基于GPS和原子钟时间源,采用多点授时机制的物理时钟类型。缺点-物理时钟,多点授时带来的误差;优点-去中性化带来的高可靠,高性能
- HLC:混合逻辑时钟,多时间源,多点授时。
- TSO:单时间源,单点授时,优点-实现简便,保证时钟单调递增,简化事务冲突时设计。缺点-集群不能大范围部署,同时性能也有上限
- STP:巨杉的单时间源,多授时点
TIDB
TIDB的全局时钟由两部分构成:高位物理时间(操作系统毫秒时间);低位逻辑时间,18位数值。TIDB提供的多个节点构成Raft组,通过共识算法可以保证主节点宕机快速选主,短时间快速恢复授时服务。通过预申请时间窗口来分配时间戳,保证新主产生时间戳一定大于旧主。客户端缓存时间戳会造成不再是严格意义的单调递增
分布式授时HLC
// todo
分片
分区是将数据表按照策略切分成多个数据文件,这些文件仍然在单节点上;分片进一步将切分好文件分布到多个节点上
PGXC的hash能够过滤原有数据业务特性,保证数据均匀分布到多个分片,但是对动态扩展不友好,Range静态分片能够对业务的预估,并且高效的对数据进行扫描,但受制于单体数据库,很难变动数据和应对负载变化
NewSQL动态分片:
- 当单个分片数据量超过设定值时,分片可以一分为二,多个数据量较少时,会在一定周期内合并为一个分片
- 可以根据访问压力调度分片
NewSQL通过Group,一个主副本多个副本组成,通过共识算法完成数据同步,每个group独立运行,共享网络,节点资源,不同group主副本分布在不同节点;PGXC最小可靠单元由一个主节点,多个备节点组成set,set主备节点间复制,多数采用半同步复制,平衡可靠性和性能,所有节点主副本必须运行在set主节点
元数据的存储
静态分片,将元数据复制多份放在对应工作节点,兼顾性能和高可靠,即使协调节点是工作节点,随着集群规模扩展,导致元数据副本过多,但由于哈希分片基本属于静态分片,也不用考虑多副本一致性问题,TBase就是这样;
但是对于要更新分片时,因为副本过多,数据同步的代价过大的问题,TIDB通过paxos协议复制数据在小规模集群进行传输。TiKV存储分片数据,PD存储元数据,TiKV定期主动向PD报送元数据心跳,PD将分片调度指令放在心跳返回信息中。等TiKV下次发送心跳时,PD就能了解调度执行情况。由于心跳包含全量分片元数据,PD都不用持久化元数据,仅仅可能作为缓存而已;适用于副本少,参与节点少情况
CockroachDB基于Gossip的去中性化P2P架构,每个节点保存完整元数据,通过小范围传播实现最终一致性,在节点请求过程中不断更新元数据,促成各节点元数据达成一致;适用于副本多,节点多情况
//todo Raft,Paxos对数据复制效率对影响,Raft的阻塞优化,并x
原子性保证
tcc仅仅是应用层的分布式事务框架,依赖于业务编码实现,对业务侵入比较深。而且要求tcc操作是幂等操作;
2pc的问题是由于要锁定对应数据行,会造成同步阻塞的问题;而且事务管理器一旦故障,会发生单点故障的问题;最致命的是在最后一个阶段commit的时候如果出现网络问题,会导致部分数据未收到请求而导致数据不一致的问题
GoldenDB和Percolator对2pc的优化
使用了XA事务的延迟是单机事务的10倍以上,优化方法:
- 缓存写提交:将所有写操作缓存起来,直到commit时一起执行
- 缺点:长事务,海量并发撑爆内存 2事务间竞争由fisrt write win变成first commit win
- pipeline:准备阶段按照顺序将sql转为k/v操作,但并不等待返回结果,直接执行下一个k/v操作
- 并行提交,不要纠结于一次事务中搞定所有事情,做最少的工作,留下必要的线索,后续通过异步进程,完成收尾工作