从分布式数据库的角度浅析 CAP 理论

501 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

1 CAP 理论

1.1 概述

CAP 即:

  • C(Consistency):一致性
  • A(Availability):可用性
  • P(Partition tolerance):分区容忍性

CAP 理论指的是:一个分布式系统不可能同时很好的满足一致性、可用性和分区容忍性,最多只能较好的满足其中两个。

CAP 是一个较为顶层、较为抽象的理论,结合不同的应用场景是可以延伸出多种不同的理解的。本文主要是笔者从分布式数据库的角度出发,对 CAP 理论的个人理解,如有纰漏与错误之处,欢迎随时指正。

1.2 一致性

在分布式环境下,一致性通常指存储在不同节点中的数据能否保持一致,当其中一个节点被更新后,其他节点能否被同步更新,以保证所有用户访问到的数据都是最新的数据。

对于分布式数据库来讲,我们可以将一致性进一步理解为事务一致性。也就是说以多个节点存储数据时,当对其中一个节点的数据进行了更新后,系统是否能在同一个事务内,完成其它节点的数据更新,如果能做到那我们就视之为强一致性。如果是在当前事务之外,通过异步的方式来更新其它节点数据,这就只能称之为最终一致性( Eventual Consistency )。

1.3 可用性

可用性指的系统必须一直处于可用的状态,能够在有限的时间内返回结果

对于分布式数据库来讲,能够返回结果这样的可用性是最基本的原则,必须满足。在这样的基础上,可用性的概念还可以进一步延伸至高性能,也就是对于数据库的读、写操作,完成的时间越短越好。

1.4 分区容忍性

分区容忍性在分布式系统中的概念,是由于网络故障而使得部分节点无法连通,从而形成了网络上的不同分区,此时的分布式系统若还可以正常提供服务,那么就可以说其具有良好的分区容忍性。

如果从分布式数据库的角度出发,笔者更倾向于将分区容忍性理解为横向可扩展性,当业务数据的体量随着时间变得越来越大,是否能够通过增加新的数据库存储节点而平滑的完成扩展。

2 分布式数据库与 CAP

2.1 CA 模型举例

传统的关系型数据库满足 CA 模型,其必须要遵守的 ACID 原则就包含对一致性的描述,各类关系型数据库产品也都提供了多种高可用方案,比如 Oracle 的 RAC ,提供多个数据库服务实例节点形成集群(但存储仍是共用的):

再比如 MySQL 的 MHA ,当主节点出现故障时,从节点将自动提升为新的主节点(主从节点之间会进行数据的同步):

传统数据库为了应对不断增长的数据体量,从业务的角度其实也做过很多的拆分方案,比如:

  • 读写分离(读库写库定时同步)
  • 按业务线进行纵向拆分,不同的库对应不同的业务线
  • 按指定的范围进行横向拆分,比如按不同省市自治区进行拆分(但这样数据会很不均衡)
  • 使用散列分片( sharding )进行横向拆分,比如按用户 id 取余进行拆分

无论是高可用的方案,还是业务拆分的方案,最终的数据存储,其实还都是集中式的(即单台存储需要持有完整的数据,来确保数据库的可靠性和数据的持续可用性)。受限于关系型数据库的特性(结构化的数据),数据之间存在着复杂的业务关联,是很难将数据放置在不同的存储分区的,不具备分区容忍性。

2.2 AP 模型举例

大部分的 NoSQL 数据库牺牲了强一致性(采用最终一致性),满足 AP 模型。

传统的关系型数据库在高并发、海量数据存储等场景下不堪重负,也不具备良好的扩展性, NoSQL ( Not only SQL )数据库的出现就是为了解决关系型数据库的这些短板(但并不是替代,它们各有各的应用场景)。

NoSQL 是对不同于传统关系型数据库的非关系型数据库的统称, NoSQL 本身就是针对分布式而设计,天然支持 Sharding 分片集群,具备良好的分区容忍性。

我们以 Redis 为例, Redis 是一个 key-value 型的 NoSQL 数据库,其高可用的方案如下图:

在高可用的方案下,每一个主节点至少配备一个从节点,当主节点发生故障时,从节点提升为新的主节点。这里注意一下主从节点的大致同步过程:

  • 客户端发起命令,主节点执行命令,执行完成后,直接相应客户端;
  • 主节点异步的将命令发送给从节点,从节点执行命令,以完成数据的同步。

这里需要强调的是,当主节点完成了命令的执行,当前事务就结束了,并不会等待从节点的同步过程。这就是最终一致性的体现。

我们再谈谈 Redis 的横向扩展性。 Redis 集群引入了哈希槽的概念(共 16384 个哈希槽),每当执行写入操作时,会通过 CRC16(key) % 16384 这样的方式来决定数据写入哪一个槽上。默认情况下,槽会平均分到各个主节点上。当我们为集群增加主节点时,我们会将前几个主节点上的部分的槽迁移至新的主节点,能够实现平滑的扩容。

2.3 CP 模型举例

不论是广泛意义上的分布式系统,还是特指数据库应用服务,可用性都是必须要保证的,毕竟用户是无法容忍一个不可用的系统的。因此会有这样一种说法,我们可以有放弃了分区容忍性的 CA 模型,可以有放弃了一致性的 AP 模型,但一般不会采用放弃可用性的 CP 模型。

但随着技术的发展,上面的说法也不是绝对的了。有一种说法: NewSQL 在理想情况下可以同时满足 CAP 。其实这里还是牺牲了一些 A 的(此时 A 理解为高性能更为贴切),所以我们可以将 NewSQL 视为 CP 模型。

NewSQL 这类数据库不仅具有 NoSQL 对海量数据的存储管理能力及分布式可扩展性,还支持传统的 RDBMS 的 ACID 、事务、 SQL 等特性,所以也可以称 NewSQL 为“分布式的关系型数据库”。 这里要注意的是, NewSQL 的性价比其实不如 RDBMS ,如果不是高并发场景,传统的 RDBMS 就够用了。相同的业务交易, NewSQL 的交易时间一般会是 RDBMS 的数倍以上甚至更多。

为了保证强一致性, NewSQL 数据库在执行一个节点的写入操作后,必须等待其它节点的数据同步完成,才能结束当前事务,这样的强一致性的保证,很明显是建立在牺牲性能的基础上的。

NewSQL 的典型代表产品有 PingCAP 公司的 TiDB ,还有蚂蚁的 OceanBase ,这两个都是国内的产品。笔者在项目中实际使用过 OceanBase ,能够兼容 95% 以上的 Oracle 语法,不过数据体量大起来后,查询速度确实不太理想。不过笔者认为,就高并发、高可用领域来讲,国内做的应该不比国外差,甚至更好,毕竟我们的体量(双 11 , 12306 什么的)在这摆着呢,相信会越来越好。