Spring Cloud 入门 — ZooKeeper 服务注册中心
介绍
之前我们介绍了 Eureka,现在我们介绍另一个服务注册中心—ZooKeeper。ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,是 Google 的 Chubby 一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper 的特性
- 顺序一致性:从同一个客户端发起的事务请求,最终将会严格地按照其发起顺序被应用到 ZooKeeper 中去。
- 原子性:所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,即整个集群要么都应用了某个事务,要么都没有应用。
- 单一视图:无论客户端连接的是哪个 ZooKeeper 服务器,其看到的服务端数据模型都是一致的。
- 可靠性:一旦服务端成功的应用了一个事务,并完成对客户端的响应,那么该事务所引起的服务端状态变更将会被一直保留,除非有另一个事务对其进行了变更。
- 实时性:ZooKeeper 保证在一定的时间段内,客户端最终一定能够从服务端读取到最新的数据状态。
使用Docker安装zookeeper【单机】
关于 docker 的安装及简单使用在之前的文章中已经介绍了,以下的关于 Zookeeper 的案例都是单机的,关于 Zookeeper 的集群及其它这里不做赘述。
拉取 zookeeper 镜像
docker pull zookeeper:3.6.1
运行
docker run --name zookeeper3.6.1 -p 2181:2181 --restart always -d 镜像ID
查看 zookeeper
docker ps
查看 zookeeper 日志
docker logs 容器id 如下面的: docker logs a716ebfe4f5a
ZooKeeper 服务提供者模块
创建服务提供者
导入 pom 依赖
<!--zookeeper-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--zookeeper3.6.1-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
由于
spring-cloud-starter-zookeeper-discovery
自带的是zookeeper3.5.3
而我们使用是zookeeper3.6.1
为了避免出现问题【虽然测试的时候没发现】,我们移除原有自带的zookeeper3.5.3
,手动导入zookeeper3.6.1
;由于我本地依赖引入的lombok
其中自带了slf4j
依赖,而zookeeper3.6.1
也自带了slf4j
依赖,导致出现了依赖冲突,所以我这里移除了zookeeper3.6.1
自带的slf4j
依赖,没有出现依赖冲突的可以不用移除。
添加 application.yml 配置
server:
port: 8004
spring:
application:
name: zk-payment-provider # 服务别名
cloud:
zookeeper:
connect-string: 192.168.0.106:2181 # zookeeper地址
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class ZkPaymentProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ZkPaymentProviderApplication.class, args);
}
}
业务类
@RestController
public class ZkPaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/payment/zk")
public String paymentzk(){
return "spring cloud with zookeeper port: "+serverPort+"\t"+ UUID.randomUUID().toString();
}
}
测试:启动应用程序,并访问 http://localhost:8004/payment/zk
查看 服务是否注册进 ZooKeeper
步骤:
进入zookeeper
docker exec -it 容器ID /bin/bash
启动 zookeeper 客户端 zkCli.sh
cd bin ./zkCli.sh
列表 zookeeper 信息
ls /
查看 zookeeper 信息
get /
退出
Ctrl + C 再输入 exit
具体操作流程如下:
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a716ebfe4f5a 3bbbc7545ea8 "/docker-entrypoint.…" 56 minutes ago Up 56 minutes 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, 8080/tcp zookeeper3.6.1
[root@localhost ~]# docker exec -it a716ebfe4f5a /bin/bash
root@a716ebfe4f5a:/apache-zookeeper-3.6.1-bin# ls
LICENSE.txt NOTICE.txt README.md README_packaging.md bin conf docs lib
root@a716ebfe4f5a:/apache-zookeeper-3.6.1-bin# cd bin/
root@a716ebfe4f5a:/apache-zookeeper-3.6.1-bin/bin# ls
README.txt zkCli.cmd zkEnv.cmd zkServer-initialize.sh zkServer.sh zkSnapShotToolkit.sh zkTxnLogToolkit.sh
zkCleanup.sh zkCli.sh zkEnv.sh zkServer.cmd zkSnapShotToolkit.cmd zkTxnLogToolkit.cmd
root@a716ebfe4f5a:/apache-zookeeper-3.6.1-bin/bin# ./zkCli.sh
Connecting to localhost:2181
2020-10-29 02:27:32,830 [myid:] - INFO [main:Environment@98] - Client environment:zookeeper.version=3.6.1--104dcb3e3fb464b30c5186d229e00af9f332524b, built on 04/21/2020 15:01 GMT
2020-10-29 02:27:32,837 [myid:] - INFO [main:Environment@98] - Client st/127.0.0.1:2181
2020-10-29 02:27:32,980 [myid:localhost:2181] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1420] - Session establishment complete on server localhost/127.0.0.1:2181, session id = 0x100004078b60005, negotiated timeout = 30000
WATCHER::
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0] ls /
[services, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /services
[zk-payment-provider]
[zk: localhost:2181(CONNECTED) 2] ls /services/zk-payment-provider
[11754915-53f9-4444-977f-7384e22cd514]
[zk: localhost:2181(CONNECTED) 3] ls /services/zk-payment-provider/11754915-53f9-4444-977f-7384e22cd514
[]
[zk: localhost:2181(CONNECTED) 4] get /services/zk-payment-provider
[zk: localhost:2181(CONNECTED) 5] get /services/zk-payment-provider/11754915-53f9-4444-977f-7384e22cd514
{"name":"zk-payment-provider","id":"11754915-53f9-4444-977f-7384e22cd514","address":"DESKTOP-6BVONHQ","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"zk-payment-provider","metadata":{"instance_status":"UP"}},"registrationTimeUTC":1603938189660,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
[zk: localhost:2181(CONNECTED) 6]
以下为服务的详情信息:
{"name":"zk-payment-provider","id":"11754915-53f9-4444-977f-7384e22cd514","address":"DESKTOP-6BVONHQ","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"zk-payment-provider","metadata":{"instance_status":"UP"}},"registrationTimeUTC":1603938189660,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
服务提供者集群
修改 原有服务提供者
application.yml
配置名为application-one.yml
并复制一份修改名称为application-two.yml
,具体配置如下:
application-one.yml
server:
port: 8004
spring:
application:
name: zk-payment-provider
cloud:
zookeeper:
connect-string: 192.168.0.106:2181
application-two.yml
server:
port: 8005
spring:
application:
name: zk-payment-provider
cloud:
zookeeper:
connect-string: 192.168.0.106:2181
修改原有的服务,并指定运行的配置文件
copy 修改后的服务,并修改名称 与 运行的配置文件
启动这两个服务提供者,在 zookeeper 的客户端 zkCli 中查看服务信息,如下图:可以看到服务
zk-payment-provider
下存在两个服务节点,并且测试能够正常访问。
[zk: localhost:2181(CONNECTED) 0] ls /services
[zk-payment-provider]
[zk: localhost:2181(CONNECTED) 1] ls /services/zk-payment-provider
[5ac84b3b-f4f1-4cf2-9ef3-8d7256b78893, 6cbbe9a2-4016-4b69-ae5d-0e2aa61ebc0d]
ZooKeeper 服务消费者模块
导入 pom 依赖
<!--zookeeper-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--zookeeper3.6.1-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
添加 application.yml 配置
server:
port: 80
spring:
application:
name: zk-order-concumer
cloud:
zookeeper:
connect-string: 192.168.0.106:2181
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class ZkOrderConcumerApplication {
public static void main(String[] args) {
SpringApplication.run(ZkOrderConcumerApplication.class, args);
}
}
业务类
@RestController
@Slf4j
public class OrderZkController {
/**
* 微服务别名
*/
private static final String INVOKE_URL = "http://zk-payment-provider";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/zk")
public String paymentInfo(){
String msg = restTemplate.getForObject(INVOKE_URL+"/payment/zk", String.class);
return msg;
}
}
配置类
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //开启负载均衡【默认轮询】
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
测试
启动服务,调用:http://localhost/consumer/payment/zk 可以看到服务使用
轮询
的负载均衡规则 轮流调用 8004 与 8005 服务提供者,同时再 zookeeper 中也可以看到服务已经注册到其中了。