一.背景

——随着互联网的发展,越来越多的系统/网站走向了分布式之路,但是分布式带给我们的复杂性是难以想象的,这就需要专门有第三方统一管理微服务、配置、资源等。
第三方系统必须要具有下面两个特征:
1.集群部署
2.数据一致性

——目前业内有很多这种产品:zookeeper、etcd、consul,三者各有各的特点。这里就不一一说明三者的优缺,仅仅分析consul的优势
1.封装了服务发现的api,开发调用非常简单
2.提供了健康检查功能
3.使用了raft算法保证了一致性,比复杂的paxos算法更直接,相比而言,zk采用的是paxos,二etcd采用的是raft
4.支持多数据中心,保证多机房使用。
5.支持 http 和 dns 协议接口.,zookeeper 的集成较为复杂,,etcd 只支持 http 协议
6.官方提供web管理界面, etcd 无此功能

二:consul的基本概念

agent
组成 consul 集群的每个成员上都要运行一个 agent,可以通过 consul agent 命令来启动。agent 可以运行在 server 状态或者 client 状态。自然的,运行在 server 状态的节点被称为 server 节点;运行在 client 状态的节点被称为 client 节点。

client 节点
负责转发所有的 RPC 到 server 节点。本身无状态,且轻量级,因此,可以部署大量的 client 节点。

server 节点
负责组成 cluster 的复杂工作(选举、状态维护、转发请求到 lead),以及 consul 提供的服务(响应 RCP 请求)。考虑到容错和收敛,一般部署 3 ~ 5 个比较合适。

datacenter
多机房使用的数据共享

基本架构图


三.安装和启动

consul支持Mac os   、Linux、Windows等常用操作系统,下载地址: 点击下载  
consul可以配置其web ui查看当前的服务  key/value   数据节点等
web-ui下载地址: 点击下载
下载后解压,直接运行

consul需要用agent启动,启动模式可以是server和client
以window单机启动server为例:
配置config.conf文件
[html]  view plain  copy
  1. {  
  2.   "datacenter":"dc1",//数据中心名称  
  3.   "data_dir": "D:\\consul\\consul\\data",//数据存储目录  
  4.   "log_level": "INFO",//日志级别  
  5.   "node_name": "node1",//server节点名称  
  6.   "server": true,//是否开启服务模式  
  7.   "ui":true,//是否开启web-ui  
  8.   "bind_addr":"192.168.100.110",//绑定的地址  
  9.   "bootstrap":true,//引用启动  
  10.   "ui_dir": "D:\\consul\\consul\\webui"//web-ui地址  
  11. }  
进入consul根目录  启动命令:consul.exe agent -config-file config.conf
启动成功后,浏览器打开http://127.0.0.1:8500/ui/ 可以看到整个consul的所有信息


如果需要配置集群的话
server node1 配置信息
[html]  view plain  copy
  1. {  
  2.   "datacenter":"dc1",  
  3.   "log_level": "INFO",  
  4.   "node_name": "node1",  
  5.   "server": true,  
  6.   "ui":true,  
  7.   "bind_addr":"192.168.100.110",  
  8.   "cluster_addr":"10.10.105.71",  
  9.   "bootstrap":true,  
  10.   "join":"10.10.105.72"  
  11.   "ui_dir": "D:\\consul\\consul\\webui"  
  12. }  

server node2 配置信息
[html]  view plain  copy
  1. {  
  2.   "datacenter":"dc1",  
  3.   "log_level": "INFO",  
  4.   "node_name": "node2",  
  5.   "server": true,  
  6.   "ui":true,  
  7.   "bind_addr":"192.168.100.111",  
  8.   "cluster_addr":"10.10.105.72",  
  9.   "bootstrap":true  
  10. }  

启动两个节点  启动命令:consul.exe agent -config-file config.conf
这样就完成了集群部署
打开consul的web-ui :http://127.0.0.1:8500/


四.服务注册与发现的两种方式

——Consul支持两种服务注册的方式,一种是通过Consul的服务注册HTTP API,由服务自身在启动后调用API注册自己,另外一种则是通过在配置文件中定义服务的方式进行注册。Consul文档中建议使用后面一种方式来做服务 配置和服务注册。

1.1首先我们来了解用配置注册服务
创建一个叫redis-server1.json文件
[html]  view plain  copy
  1. {  
  2.   "service": {  
  3.     "name": "redis-server1",  
  4.     "tags": ["master"],  
  5.     "address": "127.0.0.1",  
  6.     "port": 6379,  
  7.     "checks": [  
  8.       {  
  9.         "http": "http://localhost:6379",  
  10.         "interval": "10s"  
  11.       }  
  12.     ]  
  13.   }  
  14. }  
再创建一个client节点
[html]  view plain  copy
  1. {  
  2.   "datacenter":"dc1",  
  3.   "log_level": "INFO",  
  4.   "node_name": "node3",  
  5.   "server": false,  
  6.   "bind_addr":"192.168.100.112",  
  7.   "config_dir":"./conf"  
  8. }  
把json文件放到conf文件夹下面,利用consul.exe agent -config-file config.conf ,client注册一个redis服务。
json文件定义中包含服务的name、address、port等,还包含一个服务检测的配置,这里 我们每隔10s对服务进行一次健康检查。同理,我们可以在其它节点上也建立同样配置文件(需重启,并带上 -config-dir命令行选项),服务注册就这么简单。

1.2使用java代码注册服务
首先利用maven把封装consul的客户端jar包导入
[html]  view plain  copy
  1. <dependency>  
  2.      <groupId>com.orbitz.consul</groupId>  
  3.       <artifactId>consul-client</artifactId>  
  4.       <version>0.12.3</version>  
  5. </dependency>  
注册代码:
[java]  view plain  copy
  1. Consul client = Consul.builder().build();  
  2. String serviceName = UUID.randomUUID().toString();  
  3. String serviceId = UUID.randomUUID().toString();  
  4. client.agentClient().register(8080new URL("http://localhost:1337/health"), 1000L, serviceName, serviceId);  
这样就完成了服务注册,并且添加了健康检查的url,比较简单。

——同样Consul提供了两种发现服务的方式,一种是通过HTTP API查看存在哪些服务;另外一种是通过consul agent内置的DNS服务来做。两者的差别在于后者可以根据服务check的实时状态动态调整available服务节点列表。

2.1.DNS发现服务
在配置和部署完client服务后,我们就可以通过DNS命令来查询服务的具体信息了。consul为服务编排的内置域名为 “NAME.service.consul",这样我们的redis的域名为:redis.service.consul 进行查询服务

2.2.java代码发现服务
[java]  view plain  copy
  1. HealthClient healthClient = Consul.newClient().healthClient();  
  2. ConsulResponse<List<ServiceHealth>> response = client2.healthClient().getHealthyServiceInstances(serviceName);//获取健康的服务  
  3. ServiceHealthCache svHealth = ServiceHealthCache.newCache(healthClient, serviceName);//创建今天服务  
  4. svHealth.start();//开始监听服务  
上面用代码实现了服务的发现,其发现是排除了一些不健康的服务,这正是consul最大的优点,使得服务变化通知更加简单。

这里分析下consul和zookeeper服务变更通知的区别:
zookeeper:客户端和服务端通过建立tcp长连接进行服务变更通知,一旦服务端有服务变化,通过socket发送消息给客户端。优点是简单,服务端主动推送消息到客户端,缺点是长连接往往不稳定,链路断开,客户端经常收不到服务端推送的消息。

consul:是基于http协议,客户端通过http api主动查询服务,如果有变更则返回服务信息,我们都知道http是一个request,一个response,而consul怎样保证服务端一有变更马上response到客户端呢,这里consul解决方案是:1轮循;2阻塞查询,通过轮循调用服务端,并且不及时返回服务信息,而是等待一定时间在返回,在规定时间内如果有服务变更则马上返回变更信息,这样就客户端就可以及时的知道服务变更。


五.consul的其它使用

——consul做为分布式框架绝不仅仅满足服务注册和发现,它还可以

1.分布式key/value,用于做配置中心。
2.分布式session,用于解决session的问题。
3.分布式锁,其key/value也可以用于分布式锁的问题
4.资源中心,动态管理redis、datasource、rabbitmq等资源
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐