挂一部分机器,不会丢数据、不会不可服务,是对古代数据库的一个比拟根本的要求。
对于晚期的单机数据库,个别应用主备架构。主备架构有很多的缺点,并且这些缺点是无解的。穿过主备架构里各种“优化”的名词,最初也无非是抉择一碗毒药而已,这几个毒药包含:
- 脑裂,两个节点同时写入的抵触数据无奈合并,只能丢掉一部分。想要不脑裂?那只能就义可用性。
- 同步复制,备机不可用的状况下,算不算写入胜利?算,可能丢数据;不算,备机不可用 == 集群不可用,就义可用性。
- 异步复制,这齐全躺平了,不思考一致性。
- 所谓 semi-sync 等计划,也属于主备架构的一种。
- 业务本人去容错,做针对本人业务场景的对账、弥补等计划。
其实能够看出,主备架构是 CAP 实践做取舍的重灾区,一致性和可用性之间的关系特地矛盾。所谓一致性和可用性“兼顾”的主备计划,实际上是“兼不顾”。
最佳实际:在这个时代,凡是数据有肯定的重要性,都不应该抉择主备架构的产品。
分布式数据库,除了扩展性之外,解决传统数据库主备构造的容灾问题也是其次要工作。Paxos\Raft(包含其余变种协定)成为了支流抉择。其共通点是,每份数据会存在三个正本,并且可能保障在一个正本挂掉的状况下,不影响可用性,并且不会呈现任何一致性问题(脑裂、丢数据、丢更新等)。
本文无心去解析 Paxos\Raft 协定,此类文章已多如牛毛。但有个疑难是,是否一个数据库只有应用了 Paxos\Raft 协定,那就肯定是平安稳固牢靠的呢?
咱们将探讨几个问题:
- 除了协定自身,还有什么样的因素影响分布式数据库的可用性
- 如何计算不同架构的分布式数据库的可用性
- KV 层的可用性和关系型数据库的可用性是否等价
- 数据库的可用性和利用的可用性是否是等价的
从 1 +1= 2 说起
咱们先从一个最简略的例子说起。如果有以下的数据库构造:
请问,当挂一个节点和两个节点的状况下,可用性别离是?不言而喻,挂一台机器的状况下,可用性是 100%;挂两台机器的状况下,可用性是 0%,所有数据都不可用,如果这两台机器被彻底的捣毁,那代表所有数据都失落了。
调度就是一个填图游戏
如果咱们有 6 台机器,咱们想将数据库部署在这 6 台机器上,进一步晋升扩展性和容灾性:
- 为了晋升扩展性,咱们会对数据进行分片
- 每个分片须要存在三个正本
- 为了保障容灾,每个分片的三个正本须要调配在不同的机器上
如果咱们把数据切成了 12 个分片,共有 12*3=36 份正本:
上面咱们来做一个填图游戏,将下面的正本填充到上面的 6 台机器中(需满足下面的束缚,并且每台机器调配到 6 个正本),你能想到多少不同的填充形式:
模型 1,齐全的随机调度
咱们平均的将 12 个 leader 正本扩散在集群中,每个节点调配到两个 leader 正本,除了这两个限定条件,分片与分片之间的调度是无关系的。
目前市面上常见的应用分布式 KV+SQL 的分布式数据库,个别应用的都是此类模型。
这种状况下,如果挂两台机器,咱们剖析下会是什么样的状况。例如,节点 1 和节点 2 同时宕机,因为 p1、p6 均有两个正本在这两个节点上,因而 p1 和 p6 处于不可用的状态。咱们枚举一下可能呈现的状况:
一个比拟直观的事实:在此模型下,任意挂两台机器,均会导致局部数据不可用。
设分片数不是 12 而是 M,机器数不是 6 而是 N,咱们做几个简略的计算:
以一个 N =50 节点的集群为例,咱们看一下 m 的取值与可用性的概率关系:
能够直观发现,可用性会随着 m 的增长,迅速降落。当 m =1(每个机器只存一个正本的状况下),可用性最高,达到 96%。
什么状况下 m 会变大?
如果设计数据库时,将单分片的大小限定的比拟小,例如单个分片 96M,那么 m 就容易十分大(50 个 96M 大概只有 5 个 G 的数据,每个节点只存 100G 的数据,也有 1000 个分片了)。
模式 1 下,各分片(或者说各 Paxos 协定组)的正本散布不足协调,如果单节点分片数略多,只有同时挂两台或者更多机器,简直肯定会有一部分数据不可用或者失落。
数据可用性!= 业务可用性
回到下面的例子中来,12 个分片中,有 2.4 个不可用,如同也能够嘛,毕竟挂了 33% 的机器嘛,是不是只影响了 20% 的业务?
咱们须要明确的是,20% 的不可用,仅仅的指数据层面的。例如咱们把它设想成一个 KV 数据库,那么的确,对于这个 KV 数据库来说,“只有”20% 的数据不可用。
但!数据的可用性和业务的可用性很多时候是不等价的!
第一个点不言而喻,不可用的背地,一种状况是数据失落,对于有的业务来说(例如存银行的账户余额),无论失落的比例有如许的低,都是无奈承受的。对于此类业务,失落的概率必须有限趋近于 0。
第二个点则更为费解。
咱们晓得,绝大多数业务,不会间接拜访 KV 数据库的。个别状况下,咱们会在 KV 之上构建一个关系型数据库。关系型数据库比 KV 数据库多了两层概念,表和索引。从业务角度来看,一次业务申请,会操作多个表的多个索引。
例如,业务接到某个 HTTP 申请后,会执行这样一段操作:
begin; ## 依据 user_id 上的索引查问一下用户的余额,并且这个查问还须要对主键进行一个回表(波及到 2 个 key)select * from user_info where user_id=xxx; ## 依照 item_id 对库存进行扣减(波及到 1 个 key)update items set count=count-1 where item_id=xxx ## 向订单表 orders 中写入一条记录(留神,orders 表还有 5 个二级索引,所以等于要写 6 个 key)insert into orders xxx; commit;
这次 HTTP 申请的解决中,一共波及了三张表的 9 个索引(主键或二级索引)的 9 个 key,并且这 9 个 key 之间没有任何的关联关系,也就是说,他们是平均的散布在集群中的。
尽管每个 key(也即 key 所在的分片)的可用性“高达“80%,但指数是一个可怕的货色,它会放大你所有的坏运气,9 个 key 运气都很好,全副可用的概率只有 0.89=13% 也即,从业务角度看,HTTP 申请的成功率只有 13%,失败率 87% 了。87% vs 20%,这就是业务最终看到的不可用性与 KV 层看到的不可用性。
两个论断:
- 关系模型(表、索引)的引入,会指数放大 KV 层的不可用性
- 个别业务会在一次申请内操作多个表、索引、Key,会持续指数放大 KV 层的不可用性
模型 2,分片之间存在肯定的绑定关系的调度
在模型 1 中,m 的值回升后,因为指数关系,可用性会迅速降落。如果 M 仅与节点数 N 相干,而与单节点正本数 m 无关,则能将可用性维持在一个比拟好的数字上。
在模型 2 中,咱们将节点每三个组成一个组,每个组的每个节点,所蕴含的正本来自雷同的分片,如上图所示。p1-p6、p7-p12 各属于一个组。咱们枚举一下可能呈现的状况:
计算下,任意挂两台机器,齐全可用或者不丢数据(不存在不可用或者丢数据的分片)的概率为:
咱们能够看到,随着机器数的减少,可用性会迅速减少,20 个节点的时候便能超过 90%。
模型 2 绝对于模型 1,不同分片(或者说不同 Paxos 协定组)之间的调度有了肯定的绑定关系,使其变成了仅与节点数成线性关系的量,显著的晋升了可用性。
留神,这里说的“组”,不是平时说的 Paxos 组、Raft 组之类的概念,它是一种调度上的概念。一个直观的形容,节点、“组”、Paxos\Raft 组、分片之间的关系:
- 节点与“组”:3 对 N,N>=1,也即 1 个“组”蕴含 3 个节点,一个节点可能属于多个“组”
- “组”与 Paxos\Raft 组:1 对 N,N>=1
- Paxos\Raft 组与分片:通常状况下是 1 对 N,很多数据库实现是 1 对 1
在有“组”概念的数据库里,它有不同的名字。例如对于 PolarDB- X 来说,他对应的是“DN”这个名字,每个 DN 领有三个节点(三个过程),每个 DN 有一个 Paxos 组,每个 DN(Paxos 组)有若干分片。
表组 & 本地索引
模型 2 很大水平上升高了单分片故障的危险,然而,上文中咱们说过,业务申请中的多个事务、多个表、多个索引,都会放大这个不可用性。对于稳定性要求特地高的业务,分布式数据库须要提供更多能力来进一步升高此类危险。
PolarDB- X 应用表组技术来解决此类问题:
PolarDB-X:PolarDB-X 数据分布解读(四):通明 vs 手动
其外围思路是,将同一次业务申请中波及到的数据,尽量绑定在一起,调度到类似的地位上,这样其可用性不会受波及到的数据量指数影响。
例如,某业务有用户这个概念,那么在 PolarDB- X 中,能够应用分区表、表组、本地索引等工具,将一个用户波及的多个表(例如用户详情、操作日志、地址列表等)、多个记录、多个索引绑定在同一个 DN 上。
如咱们《PolarDB-X 数据分布解读(四)》中所说,这实际上是数据库手动模式的一个利用。数据库须要提供更多的工具来达成外围业务对稳定性和数据安全性的要求。
自建 vs 云服务
在云上,自建的分布式数据库会存在一些额定的问题。
云上自建,通常状况下,咱们会购买一批的 ECS,在 ECS 上部署分布式数据库。
这里一个很大的危险点是,ECS 都是虚拟化的(除非购买独享物理机的那种超大规格),一台物理机上会虚拟化出多台 ECS,而作为一般的云用户,是无奈感知到 ECS 的调度策略的。
例如,多个节点,甚至同一份数据的多个正本所在的 ECS 会在一台物理机上:
这种节点的物理散布,自建数据库是无奈感知,也无法控制的。
此外,自建还容易呈现如下问题:
- 同一个物理机上,多个数据库节点的 IO、网络带宽争抢等问题
- 买到的同 CPU 内存规格的 ECS,可能对应不同的 CPU 型号,性能之间存在差别
以上问题,会极大的减少云上自建分布式数据库的故障危险和概率。
通常状况下,有以下几种解决形式:
1. 三可用区部署。因为不同可用区的 ECS 必定在不同的物理机上,通过数据库外部的 locality 等能力,能够确保对于同一个分片的三个正本不在同一台物理机上。毛病是:
- 仍然无法控制同可用区内的物理散布状况
- 多可用区带来的响应工夫的变动
2. 购买独立的物理机规格的 ECS。齐全本人运维物理机外部的虚拟化、隔离、节点散布等。毛病是:
- 贵
- 运维要求很高
- 对于机架、交换机等仍然无法控制
云厂商提供的分布式数据库服务则能很好的解决此类问题。例如云上的 PolarDB- X 服务会做到以下几点:
- 同一个集群的所有节点肯定都在不同的物理机上、不同的机架上
- 同一个集群的所有节点应用的物理机的 CPU 等型号都是统一的
云上自建数据库,会面临更多的稳定性危险。云上自建分布式数据库,此类危险会指数回升。
最初
模型 1 因为看起来十分的洁净、很容易做到分层清晰(每个分片能够自在调度,也不必思考索引之间的地位关系),特地适宜做一些数据库畛域的玩具级我的项目。但用在关系型数据库(因为大量的表、二级索引会急剧放大这种效应)中,是一种典型的“驴粪蛋,表面光”。在面临多机故障的状况下,其不出问题的概率会随着数据量和节点数的增长迅速降到 0(趁着没出事,快跑路吧!)。
模型 2 则更适宜生产级的数据库应用。如果读者要应用分布式数据库,倡议认真甄别其是否有相似模型 2 的调度策略。
表组、本地索引等能力也是生产级数据库不可或缺的。这些能力的正当应用,会防止指数级放大不可用性。对于稳定性要求更高的利用,须要抉择有这些能力的数据库。
当初咱们能够答复文章结尾的几个问题了。
- Paxos\Raft 协定是基本,协定上有问题根本跟数据安全就没啥关系了。
- 只有协定也是万万不行的,如果短少有绑定关系的调度策略、表组、本地索引等能力,都会极大的影响最终业务层看到的可用性。
- 关系模型、业务对数据库的应用逻辑等,都会成指数的放大 KV 层的不可用性。
欢送大家继续关注,咱们会在后续的文章里,带来更多生产级数据库在设计与计划抉择上的一些思考。
本文作者:梦实
原文链接
本文为阿里云原创内容,未经容许不得转载。