深入理解Consul注册中心机制_雪中的记忆的博客-程序员宝宝_consul注册中心

技术标签: 微服务  consul  服务发现  系统架构  分布式  

概述

Consul作为注册中心,提供服务发现、配置、健康检查、安全服务通信以及多数据中心等功能, 这些功能可以根据需要单独使用,也可以一起使用来构建完整的微服务系统。

Consul agent

Consul agent是Consul的核心进程。它是运行在Consul节点上,这些节点共同组成Consul集群。agent进程用于维护成员信息、注册服务、成员健康检查等功能,agent有如下两种模式运行:

  • 客户端模式(client)通过Client模式启动节点加入Consul集群中,这种模式启动的节点数量没有限制,而且它们可以轻松扩展到数千或数万。在同一个数据中心组成的集群中,所有节点参与gossip协议。通过使用gossip协议检测节点故障, 比单纯的心跳方案具有更大的可扩展性。它还为节点提供故障检测;如果agent不可达,则节点可能出现故障。Client节点缓存server节点的数据,用以提高性能和可用性。
  • 服务端模式(server)通过Server模式启动agent节点参与选举。在生产环境中3到5台服务器组成。这在故障情况下的可用性和性能之间取得了平衡,因为随着增加更多的服务器,一致性会逐渐变慢。集群中所有Server启动模式的agent节点参与Raft协议,共同选举出领导者。选举出领导者的节点负责查询数据以及数据同步到其它Server节点上

agent节点启动

  1. 从官网下载Consul压缩包

  2. 解压启动。如下:

    [[email protected] consul]# consul agent -data-dir=/tmp/consul -node=server184.43 -datacenter=unite-dc -server=true
    ==> Starting Consul agent...
               Version: 'v1.7.2'
               Node ID: '74124b5b-aedc-59c3-5e6c-436443f2c025'
             Node name: 'server184.43'
            Datacenter: 'unite-dc' (Segment: '<all>')
                Server: true (Bootstrap: false)
           Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: -1, DNS: 8600)
          Cluster Addr: 172.27.185.43 (LAN: 8301, WAN: 8302)
               Encrypt: Gossip: false, TLS-Outgoing: false, TLS-Incoming: false, Auto-Encrypt-TLS: false
    
    ==> Log data will now stream in as it occurs:
    
        2022-03-14T11:50:01.620+0800 [WARN]  agent: Node name will not be discoverable via DNS due to invalid characters. Valid characters include all alpha-numerics and dashes.: node_name=server184.43
        2022-03-14T11:50:01.625+0800 [INFO]  agent.server.raft: initial configuration: index=0 servers=[]
        2022-03-14T11:50:01.625+0800 [INFO]  agent.server.serf.wan: serf: EventMemberJoin: server184.43.unite-dc 172.27.185.43
        2022-03-14T11:50:01.626+0800 [INFO]  agent.server.serf.lan: serf: EventMemberJoin: server184.43 172.27.185.43
        2022-03-14T11:50:01.627+0800 [INFO]  agent: Started DNS server: address=127.0.0.1:8600 network=udp
        2022-03-14T11:50:01.627+0800 [INFO]  agent.server.raft: entering follower state: follower="Node at 172.27.185.43:8300 [Follower]" leader=
        2022-03-14T11:50:01.628+0800 [INFO]  agent.server.serf.wan: serf: Attempting re-join to previously known node: server29.6.dc1: 172.27.185.43:8302
        2022-03-14T11:50:01.629+0800 [INFO]  agent.server.serf.lan: serf: Attempting re-join to previously known node: server29.6: 172.27.185.43:8301
        2022-03-14T11:50:01.629+0800 [INFO]  agent.server: Adding LAN server: server="server184.43 (Addr: tcp/172.27.185.43:8300) (DC: unite-dc)"
        2022-03-14T11:50:01.629+0800 [INFO]  agent.server: Handled event for server in area: event=member-join server=server184.43.unite-dc area=wan
        2022-03-14T11:50:01.630+0800 [INFO]  agent: Started DNS server: address=127.0.0.1:8600 network=tcp
        2022-03-14T11:50:01.630+0800 [INFO]  agent: Started HTTP server: address=127.0.0.1:8500 network=tcp
        2022-03-14T11:50:01.631+0800 [INFO]  agent: started state syncer
    ==> Consul agent running!
    ....
    

通过consul agent命令启动成功后,通过日志输出有如下关键信息。如下:

  • Node name是节点名字,在集群中唯一的。启动时通过-node配置自定义设置节点名字
  • Datacenter是数据中心名字,通过-datacenter配置数据中心名字
  • Server是Consul agent运行(server还是client)模式,通过-server配置。

agent节点状态

alive状态

该节点状态处于正常状态。 当agent节点首次启动时,通过如下配置自动完成加入集群中。一旦节点加入集群后,该节点的信息会传递给整个集群,集群中所有的节点成员都会知道彼此的存在。如果该节点是Server模式运行的,其它Server节点会进行日志复制。

retry_join = ["172.26.4.38","172.26.4.125"]

failed状态

当出现网路故障或者agent进程关闭时,这些节点可能无法被其它节点访问,把这些节点标记为失败(failed)状态。 此时对failed状态的节点,Consul Server(领导者)节点会尝试重新连接该节点。可以看到leader节点日志输出如下:

# client29.118 has failed, no acks received
2021-11-24T16:10:06.279+0800 [INFO]  agent.server.memberlist.lan: memberlist: Suspect client29.118 has failed, no acks received
2021-11-24T16:10:10.268+0800 [INFO]  agent.server.serf.lan: serf: EventMemberFailed: client29.118 172.24.29.118
2021-11-24T16:10:10.269+0800 [INFO]  agent.server: member failed, marking health critical: member=client29.118
2021-11-24T16:10:36.310+0800 [INFO]  agent.server.serf.lan: serf: attempting reconnect to client29.118 172.24.29.118:8301
2021-11-24T16:12:06.314+0800 [INFO]  agent.server.serf.lan: serf: attempting reconnect to client29.118 172.24.29.118:8301

从日志输出看出,当节点标记为故障状态,leader节点会默认每隔30s尝试重新进行连接。此时通过Consul命令查看节点状态,client29.118节点状态是failed状态。如下:

[[email protected] consul]# consul members
Node           Address             Status  Type    Build  Protocol  DC             Segment
server29.6     172.24.29.6:8301    alive   server  1.7.2  2         test-leave-dc  <all>
server29.9     172.24.29.9:8301    alive   server  1.7.2  2         test-leave-dc  <all>
service29.186  172.24.29.186:8301  alive   server  1.7.2  2         test-leave-dc  <all>
client29.118   172.24.29.118:8301  failed  client  1.7.2  2         test-leave-dc  <default>

注意:当网络恢复或者agent被重新启动,节点状态更新为正常(alive)状态。

left状态

对于failed状态的节点,默认72小时,Consul会完全的把它从集群中移除掉,此时的节点标记为离开(left)状态,和失败状态(failed)不同。left状态节点上注册所有服务会被删除,如果节点是server模式启动,停止对它的日志复制。该值由如下参数设置。

reconnect_timeout = "1h"  //可以用“s”、“m”、“h”表示秒、分钟或小时。该值必须为大于8小时。

注意建议将其值设置为节点或者网路分区的最大预期恢复中断的两倍。时间设置过低可能会导致节点故障或者网络分区期间,从Consul集群中删除节点,导致集群恢复复杂。对于failed状态的节点,可以在其它节点发送HTTP请求,强制把它从failed状态变成left状态,对left状态的节点,leader节点不会尝试重新连接。

curl http://172.24.29.186:8500/v1/agent/force-leave/client29.118

leader节点日志变化如下:

2021-11-24T16:27:13.767+0800 [INFO]  agent.server.serf.lan: serf: EventMemberLeave (forced): client29.118 172.24.29.118
2021-11-24T16:27:13.767+0800 [INFO]  agent.server: deregistering member: member=client29.118 reason=left

对于left状态节点,serf组件内有tombstone_timeout参数控制left状态的节点被收割需要时间。收割理解为节点是left状态,从成员中移除掉。默认24小时后,left状态的节点从成员中移除掉。

注意agent进程优雅的关闭,节点会从alive状态变为left状态。

Consul Architecture

下图表示是系统中多数据中心组成Consul集群架构图。每个数据中心都是局域网内Consul集群。如下图所示,有两个数据中心,分别是DATACENTER1DATACENTER2。不同的数据中心之间不会进行数据同步,但是可以通过RPC请求其它数据中心数据。 在DATACENTER1的数据中心,存在两种启动模式agent节点,分别是Server和Client。
在这里插入图片描述

从上图看出Consul需要多个不同的端口才能正常工作,其中一些端口使用TCP、UDP或者两种协议。主要端口详情如下:

  1. Server RPC(TCP)端口是8300。用于其它Client节点请求Server节点以及Server节点之间交互请求端口。
  2. HTTP(TCP)端口8500。用于客户端通过HTTP API通信端口。
  3. LAN Serf( TCP and UDP )端口8301。用于集群所有节点之间Gossip协议通信端口 。
  4. DNS( TCP and UDP )端口8600。用于解析DNS查询信息。

Raft协议在Consul应用

所有Consul Server节点参与Raft协议,共同组成Peer SetPeer set理解为参与日志复制所有成员的集合。所有Consul Client节点把请求转发给Consul Server节点。这种设计主要原因是,随着更多Consul节点成员的加入到Peer Set中。 quorum 的大小也会增加。quorum 理解为多数派。对于N个Consul Server节点成员,quorum要求至少有(N/2)+1成员。例如,peer set有5个Server节点,就须要至少3个节点才能造成quorum。

注意: Raft协议理解共识(Consensus)协议。

启动选举

当Consul通过Server模式启动agent进程时,这种模式允许它们选举出领导者。通过查看Consul启动日志看出选举过程,如下通过三个Server节点组成Peer set参与选举。

  1. 引导模式启动,通过配置bootstrap_expect = 3期望``Peer set`大小为3。

    [INFO] bootstrap_expect > 0: expecting 3 servers
    
  2. 在Raft协议初始化状态下,Server节点启动默认是跟随者(follower)状态。

    [INFO] agent.server.raft: initial configuration: index=0 servers=[]
    [INFO] agent.server.raft: entering follower state: follower="Node at 172.24.29.6:8300 [Follower]" leader=
    
  3. 从 Consul启动完成后,使用配置retry_join = ["172.26.4.38","172.26.4.125"]属性,通过self组件发现参与选举的节点数。当达到期望节点数后 最先超时的跟随者节点会增加自己的任期编号,并推举自己为候选人(candidate),给自己投票,然后向其它节点发送请求投票 RPC 消息,请它们选举自己为领导者。

    [INFO] Consul agent running! Consul Agent
    [INFO] agent.server.raft: no known peers, aborting election #没有发现peer set,停止选举
    #发现预期Peer set数目,尝试引导
    [INFO] agent.server: Found expected number of peers, attempting bootstrap
    #最先超时的节点 增加自己的任期(term)编号,推举自己为候选人,给自己投票
    [INFO] agent.server.raft: heartbeat timeout reached, starting election: last-leader=  
    [INFO] agent.server.raft: entering candidate state: node="Node at 172.24.29.6:8300 [Candidate]" term=2  
    
  4. 获取票数最多的节点,它就会成为本届任期内新的领导者。如果节点当选领导者后,它将周期性地发送心跳消息,通知其它跟随者节点不再发起选举。

    [INFO]  agent.server.raft: election won: tally=2
    [INFO]  agent.server.raft: entering leader state: leader="Node at 172.24.29.6:8300 [Leader]"
    
  5. 开始日志复制

    #已经添加Peer set中,开始日志复制,peer指向其它节点id
    [INFO]  agent.server.raft: added peer, starting replication: peer=e6a8a239-1c5a-3a17-20ab-176fc8c5056e
    [INFO]  agent.server.raft: added peer, starting replication: peer=b4b9fee5-54d9-0455-2cf0-dc647a3af745l
    

当一个RPC请求到达非Leader Server节点,请求就会被转发到Leader节点。请求分为两种类型:

  • 查询(query)类型,这意味着它是只读的,Leader会基于FSM状态机生成相应的结果;
  • 操作(transaction)类型,即修改状态,Leader节点产生一个新的日志条目,并基于Raft算法进行管理。一旦日志条目应用于 FSMFSM可以理解为有限状态机,有限个状态以及在这些状态之间的转移和动做等行为的数学模型。新日志的应用,FSM会发生状态转换,相同的日志序列的应用必须致使相同的状态。

每一个数据中心选择独立的Leader和维护Peer set。数据按照数据中心进行划分,因此每一个Leader只负责在相应数据中心的数据。

一致性(Consistency)模式

虽然全部日志副本的写入都是基于Raft,读取更灵活。但为了支持开发人员可能须要的各类权衡,Consul支持3种不一样的一致性模式。

​ 三种读模式是:

  • default:客户端访问领导者节点执行读操作,领导者确认自己处于稳定状态时(在 leader leasing 时间内),返回本地数据给客户端,否则返回错误给客户端。在这种情况下,客户端是可能读到旧数据的,比如此时发生了网络分区错误,新领导者已经更新过数据,但因为网络故障,旧领导者未更新数据也未退位,仍处于稳定状态。
  • consistent:客户端访问领导者节点执行读操作,领导者在和大多数节点确认自己仍是领导者之后返回本地数据给客户端,否则返回错误给客户端。在这种情况下,客户端读到的都是最新数据。
  • stale:从任意节点读数据,不局限于领导者节点,客户端可能会读到旧数据

Gossip协议在Consul应用

Consul使用Gossip协议管理成员并向集群广播消息,Gossip协议是通过使用Serf库提供的。Serf是一个用于集群节点成员(membership)发现、故障检测(failure detection)和编排的工具组件。它是分散的、容错的和高可用性的。非常轻量级运行在内存中脚本中,使用UDP消息进行通信,它使用gossip协议。Consu屏蔽Serf的抽象提供这些特性。Consul使用两个不同的Gossip Pool,如下:

  1. LAN Gossip Pool
  2. WAN Gossip Pool

在Consul中,每个数据中心都有一个LAN Gossip Pool,这里面包含这个数据中心的所有成员节点。主要作用如下:

  1. 成员信息允许客户端自动发现服务器,减少所需的配置。
  2. 分布式故障检测工作由整个集群节点共同分担,而不是集中在Consul Server节点上。
  3. Gossip Pool具有可靠和快速的事件广播。

在多数据中心组成服务中,WAN Gossip Pool是唯一的。不同数据中心下的所有节点都参与 WAN Pool, 该池允许服务器执行跨数据中心请求。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/suntj123456/article/details/123475365

智能推荐

discuz7.0 _post.php xss跨站漏洞-学习笔记_小龙在山东的博客-程序员宝宝

漏洞名称discuz7.0 _post.php xss跨站漏洞发布时间2014-06-02漏洞分类反射型xss漏洞缺陷代码没有对所有参数进行过滤。if($action == 'reply') { $addfeedcheck = $customaddfeed &amp; 4 ? 'checked="checked"': '';} elseif(!empty($special) &amp;&amp; $action != 'reply') { $addfeedcheck = $

rtems网络移植-网卡的注册和初始化_weixin_33961829的博客-程序员宝宝

上篇博文介绍了在rtems下实现和网卡lan8710的通信,接下来就是实现网卡的标准化注册和初始化。在这里本人参考了rtems m68k中gen68360的网络驱动文件和《tcp/ip详解卷二》:首先是驱动的attach函数:The driver attach function is responsible for configuring the driv...

Convert java.awt.image.BufferedImage to java.awt.Image_iteye_7729的博客-程序员宝宝

参考http://www.java2s.com/Code/Java/2D-Graphics-GUI/ConvertjavaawtimageBufferedImagetojavaawtImage.htm使用javax.swing.GrayFilter.createDisabledImage(Image i)得到的是java.awt.Image无法使用ImageIO.write()来输出文件...

第三次周赛C - Problem C CodeForces - 822A_Elenaaab的博客-程序员宝宝

Holidays have finished. Thanks to the help of the hacker Leha, Noora managed to enter the university of her dreams which is located in a town Pavlopolis. It’s well known that universities provide stud...

linux scala安装与配置详解_IT狗探求的博客-程序员宝宝_linux配置scala

一.配置前准备1.scala运行在jvm虚拟机,需要配置jdk,具体见linux jdk1.8环境配置;2.官网下载scala,本文使用scala-2.11.8二.scala安装和配置1.定位到 /opt/software目录,如果不存在,新增目录mkdir -p /opt/software2.上传scala包到 /opt/software目录3.解压tar -zxvf scala-2.11.8.tgz4.复制解压包到 /usr/local/scala目录cp -r

随便推点

文件dos转为unix格式_smile~成长的博客-程序员宝宝

dos格式和unix格式差别就在于换行符。 只要把所有的换行符统一,就完成了转换。1.vim 打开文件,编辑款是否是dos2.vim -b 打开文件,看是否有^M3.cat -v 看文件,看是否有^M解决办法:1、unix2dos 文件 是转为dos格式dos2unix 文件 是转为unix2、执行这个命令sed -i ‘s/\r//g’ 文件名...

嵌入式环境搭建之ssh_冀博的博客-程序员宝宝

快毕业了。临走前帮导师搭建了gerrit,git服务器,其中涉及ssh的知识,就总结了下。希望对大家有帮助一、前言(ssh出世的原因)万物有因就有果,既然ssh存在,就必然有它存在的理由!许多网络程序,如telnet、rsh、rlogin或rexec,用明文(plain text)传送口令和秘密的信息,所以可利用任何连接到网络上的计算机监听这些程序和服务器之间的通信并获取口令和秘密信息。现在,te

新手程序员如何快速成长?_六月的雨儿的博客-程序员宝宝

作为一个新手,我们该如何让自己快速的成长起来?这篇文章从几个方面给与您一些建议,有心人可以看看,参考参考。java学习方法和免费教程推荐: 干货总结,自学java需要避免的几个坑。关于java的最基础的知识(1-5) 关于java的最重要的基础知识(6-10)一、让我们做更多种类的事 为什么有人说小公司锻炼人? 在小公司,条件并不那么齐备,很多事情都需要程序员自己做,自己去澄清需求、自己做设计、自己搭建...

Sqllibs-less29-31-WAF_xor0ne_10_01的博客-程序员宝宝

文章目录29.less29-Protection with WAF30.less30-Protection with WAF-Double Quotes31.less31-FUN with WAF本文主要来自于:https://www.cnblogs.com/lcamry/category/846064.html29.less29-Protection with WAF参考链接:https://www.cnblogs.com/lcamry/p/5762952.html首先先看下tomcat中的ind

浏览器调用摄像头getUserMedia_明明很开心_l的博客-程序员宝宝_webkitgetusermedia

浏览器调用摄像头getUserMedia2018年启动QQ浏览器会启动摄像头的新闻闹得沸沸扬扬。前段时间公司让研究一下这个浏览器启用摄像头的功能,希望能够实现浏览器网页扫描二维码的功能。现在写下来记录一下。浏览器启用摄像头是使用getUserMedia这个api实现的,调用后会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。。此流可以...

css的三种嵌入样式_ahgtw68680的博客-程序员宝宝

1. 内联式样式  以css形式嵌入到页面的元素中,比如input2.嵌入式样式  以style容器形式嵌入到页面的head标签中,&lt;style&gt;&lt;/style&gt;3.外部式样式  以.css文件存在外部中,通过&lt;link rel="stylesheet" href="*.css" type="text/css"/&gt;嵌入到页面中。...