一、什么是Zookeeper?
1、Zookeeper是一个基于观察者设计模式的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者注册;
一旦这些数据的状态发生变化,Zookeeper就将负责通知以及在Zookeeper上注册的那些观察者做出相应的反应;
从而实现集群中类似Master/Slave管理模式!
2、一句话,简而言之—— Zookeeper = 文件系统 + 通知机制
Zookeeper也是一个倒装式的文件系统;——类似于linux
3、Zookeeper能干些什么?
-
命名服务:统一命名服务,如Dubbo的服务注册中心;
-
配置服务:如淘宝开源配置管理框架Diamond,在大型的分布式系统中,为了服务海量的请求,同一个应用常常需要多个实例。如果存在配置更新的需求,常常需要逐台更新,给运维增加了很大的负担,同时带来了一定的风险(哦诶之会存在不一致的窗口期,或个别节点忘记更新)。Zookeeper可以用来做几种的配置管理,存储在zookeeper集群中的配置,如果发生变更会主动推送到连接配置中心的应用节点,实现一处更新处处更新的效果!
-
集群管理:如Hadoop分布式集群管理;
-
分布式消息同步和协调机制:
-
负载均衡:
-
对Dubbo的支持:
-
Zookeeper提供了一套很好的分布式集群管理机制,就是它这种基于层次型的目录树的数据结构,并对树中的节点进行有效管理,
从而可以设计出多种多样的分布式的数据管理模型,作为分布式系统的沟通调度桥梁!
二、Zookeeper的安装配置
官网下载安装包,本次版本选择zookeeper-3.4.9.tar.gz
1、在根目录创建一个专门给zookeeper工作的目录;
2、拷贝下载好的zookeeper安装包到 /opt 目录下并解压,之后再将解压包拷贝到 /myzookeeper 目录下:
3、进入 /myzookeeper/zookeeper-3.4.9/conf 文件夹下,拷 zoo_sample.cfg 为 zoo.cfg:
4、修改zookeeper的核心配置文件 zoo.cfg,解读其关键配置:
-
tickTime: 通信的心跳间隔时间,单位为毫秒,默认为 2000ms;
-
initLimit: 集群中Follower 与Leader 之间初始连接时能容忍的最多心跳数;
-
syncLimit: 集群中Leader与Follower之间的最大响应时间,如果超过,Leader就认为Follower死掉了,姜葱服务列表中移除Follower;
-
dataDir: 数据目录;
-
clientPort: 默认端口 :2181
5、直接开启服务(解压直接用):——机器必须已经安装了JDK,因为Zookeeper服务器使用java编写的,需要jvm;
-
启动服务:./zkServer.sh start
可以使用另一个客户端,和zookeeper互动:
-
关闭服务:./zkServer.sh stop
-
客户端连接:./zkCli.sh
-
退出:quit
-
创建节点:create /testNode v1
-
获取节点的值:get /testNode
-
重新设置节点的值:set /testNode v2
-
删除节点:delete /testNode
操作 zookeeper 就仿佛在操作一个Map一样简单,只不过它的 key 是一个路径path而已!
三、使用Zookeeper代替Eureka,作为服务注册中心
1、关闭防火墙(我是用的是Ubuntu系统):sudo ufw disable
如果是Centos系统,则使用命令:sudo systemctl stop firewalld
确保zookeeper所在机器与本机测试环境相互 ping 通:
2、快速创建一个新的支付服务提供者 cloud-provider-payment8004
pom.xml文件:只需要将Eureka客户端的依赖,换成zookeeper客户端的依赖即可(简单的做个服务,数据库4项就不要了):
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.jiguiquan.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-provider-payment8004</artifactId> <dependencies> <!--公共服务模块依赖--> <dependency> <groupId>com.jiguiquan.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--springboot项目web和actuator最好一起走--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--SpringBoot整合zookeeper的客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> <!--热部署devtools--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--测试--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> </project>
3、配置文件application.yml如下:
server: port: 8004 spring: application: name: cloud-provider-payment cloud: zookeeper: connect-string: 192.168.44.129:2181
4、主启动类 com.jiguiquan.springcloud.PaymentMain8004.java:
@SpringBootApplication @EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为服务中心时,向其注册服务,以后很常见 public class PaymentMain8004 { public static void main(String[] args) { SpringApplication.run(PaymentMain8004.class, args); } }
5、写个最简单的 PaymentController:
@RestController @Slf4j public class PaymentController { @Value("${server.port}") private String serverPort; @RequestMapping("/payment/zk") public String paymentzk(){ return "Springcloud with zookeeper: "+ serverPort + "\t" + UUID.randomUUID().toString(); } }
6、先启动Zookeeper服务,使用zkCli连接:
...启动服务端 root@Ubuntu:/myzookeeper/zookeeper-3.4.9/bin# ./zkServer.sh start ...使用zkCli客户端连接 root@Ubuntu:/myzookeeper/zookeeper-3.4.9/bin# ./zkCli.sh ...zookeeper下除了原始的 /zookeeper节点外,没有任何其他节点!! [zk: localhost:2181(CONNECTED) 0] ls / [zookeeper] [zk: localhost:2181(CONNECTED) 1] get /zookeeper cZxid = 0x0 ctime = Thu Jan 01 08:00:00 CST 1970 mZxid = 0x0 mtime = Thu Jan 01 08:00:00 CST 1970 pZxid = 0x0 cversion = -1 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 0 numChildren = 1 [zk: localhost:2181(CONNECTED) 2]
7、此时启动 cloud-provider-payment8004 项目,直接报错:
究其原因,真如截图所说,是因为我们映入的jar包中自带的zookeeper的版本为zookeeper-3.5.3-beta.jar:
处理办法:
卸载服务器上的zookeeper服务,换为3.5.3?显然不可以,因为此zookeeper可能有很多服务都在用,不能轻易卸载!!
从本Java程序入手,将spring-cloud-start-zookeeper-discovery依赖自带的zookeeper排除掉,换成我们需要的zookeeper版本即可——可行!
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <!--排除此starter依赖自带的zookeeper版本,换成我们自己需要的zookeeper版本--> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.9</version> </dependency>
8、再次启动 cloud-provider-payment8004 服务,此次,没有报任何的错误:
具体,有没有注册成功,我们可以使用 .zkCli.sh 客户端连接到 zookeeper 查看:
[zk: localhost:2181(CONNECTED) 2] ls / [services, zookeeper] [zk: localhost:2181(CONNECTED) 3] ls /services [cloud-provider-payment]
很明显,cloud-provider-payment 服务已经成功入驻进 zookeeper 服务;
9、我们继续向下深挖:
将其中的服务详细信息格式化后看一下:
{ "name":"cloud-provider-payment", "id":"50ff9ca1-3868-4358-bcfa-f6a68b57be76", "address":"localhost", "port":8004, "sslPort":null, "payload":{ "@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance", "id":"application-1", "name":"cloud-provider-payment", "metadata":{ } }, "registrationTimeUTC":1584029149663, "serviceType":"DYNAMIC", "uriSpec":{ "parts":[ { "value":"scheme", "variable":true }, { "value":"://", "variable":false }, { "value":"address", "variable":true }, { "value":":", "variable":false }, { "value":"port", "variable":true } ] } }
可以,很清楚看出来,此服务 cloud-provider-payment8004 注册在 Zookeeper 中的详细信息!
10、服务注册进Zookeeper后,是临时节点还是持久节点?
zookeeper有四种节点:
-
临时节点;
-
临时有序节点;
-
持久节点;
-
持久有序节点;
经过简单对payment8004的启停,可以发现在简单心跳检测时间后,zookeeper就会将对应的节点删除,
可以知道zookeeper作为服务注册中心,创建的是临时节点;
且Zookeeper没有类似于Eureka那样的自我保护机制;
四、创建订单服务cloud-consumerzk-order80服务,并注册进Zookeeper
1、创建module,pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud2020</artifactId> <groupId>com.jiguiquan.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumerzk-order80</artifactId> <dependencies> <!--公共服务模块依赖--> <dependency> <groupId>com.jiguiquan.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--springboot项目web和actuator最好一起走--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--SpringBoot整合zookeeper的客户端--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <!--排除此starter依赖自带的zookeeper版本,换成我们自己需要的zookeeper版本--> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.9</version> </dependency> <!--热部署devtools--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--测试--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies> </project>
2、application.yml如下:
server: port: 80 spring: application: name: cloud-consumerzk-order cloud: zookeeper: connect-string: 192.168.44.129:2181
3、编写主启动类:OrderZKMain80.java:
@SpringBootApplication @EnableDiscoveryClient public class OrderZKMain80 { public static void main(String[] args) { SpringApplication.run(OrderZKMain80.class, args); } }
4、编写简单业务类OrderController.java:
@RestController @Slf4j public class OrderZkController { public static final String INVOKE_URL = "http://cloud-provider-payment"; @Autowired private RestTemplate restTemplate; @GetMapping("/consumer/payment/zk") public String paymentInfo(){ return restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class); } }
5、启动服务cloud-consumerzk-order80,之后检查zookeeper中的节点列表:
可见,Order80已经注册进了Zookeeper;
6、使用以下路径访问:http://localhost/consumer/payment/zk
访问正常!Zookeeper作为服务注册中心,一切正常!Over
个人此项目代码地址(持续更新):