分布式系统中的CAP理论

前言

一个分布式系统, 我们要关注的是它的可用性、一致性、分区容错性

  1. Consistency 一致性
  2. Availability 可用性
  3. Partition tolerance 分区容错性

什么样的系统适合CAP理论

在了解什么是CAP之前, 我们先来看看什么样的系统适合CAP理论.

参考资料里的所有英文文章得知

  1. Silverback提到A distributed system (generally running in a datacenter).
  2. Wikipedia提到A distributed data store.
  3. IBM只提到了a distributed computer system.
  4. Robert Greiner一开始提到any distributed system, 两个月后重新定义为In a distributed system (a collection of interconnected nodes that share data.)

大家都认为, 分布式系统才适合CAP理论, 但是, 不是所有分布式系统都适合.
Robert Greiner强调了这个分布式系统是interconnected互联和share data共享数据的.

举一个反例, 比如Memcache集群.
Memcache集群
Memcache的各个节点之间是不互联和共享数据的, 客户端根据路由规则, 自行决定存储数据到哪个节点上.
这确实是一个分布式系统, 但是却不适用于CAP理论.

举一个正例, 比如MySQL集群.
MySQL我们熟, 主从复制, 就是interconnectedshare data.

In a distributed system (a collection of interconnected nodes that share data.)

所以这里还是以Robert Greiner的文章为准, 一个互联且共享数据的节点集合, 才是适用CAP的分布式系统.

什么是CAP

我们假设一个分布式系统有4个终端, 数据库DB1DB2以及应用端App1App2.
分布式系统
假设有数据a=1

C 一致性

参考资料里的所有英文文章得知

  1. Silverback提到all nodes have access to the same data simultaneously.
  2. Wikipedia提到Every read receives the most recent write or an error.
  3. IBM提到where all nodes see the same data at the same time.
  4. Robert Greiner一开始提到All nodes see the same data at the same time., 两个月后重新定义为A read is guaranteed to return the most recent write for a given client.

在客户端看来, 每次读都要能读到最新写入的数据.
举个例子, 如果App1DB1写入数据a=2, 然后从APP2DB2得到数据a=2, 对于客户端来说, DB1DB2的数据保持一致.

但是实际情况下, 对于这个最新写入的理解, 是不同的.
同一时刻, 不同节点可能拥有不同的最新数据.
我举个例子, 在事务执行过程中, 不同的节点的数据并不完全一致.

App1 App2
start transaction
update t set a = 2
t1 select a from t(a=1)
t2 select a from t(a=2)
commit
t3 select a from t(a=2)

t1t2时刻, App1能读到最新写入的a=2的数据. App2能读到最新写入的a=1的数据.
此时, App1的事务还没有提交, 对于App2来说, App1的写入的数据是感知不到的, App2的最新数据还是a=1.
等到t3时刻, App1提交事务后, App2才能读到最新的a=2.

如果App1的事务回滚了, 那么App2是不知道a=2这个事件发生过的.

A 可用性

参考资料里的所有英文文章得知

  1. Silverback提到a promise that every request receives a response, at minimum whether the request succeeded or failed.
  2. Wikipedia提到Every request receives a (non-error) response, without the guarantee that it contains the most recent write.
  3. IBM提到which guarantees that every request receives a response about whether it succeeded or failed..
  4. Robert Greiner一开始提到Every request gets a response on success/failure., 两个月后重新定义为A non-failing node will return a reasonable response within a reasonable amount of time (no error or timeout).

SilverbackIBMRobert Greiner都认为只要每个请求能收到响应, 无论是成功还是失败, 就算满足可用性.
Robert Greiner的第二篇文章和Wikipedia则认为请求要返回合理的成功的响应, 无论数据对错. 也就是说, 可用性的定义更严格一点.

我个人赞同第二种观点, 成功和失败的定义太广泛. 请求超时、错误也算失败的响应, 但这算可用吗? 我认为是不可用的.
比如App1读取DB1的数据

  1. 得到正确的数据a=1, DB1是可用的.
  2. 得到错误的数据a=111, DB1是可用的.
  3. 得到connection timeout, DB1是不可用的.

P 分区容错性

参考资料里的所有英文文章得知

  1. Silverback提到the system will continue to work even if some arbitrary node goes offline or can’t communicate.
  2. Wikipedia提到The system continues to operate despite an arbitrary number of messages being dropped (or delayed) by the network between nodes.
  3. IBM提到where the system continues to operate even if any one part of the system is lost or fails..
  4. Robert Greiner一开始提到System continues to work despite message loss or partial failure., 两个月后重新定义为The system will continue to function when network partitions occur.

分区容错性就是当网络发生分区的时候, 集群能够继续完成工作, 返回合理的成功的响应.
网络分区是一种现象, 举个例子, 就是DB1DB2之间的通信断了, 主从复制失败.

总结

C: 对客户端来说, 读操作保证能够返回最新的写操作结果. 这就是一致性.
A: 对客户端来说, 非故障的节点在合理的时间内返回合理的响应, 不是错误和超时的响应. 这就是可用性
P: 对集群来说, 当出现网络分区后, 系统能够继续返回合理的响应. 这就是分区容错性

那么CAP能同时做到吗?

正常情况下是可以的, 我们说的只能三选二的情况一般都是网络故障的时候, 才会进行取舍.
还是以这张图为例
分布式系统
因为网络的不可靠性, **P分区容错性是一定要保证的.
那么当DB1DB2之间的网络发生故障, 此时就要对
AC**进行取舍.

  1. 保障**A**, App能正常读写DB1DB2, 但是一旦进行了写入操作, DB1DB2是不能进行通信做主从复制的, 换句话说, 就会导致数据不一致的情况.
  2. 保障**C**, 那么为了保证数据一致性, App就应该等待DB1DB2之间的网络恢复, 这样就不能访问数据库了, 舍弃了可用性.

那有人问, 能不能只保证**AC?
可以啊, 我们把两个数据库都放在一台服务器上, 这样就不会因为网络分区导致
AC**二选一的问题了, 因为根本没有网络.
但是这还能叫做分布式吗?

参考资料