Vic's blog Vic's blog
首页
  • 前端文章

    • JavaScript
    • Vue
    • HTML
    • CSS
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 微服务
  • Database
  • Python
  • 学习笔记

    • Java面试宝典
    • 《一个人工智能的诞生》笔记
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 学习笔记

    • 《Git》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 大数据
  • 微服务
  • Java面试
关于
  • 网站
  • 资源
  • Vue资源
  • Java面试真题汇总
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Vic xu

永远期待美好的事情将会发生
首页
  • 前端文章

    • JavaScript
    • Vue
    • HTML
    • CSS
  • 学习笔记

    • 《JavaScript教程》笔记
    • 《JavaScript高级程序设计》笔记
    • 《ES6 教程》笔记
    • 《Vue》笔记
    • 《TypeScript 从零实现 axios》
    • TypeScript笔记
    • JS设计模式总结笔记
  • 微服务
  • Database
  • Python
  • 学习笔记

    • Java面试宝典
    • 《一个人工智能的诞生》笔记
  • 技术文档
  • GitHub技巧
  • 博客搭建
  • 学习笔记

    • 《Git》学习笔记
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
  • 大数据
  • 微服务
  • Java面试
关于
  • 网站
  • 资源
  • Vue资源
  • Java面试真题汇总
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 蚂蚁集团分布式注册中心建设分享

    • 蚂蚁集团分布式注册中心建设分享
      • 前言
        • 注册中心是什么?
          • 服务注册&服务发现
          • 调用流程
          • 心跳
          • Dubbo注册中心
          • 注册中心的本质
        • 蚂蚁注册中心编年史
          • 一、史前时代
          • 二、硬负荷时代
          • 三、第一代注册中心 --硬负载到软负载的演变
          • 四、第二代注册中心 --ScaleUp?ScaleOut?it‘s a problem
          • 五、第五代注册中心 --Meta节点的诞生
          • 六、第六代注册中心 --面向运维的注册中心
        • 开源
          • 共同建设
          • 后台
          • 微服务
          xushengli
          2021-08-12

          蚂蚁集团分布式注册中心建设分享

          # 蚂蚁集团分布式注册中心建设分享

          # 前言

          image-20210818141224014

          这篇文章是基于 SOFA Meetup 合肥站的分享总结,主要针对于注册中心的定位以及功能介绍,通过对蚂蚁注册中心发展史的分析,带领大家了解,蚂蚁的注册中心是如何一步一步演变为现在的规模和特性的。

          # 注册中心是什么?

          # 服务注册&服务发现

          注册中心简单来说,是为了解决分布式场景下,服务之间互相发现的问题。

          如下图所示,服务 A 想要调用服务 B 的时候,需要知道 B 的地址在哪里,如何解决这个问题?

          服务A-->服务B:😍
          
          1

          一般来说,分为两个点:

          服务发现:一个中心化的组件或者说是存储,它承载了所有服务的地址,同时提供出来一个可供查询和订阅的能力,服务的消费方可以通过和这个中心化的存储交互,获取服务提供方的地址列表。

          服务注册:同样是上文中心化的组件,但是需要对服务信息信息有以下两种措施

          • 服务连接注册中心,同时上报自身的服务以及元数据(也是今天本文讲述的重点)。
          • 有一个集中的控制面(control plane)将用户定义的服务和 IP 的映射写入注册中心,例如 AWS 的 CloudMap。

          # 调用流程

          image-20210818101853998

          如上图所示,就是目前一种主流的注册中心模式,SOFARegistry 和 Nacos 都是这种模式。

          1. 服务 A,服务 B 通过 SDK 或者 REST 将自身的服务信息上报给注册中心;
          2. 服务 A 需要调用服务 B 的时候,就对注册中心发起请求,拉取和服务 B 相关的服务 IP 列表以及信息;
          3. 在获取到服务 B 的列表之后,就可以通过自身定义的负载均衡算法访问服务 B。

          # 心跳

          心跳是注册中心用于解决服务不可用时,及时拉出服务降低影响的默认方式,如下图所示。

          1. 服务B的一个节点断网或是hang住,引发心跳超时;或是宕机,断链直接引发心跳失败;

          2. 注册中心把问题节点从自身的存储中拉出(这里拉出的具体表现:有的是直接删除,有的是标记为不健康)

          3. 服务A收到注册中心的通知,获取到服务B最新的列表。

            image-20210818101944779

          # Dubbo注册中心

          下面通过 Dubbo 的例子,我们来看一下注册中心是如何使用的,以及流程:首先,Dubbo 在 2.7 和 3.0 中的配置略有不同,但是都是简单易懂的。

          Dubbo-2.7

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www. springf ramework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
          <!-- 提供方应用信息,用于计算依赖关系 -->
                              
          
          <dubbo:application name="hello-world-app"/>
                                                   
          <!-- 使用multicast广播注册中心暴露服务地址 -—>
          <dubbo:registry address="multicast://224.5.6.7:1234" />
                                                              
          <!-- 用dubbo协议在20880端口暴露服务 -->
          <dubbo:protocol name="dubbo" port="20880" />
                                                   
          <!-- 声明需要暴露的服务接口 -->
          ref="demoService"
          <dubbo:service interface="org.apache.dubbo.demo.DemoService"
                                                                      
          <!-- 和本地bean一样实现服务 -->
          <bean id="demoService" class="org.apache. dubbo. demo. provider.DemoServiceImpl"/>
          </beans>
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23

          Dubbo-3.0

          # application.properties
          dubbo
          	registry
          		address: zookeeper://127.0.0.1:2181
          
          1
          2
          3
          4

          在 RPC 客户端只需要配置一个注册中心的地址即可,地址中包含了基础三元素:

          1. protocol(协议类型)比如,zookeeper;
          2. host;
          3. port。

          基于此,Doubbo的注册流程如下所示:

          1. 服务的生产方通过 Dubbo 客户端向注册中心(Registry)发起注册行为(register);
          2. 服务的消费方通过 Dubbo 客户端订阅信息(subscribe);
          3. 注册中心通过通知的方式,下发服务列表给服务消费方。

          组件流程图:

          image-20210818102021649

          # 注册中心的本质

          通过前文的讲解,以及 Dubbo 组件的具体例子,我们大概可以归纳注册中心的本质。

          “存储” + “可运维”

          1. 一方面,注册中心需要存储能力去记录服务的信息,比如应用列表;
          2. 另一方面,注册中心在实践过程中,需要提供必需的运维手段,比如关闭某一服务流量

          # 蚂蚁注册中心编年史

          # 一、史前时代

          史前时代的蚂蚁是相当久远的架构,当时所有服务部署在同一台物理机或者JVM上,服务之间不存在有跨机器调用的场景,这里略过不表述。

          单体服务

          image-20210818102053899

          # 二、硬负荷时代

          后来,为了解决应用之间的耦合带来的部署难,运维难问题,我们对服务进行了拆分,拆分后的服务,遇到了一个问题,就是如何处理服务之间的调用关系,这个时候,蚂蚁用了两种硬负载F5或是LVS。

          通过简单的四层代理,我们可以把服务部署在代理的后面,服务与服务之间通过代理互相访问,达到了跨机调用的目的。

          F5硬负载均衡

          image-20210818102122364

          # 三、第一代注册中心 --硬负载到软负载的演变

          通过硬负载访问的方式,一方面解决了服务之间调用的问题,部署架构也简单易懂;另一方面,在业务快速增长之后,却带来了一定的问题:

          1. 单点的问题(所有调用都走F5的话,F5一旦挂了,很多服务会不可用);
          2. 容量问题(F5承载的流量太高,本身会到一个性能瓶颈);

          这个时候,蚂蚁引进了阿里集团的一款产品叫 ConfigServer,作为注册中心进行使用,这个注册中心的架构就和开头提到的架构很像了,服务之间可以通过 IP 直接访问,而降低了对负载均衡产品的强依赖,减少了单点风险。

          image-20210818102156365

          # 四、第二代注册中心 --ScaleUp?ScaleOut?it‘s a problem

          但是,问题还在持续,那就是注册中心,本身就是一个单点,那么,他就会持续遇到上文中所说的两个问题:

          1. 单点风险(注册中心本身是单机应用)
          2. 容量瓶颈(单台注册中心的连接数和存储数据的容量是有限的)

          解决的方式有两种:

          1. scale-up(淘宝):通过增加机器的配置,来增强容量以及扛链接能力(弹性扩容);同时,通过主-备这样的架构,来保障可用性;

          2. scale-out(蚂蚁):通过分片机制,将数据和链接均匀分布在多个节点上,做到水平拓展;通过分片之后的备份,做到高可用。

            两种节点拓展方式:

            Scale Up:称为单节点系统,指系统中只包括一个有效节点(如果需要HA时,可以将两个单节点以System Replication形式构成单节点的HA架构)。这种架构的系统只具有垂直扩展能力,当需要扩展系统时,通过在节点上增加更多的CPU、内存和硬盘来扩大系统的能力。

            Scale Out:称为集群系统。指由多个节点组成的SAP HANA系统,这种系统的扩展主要以水平扩展方式(指增加节点的方式)来进行。

          蚂蚁和淘宝走了两条不同的路,也推进了蚂蚁后面演进出一套独立的生态系统。

          蚂蚁的演进架构如下,产生了两种不同的应用节点:

          1. Session 节点,专门用来抗链接使用,本身无状态可以快速扩展,单机对资源的占用很小;
          2. Data 节点,专门用来存储数据,通过分片的方式降低单个节点的存储量,控制资源占用;(分布式存储系统?)
          image-20210818102219244

          # 五、第五代注册中心 --Meta节点的诞生

          上面的架构已经很符合目前主流的分布式架构了,但是在运维过程中,产生了一系列问题,比如:

          1. 所有Data都是分布式的,Data之间的服务发现需要通过启动时给定一个配置文件,这样就和标准运维脱钩;
          2. Data节点的上下限需要去及时修改配置文件,否则集群重启会收到影响;
          3. 分布式存储一致性问题,每次迭代发布,需要锁定pass平台,防止节点变动带来的不一致。

          从CAP定理方向思考分布式架构带来的一些问题

          所有这些问题的产生,我们发现可以引入一个元数据管理中心(Meta)节点来,解决对Data和Session管理的问题,Data和Session通过4层负载或是7层负载对Meta访问即可。

          简单理解四层和七层负载均衡:理解网络的7层协议,所谓四层就是基于IP+端口的负载均衡;七层就是基于URL等应用层信息的负载均衡;

          对比业界的解决方案,都有类似的模型,比如HDFS的Name Node、kafka依赖于ZK,OceanBase依赖于RootServer或者配置中心Apollo依赖于Euraka。

          Meta节点的出现,缓解了手工运维注册中心的瓶颈,但是,依然没有从根本上解决问题,那么问题在哪里?详见下文分析

          通过Meta节点管理元数据,自动化的实现云数据和资源管理

          # 六、第六代注册中心 --面向运维的注册中心

          上文说到,Meta节点(元数据节点)的出现,解决了Data以及Session之间服务发现的问题,但是,从云测来讲,还是有很多问题解决不了,比如:

          1. Data节点的发布在数据量大的前提下,依然是个痛点;

          2. session节点的新加节点上,可能很久都没有流量。

          等等,对于这些问题,在SOFARegistry的基础上,我们快速迭代了6.0版本,主要是面向运维的注册中心。

          Data节点发布难的问题,说到底是一个影响范围的问题,如何控制单一Data节点发布或者挂掉对数据的影响面,是解决问题的本院,这里我们采用了两个措施:

          1. 改进存储数据算法(consistent-hash -> hash-slot);
          2. 应用级服务发现

          从删除节点和增加节点的优点上分析一致性哈希-->哈希槽 两种算法的区别

          # 存储算法的演进

          之前我们使用了一致性Hash的算法,如下图所示,每一个节点承载一部分数据,通过存储进行hash运算,算出存储内容(文件)的hash值,再计算出hash值落在哪一个Data锁所负责的存储区间,来存储数据。

          当Data节点宕机或者重启时,由下一个Data节点接收宕机节点的数据及数据的访问支持。

          这样依赖,数据迁移的粒度只能以单个 Data 节点所存储的数据为单位,在单个节点数据量较大(单节点 8G)的情况下,对数据的重建有一定的影响,而且,在 Data 连续宕机的情况下,可能存在数据丢失或是不一致的场景。

          改进后的算法,我们参考了 Redis Cluster 的算法机制,使用 hash slot (hash 槽)进行数据分片

          image-20210818102238172

          这样,在Data发布的过程中,可以控制数据的迁移以slot为单位(单个Data节点多个slot,可配置)

          image-20210818102305372

          同时,为了解决迁移或是宕机期间,数据写入不一致的场景,我们引入了数据回放的补偿机制,Data 在 promotion 为 slot 的 master 之后,会主动地去和所有的 Session 完成一次数据比对/校验,增量同步新增数据。

          (2)应用级服务发现

          应用级服务发现是为了解决数据存储量大的问题,因为篇幅原因,这里略过不表述。

          # 开源

          SOFARegistry 从项目早期就开始了开源的进程,与目前主流的注册中心的对比如下:

          我们认为,注册中心首先需要解决的是可用性的问题,所以,在分布式一致性的问题上,我们选择了 AP 的模型,这点也和主流的注册中心,例如 Euraka 以及 Nacos 保持一致的观点。

          其次,在性能方面,基于长连接的 SOFARegistry 拥有更短的推送延迟,相较于 Nacos 1.0 的推送时延更短(Nacos 1.0 基于 Long Polling 的模型,Nacos 2.0 也使用了长连接的模型)。

          在协议方面,SOFARegistry 使用了蚂蚁开源协议栈:BOLT 协议(类似于 HTTP 2.0)的流式协议,更加轻量级,同时协议本身的全双工模式:无阻塞,大大提升了资源利用率。

          image-20210818102336105

          和大家所熟知的 Nacos 对比,我们在金融级和分布式(存储量级)上具有很大优势,易用性和云原生方面,目前还在追赶。

          image-20210818102422704

          # 共同建设

          SOFARegistry 是一个开源项目,也是开源社区 SOFA 重要的一环,我们希望用社区的力量推动 SOFARegistry 的前进,而不是只有蚂蚁的工程师去开发。我们在今年也启动了两个项目,用于支持更多的开发者参与进来:

          Trun-Key Project (开箱即用计划):

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

          Deep-Dive Project(深入浅出计划):

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

          计划目前还处在初期阶段,欢迎大家加入进来,可以帮助我们解决一个 issue,或是写一篇文档,都可以更好地帮助社区,帮助自己去成长。

          编辑 (opens new window)
          上次更新: 2021/08/20, 10:37:42
          最近更新
          01
          万字长文:选 Redis 还是 MQ,终于说明白了!
          10-11
          02
          Typora+gitee+自定义命令实现图床
          09-13
          03
          字节终面:两个文件的公共url怎么找?
          09-09
          更多文章>
          Theme by Vdoing | Copyright © 2019-2022 Vic | MIT License
          • 跟随系统
          • 浅色模式
          • 深色模式
          • 阅读模式
          ×