Consul 服务注册与发现一站式解决方案

 

consul简介

 

  • Consul 是一个支持多数据中心分布式高可用的服务发现和配置共享的服务软件,由 HashiCorp 公司用 Go 语言开发, 基于 Mozilla Public License 2.0 的协议进行开源. Consul 支持健康检查,并允许 HTTP 和 DNS 协议调用 API 存储键值对.
  • 一致性协议采用 Raft 算法,用来保证服务的高可用. 使用 GOSSIP 协议管理成员和广播消息, 并且支持 ACL 访问控制.
  • Consul 的方案更 "一站式",内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其他工具(比如 ZooKeeper 等)。使用起来也较为简单。Consul 用 Golang 实现,因此具有天然可移植性(支持 Linux、windows 和 Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合

 

使用场景

 

  • docker 实例的注册与配置共享
  • coreos 实例的注册与配置共享
  • vitess 集群
  • SaaS 应用的配置共享
  • 与 confd 服务集成,动态生成 nginx 和 haproxy 配置文件

产品对比

 

同类工具有以下这些

etcd Distributed reliable key-value store for the most critical data of a distributed system

zookeeper Apache ZooKeeper is an effort to develop and maintain an open-source server which enables highly reliable distributed coordination.

 

相同点

  • 架构类似,都有服务节点,而这些服务节点的操作都要求达到节点的仲裁数(通常,节点的仲裁数遵循的是简单多数原则
  • 强一致性,用于构建复杂的分布式系统

不同点

  • zooKeeper, etcd只提供一个原始的K/V值存储,并要求开发人员构建他们自己的系统来提供服务发现功能,cosnul提供服务发现功能
  • consul基于gossip的健康检查机制脱颖而出。ZooKeeper健康检查机制需要胖客户端,增加了工作量。etcd无健康检查功能
  • consul使用Raft算法来保证一致性, 比复杂的Paxos算法更直接. 相比较而言, zookeeper采用的是 Paxos, 而 etcd 使用的则是 Raft.
  • 支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障, 而其部署则需要考虑网络延迟, 分片等情况等. zookeeper和etcd 均不提供多数据中心功能的支持.
  • 支持 http 和 dns 协议接口. zookeeper的集成较为复杂, etcd 只支持 http 协议.
  • 官方提供web管理界面, etcd 无此功能

 

架构

 

术语解释

Consul集群间使用了GOSSIP协议通信和raft一致性算法。

  • Agent——agent是一直运行在Consul集群中每个成员上的守护进程。通过运行consul agent来启动。agent可以运行在client或者server模式。指定节点作为client或者server是非常简单的,除非有其他agent实例。所有的agent都能运行DNS或者HTTP接口,并负责运行时检查和保持服务同步。
  • Client——一个Client是一个转发所有RPC到server的代理。这个client是相对无状态的。client唯一执行的后台活动是加入LAN gossip池。这有一个最低的资源开销并且仅消耗少量的网络带宽。
  • Server——一个server是一个有一组扩展功能的代理,这些功能包括参与Raft选举,维护集群状态,响应RPC查询,与其他数据中心交互WAN gossip和转发查询给leader或者远程数据中心。
  • DataCenter——我们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。
  • Consensus——一致性,使用Consensus来表明就leader选举和事务的顺序达成一致。为了以容错方式达成一致,一般有超过半数一致则可以认为整体一致。Consul使用Raft实现一致性,进行leader选举,在consul中的使用bootstrap时,可以进行自选,其他server加入进来后bootstrap就可以取消。
  • Gossip——Consul建立在Serf的基础之上,它提供了一个用于多播目的的完整的gossip协议。Serf提供成员关系,故障检测和事件广播。Serf是去中心化的服务发现和编制的解决方案,节点失败侦测与发现,具有容错、轻量、高可用的特点。
  • LAN Gossip——

Consul中的每个数据中心有一个LAN池,它包含了这个数据中心的所有成员,包括clients和servers。LAN池用于以下几个目的:

成员关系信息允许client自动发现server, 减少了所需要的配置量。

分布式失败检测机制使得由整个集群来做失败检测这件事, 而不是集中到几台机器上。

gossip池使得类似领导人选举这样的事件变得可靠而且迅速。

  • WAN Gossip——

WAN池是全局唯一的,因为所有的server都应该加入到WAN池中,无论它位于哪个数据中心。由WAN池提供的成员关系信息允许server做一些跨数据中心的请求。一体化的失败检测机制允许Consul优雅地去处理:整个数据中心失去连接, 或者仅仅是别的数据中心的某一台失去了连接。

  • RPC——远程过程调用。这是一个允许client请求server的请求/响应机制。

 

架构分解

  • 首先,我们可以看到有两个数据中心,标签为"Datacenter 1"和"Datacenter 2"。consul对多数据中心提供最高等级的支持并预期这将成为普遍情况。
  • 在每个数据中心内,混合有客户端和服务器。预期由3到5个服务器。强调在失败情况下的可达到和性能之间的平衡,因为添加更多机器会导致一致性变得日益缓慢。不过,对于客户端的数量没有限制,而且可以很容易的扩展到成千上万。
  • 在一个数据中心内的所有节点加入一个gossip 协议。这意味着对于一个给定的数据中心,有一个包含所有节点的gossip池。这服务于几个目的:
  • 首先,不需要用服务器地址来配置客户端;发现是自动完成的。
  • 其次,检测节点失败的工作不是放置在服务器上,而是分布式的。这使得失败检测比心跳机制更加可扩展。
  • 另外,当重要事件比如leader选举发生时它被用来作为消息层(messaging layer)来通知。
  1. 每个数据中心中的服务器是单个Raft 端集合(peer set)的所有组成部分。这意味着他们一起工作来选举leader,一个有额外职责的被选定的服务器。leader负责处理所有请求和事务。事务也必须复制到所有作为一致协议一部分的端(peer)。因为这个要求,当一个非leader服务器收到RPC请求时,它转发请求到集群leader。
  • 服务器节点也作为广域网 gossip 协议池的一部分运作。这个池和局域网池有所不同,因为它为因特网的高延迟做了优化并预期只包含其他consul服务器(注:特指在其他数据中心中的consul服务器,见图中的"Datacenter 2")节点。这个池的目的是容许数据中心们以低接触(low-touch)风格相互发现。上线一个新的数据中心和加入现有的广域网gossip一样容易。因为服务器都在全体经营这个池,池可以开启跨数据中心请求。当服务器收到一个给不同数据中心的请求时,它转发请求到正确的数据中心中的任意服务器。这个服务器可能随即转发给本地leader。
  • 这使得数据中心之间的耦合的非常低。而因为失败检测,连接缓存和多路通讯,跨数据中心请求相对比较快而可靠。

 

Gossip协议

 

  • Gossip算法如其名,灵感来自办公室八卦,只要一个人八卦一下,在有限的时间内所有的人都会知道该八卦的信息,这种方式也与病毒传播类似,因此Gossip有众多的别名“闲话算法”、“疫情传播算法”、“病毒感染算法”、“谣言传播算法”。
  • 但Gossip并不是一个新东西,之前的泛洪查找、路由算法都归属于这个范畴,不同的是Gossip给这类算法提供了明确的语义、具体实施方法及收敛性证明。
  • http://blog.csdn.net/u012422829/article/details/77828870

Anti-Entropy(反熵)

  • Consule 使用一个高级的方式来维护 service 和 health 信息的方法。Anti-Entropy(反熵 ) 机制被用来保证在不同节点上的备份(replica)都持有最新版本
  • Agent
  •   每个Consul agent维护它自己的服务集合以及检查注册和健康信息。agent负责执行自己的健康检查和更新本地状态。
  • Catalog
  •   Consul的服务发现基于一个服务目录。这个目录是通过聚合agents提交的信息形成的。目录维护了集群的高级视图,它包括哪些服务可用,哪些节点允许这些服务,健康信息等等。目录是用来展示这些信息的,可以通过各种Consul提供的接口,包含DNS和HTTP。
  •   与agent相比,目录上下文中的服务和检查的字段更为有限。这是因为目录只服务于记录和返回关于服务,节点和健康的信息。
  •   只有server节点维护目录。这是因为目录是通过Raft日志复制来提供一个统一的集群视图。
  • http://blog.mallux.me/2017/03/19/consul/
  • http://www.voidcn.com/article/p-oqtnkvov-ye.html

一致性Raft

  • Consul使用Raft算法实现分布式存储的一致性。Raft节点在集群中有follower,candidate或leader三种状态,初始为follower,在这个状态下节点可以接收来自leader的日志单元和投票选leader。如果一段时间内收不到来自leader的心跳,则升级为candidate向集群所有node发送投票邀请,如果candidate收到过半节点的投票则升级为leader,leader负责接收日志单元并复制给所有follower
  • 集群当选出leader后才能接收新的日志单元,节点收到日志时把日志转发给leader,leader将日志保存到本地存储复制给所有follower,当超过半数的follower成功复制后日志单元状态变为‘committed’,进而交给状态机去执行。然后leader会将日志单元的committ状态发送给所有follower让他们来更新到各自状态机。
  • Consul自动的通过快照机制将Raft日志压缩来避免其无限增长
  • 在consul集群里,只有server结点通过Raft算法进行数据一致性管理,原因是Raft集群的结点数量不能太多(在3-5),如果client也参与到Raft那么随着集群结点数量增加,在Raft算法下集群效率会下降,client结点只是将数据请求转发给server

 

Raft启动方式

  • Raft集群的启动方式有两种,其中一种直接的办法是用个配置文件记录所有server的列表,每个server启动后用这个静态的列表作为Raft的server,但这需要所有server维护一个静态的配置文件
  • ‘-bootstrap’参数,如果集群先启动一个server并且他优先成为leader(Consul在这里做了特殊设置,让这个bootstrap server从log中恢复成leader状态),之后加入的所有server一直是follower状态。但这还有个问题,就是还是得固定一台server成为第一个leader,启动参数必须与其他server不同(必须带有-bootstrap)
  • ‘-bootstrap-expect’参数,所有server都用同一参数’-boostrap-expect N’说明集群的server个数为N,在有N个server join进来后,cluster开始启动raft逻辑选主。注意,N一定要与server总数相同,否则会出现split-brain(双主)问题,比如N=3 儿集群server总数为7,就很可能出现两个leader的情况。

读操作一致性

  • 对于读操作,consul支持多种一致性模式:
  • ‘default’, 这种模式下如果leader因为与成员分离导致新的leader被选出的情况下,虽然旧的leader不能再提交日志,但还可以负责进行读取操作,这回导致部分读取的数据是过期的。但这种状态不会维持多长时间,因为旧的leader的状态很快就会降级为follower
  • ‘consistent’,这种模式下要求leader给follower发消息确认仍然是leader,这就造成了读取操作时多了一步操作增加了延迟
  • ‘stale’,这个模式下每个server都可以负责读取,这就导致读出来的数据因为还未在leader把数据复制到全部follower时被读出儿造成不一致,但这种情况也是少数,并且效率会非常快,并且即便没有leader的情况下还能够提供读操作

 

健康检查

  • Agent的一个重要任务是做系统级和程序级的健康检测,检测通过配置文件或HTTP接口来定义并被保存到Agent所运行的节点
  • 定时脚本检查(script+Interval), 调用一个第三方的程序进行健康检测,使用退出码或标准输出来表明检测结果(类似Nagios), 输出内容不能超过4K,默认的检查超时时间是30秒,可以通过配置文件里的”timeout”来定义。Agent使用enable_script_checks参数来打开这种检查
  • 脚本退出码与检测结果对应关系:
  • 0, passing
  • 1, warning
  • other, failing
  • 脚本的任何输出内容会被保存到消息的‘Output’字段, Agent启动后
  • 定时HTTP检查(HTTP+Interval), 定时通过HTTP GET调用指定的URL,根绝HTTP返回码判断服务状态。‘2xx’表示通过检查,‘429’表示警告,其余均表示故障。默认情况下http请求的timeout与检查的interval相同,最长为10秒。可以通过‘timeout’来在配置文件里设置。检查返回的内容大小不能超过4K,超过部分会被截断。默认情况下支持SSL,可以通过tls_skip_verify来关掉。
  • 定时TCP检查(TCP+Interval), 定时通过TCP连接检查指定host/IP和端口,根据是否能够建立连接成功与否判定service状态,成功连接表示service正常,否则表示事态危急. 默认超时时间10秒。
  • TTL检查,通过服务主动的定时更新TTL,超过时间的定位service故障。
  • 定时Docker检查,通过调用常驻docker里的一个检查程序来进行,这个程序通过调用Docker Exec API来启动,需要consul agent具有调用Docker HTTP API或Unix Socket的权限。consul用 DOCKER_HOST 来定位Docker API端点,检查程序运行完后要返回适当的退出码和输出,输出内容不能超过4K。Agent需要通过enable_script_check来打开这种检查
  • 默认会将check的状态设置为‘critical’,这是防止服务在没有被检查前就被加入到调用这个服务的系统里

 

 

状态监视

  • 使用Whach可以监视KV、nodes、service、checks等对象的变化,当有更新时会触发watch定义的可执行的handler。
  • Watch通过阻塞的HTTP API实现,Agent会根据调用相应api请求自动监视指定内容,当有变化时通知handler
  • Watch还可以加入到Agent的配置文件中的watches生成
  • watch还可以通过‘consule watch’命令来直接运行并把结果输出到处理程序
  • 当watch监控到数据的更新,可以调用一个handler还做后续处理,watch会将监控的结果以JSON格式发送给handler的标准输入(stdin), watch不同的对象结果的格式会不同
  • watch的类型:
  • Key
  • keprefix
  • services
  • nodes
  • service
  • checks
  • event

 

Session会话

  • Consul 提供了一个可用于 构建分布式锁 的会话(session)机制。 Session 充当节点、运行状况检查和键/值数据之间的绑定层。 它们旨在提供细粒度的锁定,并受到松散耦合的分布式系统的分布式锁服务(The Chubby Lock Service for Loosely-Coupled Distributed Systems)的大量启发。
  • Consul 中的 session 表示具有非常特定语义的 contract 。 当构建会话时,可以提供节点名称、健康检查列表、行为、TTL 和 锁定延迟。 新构造的 session 具有可用于识别它的命名 ID。 此 ID 可与 KV 存储一起使用以获取锁:用于互斥的咨询机制。
  • Consule 提供的 contract ,在下列任何情况下,会话将失效:
  • 节点已取消注册
  • 任何健康检查都被取消注册
  • 任何健康检查都进入临界状态
  • 会话被明确销毁
  • TTL 到期(如果适用)
  • 当 session 无效时,会被销毁,不能再使用。 相关锁的操作取决于在创建时指定的行为。 Consul 支持 release 和 delete 行为。 如果未指定任何内容,则 release 行为是缺省值。

 



 

 

命令

kv - Key/Value存储

agent - Agent控制

catalog - 管理nodes和services

health - 管理健康监测

session - Session操作

acl - ACL创建和管理

event - 用户Events

status - Consul系统状态

 

Agent API

/v1/agent/checks : 返回本地agent注册的所有检查(包括配置文件和HTTP接口)

/v1/agent/services : 返回本地agent注册的所有 服务

/v1/agent/members : 返回agent在集群的gossip pool中看到的成员

/v1/agent/self : 返回本地agent的配置和成员信息

/v1/agent/join/<address> : 触发本地agent加入node

/v1/agent/force-leave/<node>>: 强制删除node

/v1/agent/check/register : 在本地agent增加一个检查项,使用PUT方法传输一个json格式的数据

/v1/agent/check/deregister/<checkID> : 注销一个本地agent的检查项

/v1/agent/check/pass/<checkID> : 设置一个本地检查项的状态为passing

/v1/agent/check/warn/<checkID> : 设置一个本地检查项的状态为warning

/v1/agent/check/fail/<checkID> : 设置一个本地检查项的状态为critical

/v1/agent/service/register : 在本地agent增加一个新的服务项,使用PUT方法传输一个json格式的数据

/v1/agent/service/deregister/<serviceID> : 注销一个本地agent的服务项

 

Catalog API

/v1/catalog/register : Registers a new node, service, or check

/v1/catalog/deregister : Deregisters a node, service, or check

/v1/catalog/datacenters : Lists known datacenters

/v1/catalog/nodes : Lists nodes in a given DC

/v1/catalog/services : Lists services in a given DC

/v1/catalog/service/<service> : Lists the nodes in a given service

/v1/catalog/node/<node> : Lists the services provided by a node

 

Health API

/v1/healt/node/<node>: 返回node所定义的检查,可用参数?dc=

/v1/health/checks/<service>: 返回和服务相关联的检查,可用参数?dc=

/v1/health/service/<service>: 返回给定datacenter中给定node中service

/v1/health/state/<state>: 返回给定datacenter中指定状态的服务,state可以是"any", "unknown", "passing", "warning", or "critical",可用参数?dc=

Session API

/v1/session/create: Creates a new session

/v1/session/destroy/<session>: Destroys a given session

/v1/session/info/<session>: Queries a given session

/v1/session/node/<node>: Lists sessions belonging to a node

/v1/session/list: Lists all the active sessions

ACL API

/v1/acl/create: Creates a new token with policy

/v1/acl/update: Update the policy of a token

/v1/acl/destroy/<id>: Destroys a given token

/v1/acl/info/<id>: Queries the policy of a given token

/v1/acl/clone/<id>: Creates a new token by cloning an existing token

/v1/acl/list: Lists all the active tokens

Event API

/v1/event/fire/<name>: 触发一个新的event,用户event需要name和其他可选的参数,使用PUT方法

/v1/event/list: 返回agent知道的events

Status API

/v1/status/leader : 返回当前集群的Raft leader

/v1/status/peers : 返回当前集群中参与投票的节点

自定义事件

Event:

consul event -name=test -http-addr=localhost:8500

consul watch -type=event -name=test "echo 'see it'”

Key:

curl -XPUT 'http://localhost:8500/v1/kv/web/k1' -d '{"name":"mm"}’

consul watch -type=key –key=web/k1 "echo 'see it'”

更多内容见:

http://blog.csdn.net/younger_china/article/details/52243799

 

 


 

Why client per node

SRV 中的target实际指向了注册节点的域名,所以说明 consul 的 DNS 规则是不管你service 注册的时候无论你怎么提交自己的 IP, 在 DNS 上,永远以注册的Consul节点的 IP 作为 Service 的实际 IP,都是 SRV 规则导致的,

所以总结一下,在本地部署 consul Client 的原因是标识 Service 的实际 IP, 这确实也是逼不得已的方式,如果使用 HTTPDNS 的话,效率不但低,而且算是一个私有协议,不利于和基础环境的融合.

 

 

posted @ 2019-02-12 17:16  过山车  阅读(6432)  评论(0编辑  收藏  举报