「如何实现流动式软件发布」线上课堂开课啦,快来报名参与课堂抽奖吧~ 了解详情
写点什么

蚂蚁金服服务注册中心数据一致性方案分析

2020 年 3 月 06 日

蚂蚁金服服务注册中心数据一致性方案分析

SOFARegistry 是蚂蚁金服开源的具有承载海量服务注册和订阅能力的、高可用的服务注册中心,在支付宝/蚂蚁金服的业务发展驱动下,近十年间已经演进至第五代。


《剖析 | SOFARegistry 框架》系列由 SOFA 团队和源码爱好者们出品,项目代号:<SOFARegistry:Lab/>,文末包含往期系列文章。


GitHub 地址:


https://github.com/sofastack/sofa-registry


1 概述

在前面的文章已经做过介绍,与其他注册中心相比,SOFARegistry 主要特点在于支持海量数据、支持海量客户端、秒级的服务上下线通知以及高可用特性。本文将从如下几个方面来讲述 SOFARegistry 的一致性方案:


  • MetaServer 数据一致性


为支持高可用特性,对于 MetaServer 来说,存储了 SOFARegistry 的元数据,为了保障 MetaServer 集群的一致性,其采用了 Raft 协议来进行选举和复制。


  • SessionServer 数据一致性


为支持海量客户端的连接,SOFARegistry 在客户端与 DataServer 之间添加了一个 SessionServer 层,客户端与 SessionServer 连接,避免了客户端与 DataServer 之间存在大量连接所导致的连接数过多不可控的问题。客户端通过 SessionServer 与 DataServer 连接的时候,Publisher 数据同时会缓存在 SessionServer 中,此时就需要解决 DataServer 与 SessionServer 之间数据一致性的问题。


  • DataServer 数据一致性


为支持海量数据,SOFARegistry 采用了一致性 Hash 来分片存储 Publisher 数据,避免了单个服务器存储全量数据时产生的容量瓶颈问题。而在这个模型中,每个数据分片拥有多个副本,当存储注册数的 DataServer 进行扩容、缩容时,MetaServer 会把这个变更通知到 DataServer 和 SessionServer,数据分片会在集群内部进行数据迁移与同步,此时就出现了 DataServer 内部数据的一致性问题。


2 MetaServer 数据一致性

MetaServer 在 SOFARegistry 中,承担着集群元数据管理的角色,用来维护集群成员列表,可以认为是 SOFARegistry 注册中心的注册中心。当 SessionServer 和 DataServer 需要知道集群列表,并且需要扩缩容时,MetaServer 将会提供相应的数据。



图 1 MetaServer 内部结构


图源自 《蚂蚁金服服务注册中心 MetaServer 功能介绍和实现剖析 | SOFARegistry 解析》


因为 SOFARegistry 集群节点列表数据并不是很多,因此不需要使用数据分片的方式在 MetaServer 中存储。如图 1 所示,集群节点列表存储在 Repository 中,上面通过 Raft 强一致性协议对外提供节点注册、续约、列表查询等 Bolt 请求,从而保障集群获得的数据是强一致性的。


Raft 协议


关于 Raft 协议算法,具体可以参考 The Raft Consensus Algorithm 中的解释。在 SOFAStack 体系中,对于 Raft 协议有 SOFAJRaft 实现。


SOFAJRaft 源码解析系列:https://www.sofastack.tech/tags/剖析-sofajraft-实现原理/


下面对 Raft 协议算法的原理进行简要介绍。


Raft 协议由三个部分组成,领导人选举(Leader Election)、日志复制(Log Replication)、安全性(Safety)。


  • 领导人选举


通过一定的算法选举出领导人,用于接受客户端请求,并且把指令追加到日志中。



图 2 Raft 状态机状态转换图


图源自 Understanding the Raft consensus algorithm: an academic article summary


  • 日志复制


领导人接受到客户端请求之后,把操作追加到日志中,同时与其他追随者同步消息,最终 Commit 日志,并且把结果返回给客户端。



图 3 复制状态机


图源自 Raft 一致性算法笔记


  • 安全性


安全性保证了数据的一致性。


基于 Raft 协议的数据一致性保障



图 4 SOFARegistry 中的 Raft 存储过程


图源自 《蚂蚁金服服务注册中心 MetaServer 功能介绍和实现剖析 | SOFARegistry 解析》


如图 4 所示,SOFARegistry 中的 Raft 协议数据存储经历了如上的一些流程。客户端发起 Raft 协议调用,进行数据注册、续约、查询等操作时,会通过动态代理实现 ProxyHandler 类进行代理,通过 RaftClient 把数据发送给 RaftServer ,并且通过内部的状态机 Statemachine ,最终实现数据的操作,从而保证了 MetaServer 内部的数据一致性。


3 SessionServer 数据一致性

SessionServer 在 SOFARegistry 中,承担着会话管理及连接的功能。同时,Subscriber 需要通过 SessionServer 来订阅 DataServer 的服务数据,Publisher 需要通过 SessionServer 来把服务数据发布到 DataServer 中。


在这个场景下,SessionServer 作为中间代理层,缓存从 DataServer 中获取的数据成了必然。DataServer 的数据需要通过 SessionServer 推送到 Subscriber 中,触发 SessionServer 推送的场景有两个:一个是 Publisher 到 DataServer 的数据发生变化;另外一个是 Subscriber 有了新增。


而在实际的场景中,Subscriber 新增的情况更多,在这种场景下,直接把 SessionServer 缓存的数据推送到 Subscriber 中即可,能够大大减轻 SessionServer 从 DataServer 获取数据对 DataServer 的压力。因此,这也进一步确认了在 SessionServer 缓存数据的必要性。



图 5 两种场景的数据推送对比图


SessionServer 与 DataServer 数据对比机制


当服务 Publisher 上下线或者断连时,相应的数据会通过 SessionServer 注册到 DataServer 中。此时,DataServer 的数据与 SessionServer 会出现短暂的不一致性。为了保障这个数据的一致性,DataServer 与 SessionServer 之间通过推和拉两种方式实现了数据的同步。


  • 数据推送模式

  • DataServer 在服务数据有变化时会主动通知到 SessionServer 中,此时 SessionServer 会比对两者数据的版本号 version ,对比之后若需要更新数据,则会主动向 DataServer 获取相应的数据。

  • 数据拉取模式

  • SessionServer 会每隔一定的时间(默认 30s)主动向 DataServer 查询所有 dataInfoId 的 version 信息,若发现有版本号有变化,则会进行相应的同步操作。

  • SessionServer 从 DataServer 同步数据:常规情况下,一般是 DataServer 的数据要比 SessionServer 更新,此时,当 SessionServer 发现数据版本号有变化时,会主动拉取 DataServer 的数据进行同步。注意,此时缓存的数据只与当前 SessionServer 管理的客户端所订阅的服务信息有关,并不会缓存全量的数据,而且容量也不允许;

  • DataServer 从 SessionServer 同步数据:特殊情况下,DataServer 数据出现缺失,并且副本数据也出现问题之后,当 SessionServer 与 DataServer 数据进行版本号比对时,会触发数据恢复操作,能够把 SessionServer 内存中所存储的全量数据恢复到 DataServer 中,实现了数据的反向同步与补偿机制;

  • 数据的缓存方式

  • SOFARegistry 中采用了 LoadingCache 的数据结构来在 SessionServer 中缓存从 DataServer 中同步来的数据。每个 cache 中的 entry 都有过期时间,在拉取数据的时候可以设置过期时间(默认是 30s),使得 cache 定期去 DataServer 查询当前 session 所有 sub 的 dataInfoId,对比如果 session 记录的最近推送 version(见 com.alipay.sofa.registry.server.session.store.SessionInterests#interestVersions )比 DataServer 小,说明需要推送,然后 SessionServer 主动从 DataServer 获取该 dataInfoId 的数据(此时会缓存到 cache 里),推送给 client。

  • 同时,当 DataServer 中有数据更新时,也会主动向 SessionServer 发请求使对应 entry 失效,从而促使 SessionServer 去更新失效 entry。


SessionServer 与 Subscriber 之间的数据一致性同步


当 SessionServer 的数据发生变更时,会与 Subscriber 之间进行数据同步,把变化的 dataInfoId 数据推送到 Subscriber 中,保证客户端本地所缓存的数据与 SessionServer 中的一致。


4 DataServer 数据一致性

DataServer 在 SOFARegistry 中,承担着核心的数据存储功能。数据按 dataInfoId 进行一致性 Hash 分片存储,支持多副本备份,保证数据高可用。这一层可随服务数据量的规模的增长而扩容。


如果 DataServer 宕机,MetaServer 能感知,并通知所有 DataServer 和 SessionServer,数据分片可 failover 到其他副本,同时 DataServer 集群内部会进行分片数据的迁移。


DataServer 请求接收过程


在讲解一致性之前,先讲一下 DataServer 的启动之后关于数据同步方面做了哪些事情。DataServer 启动之时,会启动一个数据同步 Bolt 服务 openDataSyncServer ,进行相应的 DataServer 数据同步处理。


启动 DataSyncServer 时,注册了如下几个 handler 用于处理 bolt 请求 :



图 5 DayaSyncServer 注册的 Handler


  • getDataHandler


该 Handler 主要用于数据的获取,当一个请求过来时,会通过请求中的 DataCenter 和 DataInfoId 获取当前 DataServer 节点存储的相应数据。


  • publishDataProcessor \ unPublishDataHandler


当有数据发布者 publisher 上下线时,会分别触发 publishDataProcessor 或 unPublishDataHandler ,Handler 会往 dataChangeEventCenter 中添加一个数据变更事件,用于异步地通知事件变更中心数据的变更。


事件变更中心收到该事件之后,会往队列中加入事件。此时 dataChangeEventCenter 会根据不同的事件类型异步地对上下线数据进行相应的处理。与此同时,DataChangeHandler 会把这个事件变更信息通过 ChangeNotifier 对外发布,通知其他节点进行数据同步。


  • notifyFetchDatumHandler


这是一个数据拉取请求,当该 Handler 被触发时,通知当前 DataServer 节点进行版本号对比,若请求中数据的版本号高于当前节点缓存中的版本号,则会进行数据同步操作,保证数据是最新的。


  • notifyOnlineHandler


这是一个 DataServer 上线通知请求 Handler,当其他节点上线时,会触发该 Handler,从而当前节点在缓存中存储新增的节点信息。用于管理节点状态,究竟是 INITIAL 还是 WORKING 。


  • syncDataHandler


节点间数据同步 Handler,该 Handler 被触发时,会通过版本号进行比对,若当前 DataServer 所存储数据版本号含有当前请求版本号,则会返回所有大于当前请求数据版本号的所有数据,便于节点间进行数据同步。


  • dataSyncServerConnectionHandler


连接管理 Handler,当其他 DataServer 节点与当前 DataServer 节点连接时,会触发 connect 方法,从而在本地缓存中注册连接信息,而当其他 DataServer 节点与当前节点断连时,则会触发 disconnect 方法,从而删除缓存信息,进而保证当前 DataServer 节点存储有所有与之连接的 DataServer 节点。


最终一致性


SOFARegistry 在数据存储层面采用了类似 Eureka 的最终一致性的过程,但是存储内容上和 Eureka 在每个节点存储相同内容特性不同,采用每个节点上的内容按照一致性 Hash 数据分片来达到数据容量无限水平扩展能力。


SOFARegistry 是一个 AP 分布式系统,表明了在已有条件 P 的前提下,选择了 A 可用性。当数据进行同步时,获取到的数据与实际数据不一致。但因为存储的信息为服务的注册节点,尽管会有短暂的不一致产生,但对于客户端来说,大概率还是能从这部分数据中找到可用的节点,不会因为数据暂时的不一致对业务系统带来致命性的伤害。


集群内部数据迁移过程


SOFARegistry 的 DataServer 选择了“一致性 Hash 分片”来存储数据。在“一致性 Hash 分片”的基础上,为了避免“分片数据不固定”这个问题,SOFARegistry 选择了在 DataServer 内存里以 dataInfoId 的粒度记录操作日志,并且在 DataServer 之间也是以 dataInfoId 的粒度去做数据同步。



图 6 DataServer 之间进行异步数据同步


数据和副本分别分布在不同的节点上,进行一致性 Hash 分片,当时对主副本进行写操作之后,主副本会把数据异步地更新到其他副本中,实现了集群内部不同副本之间的数据迁移工作。


5 总结

在分布式系统的设计中,可用性、分区容错性、一致性是我们必须进行权衡的选项,CAP 理论告诉我们,这三者中只能同时满足两个的要求。在设计分布式系统时,如何进行权衡选择,是摆在每个系统设计者面前的一个难题。


SOFARegistry 系统分为三个集群,分别是元数据集群 MetaServer、会话集群 SessionServer、数据集群 DataServer。复杂的系统有多个地方需要考虑到一致性问题,SOFARegistry 针对不同模块的一致性需求也采取了不同的方案。对于 MetaServer 模块来说,采用了强一致性的 Raft 协议来保证集群信息的一致性。对于数据模块来说,SOFARegistry 选择了 AP 保证可用性,同时保证了最终一致性。


SOFARegistry 的设计给了我们启示,在设计一个多模块的分布式系统时,可以根据不同模块的需求选择不同的一致性方案,同时 CAP 三者的权衡也需要结合系统不同模块的目标作出合理的权衡,不必拘泥。


文中涉及的相关链接



6 SOFARegistryLab 系列阅读


本文转载自公众号金融级分布式架构(ID:Antfin_SOFA)。


原文链接


https://mp.weixin.qq.com/s/5GddbUUxOA1l8hXafLmAQw


2020 年 3 月 06 日 10:001106

评论

发布
暂无评论
发现更多内容

ARTS 打卡计划-1

TinyKing

Git工作流中常见的三种分支策略:GitFlow、GitHubFlow和GitLabFlow

华为云开发者社区

git 软件开发 工作流 GitFlow GitHubFlow

北鲲云超算平台解决生物科学领域困境,探索更多可能性

北鲲云

图解堆排序,带你彻底了解清楚!

程序员的时光

Java 算法 排序算法 堆排序 面试、

Vue进阶(幺零六):子组件处理父组件异步值传递给子组件处理

No Silver Bullet

Vue 组件 监听 7月日更

Go 学习笔记之 方法

架构精进之路

go 7月日更

官宣!DataPipeline2021数据管理与创新大会将于7.29北京重装开启!

DataPipeline数见科技

大数据 数据融合 数据管理

【Flutter 专题】86 初识状态管理 Bloc (一)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 7月日更

架构之:REST和RESTful

程序那些事

微服务 软件架构 程序那些事

Vue进阶(幺捌伍):动态设置系统字体

No Silver Bullet

Vue 7月日更 字体设置

什么是网络单纯型算法

华为云开发者社区

算法 线性规划 单纯型算法 网络单纯型 计算矩阵

EasyRecovery深度扫描以恢复桌面遗失数据的方法

淋雨

EasyRecovery 文件恢复 硬盘数据恢复

索信达首席科学家张磊:以AI创新技术满足金融场景的“私人定制”

索信达控股

大数据 数字化转型 银行数字化转型 银行大数据

《面试补习》- 你来说说什么是限流?

九灵

Java 面试 分布式 sentinel 限流

超视频化到来,你能看见什么?

阿里云视频云

阿里云 计算机视觉 音视频 视频 视频云

IPFS挖矿值得投资吗?IPFS挖矿前景如何?

IPFS老胡

Rust从0到1-并发-线程

rust 线程 并发 Thread Concurrency

牙膏踩爆!Intel 5nm工艺曝光:直逼IBM 2nm

新闻科技资讯

图扑软件受邀核电数字化技术大会,技术创新助力行业革新

一只数据鲸鱼

数据可视化 核电 核电站 数字大会

建立对分布式锁的系统认知-从Redlock开始

刘绍

程序员 分布式 分布式锁 RedLock redisson

带你换个角度理解图卷积网络

华为云开发者社区

神经网络 卷积神经网络 图神经网络 卷积 图网络

手写QuickSort算法

实力程序员

成长 C语言 算法 排序 实力程序员

工业互联网赋能 浪潮云洲助力区域品牌“走出去”

浪潮云

工业互联网

【LeetCode】减小和重新排列数组后的最大元素Java题解

HQ数字卡

算法 LeetCode 7月日更

怎么借助Camtasia给电脑游戏录屏

淋雨

视频剪辑 Camtasia 录屏

Jira 要停售本地私有化部署的版本了,这对国产项目管理软件是机会吗?

万事ONES

项目管理 Atlassian Jira ONES

对话系统简介与OPPO小布助手的工程实践

OPPO小布助手

人工智能 对话 智能助手 智能对话

微信架构图

Geek_36d3e5

如何打造高效好用的终端?拿来吧你!

童欧巴

前端 iterm2 Oh My Zsh

对产品来说,颜值、体验是不是很重要?

石云升

用户体验 职场经验 7月日更

IPFS算力挖矿排行榜,IPFS挖矿公司排行榜

IPFS老胡

蚂蚁金服服务注册中心数据一致性方案分析-InfoQ