Zookeeper
maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
配置信息
spring.cloud.zookeeper.enabled=true
spring.cloud.zookeeper.connect-string=192.168.56.2:2181
spring.cloud.zookeeper.discovery.enabled=true
注册元数据
{
"name": "zkreg-client",
"id": "bdf16c2b-5d0b-462a-a532-bf9bc311004d",
"address": "DESKTOP-94SCF9A",
"port": 10100,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "zkreg-client",
"metadata": {}
},
"registrationTimeUTC": 1543550254396,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [{
"value": "scheme",
"variable": true
},
{
"value": "://",
"variable": false
},
{
"value": "address",
"variable": true
},
{
"value": ":",
"variable": false
},
{
"value": "port",
"variable": true
}]
}
}
缺点
Zookeeper作为注册中心,主要是满足了CAP中的CP 要求,P没什么好说的分区容错性必须要保证,然后需要保证可用性,而zk的可用性在大并发情况下它的选举算法势必会导致部分请求丢失。优点是一致性,但是一致性像在这种情况显得没有必要。而 Eureka即是AP的例子,比较适合做注册中心。
Eureka
服务端
maven配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
配置信息
# 关闭自我保护模式
eureka.server.enable-self-preservation=false
# 设置清理无效节点的时间间隔,默认60000,即是60s
eureka.server.eviction-interval-timer-in-ms=5000
# 使用ip进行发布
eureka.instance.prefer-ip-address=true
# eureka服务器的地址(注意:地址最后面的 /eureka/ 这个是固定值)
eureka.client.serviceUrl.defaultZone=http://192.168.56.1:${server.port}/eureka/
# 是否从eureka获取注册信息, 因为本身所以不需要
eureka.client.fetch-registry=false
# 是否注册到eureka,如果是集群就需要配置成true
# 并且上面的defaultZone需要配置集群的另外的节点
eureka.client.register-with-eureka=false
备注:
ureka Server通过“自我保护模式”来解决这个问题----当Eureka Server 节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。一旦进入该模式,Eureka Server就会保护服务注册表中的信息,不再删除服务注册表中的数据(也就是不会注销任何微服务)。当网络故障恢复后,该Eureka Server 节点会自动退出自我保护模式。
注解
@EnableEurekaServer
注册元数据
GET http://192.168.56.1:10200/eureka/apps/EUREKAREG-CLIENT-SPRING
<application>
<name>EUREKAREG-CLIENT-SPRING</name>
<instance>
<instanceId>DESKTOP-94SCF9A:eurekareg-client-spring:10300</instanceId>
<hostName>192.168.56.1</hostName>
<app>EUREKAREG-CLIENT-SPRING</app>
<ipAddr>192.168.56.1</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">10300</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>5</renewalIntervalInSecs>
<durationInSecs>10</durationInSecs>
<registrationTimestamp>1543565263391</registrationTimestamp>
<lastRenewalTimestamp>1543565338399</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1543565263391</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>10300</management.port>
</metadata>
<homePageUrl>http://192.168.56.1:10300/</homePageUrl>
<statusPageUrl>http://192.168.56.1:10300/actuator/info</statusPageUrl>
<healthCheckUrl>http://192.168.56.1:10300/actuator/health</healthCheckUrl>
<vipAddress>eurekareg-client-spring</vipAddress>
<secureVipAddress>eurekareg-client-spring</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1543565263391</lastUpdatedTimestamp>
<lastDirtyTimestamp>1543565263335</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
客户端
spring客户端
maven配置
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
配置信息
# Eureka启用Security后客户端使用http://qb:123456@192.168.56.1:10200/eureka/ 连接上来会报错下面的错误
# com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server
# eureka服务器的地址(注意:地址最后面的 /eureka/ 这个是固定值)
eureka.client.serviceUrl.defaultZone=http://192.168.56.1:10200/eureka/
#设置拉取服务注册信息时间,默认60s
eureka.client.registry-fetch-interval-seconds=30
#自定义实例ID
#eureka.instance.instanceId=${spring.application.name}:${random.value}
#显示IP地址
eureka.instance.prefer-ip-address=true
#指定续约更新频率,默认是30s
eureka.instance.lease-renewal-interval-in-seconds=5
#设置过期剔除时间,默认90s
eureka.instance.lease-expiration-duration-in-seconds=10
注解
@EnableEurekaClient
非spring客户端
这里以java模拟http请求作为示例,当然其他异构语言只要使用 http协议调用各api同样可以实现向eureka注册
以java作为示例需要依赖一下工具包
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.1.41</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
注册实例
l 接口代码
MediaType JSON = MediaType.get("application/json; charset=utf-8");
URL url = ResourceUtils.getURL("classpath:reg-instance.json");
RequestBody body = RequestBody.create(JSON, IOUtils.toString(url, Charset.defaultCharset()));
String regAPI = "http://192.168.56.1:10200/eureka/apps/eurekareg-client-rest";
Request request = new Request.Builder().url(regAPI).post(body).build();
Response response = client.newCall(request).execute();
l 请求报文reg-instance.json
其中红色部分注册信息同properties/yml 中的eureka.instance.*前缀属性
{
"instance": {
"instanceId": "DESKTOP-94SCF9A:eurekareg-client-rest:10301",
"app": "eurekareg-client-rest",
"appGroutName": null,
"ipAddr": "192.168.56.1",
"sid": "na",
"homePageUrl": null,
"statusPageUrl": null,
"healthCheckUrl": null,
"secureHealthCheckUrl": null,
"vipAddress": "eurekareg-client-rest2",
"secureVipAddress": "eurekareg-client-rest2",
"countryId": 1,
"dataCenterInfo": {
"@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
"name": "MyOwn"
},
"hostName": "192.168.56.2",
"status": "UP",
"leaseInfo": null,
"isCoordinatingDiscoveryServer": false,
"lastUpdatedTimestamp": 1529391461000,
"lastDirtyTimestamp": 1529391461000,
"actionType": null,
"asgName": null,
"overridden_status": "UNKNOWN",
"port": {
"$": 10301,
"@enabled": "false"
},
"securePort": {
"$": 10302,
"@enabled": "false"
},
"metadata": {
"@class": "java.util.Collections$EmptyMap"
}
}
}
销毁实例
l 接口代码
OkHttpClient client=new OkHttpClient();
String deleteAPI="http://192.168.56.1:10200/eureka/apps/eurekareg-client-rest/DESKTOP-94SCF9A:eurekareg-client-rest:10301";
Request request=new Request.Builder().url(deleteAPI).delete().build();
Response response=client.newCall(request).execute();
log.info("\n{}",response.body().string());
实例暂停/下线/脱网
l 接口代码
OkHttpClient client=new OkHttpClient();
String outServiceAPI="http://192.168.56.1:10200/eureka/apps/eurekareg-client-rest/DESKTOP-94SCF9A:eurekareg-client-rest:10301/status?value=OUT_OF_SERVICE ";
FormBody body=new FormBody.Builder().build();
Request request=new Request.Builder().url(outServiceAPI).put(body).build();
Response response=client.newCall(request).execute();
log.info("\n{}",response.body().string());
恢复实例
l 接口代码
OkHttpClient client=new OkHttpClient();
String outServiceAPI="http://192.168.56.1:10200/eureka/apps/eurekareg-client-rest/DESKTOP-94SCF9A:eurekareg-client-rest:10301/status?value=UP ";
FormBody body=new FormBody.Builder().build();
Request request=new Request.Builder().url(outServiceAPI).delete(body).build();
Response response=client.newCall(request).execute();
log.info("\n{}",response.body().string());
应用实例发送心跳
l 接口代码
OkHttpClient client=new OkHttpClient();
String outServiceAPI="http://192.168.56.1:10200/eureka/apps/eurekareg-client-rest/DESKTOP-94SCF9A:eurekareg-client-rest:10301";
FormBody body=new FormBody.Builder().build();
Request request=new Request.Builder().url(outServiceAPI).put(body).build();
Response response=client.newCall(request).execute();
log.info("\n{}",response.body().string());
修改实例参数
例如修改eureka.instance.lease-renewal-interval-in-seconds=5这些配置,通过删除实例后重新添加实例
缺点
一致性较差,eureka分区节点挂了以后,数据一致性没法保证。客户端拉取服务信息可能是过期的服务列表。另外服务信息不做持久保存。使用eureka 应付规模不大的分布式环境足够,所以应对大型的分布式环境Consul时最优解。
Consul
介绍
consul是google开源的一个使用go 语言开发的服务发现、配置管理中心服务。内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value存储、多数据中心方案,不再需要依赖其他工具(比如ZooKeeper 等)。服务部署简单,只有一个可运行的二进制的包。每个节点都需要运行agent,他有两种运行模式server和 client。每个数据中心官方建议需要3或5个 server节点以保证数据安全,同时保证server-leader的选举能够正确的进行。
@client
CLIENT表示consul的client 模式,就是客户端模式。是consul节点的一种模式,这种模式下,所有注册到当前节点的服务会被转发到SERVER,本身是不持久化这些信息。
@server
SERVER表示consul的server 模式,表明这个consul是个server,这种模式下,功能和CLIENT 都一样,唯一不同的是,它会把所有的信息持久化的本地,这样遇到故障,信息是可以被保留的。
@server-leader
中间那个SERVER下面有LEADER的字眼,表明这个 SERVER是它们的老大,它和其它SERVER不一样的一点是,它需要负责同步注册的信息给其它的SERVER ,同时也要负责各个节点的健康监测。
@raft
server节点之间的数据一致性保证,一致性协议使用的是raft,而zookeeper 用的paxos,etcd采用的也是taft 。
@服务发现协议
consul采用http和dns 协议,etcd只支持http
@服务注册
consul支持两种方式实现服务注册,一种是通过consul的服务注册http API ,由服务自己调用API实现注册,另一种方式是通过json个是的配置文件实现注册,将需要注册的服务以 json格式的配置文件给出。consul官方建议使用第二种方式。
@服务发现
consul支持两种方式实现服务发现,一种是通过http API来查询有哪些服务,另外一种是通过 consul agent 自带的DNS(8600端口),域名是以 NAME.service.consul的形式给出,NAME即在定义的服务配置文件中,服务的名称。DNS 方式可以通过check的方式检查服务。
@服务间的通信协议
Consul使用gossip协议管理成员关系、广播消息到整个集群,他有两个gossip pool (LAN pool和WAN pool),LAN pool 是同一个数据中心内部通信的,WAN pool是多个数据中心通信的,LAN pool有多个, WAN pool只有一个。
安装部署
安装golang
安装consul需要os先安装 golang环境
https://dl.google.com/go/go1.11.2.linux-amd64.tar.gz
cp go1.11.2.linux-amd64.tar.gz /usr/local
gunzip go1.11.2.linux-amd64.tar.gz
tar -xvf go1.11.2.linux-amd64.tar
export PATH=$PATH:/usr/local/go/bin
安装系统
需要内核 >= 2.6.23
安装介质
https://releases.hashicorp.com/consul/1.4.0/consul_1.4.0_windows_amd64.zip
https://releases.hashicorp.com/consul/1.4.0/consul_1.4.0_linux_amd64.zip
https://releases.hashicorp.com/consul/1.4.0/consul_1.4.0_solaris_amd64.zip
https://releases.hashicorp.com/consul/1.4.0/consul_1.4.0_darwin_amd64.zip
检查安装
开发者模式
consul agent -dev -bind=192.168.56.101 -client=0.0.0.0
开发模式,自带了web ui,直接http://192.168.56.101 :8500/ 即可,非常方便
自带UI
springboot集成
配置
spring.application.name=consulreg-client-springserver.port=10400spring.cloud.consul.host=192.168.56.101 spring.cloud.consul.port=8500spring.cloud.consul.discovery.tags=version=1.0,mail=yuanjun3@asiainfo-sec.comspring.cloud.consul.discovery.health-check-path= /heartbeatspring.cloud.consul.discovery.health-check-interval=5s
心跳接口
@RestControllerpublic class HeartBeatControl{ @RequestMapping(path=" /heartbeat", method=RequestMethod.GET) public void heartbeat(){ } }
注册结果
替换eureka为consul注意事项
最后提醒一下:如果使用consul来替换eureka,而你的项目中又依赖了 eureka的jar包,最好将eureka的自动配置从启动类里排除掉,参考下面:
优点
1. 有Google大厂支持维护,可靠性有保障
2. 支持数据持久化(eureka不支持 )
3. 支持集群部署,并且支持server(专做状态维护 )和client(负载均衡)两种模式 ( 较zk可用性高)
4. 支持开发模式
5. springboot原生支持集成
6. 界面UI美观,可读性好,( 功能较eureka好一些,zookeeper只有简单的zkui 等界面 )
7. 提供rest风格的api( zk不支持)