神一样的CAP理论被应用在何方?( 二 )


目前作为注册中心的一些组件大致有:

  • Dubbo 的 Zookeeper
  • Spring Cloud 的 Eureka , Consul
  • RocketMQ 的 nameServer
  • HDFS 的 nameNode
目前微服务主流是 Dubbo 和 Spring Cloud , 使用最多是 Zookeeper 和 Eureka , 我们就来看看应该根据 CAP 理论怎么去选择注册中心 。(Spring Cloud 也可以用 ZK , 不过不是主流不讨论)
Zookeeper 选择 CP
Zookeeper 保证 CP , 即任何时刻对 Zookeeper 的访问请求能得到一致性的数据结果 , 同时系统对网络分割具备容错性 , 但是它不能保证每次服务的可用性 。
从实际情况来分析 , 在使用 Zookeeper 获取服务列表时 , 如果 ZK 正在选举或者 ZK 集群中半数以上的机器不可用 , 那么将无法获取数据 。所以说 , ZK 不能保证服务可用性 。
Eureka 选择 AP
Eureka 保证 AP , Eureka 在设计时优先保证可用性 , 每一个节点都是平等的 。
一部分节点挂掉不会影响到正常节点的工作 , 不会出现类似 ZK 的选举 Leader 的过程 , 客户端发现向某个节点注册或连接失败 , 会自动切换到其他的节点 。
只要有一台 Eureka 存在 , 就可以保证整个服务处在可用状态 , 只不过有可能这个服务上的信息并不是最新的信息 。
ZK 和 Eureka 的数据一致性问题
先要明确一点 , Eureka 的创建初心就是为一个注册中心 , 但是 ZK 更多是作为分布式协调服务的存在 。
只不过因为它的特性被 Dubbo 赋予了注册中心 , 它的职责更多是保证数据(配置数据 , 状态数据)在管辖下的所有服务之间保持一致 。
所以这个就不难理解为何 ZK 被设计成 CP 而不是 AP , ZK 最核心的算法 ZAB , 就是为了解决分布式系统下数据在多个服务之间一致同步的问题 。
更深层的原因 , ZK 是按照 CP 原则构建 , 也就是说它必须保持每一个节点的数据都保持一致 。
如果 ZK 下节点断开或者集群中出现网络分割(例如交换机的子网间不能互访) , 那么 ZK 会将它们从自己的管理范围中剔除 , 外界不能访问这些节点 , 即使这些节点是健康的可以提供正常的服务 , 所以导致这些节点请求都会丢失 。
而 Eureka 则完全没有这方面的顾虑 , 它的节点都是相对独立 , 不需要考虑数据一致性的问题 , 这个应该是 Eureka 的诞生就是为了注册中心而设计 。
相对 ZK 来说剔除了 Leader 节点选取和事务日志机制 , 这样更有利于维护和保证 Eureka 在运行的健壮性 。
 
神一样的CAP理论被应用在何方?

文章插图
 
 
再来看看 , 数据不一致性在注册服务中会给 Eureka 带来什么问题 , 无非就是某一个节点被注册的服务多 , 某个节点注册的服务少 , 在某一个瞬间可能导致某些 IP 节点被调用数多 , 某些 IP 节点调用数少的问题 。
也有可能存在一些本应该被删除而没被删除的脏数据 。
 
神一样的CAP理论被应用在何方?

文章插图
 
 
服务注册应该选择 AP 还是 CP
对于服务注册来说 , 针对同一个服务 , 即使注册中心的不同节点保存的服务注册信息不相同 , 也并不会造成灾难性的后果 。
对于服务消费者来说 , 能消费才是最重要的 , 就算拿到的数据不是最新的数据 , 消费者本身也可以进行尝试失败重试 。总比为了追求数据的一致性而获取不到实例信息整个服务不可用要好 。
所以 , 对于服务注册来说 , 可用性比数据一致性更加的重要 , 选择 AP 。
分布式锁 , 是选择 CA 还是选择 CP?
这里实现分布式锁的方式选取了三种:
  • 基于数据库实现分布式锁
  • 基于 redis 实现分布式锁
  • 基于 Zookeeper 实现分布式锁
基于数据库实现分布式锁
构建表结构:
 
神一样的CAP理论被应用在何方?

文章插图
 
 
利用表的 UNIQUE KEY idx_lock(method_lock)作为唯一主键 , 当进行上锁时进行 Insert 动作 , 数据库成功录入则以为上锁成功 , 当数据库报出 Duplicate entry 则表示无法获取该锁 。


推荐阅读