Consul详解

近期在微服务业务中用的注册中心,在此简单记录下以备后用。

一 概述

1.1 概念

Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。Consul 是分布式的、高可用的、 可横向扩展的。

1.2 特征

服务发现: Consul 提供了通过 DNS 或者 HTTP 接口的方式来注册服务和发现服务。一些外部的服务通过 Consul 很容易的找到它所依赖的服务。

健康检测: Consul 的 Client 提供了健康检查的机制,可以通过用来避免流量被转发到有故障的服务上。

Key/Value 存储: 应用程序可以根据自己的需要使用 Consul 提供的 Key/Value 存储。 Consul 提供了简单易用的 HTTP 接口,结合其他工具可以实现动态配置、功能标记、领袖选举等等功能。

多数据中心: Consul 支持开箱即用的多数据中心. 这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域。

1.3 架构图及解析

1.3.1 内部架构及原理

1.3.1.1架构图

1.2.1.2 图解

首先Consul支持多数据中心,在上图中有两个DataCenter,他们通过Internet互联,同时请注意为了提高通信效率,只有Server节点才加入跨数据中心的通信。

在单个数据中心中,Consul分为Client和Server两种节点(所有的节点也被称为Agent),Server节点保存数据,Client负责健康检查及转发数据请求到Server;Server节点有一个Leader和多个Follower,Leader节点会将数据同步到Follower,Server的数量推荐是3个或者5个,在Leader挂掉的时候会启动选举机制产生一个新的Leader。

集群内的Consul节点通过gossip协议(流言协议)维护成员关系,也就是说某个节点了解集群内现在还有哪些节点,这些节点是Client还是Server。单个数据中心的流言协议同时使用TCP和UDP通信,并且都使用8301端口。跨数据中心的流言协议也同时使用TCP和UDP通信,端口使用8302。

集群内数据的读写请求既可以直接发到Server,也可以通过Client使用RPC转发到Server,请求最终会到达Leader节点,在允许数据轻微陈旧的情况下,读请求也可以在普通的Server节点完成,集群内数据的读写和复制都是通过TCP的8300端口完成。

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

Gossip —— Gossip protocol 也叫 Epidemic Protocol (流行病协议),实际上它还有很多别名,比如:“流言算法”、“疫情传播算法”等。 这个协议的作用就像其名字表示的意思一样,非常容易理解,它的方式其实在我们日常生活中也很常见,比如电脑病毒的传播,森林大火,细胞扩散等等。

Client —— 一个 Client 是一个转发所有 RPC 到 server 的代理。这个 client 是相对无状态的。client 唯一执行的后台活动是加入 LAN gossip 池。这有一个最低的资源开销并且仅消耗少量的网络带宽。

Server —— 一个 server 是一个有一组扩展功能的代理,这些功能包括参与 Raft 选举,维护集群状态,响应 RPC 查询,与其他数据中心交互 WAN gossip 和转发查询给 leader 或者远程数据中心。

DataCenter —— 虽然数据中心的定义是显而易见的,但是有一些细微的细节必须考虑。例如,在 EC2 中,多个可用区域被认为组成一个数据中心。我们定义数据中心为一个私有的,低延迟和高带宽的一个网络环境。这不包括访问公共网络,但是对于我们而言,同一个 EC2 中的多个可用区域可以被认为是一个数据中心的一部分。

Consensus —— 一致性,使用 Consensus 来表明就 leader 选举和事务的顺序达成一致。为了以容错方式达成一致,一般有超过半数一致则可以认为整体一致。Consul 使用 Raft 实现一致性,进行 leader 选举,在 consul 中的使用 bootstrap 时,可以进行自选,其他 server 加入进来后 bootstrap 就可以取消。

LAN Gossip —— 它包含所有位于同一个局域网或者数据中心的所有节点。

WAN Gossip —— 它只包含 Server。这些 server 主要分布在不同的数据中心并且通常通过因特网或者广域网通信。

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

1.3.2 Consul服务发现原理

1.3.2.1 原理图

1.3.2.2 图解

首先需要有一个正常的Consul集群,有Server,有Leader。这里在服务器Server1、Server2、Server3上分别部署了Consul Server,假设他们选举了Server2上的Consul Server节点为Leader。这些服务器上最好只部署Consul程序,以尽量维护Consul Server的稳定。

然后在服务器Server4和Server5上通过Consul Client分别注册Service A、B、C,这里每个Service分别部署在了两个服务器上,这样可以避免Service的单点问题。服务注册到Consul可以通过HTTP API(8500端口)的方式,也可以通过Consul配置文件的方式。Consul Client可以认为是无状态的,它将注册信息通过RPC转发到Consul Server,服务信息保存在Server的各个节点中,并且通过Raft实现了强一致性。

最后在服务器Server6中Program D需要访问Service B,这时候Program D首先访问本机Consul Client提供的HTTP API,本机Client会将请求转发到Consul Server,Consul Server查询到Service B当前的信息返回,最终Program D拿到了Service B的所有部署的IP和端口,然后就可以选择Service B的其中一个部署并向其发起请求了。如果服务发现采用的是DNS方式,则Program D中直接使用Service B的服务发现域名,域名解析请求首先到达本机DNS代理,然后转发到本机Consul Client,本机Client会将请求转发到Consul Server,Consul Server查询到Service B当前的信息返回,最终Program D拿到了Service B的某个部署的IP和端口。

图中描述的部署架构笔者认为是最普适最简单的方案,从某些默认配置或设计上看也是官方希望使用者采用的方案,比如8500端口默认监听127.0.0.1,当然有些同学不赞同,后边会提到其他方案。

1.4 为什么使用服务发现

防止硬编码、容灾、水平扩缩容、提高运维效率等等,只要你想使用服务发现总能找到合适的理由。

一般的说法是因为使用微服务架构。传统的单体架构不够灵活不能很好的适应变化,从而向微服务架构进行转换,而伴随着大量服务的出现,管理运维十分不便,于是开始搞一些自动化的策略,服务发现应运而生。所以如果需要使用服务发现,你应该有一些对服务治理的痛点。

但是引入服务发现就可能引入一些技术栈,增加系统总体的复杂度,如果你只有很少的几个服务,比如10个以下,并且业务不怎么变化,吞吐量预计也很稳定,可能就没有必要使用服务发现。

二 consul与其他框架差异

名称

优点

缺点

接口

一致性算法zookeeper

1.功能强大,不仅仅只是服务发现 2.提供 watcher 机制能实时获取服务提供者的状态 3.dubbo 等框架支持

1.没有健康检查 2.需在服务中集成 sdk,复杂度高 3.不支持多数据中心

sdk

Paxos

consul

1.简单易用,不需要集成 sdk 2.自带健康检查 3.支持多数据中心 4.提供 web 管理界面

1.不能实时获取服务信息的变化通知

http/dns

Raft

etcd

1.简单易用,不需要集成 sdk 2.可配置性强

1.没有健康检查 2.需配合第三方工具一起完成服务发现 3.不支持多数据中心

http

Raft

三 安装部署

3.1 物理服务器安装部署

3.1.1 linux安装

wget https://releases.hashicorp.com/consul/1.5.1/consul_1.5.1_linux_amd64.zip

unzip consul_0.8.1_linux_amd64.zip

mv consul /usr/local/bin/

3.1.2 superviosr启动

配置

mkdir -p /data/consul/{data,logs}

cat < /etc/supervisord.d/consul.conf >EOF

[program:consul]

command=consul agent -server -bootstrap-expect 3 -data-dir /data/consul/data -bind=172.16.100.2 -ui -client 0.0.0.0 -advertise=172.16.100.2 -node=go2cloud-platform-test -rejoin

user=root

stdout_logfile=/data/consul/logs/consul.log

autostart=true

autorestart=true

startsecs=60

stopasgroup=true

ikillasgroup=true

startretries=1

redirect_stderr=true

EOF

⚠️:启动后需要手动在其他两个节点手动加入consul join 172.16.100.2

查看

[root@go2cloud_platform_pord conf.d]# supervisorctl status consul

consul RUNNING pid 11838, uptime 0:13:28

其他命令

# 查看集群成员

consul members

# 查看集群状态

consul info

# 帮助

consul agent -h

3.2 Docker部署

# 拉取镜像

docker pull consul

然后就可以启动集群了,这里启动4个Consul Agent,3个Server(会选举出一个leader),1个Client。

#启动第1个Server节点,集群要求要有3个Server,将容器8500端口映射到主机8900端口,同时开启管理界面

docker run -d --name=consul1 -p 8500:8500 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --bootstrap-expect=3 --client=0.0.0.0 -ui

#启动第2个Server节点,并加入集群

docker run -d --name=consul2 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2

#启动第3个Server节点,并加入集群

docker run -d --name=consul3 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=true --client=0.0.0.0 --join 172.17.0.2

#启动第4个Client节点,并加入集群

docker run -d --name=consul4 -e CONSUL_BIND_INTERFACE=eth0 consul agent --server=false --client=0.0.0.0 --join 172.17.0.2

第1个启动容器的IP一般是172.17.0.2,后边启动的几个容器IP会排着来:172.17.0.3、172.17.0.4、172.17.0.5。

这些Consul节点在Docker的容器内是互通的,他们通过桥接的模式通信。但是如果主机要访问容器内的网络,需要做端口映射。在启动第一个容器时,将Consul的8500端口映射到了主机的8900端口,这样就可以方便的通过主机的浏览器查看集群信息。

配置文件方式注册服务

# 编写service.json

{

"services": [

{

"id": "hello1",

"name": "hello",

"tags": [

"primary"

],

"address": "172.17.0.5",

"port": 5000,

"checks": [

{

"http": "http://localhost:5000/",

"tls_skip_verify": false,

"method": "Get",

"interval": "10s",

"timeout": "1s"

}

]

}

]

}

# 将json文件拷贝进容器内

docker cp myservice.json consul1:/consul/config

# 重载配置文件

docker exec consul1 consul reload

此时已经有了服务,只是服务不可用,consul发送给服务的请求不可达

3.3 k8s中部署

可以自己去写yaml资源清单文件或者利用官方提供好的helm的charts来安装

利用helm进行安装

# 查询helm

[root@master opt]# helm search consul

NAME CHART VERSION APP VERSION DESCRIPTION

apphub/consul 5.3.3 1.6.0 Highly available and distributed service discovery and ke...

apphub/prometheus-consul-exporter 0.1.4 0.4.0 A Helm chart for the Prometheus Consul Exporter

bitnami/consul 5.3.3 1.6.0 Highly available and distributed service discovery and ke...

incubator/ack-consul 0.5.0 0.5.0 Install and configure Consul on Kubernetes.

stable/consul 3.8.1 1.5.3 Highly available and distributed service discovery and ke...

stable/prometheus-consul-exporter 0.1.4 0.4.0 A Helm chart for the Prometheus Consul Exporter

# 安装consul

[root@master opt]# helm install stable/consul -n consul

NAME: consul

LAST DEPLOYED: Fri Nov 22 09:52:52 2019

NAMESPACE: default

STATUS: DEPLOYED

RESOURCES:

==> v1/ConfigMap

NAME DATA AGE

consul-tests 1 3m4s

==> v1/Pod(related)

NAME READY STATUS RESTARTS AGE

consul-0 0/1 ContainerCreating 0 3m4s

==> v1/Secret

NAME TYPE DATA AGE

consul-gossip-key Opaque 1 3m4s

==> v1/Service

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

consul ClusterIP None 8500/TCP,8400/TCP,8301/TCP,8301/UDP,8302/TCP,8302/UDP,8300/TCP,8600/TCP,8600/UDP 3m4s

consul-ui NodePort 10.107.180.193 8500:30082/TCP 3m4s

==> v1beta1/PodDisruptionBudget

NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE

consul-pdb N/A 1 0 3m4s

==> v1beta1/StatefulSet

NAME READY AGE

consul 0/3 3m4s

NOTES:

1. Watch all cluster members come up.

$ kubectl get pods --namespace=default -w

2. Test cluster health using Helm test.

$ helm test consul

3. (Optional) Manually confirm consul cluster is healthy.

$ CONSUL_POD=$(kubectl get pods -l='release=consul' --output=jsonpath={.items[0].metadata.name})

$ kubectl exec $CONSUL_POD consul members --namespace=default | grep server

查看运行状态

我们可以看到helm安装consul使用的是statefulset,服务使用的是NodePort方式

# 查看运行状态

[root@master opt]# kubectl get pods --show-labels -l release=consul

NAME READY STATUS RESTARTS AGE LABELS

consul-0 1/1 Running 0 3m41s chart=consul-3.8.1,component=consul-consul,controller-revision-hash=consul-6969c79b5c,heritage=Tiller,release=consul,statefulset.kubernetes.io/pod-name=consul-0

consul-1 1/1 Running 0 2m56s chart=consul-3.8.1,component=consul-consul,controller-revision-hash=consul-6969c79b5c,heritage=Tiller,release=consul,statefulset.kubernetes.io/pod-name=consul-1

consul-2 1/1 Running 0 2m17s chart=consul-3.8.1,component=consul-consul,controller-revision-hash=consul-6969c79b5c,heritage=Tiller,release=consul,statefulset.kubernetes.io/pod-name=consul-2

# 查看svc

[root@master opt]# kubectl get svc -l release=consul

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

consul ClusterIP None 8500/TCP,8400/TCP,8301/TCP,8301/UDP,8302/TCP,8302/UDP,8300/TCP,8600/TCP,8600/UDP 5m23s

consul-ui NodePort 10.107.180.193 8500:30082/TCP 5m23s

# 查看server

[root@master opt]# CONSUL_POD=$(kubectl get pods -l='release=consul' --output=jsonpath={.items[0].metadata.name})

[root@master opt]# kubectl exec $CONSUL_POD consul members --namespace=default | grep server

consul-0 10.244.1.67:8301 alive server 1.5.3 2 dc1

consul-1 10.244.2.193:8301 alive server 1.5.3 2 dc1

consul-2 10.244.1.68:8301 alive server 1.5.3 2 dc1

网页进行查看

四 使用

在此演示利用python来使用consul的服务器发现与注册,已经consul的简单配置中心

4.1 服务发现与注册

#!/usr/bin/python

# -*- coding: UTF-8 -*-

import json

import requests

from consul import Consul, Check

from random import randint

# consul 操作类

class ConsulClient():

def __init__(self, host=None, port=None, token=None): # 初始化,指定consul主机,端口,和token

self.host = host # consul 主机

self.port = port # consul 端口

self.token = token

self.consul = Consul(host=host, port=port)

def register(self, name, service_id, local_ip, local_port, consul_health_url, tags=None, interval=None): # 注册服务 注册服务的服务名 端口 以及 健康监测端口

# 心跳检测url

health_check_url = ''.join(["http://", local_ip, ":", str(local_port), consul_health_url])

# 健康检查的ip,端口,检查时间

http_check = Check.http(health_check_url, "10s")

return self.consul.agent.service.register(name, service_id=service_id, address=local_ip, port=int(local_port),

check=http_check, tags=tags, interval=interval)

def deregister(self, service_id):

# 此处有坑,源代码用的get方法是不对的,改成put,两个方法都得改

de_result = self.consul.agent.service.deregister(service_id)

check_result = self.consul.agent.check.deregister(service_id)

return de_result, check_result

def getService(self, name): # 负债均衡获取服务实例

self.port = str(self.port)

url = 'http://' + self.host + ':' + self.port + '/v1/catalog/service/' + name # 获取 相应服务下的DataCenter

dataCenterResp = requests.get(url)

if dataCenterResp.status_code != 200:

raise Exception('can not connect to consul ')

listData = json.loads(dataCenterResp.text)

dcset = set() # DataCenter 集合 初始化

for service in listData:

dcset.add(service.get('Datacenter'))

serviceList = [] # 服务列表 初始化

for dc in dcset:

if self.token:

url = 'http://' + self.host + ':' + self.port + '/v1/health/service/' + name + '?dc=' + dc + '&token=' + self.token

else:

url = 'http://' + self.host + ':' + self.port + '/v1/health/service/' + name + '?dc=' + dc + '&token='

resp = requests.get(url)

if resp.status_code != 200:

raise Exception('can not connect to consul ')

text = resp.text

serviceListData = json.loads(text)

for serv in serviceListData:

status = serv.get('Checks')[1].get('Status')

if status == 'passing': # 选取成功的节点

address = serv.get('Service').get('Address')

port = serv.get('Service').get('Port')

serviceList.append({'port': port, 'address': address})

if len(serviceList) == 0:

raise Exception('no serveice can be used')

else:

service = serviceList[randint(0, len(serviceList) - 1)] # 随机获取一个可用的服务实例

return service['address'], int(service['port'])

def getServices(self):

return self.consul.agent.services()

if __name__ == '__main__':

host = '10.234.2.204'

port = '30082'

server_name = 'myapp'

server_id = server_name + '-8500'

c = ConsulClient(host, port)

# print(c.deregister(server_id))

# print(c.register(server_name, server_id, 'x.x.x.x', 8012, '/ops-audit/health'))

print(c.consul.agent.services())

print(c.getService(server_name))

from apps.jumpserver.conf import get_consul_server

print(get_consul_server('cmp', 'SMARTOPS_API_URL'))

# server_name2 = 'myconsulapp'

# local_port = '8000'

# server_id2 = server_name2 + '-' + local_port

# print(c.register(server_name2, server_id2, '10.234.2.186', '8000', '/ops-audit/health'))

注意,需要写在服务启动的时候去注册,在利用到服务发现的地方查询可用的后端服务器来获取服务的ip及端口使用。

在服务停止的时候去注销服务。

4.2 配置中心

在consul页面Key/Value配置

def get_config(CONSUL_HOST, CONSUL_PORT, KEY_NAME):

c = consul.Consul(CONSUL_HOST, CONSUL_PORT)

index = None

index, data = c.kv.get(KEY_NAME, index=index)

return yaml.safe_load(data.get("Value").decode(encoding='utf-8'))

一般情况下需要去启一个进程一直watch consul的配置来实时更新应用中的配置,或者每次利用配置的时候去单独调用获取配置。

参考链接

python consul配置中心_微服务注册发现配置中心-consul相关推荐

  1. Nacos微服务注册发现、配置和管理微服务

    目录 Nacos介绍 什么是 Nacos? Nacos 地图 Nacos 生态图 Nacos 概念 地域 可用区 接入点 命名空间 配置 配置管理 配置项 配置集 配置集 ID 配置分组 配置快照 服 ...

  2. 微服务注册发现集群搭建——Registrator + Consul + Consul-template + nginx

    在互联网应用领域,服务的动态性需求十分常见,这就对服务的自动发现和可动态扩展提出了很高的要求. 微服务系统动辄上万个服务,而且还要动态伸缩.以人工写好的IP.Port 硬编码脚本的方式无法做到大规模自 ...

  3. 微服务注册中心怎么选?

    目录 前言 CAP理论 服务注册中心解决方案 主流注册中心产品 Apache Zookeeper -> CP Spring Cloud Eureka  -> AP Consul Nacos ...

  4. 微服务:Nacos将微服务注册到指定的命名空间下

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一.指定命名空间的好处 二.创建一个命名空间? 三.配置文件编写 总结 一.指定命名空间的好处 如果咱们团队手上同时有很多个 ...

  5. Spring RSocket:基于服务注册发现的 RSocket 负载均衡

    作者 | 雷卷 来源|阿里巴巴云原生公众号 RSocket 分布式通讯协议是 Spring Reactive 的核心内容,从 Spring Framework 5.2 开始,RSocket 已经是 S ...

  6. consul 日志配置_微服务:服务注册发现+ API 网关+配置中心+服务跟踪+服务熔断...

    服务注册发现 服务注册就是维护一个登记簿,它管理系统内所有的服务地址.当新的服务启动后,它会向登记 簿交待自己的地址信息.服务的依赖方直接向登记簿要 Service Provider 地址就行了.当下 ...

  7. gateway nacos注册服务_使用Nacos作为微服务注册中心和配置中心

    使用Nacos作为微服务注册中心和配置中心 一.技术简介 Nacos是阿里系开发的兼容Spring Cloud的服务注册中心组件,是微服务国产化的先驱.Nacos作为与Eureka的对比,不仅具有Eu ...

  8. 微服务笔记:第一章_微服务简介|Eureka注册中心|Nacos注册中心|Nacos配置管理|Feign|Gateway服务网关

    微服务笔记:第一章_微服务简介|Eureka注册中心|Nacos注册中心|Nacos配置管理|Feign|Gateway服务网关 1. 微服务简介 1.1 服务架构演变 1.2 SpringCloud ...

  9. 微服务注册中心为什么要使用Consul替代Eureka?

    ---------------- 版权声明:本文为CSDN博主「fishinhouse」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明. 原文链接:https://b ...

最新文章

  1. 修正memcache.php中的错误示例
  2. Compiling Cpp(zz)
  3. 推荐算法炼丹笔记:排序模型CTR点击率预估系列
  4. 在windows下查看SQLite数据库
  5. uni-calendar更改打点颜色实现签到和缺勤不同打点颜色效果
  6. python/正则 从字符串中提取数字
  7. HDU 5666 Segment 数论+大数
  8. 软件开发的需求分析样例
  9. unzip 解压缩文件命令
  10. 软件测试中的心理学效应
  11. JDK8中String的intern()方法详细解读【内存图解+多种例子+1.1w字长文】
  12. 分享48个Go源码,总有一款适合您
  13. 联想微型计算机m4350q升级,细节:联想M4350q小巧到极致_联想ThinkCentre台式电脑_台式电脑评测-中关村在线...
  14. 阿里云服务器优惠以及采购流程
  15. 看雪4-ReeHY-main-2017
  16. Ory Hydra 详解之入门
  17. 雷达副瓣对消的matlab程序,动目标显示与脉冲多普勒雷达(MATLAB程式设计)
  18. 视觉融合-相机校准与激光点云投影
  19. 罗马音平假字复制_五十音图的那些平假字和片假字有罗马音吗?
  20. 比较全面的vps防止cc攻击

热门文章

  1. Python中文文本聚类
  2. 音影系统linux,搭建基于linux桌面环境的影音平台_linux教程
  3. 关于按照Intellij IDEA开发WebService步骤时输入http://localhost:8080/services出现404错误的解决方案
  4. 意大利菜--斐波那契汤。具体做法是把昨天的和前天剩下的汤加热后混合,得到就是今天新鲜的“斐波那契汤”
  5. FileNotFoundError: [Errno 2] No such file or directory: 'XXX' 的解决方法
  6. 模拟退火算法(Simulated Annealin)
  7. 搜索中词权重计算及实践
  8. 章节六:RASA NLU组件介绍--特征生成器
  9. 2019年全国职业院校技能大赛——移动互联软件赛项规程
  10. iOS开发者们,请您们面向未来学习,效率学习!