什么是注册中心
我们要搞清楚这个问题,咋们得从一个实际的场景中去学习,我们以购物场景为例来说明,在购物和场景中,总共涉及到三个角色,消费者,商店,商场。
在这个场景中,我们以画图来解决
图解析
优点
1、解耦
服务消费者个服务提供者解耦,各自变化,不互相影响
2、扩展
服务消费者和服务提供者增加和删除新的服务,对于双方没有任何影响
3、中介者设计模式
这是一种多对多关系的典范
注册中心类型
zookeeper
一个被广泛使用的分布式的高性能服务
consul
一个发现和配置服务的工具,提供API注册和发现服务,为了确保操作性,consul会执行健康检查
etcd
一个高可用,分布式的,一致性key-value结构,用于共享配置信息和服务发现K8s使用了etcd
eureka
这个注册中心已经闭源了,建议不要使用了
在微服务中如何使用consul
什么是Consul
Consul是一个用来实现分布式系统的服务发现与配置的开源工具。是由go语言开发。他主要由多个组成部分:
-
服务发现:客户端通过Consul提供服务,类似于API,MySQL,或者其他客户端可以使用Consul发现服务的提供者。使用类似DNS或者HTTP,应用程序和可以很轻松的发现他们依赖的服务。
-
检查健康:Consul客户端可以提供与给定服务相关的健康检查(Web服务器返回200 ok)或者本地节点(“内存利用率低于90%”)。这些信息可以监控集群的运行情况,并且使访问远离不健康的主机组件。
-
键值对存储:应用程序可以使用Cousul的层级键值对。
-
多数据中心:Consul有开箱及用的多数据中心。
Consul 的角色
client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群. server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其他数据中心通讯. 每个数据中心的 server 数量推荐为 3 个或是 5 个.
agent
组成 consul 集群的每个成员上都要运行一个 agent,可以通过 consul agent
命令来启动。agent 可以运行在 server 状态或者 client 状态。自然的,运行在 server 状态的节点被称为 server 节点;运行在 client 状态的节点被称为 client 节点。
client 节点
负责转发所有的 RPC 到 server 节点。本身无状态,且轻量级,因此,可以部署大量的 client 节点。
server 节点
负责组成 cluster 的复杂工作(选举、状态维护、转发请求到 lead),以及 consul 提供的服务(响应 RCP 请求)。考虑到容错和收敛,一般部署 3 ~ 5 个比较合适。
Consul内幕
术语
-
代理(agent):代理是Consul集群上每个成员的守护进程,它是由consul agent开始运行。代理能够以客户端或服务器模式运行。由于所有节点都必须运行代理,所以将节点引用为客户端或服务器更为简单,但还有其他实例的代理。所有代理可以运行DNS或HTTP接口,并负责运行检查和保持服务同步。
-
客户端:客户端可以将所有RPC请求转发到服务器的代理。客户端是相对无状态的。客户端执行的唯一后台活动是LANgossip池。它消耗最小的资源开销和少量的网络带宽。
-
服务器端:服务器端是具有扩展的功能的代理,它主要参与维护集群状态,响应RPC查询,与其他数据中心交换WAN gossip ,以及向上级或远程数据中心转发查询。
-
数据中心:虽然数据中心的定义似乎很明显,但仍有一些细微的细节必须考虑。我们将一个数据中心定义为一个私有、低延迟和高带宽的网络环境。这不包括通过公共互联网的通信,但是为了我们的目的,单个EC2区域内的多个可用区域将被视为单个数据中心的一部分
-
Gossip:consul是建立在serf之上的,它提供了一个完整的gossip协议,用在很多地方。Serf提供了成员,故障检测和事件广播。Gossip的节点到节点之间的通信使用了UDP协议。
-
LAN Gossip:指在同一局域网或数据中心的节点上的LAN Gossip池。
-
WAN Gossip:指包含服务器的WAN Gossip池,这些服务器在不同的数据中心,通过网络进行通信。
-
一致性协议采用 Raft 算法,用来保证服务的高可用.
-
成员管理和消息广播 采用GOSSIP协议,支持ACL访问控制。
ACL技术在路由器中被广泛采用,它是一种基于包过滤的流控制技术。控制列表通过把源地址、目的地址及端口号作为数据包检查的基本元素,并可以规定符合条件的数据包是否允许通过。
gossip就是p2p协议。他主要要做的事情是,去中心化。
这个协议就是模拟人类中传播谣言的行为而来。首先要传播谣言就要有种子节点。种子节点每秒都会随机向其他节点发送自己所拥有的节点列表,以及需要传播的消息。任何新加入的节点,就在这种传播方式下很快地被全网所知道。
Consul运行流程图
结合图进行讲解,请看图
Consul微服务中实践(如何注册,发现)
Consul如何注册,发现服务?
步骤
1、Consul下载地址
官网地址: https://www.consul.io/
下载地址: https://releases.hashicorp.com/consul/1.7.2/ 或 https://www.consul.io/downloads.html
2、服务端启动
1.1 开发模式启动命令:
consul.exe agent -dev
Version :consul版本
Node ID : consul当前启动节点编号(guid)
Node Name:节点名称(默认为电脑名称)
Datacenter:数据中心
Server:启动是服务端模式,否则就为客户端模式
Client Addr:客户端连接地址,支持http,https,gRPC,DNS。默认我们使用HTTP方式
Cluster Addr:集群地址,就是Server模式下 启动方式
Encrypt:安全
1.2 生产模式启动命令:
consul agent -server -bootstrap-expect 1 -data-dir d:/consul/data
1.2.1 会出现错误:提示
主要原因:服务端模式启动的时候,默认绑定的地址是0.0.0.0.希望绑定默认的ip地址
consul agent -server -bind=127.0.0.1 -bootstrap-expect 1 -data-dir d:/consul/data
1.3 客户端模式启动
直接使用net程序来进行启动
1.4 总结:
consul启动重要参数-bind需要是私有ip地址,默认其实就是0.0.0.0。当遇到问题的时候一定要先从环境差异性或根源上原因,如果根源上找不到知道问题,可以采用试探法解决问题。
consul有三种模式运行,client, server,dev。
注意:dev模式运行是不会持久化数据,也就重启之后保存的配置信息会丢失。
下面配上consul启动参数简单说明:
agent Consul的核心命令,主要作用有维护成员信息、运行状态检测、声明服务以及处理请求等 -server 就是代表server模式 -ui 代表开启web 控制台 -bootstrap-expect 代表想要创建的集群数目,官方建议3或者5 -data-dir 数据存储目录 -node 代表当前node的名称 -client 应该是一个客户端服务注册的地址,可以和当前server的一致也可以是其他主机地址,系统默认是127.0.0.1 -bind 集群通讯地址
运行cosnul agent以server模式: -server : 定义agent运行在server模式 -bootstrap-expect :在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap共用 -bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0 -node:节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名 -ui-dir: 提供存放web ui资源的路径,该目录必须是可读的 -rejoin:使consul忽略先前的离开,在再次启动后仍旧尝试加入集群中。 -config-dir:配置文件目录,里面所有以.json结尾的文件都会被加载 -client:consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果你要对外提供服务改成0.0.0.0
2、先下载consul包
aspnetcore nuget中进行下载
3、然后微服务提供者进行注册,代码如下
// 1、创建consul客户端连接
var consulClient = new ConsulClient(configuration =>
{
//1.1 建立客户端和服务端连接
configuration.Address = new Uri("http://127.0.0.1:8500");
});
// 2、获取服务内部地址
// 3、创建consul服务注册对象
var registration = new AgentServiceRegistration()
{
ID = Guid.NewGuid().ToString(),//服务编号,摘要:初始化System.Guid 结构的新实例。返回结果:一个新的GUID对象
Name = "teamservice", //服务名称
Address = "http://localhos", //服务地址
Port = "5001", //端口
Tags = new string[],
Check = new AgentServiceCheck //健康检查
{
// 3.1、consul健康检查超时间
Timeout = TimeSpan.FromSeconds(10),
// 3.2、服务停止5秒后注销服务
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
// 3.3、consul健康检查地址
HTTP = serviceNode.HealthCheckAddress,
// 3.4 consul健康检查间隔时间
Interval = TimeSpan.FromSeconds(10),
}
};
// 4、注册服务
consulClient.Agent.ServiceRegister(registration).Wait();
4、最后微服务发现者进行获取,服务发现代码如下
// 1、创建consul客户端连接
var consulClient = new ConsulClient(configuration =>
{
//1.1 建立客户端和服务端连接
configuration.Address = new Uri("http://127.0.0.1:8500");
});
// 2、consul查询服务,根据具体的服务名称查询
var queryResult = await consulClient.Catalog.Service("teamservice");
// 3、将服务进行拼接
var list = new List<ServiceUrl>();
foreach (var service in queryResult.Response)
{
list.Add(new ServiceUrl { Url = service.ServiceAddress + ":" + service.ServicePort });
}
Consul如何做心跳检测?
步骤
1、使用AgentServiceCheck来实现,代码配置如下
new AgentServiceCheck
{
// 3.1、consul健康检查超时间
Timeout = TimeSpan.FromSeconds(10),
// 3.2、服务停止5秒后注销服务
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
// 3.3、consul健康检查地址
HTTP = serviceNode.HealthCheckAddress,
// 3.4 consul健康检查间隔时间
Interval = TimeSpan.FromSeconds(10),
}
如何封装Consul?
步骤
1、首先根据服务角色,将服务抽象为提供者和发现者
2、然后使用ioc容器进行条件准备,使用app构建器进行服务注册
Consul如何搭建集群?
参数解释
命令行参数
-bind:为该节点绑定一个地址
-enable-script-checks=true:设置检查服务为可用
-join:加入到已有的集群中
-server 表示当前使用的server模式
-node:指定当前节点在集群中的名称
-config-file - 要加载的配置文件
-config-dir:指定配置文件,定义服务的,默认所有以.json结尾的文件都会读
-datacenter: 数据中心没名称,不设置的话默认为dc
-client: 客户端模式
-ui: 使用consul自带的ui界面
-data-dir consul存储数据的目录
-bootstrap:用来控制一个server是否在bootstrap模式,在一个datacenter中只能有一个server处于bootstrap模式,当一个server处于bootstrap模式时,可以自己选举为raft leader。
-bootstrap-expect:在一个datacenter中期望提供的server节点数目,当该值提供的时候,consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap公用
这两个参数十分重要, 二选一,如果两个参数不使用的话,会出现就算你使用join将agent加入了集群仍然会报
2018/10/14 15:40:00 [ERR] agent: failed to sync remote state: No cluster leader
配置文件参数
ui: 相当于-ui 命令行标志。
acl_token:agent会使用这个token和consul server进行请求
acl_ttl:控制TTL的cache,默认是30s
addresses:一个嵌套对象,可以设置以下key:dns、http、rpc
advertise_addr:等同于-advertise
bootstrap:等同于-bootstrap
bootstrap_expect:等同于-bootstrap-expect
bind_addr:等同于-bindca_file:提供CA文件路径,用来检查客户端或者服务端的链接
cert_file:必须和key_file一起
check_update_interval:
client_addr:等同于-client
datacenter:等同于-dc
data_dir:等同于-data-dir
disable_anonymous_signature:在进行更新检查时禁止匿名签名
enable_debug:开启debug模式
enable_syslog:等同于-syslog
encrypt:等同于-encrypt
key_file:提供私钥的路径
leave_on_terminate:默认是false,如果为true,当agent收到一个TERM信号的时候,它会发送leave信息到集群中的其他节点上。
log_level:等同于-log-level node_name:等同于-node
ports:这是一个嵌套对象,可以设置以下key:dns(dns地址:8600)、http(http api地址:8500)、rpc(rpc:8400)、serf_lan(lan port:8301)、serf_wan(wan port:8302)、server(server rpc:8300)
protocol:等同于-protocol
rejoin_after_leave:等同于-rejoin
retry_join:等同于-retry-join
retry_interval:等同于-retry-interval
server:等同于-server
syslog_facility:当enable_syslog被提供后,该参数控制哪个级别的信息被发送,默认Local0
ui_dir:等同于-ui-dir
集群搭建(单机)
因为没有资源,只能在一台机器上装伪集群,如果是三台服务器来做的话, 不需要写json配置文件,直接用命令行启动就可以
# 创建节点数据目录$ mkdir -pv /data/app/consul/{node1,node2,node3} mkdir: created directory ‘/data/app/consul/node1’mkdir: created directory ‘/data/app/consul/node2’mkdir: created directory ‘/data/app/consul/node3’
节点1配置
$ vim /data/app/consul/node1/basic.json { "datacenter": "dc1", "data_dir": "/data/app/consul/node1", "log_level": "INFO", "server": true, "node_name": "node1", "ui": true, "bind_addr": "10.208.1.10", "client_addr": "10.208.1.10", "advertise_addr": "10.208.1.10", "bootstrap_expect": 3, "ports":{ "http": 8500, "dns": 8600, "server": 8300, "serf_lan": 8301, "serf_wan": 8302 } } $ nohup /usr/bin/consul agent -config-file=/data/app/consul/node1/basic.json > /data/app/consul/node1/consul.log 2>&1 & $ tail -100f /data/app/consul/node1/consul.log
节点2配置
$ vim /data/app/consul/node2/basic.json { "datacenter": "dc1", "data_dir": "/data/app/consul/node2", "log_level": "INFO", "server": true, "node_name": "node2", "bind_addr": "10.208.1.10", "client_addr": "10.208.1.10", "advertise_addr": "10.208.1.10", "ports":{ "http": 8510, "dns": 8610, "server": 8310, "serf_lan": 8311, "serf_wan": 8312 } } $ nohup /usr/bin/consul agent -config-file=/data/app/consul/node2/basic.json -retry-join=10.208.1.10:8301 > /data/app/consul/node2/consul.log 2>&1 & $ tail -100f /data/app/consul/node2/consul.log
节点3配置
$ vim /data/app/consul/node3/basic.json { "datacenter": "dc1", "data_dir": "/data/app/consul/node3", "log_level": "INFO", "server": true, "node_name": "node3", "bind_addr": "10.208.1.10", "client_addr": "10.208.1.10", "advertise_addr": "10.208.1.10", "ports":{ "http": 8520, "dns": 8620, "server": 8320, "serf_lan": 8321, "serf_wan": 8322 } } $ nohup /usr/bin/consul agent -config-file=/data/app/consul/node3/basic.json -retry-join=10.208.1.10:8301 > /data/app/consul/node3/consul.log 2>&1 & $ tail -100f /data/app/consul/node3/consul.log
查看节点1日志变化
2019/01/24 22:48:58 [INFO] serf: EventMemberJoin: node2.dc1 10.208.1.10 2019/01/24 22:49:59 [INFO] serf: EventMemberJoin: node3.dc1 10.208.1.10 ... 2019/01/24 22:49:59 [INFO] consul: Found expected number of peers, attempting bootstrap: 10.208.1.10:8320,10.208.1.10:8300,10.208.1.10:8310 2019/01/24 22:49:59 [INFO] consul: Handled member-join event for server "node3.dc1" in area "wan" 2019/01/24 22:50:05 [WARN] raft: Heartbeat timeout from "" reached, starting election 2019/01/24 22:50:05 [INFO] raft: Node at 10.208.1.10:8300 [Candidate] entering Candidate state in term 2 2019/01/24 22:50:05 [INFO] raft: Election won. Tally: 2 2019/01/24 22:50:05 [INFO] raft: Node at 10.208.1.10:8300 [Leader] entering Leader state 2019/01/24 22:50:05 [INFO] raft: Added peer faa05ada-4e06-6d5a-f35b-286c57826231, starting replication 2019/01/24 22:50:05 [INFO] raft: Added peer be2837bd-3b87-07f9-a776-863ed5966ffb, starting replication 2019/01/24 22:50:05 [INFO] consul: cluster leadership acquired 2019/01/24 22:50:05 [INFO] consul: New leader elected: node1 2019/01/24 22:50:05 [WARN] raft: AppendEntries to {Voter be2837bd-3b87-07f9-a776-863ed5966ffb 10.208.1.10:8310} rejected, sending older logs (next: 1) 2019/01/24 22:50:05 [INFO] raft: pipelining replication to peer {Voter be2837bd-3b87-07f9-a776-863ed5966ffb 10.208.1.10:8310} 2019/01/24 22:50:05 [INFO] consul: member 'node1' joined, marking health alive 2019/01/24 22:50:05 [INFO] consul: member 'node2' joined, marking health alive 2019/01/24 22:50:05 [INFO] agent: Synced node info 2019/01/24 22:50:05 [INFO] consul: member 'node3' joined, marking health alive 2019/01/24 22:50:06 [WARN] raft: AppendEntries to {Voter faa05ada-4e06-6d5a-f35b-286c57826231 10.208.1.10:8320} rejected, sending older logs (next: 1) 2019/01/24 22:50:07 [INFO] raft: pipelining replication to peer {Voter faa05ada-4e06-6d5a-f35b-286c57826231 10.208.1.10:8320}
访问UI
查看集群信息
$ /usr/bin/consul members -http-addr=10.208.1.10:8500 Node Address Status Type Build Protocol DC Segment node1 10.208.1.10:8301 alive server 1.3.1 2 dc1 <all> node2 10.208.1.10:8311 alive server 1.3.1 2 dc1 <all> node3 10.208.1.10:8321 alive server 1.3.1 2 dc1 <all> $ /usr/bin/consul info -http-addr=10.208.1.10:8500 agent: check_monitors = 0 check_ttls = 0 checks = 0 services = 0build: prerelease = revision = f2b13f30 version = 1.3.1consul: bootstrap = false known_datacenters = 1 leader = true leader_addr = 10.208.1.10:8300 server = trueraft: applied_index = 80 commit_index = 80 fsm_pending = 0 last_contact = 0 last_log_index = 80 last_log_term = 2 last_snapshot_index = 0 last_snapshot_term = 0 latest_configuration = [{Suffrage:Voter ID:faa05ada-4e06-6d5a-f35b-286c57826231 Address:10.208.1.10:8320} {Suffrage:Voter ID:5aee898c-ead4-f844-0d70-37ee7d9e9fb3 Address:10.208.1.10:8300} {Suffrage:Voter ID:be2837bd-3b87-07f9-a776-863ed5966ffb Address:10.208.1.10:8310}] latest_configuration_index = 1 num_peers = 2 protocol_version = 3 protocol_version_max = 3 protocol_version_min = 0 snapshot_version_max = 1 snapshot_version_min = 0 state = Leader term = 2runtime: arch = amd64 cpu_count = 4 goroutines = 104 max_procs = 4 os = linux version = go1.11.1serf_lan: coordinate_resets = 0 encrypted = false event_queue = 0 event_time = 2 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 3 members = 3 query_queue = 0 query_time = 1serf_wan: coordinate_resets = 0 encrypted = false event_queue = 0 event_time = 1 failed = 0 health_score = 0 intent_queue = 0 left = 0 member_time = 5 members = 3 query_queue = 0 query_time = 1
![1587374921762](assets/1587374921762.png)