分布式理论: 再谈CAP

#分布式 #CAP #理论 #后端

Table of Contents

分布式理论: 再谈CAP

背景介绍

CAP1理论出现已经几十年了, 一个理论是有保质期的, 随着时代的进步, 理论需要不带的更新迭代.

传统的 CAP 理论认为, CAP 三者是无法并存的, 即 强一致性 & 100% 可用性 & 分区容忍性 最多是只能保证其中两个, 这是有着严格的数学证明的, 但是在实际工程的应用上, 情况有了很大的变化

本文探究在现代分布式网络架构下, 传统的 CAP 理论所面临的挑战以及一些解决方案.

什么是 CAP?

一致性( C )

CAP 理论中的一致性是指强一致性( Strong Consistency ),又叫线性一致性( Linearizable Consistency ),它要求多节点组成的分布式系统,能像单节点一样运作,如果一个写操作返回成功,那么之后的读请求都必须读到这个新数据;如果返回失败,那么所有的读操作都不能读到这个数据。

换言之, 当一个写操作得到确认后, 后续的任意读操作, 必定可以读到最新的数据.

可用性( A )

CAP 理论对可用性的定义,指的是要求系统提供的服务必须处于 100% 可用的状态,对于用户的每一个操作请求,系统总能够在有限的时间内返回结果。三个关键点:“ 100% 可用”、“有限时间内”和“返回结果”。

分区容错性( P )

分区指的是在整个分布式系统中,因为各种网络原因,系统被分隔成多个单独的部分,它不仅包含我们通常说的网络分区,也包含因为网络丢包导致的网络不通的情况。

现实的网络环境中, 始终存在的两个问题

  1. 不可靠的网络
  2. 概率性的宕机

因此分布式系统中, 分区的出现是不不可避免的, 所以对于绝大多数的分布式系统来说, 分区容忍性是必须保证的.

现实问题

100% 可用性是伪命题

在网络环境下, 哪怕分布式系统本身保证了 100% 的可用性, 但是由于调用方大概率是通过网络进行请求, 这导致网络请求的可用性是会直接影响到外部观测到的实际可用性.

举例, 我们假设以一个 Deployment 的形式部署了一个 etcd 服务, 对外以 service 的形式进行暴露, 那么此时的连通性就依赖 service 的可用性

因此, 哪怕系统本身实现了 100% 的可用性, 依然无法保证外部观测的实际可用性.

所以在实际的生产环境中, 100% 的实际可用性是一个伪命题, 即服务本身应当追求高可用, 但是无法真正达成 100% 可用.

再谈可用性

一个服务必须要保证 100% 的可用性吗?

答案是不需要, 也做不到, 只要能够保证高可用, 例如 99.999% 的可用性, 在实际的调用测可以通过 重试, 重连, 降级等等策略, 来保证在服务不可用时, 提供一个符合需求的可用能力

一致性降级

通常来讲一致性有以下几种分级

  1. 强一致性:在分布式系统中,如果一个写操作完成,那么所有的读操作都能够立即看到这个写操作的结果。这种一致性级别要求非常高,通常需要牺牲一定的性能来保证数据的强一致性。
  2. 弱一致性:在分布式系统中,数据的一致性不是即时的,可能会有一段时间的延迟。在这段时间内,系统可能处于不一致的状态。弱一致性通常用于一些对实时性要求不高的场景。
  3. 最终一致性:在分布式系统中,数据的一致性是最终达成的,即系统保证在一段时间内会达到一致的状态。最终一致性是一种折中的方式,可以在一定程度上保证数据的一致性,同时提高系统的性能。
  4. 事件 ual 一致性:事件 ual 一致性是最弱的一致性级别,系统在出现分区或故障时可以容忍数据的不一致性,但最终会达到一致的状态。

在 AP 系统中, 我们几乎无法达成强一致性, 但是我们可以追求更低等级的一致性, 因此哪怕在 AP 系统中, 依然存在着一致性的保证.

AP 再延伸: BASE

基本可用(Basically Available)

再谈可用性

软状态(Soft state)

因为不会对外部暴露出, 暂时不处理

最终一致性(Eventually consistent)

由于典型的分布式系统中, 总会存在着主备/ 读写分离的情况, 因此强一致性的保证会更加的困难

因此如果能够保证, 在一定的时间内, 能够在不同的节点上保证数据是一致的, 在绝大多数的情况下, 着就满足了我们的需求.

主流分布式系统的能力思考

Redis Cluster

Redis Cluster 通过数据 sharding, 以及主备机制来提供良好的可用性

有几个关键的技术

  1. 哈希槽: Redis Cluster 不使用一致性哈希,而是选择了一个固定数量(16384 个)的哈希槽。每个键通过 CRC16 算法对键名进行哈希计算,然后取模 16384 来决定应该放入哪个槽。 每个 Redis Cluster 节点(实例)负责维护一部分哈希槽,例如一个包含 3 个节点的集群可能会有一个节点负责 0-5460 号槽,另一个节点负责 5461-10922 号槽,第三个节点负责 10923-16383 号槽。 当需要在集群中寻找一个键的位置时,Redis 客户端会计算该键的哈希槽,并与集群中的节点信息对照,找到负责该槽的节点,然后直接与该节点通信。

  2. gossip Gossip 协议是一种节点间通信机制,它允许集群中的节点通过一个不断传播的过程来交换信息。这种方式类似于社交网络中的八卦传播,因此得名 Gossip。 在 Redis Cluster 中,各个节点周期性地向其他随机选择的节点发送信息,这些信息包括但不限于:

    • 节点的状态(例如,是否可达、是否主节点、是否投票等)
    • 集群的拓扑信息
    • 节点的配置变化
    • 键空间的变化(例如,哪些槽(slot)被指派给了哪个节点) Gossip 协议的优点在于它的扩展性和鲁棒性。因为信息是通过节点间的小量随机交换来传播的,即使有部分节点失效或网络出现问题,集群的其余部分仍然可以继续交换信息,并最终达到一致的状态视图。

MongoDB sharding

MongoDB 将数据分布在多个服务器上,称为分片(shards)。每个分片都是一个独立的数据库,集合中的数据分布在所有分片上。这种方法可以提高应用程序的可伸缩性和性能,因为它允许数据库跨多个机器进行操作,从而充分利用分布式计算资源。

MongoDB 的分片环境通常包括以下几个组件:

  1. 分片(Shards) :每个分片都是一个物理的数据库服务器,负责存储数据的子集。分片可以是一个单独的 MongoDB 实例,也可以是一个复制集。
  2. 查询路由器(Query Router) :查询路由器是由 mongos​ 进程实现的,它接收客户端应用程序的请求,并将这些请求路由到适当的分片。客户端与 mongos 进程交互,就像它是单个数据库服务器一样。
  3. 配置服务器(Config Servers) :配置服务器存储整个分片环境的元数据和配置信息。这包括数据在分片之间如何分布的信息,以及集群的状态。通常有三个配置服务器,以确保高可用性和数据一致性。

在 MongoDB 中设置分片涉及以下步骤:

  1. 选择分片键(Shard Key) :分片键是集合中的一个字段,用于决定数据如何在分片之间分布。选择一个好的分片键至关重要,因为它会直接影响到集群的性能和平衡。
  2. 配置分片环境:设置分片环境包括启动 mongod​ 实例作为分片,配置 mongos 查询路由器,以及初始化配置服务器。
  3. 启用分片:在一个集合上启用分片,将其变成一个分片集合。这涉及到在 mongos 上执行命令,来指定分片键并启用分片。
  4. 数据均衡(Balancing) :MongoDB 会自动进行数据均衡,将数据块(chunks)从一个分片移动到另一个分片,以保持数据在分片之间的均匀分布。

etcd

需要注意的是, 哪怕处于不可用状态时, 依然提供读的能力.

Raft 协议

  1. Leader Election(领导者选举) :

    • 系统启动时,节点开始作为 Follower。
    • 如果 Follower 在一定时间内没有收到 Leader 的消息,它会成为 Candidate 并开始选举过程。
    • Candidate 请求其他节点的投票。
    • 收到大多数节点投票的 Candidate 成为 Leader。
  2. Log Replication(日志复制) :

    • Leader 接收客户端的请求,将请求作为新的日志条目追加到它的日志中。
    • 然后 Leader 将这个日志条目复制到集群中的其他 Follower 节点。
    • 一旦这个日志条目被安全地复制(即复制到大多数节点),它将被提交并应用到状态机。
  3. Safety(安全性) :

    • Raft 保证了即使在出现网络分区、节点故障等问题时,已经提交的日志条目也不会丢失,并且集群最终都将达到一致的状态。

如何保证 CAP

  • Consistency: ​etcd 使用 Raft 协议来保证一致性。所有的写操作都通过 Leader 节点来协调,确保每个操作都被复制到集群的大多数节点上,并且以相同的顺序应用。
  • Availability: ** ** **在没有网络分区的情况下,**​etcd 可以提供较高的可用性。但是,当发生网络分区时,只有那些包含大多数节点的分区可以继续提供服务,以保证数据的一致性。
  • Partition Tolerance: ** ** ​etcd 通过 Raft 协议的日志复制机制来处理网络分区。即使在分区期间,系统也能保持一致的状态,等待网络恢复后同步状态。

参考

ReidsCluster: https://blog.csdn.net/weixin_​**40242845/article/details/127089280**


  1. CAP

    CAP

    CAP

    在一个分布式系统(指互相连接并共享数据的节点的集合)中,当涉及读写操作时,只能保证一致性(Consistence)、可用性(Availability)、分区容错性(Partition Tolerance)三者中的两个,另外一个必须被牺牲。

    仅关注RW. 读写

    1. 一致性(Consistency)

      对某个指定的客户端来说,读操作保证能够返回最新的写操作结果。

    2. 可用性(Availability)

      非故障的节点在合理的时间内返回合理的响应(不是错误和超时的响应)。

    3. 分区容忍性(Partition Tolerance)

      当出现网络分区后,系统能够继续“履行职责”。

     ↩︎