CAP为何不能同时满足
一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)这三项中的两项。
- 网络分区是必然存在的
网络分区是指分布式系统中节点之间因网络故障被分割成多个孤立的子集,子集内部通信正常,但子集之间完全无法通信。
- 网络不通,肯定可以导致网络分区。
- 网络延迟,只有达到心跳超时才会导致网络分区。
只要系统是分布式的,就必须接受网络分区的可能性。
如果不能容忍分区就只能干掉所有进程了:只有不运行的集群,才能杜绝网络分区的可能。
CAP 并非“三选二”:实际系统中,C 和 A 的取舍是动态的:
- 无分区时:可以同时满足 C 和 A。
- 分区发生时:只能 C 和 A 中二选一。
- 在分区发生时,C和A必然冲突
关键矛盾:在分区期间,系统无法同时做到:
- 所有节点数据一致(C)(需要节点间同步)。
- 所有请求立即响应(A)(必须容忍节点独立响应)。
以一主两从的pg集群来解释CP和AP:
- CP:向主库提交的更新,必须等到两个从库都同步成功后,这个请求才能够返回。
- 当网络分区发生的时候,这个更新的请求就会返回失败或者超时,也就是不满足A。
- AP: 向主库提交的更新结束后立马返回,在两个从库数据同步成功之前,数据是不一致的。
- 当网络分区发生的时候,从库同步数据就会失败,这就无法满足C了。
CAP本质上就是发生分区时,倾向一致性还是倾向可用性,并不能保证100%一致和100%可用。
- 脑裂风险:分区可能导致多个子集群独立选举主节点,即使后续恢复,数据合并可能冲突(如Raft协议需人工干预解决分歧)
- 分布式一致都是概率性一致,最终一致(使用消息队列),半一致(例如raft协议)。最终一致性可能不是自动的,可能是人工补数据最终一致性。
- 分布式可用都是概率性可用,部分可用(例如服务降级、服务限流、服务熔断)。
分布式系统重度依赖监控,发生脑裂了,CPU和内存满了,及时通知人工干预。
两台机器,数据库使用主从,主从自动切主,能实现高可用么?
仅仅是两台机器,互相ping不通,主认为自己是好的,从又连不上主,咋自动切呢?这是个伪命题啊。
三台机器,才能实现高可用,因为有一个人仲裁;2台机器,无法自己切主,因为都说自己是好的,也就是常说的“脑裂”。
好比夫妻吵架,谁对谁错?除非有一条法律说:老婆一定是对的。
shared-disk和shared-nothing
shared-disk:所有节点都使用了同一块“逻辑磁盘”,所以双主可写想都不要想,只能使用主从方案。PolarDB 和 Aurora 和 Oracle RAC 都属于shared-disk。
shared-nothing:两台物理机,除了网络通信之外,不进行任何资源共享,CPU、内存、磁盘都是独立的。
TiDB和Spanner一样,都是搭建在 KV 数据库集群之上的。
TiDB 底层数据叫分片,那 OceanBase 为什么叫分区呢?因为分片的意思只是数据被分开了(本身 KV 数据之间也没关系),但分区表示的是分区内部的数据之间是有联系的:OceanBase 的每个节点本身,依然是一个关系型数据库,拥有自己的 SQL 引擎、存储引擎和事务引擎。
OceanBase 在建表时就需要设定数据分区规则,之后每一行数据都属于且仅属于某个分区。在数据插入和查询的时候,需要找到这一行数据所在的区,进行针对性地路由。这和分库分表中间件(sharding-proxy)的思想一致。分区之间,通过 Multi-Paxos 协议来同步数据:每一个逻辑分区都会有多个副本分布在多台机器上,只有其中一个副本会成为 leader,并接受写请求,其他副本接受读请求。
OceanBase 数据库的存储引擎基于 LSM Tree 架构,将数据分为静态基线数据(放在 SSTable 中)和动态增量数据(放在 MemTable 中)两部分,其中 SSTable 是只读的,一旦生成就不再被修改,存储于磁盘;MemTable 支持读写,存储于内存。数据库 DML 操作插入、更新、删除等首先写入 MemTable,等到 MemTable 达到一定大小时转储到磁盘成为 SSTable。在进行查询时,需要分别对 SSTable 和 MemTable 进行查询,并将查询结果进行归并,返回给 SQL 层归并后的查询结果。当内存的增量数据达到一定规模的时候,会触发增量数据和基线数据的合并,把增量数据落盘。同时每天晚上的空闲时刻,系统也会自动每日合并。简言之:OceanBase 用内存 B+ 树和磁盘 LSM-Tree 共同构成了数据读写体系。
分库分表中间件(sharding-proxy),也会做一些并行查询,但是他们做的都是纯客户端的查询:proxy 作为标准客户端,分别从多台机器拿到数据之后,用自己的内存进行数据处理,后端数据库之间无通信。OceanBase解决了这个问题:在某台机器上的 proxy(OBServer) 接到请求以后,它会担任协调者的角色,将任务并行地分发到多个其他的 OBServer 上执行;同时,将多个子计划划分到各个节点上以后,会在各节点之间建立 M*N 个网络通信 channel,并行地传输信息。
本文发表于 0001-01-01,最后修改于 0001-01-01。
本站永久域名「 jiavvc.top 」,也可搜索「 后浪笔记一零二四 」找到我。