大纲

- 背景引入 : Eureka2.0宣布停止更新

SpringCloud 整合Zookeeper替代Eureka
- Zookeeper是什么?
- zookeeper是一个分布式协调工具,可以实现注册中心功能
- 环境要求
- Centos 7.x
- 配置好网络,可以ping通网络
- 关闭防火墙
systemctl stop firewalled
- 关闭Linux服务器防火墙后启动zookeeper服务器
- zookeeper服务器取代Eureka服务器,zk作为服务注册中心
模拟实现
Zookeeper环境搭建
- 打开虚拟机

- 使用ssh远程连接到服务器主机
- 校验主机环境


- 进入zookpeer,bin路径运行 zkServer.sh

- 运行 zkClient.sh
./zkCli.sh无需添加start ,(Server端需要)

- 此处可以看到成功进入zookeeper后会有welcome提示,与监听端口提示
- 同时进入内置命令行系统
补充 : zookeeper客户端常用命令
- 启动客户端:./zkCli.sh -server ip:port(如果连接本地Zookeeper,那么ip:port可省略)。
- 退出客户端:quit。
- 查看指定节点子节点信息:ls 节点,比如查看根节点下子节点信息(新安装的Zookeeper根节点就一个zookeeper节点)
- 创建节点:create 父节点path/子节点 [子节点数据],父节点path不能为空,可以是/或其他path(默认情况下创建的是持久化的节点,既不是顺序也不是临时的)。
- 获取节点数据:get 节点path,如果节点没有信息,返回null。
- 修改节点数据:set 节点path 节点数据。
- 删除节点:delete 节点path。
- 删除某个包含子节点的节点:deleteall 节点path(正常情况下,如果某个节点下有子节点,delete是不能删除的)。
- 帮助:help,通过它可以查看zookeeper命令详情。
Zookeeper数据结构
Zookeeper是一个树形目录服务,具有树形的结构层次,每个节点称为ZNode,每个节点会存储数据(少量数据1M)和节点信息。

节点分类
- PERSISTENT:持久化节点,即使Zookeeper服务关闭,节点信息也不会丢失。
- EPHEMERAL:临时节点,可以理解为客户端会话期间存储的节点信息,-e。
- PERSISTENT_SEQUENTIAL:持久化顺序节点,持久化节点基础上,节点的存储是有顺序的,-s。
- EPHEMERAL_SEQUENTIAL:临时顺序节点,临时节点基础上,节点的存储是有顺序的,-es。
服务提供者Payment8004
- 环境搭建
- pom文件
<?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>cloud2023</artifactId>
<groupId>top.ljzstudy.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8004</artifactId>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>top.ljzstudy.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- SpringBoot整合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.5.8版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.8</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>- 编写application.yaml文件
#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 8004
#服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 192.168.10.100:2181 #配置上文连接的开启Zookeeper Server的虚拟机ip与port- 编写主启动类
package top.ljzstudy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class,args);
}
}- 编写控制层
package top.ljzstudy.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/zk")
public String paymentzk() {
return "springcloud with zookeeper: " serverPort "t" UUID.randomUUID().toString();
}
}- 运行Payment8004,同时查看zookeeper节点变化

- 访问 : http://localhost:8004/payment/zk
GET http://localhost:8004/payment/zk
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 69
Date: Sat, 09 Sep 2023 02:06:08 GMT
Keep-Alive: timeout=60
Connection: keep-alive
springcloud with zookeeper: 8004 0bd73366-4e5f-4573-97e6-bcd4d697741a
Response code: 200; Time: 265ms; Content length: 69 bytes


- 获取格式化json传
{
"name": "cloud-provider-payment",
"id": "8e1412bd-e8ee-41bf-80be-d5e20d072a90",
"address": "DESKTOP-C0R184F",
"port": 8004,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "cloud-provider-payment",
"metadata": {}
},
"registrationTimeUTC": 1694224727460,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [
{
"value": "scheme",
"variable": true
},
{
"value": "://",
"variable": false
},
{
"value": "address",
"variable": true
},
{
"value": ":",
"variable": false
},
{
"value": "port",
"variable": true
}
]
}
}- 服务节点是临时节点还是持久节点?
- 测试,
- 先关闭payment8004服务,然后查看zookeeper节点,这次启动服务观察两次节点的变化


- 现象
- 当第一次Payment8004关闭时zookeeper服务端立即将cloud-provider-payment节点剔除
- 当Payment8004服务再次启动时访问节点数据发生变化
- 结论
- Zookeeper对于访问节点默认为临时节点
- Zookeeper与Eureka的机构思想不同,是CP架构,牺牲系统高可用以达到数据的强制一致性
服务消费者Consumerzk80
- 环境搭建
- pom文件
<?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>cloud2023</artifactId>
<groupId>top.ljzstudy.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumerzk-order80</artifactId>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--先排除自带的zookeeper-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>- 编写appliaction.yaml文件
server:
port: 80
spring:
application:
name: cloud-consumer-order #服务名称
cloud:
#注册到zookeeper地址
zookeeper:
connect-string: 192.168.10.100:2181- 编写主启动配置
package top.ljzstudy.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ZkMainApp {
public static void main(String[] args) {
SpringApplication.run(ZkMainApp.class,args);
}
}- 编写配置类
package top.ljzstudy.springcloud.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
@Slf4j
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}- 编写业务
- 编写控制层OrderZkController访问服务提供者Payment8004
package top.ljzstudy.springcloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
@Slf4j
public class OrderZkController {
public static final String INVOKE_URL = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/zk")
public String paymentInfo(){
return restTemplate.getForObject(INVOKE_URL "/payment/zk",String.class);
}
}- 测试
- 启动Consumerzk80服务

- 访问http://localhost:80/consumer/payment/zk
GET http://localhost:80/consumer/payment/zk
HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Content-Length: 69
Date: Sat, 09 Sep 2023 03:18:21 GMT
Keep-Alive: timeout=60
Connection: keep-alive
springcloud with zookeeper: 8004 02b8c343-f953-4219-93bc-94015a9a4fee
Response code: 200; Time: 1932ms; Content length: 69 bytes- 观察zookeeper客户端节点变化

{
"name": "cloud-consumer-order",
"id": "48442b14-1d74-43b2-8eb7-b719d62ca07b",
"address": "DESKTOP-C0R184F",
"port": 80,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "cloud-consumer-order",
"metadata": {}
},
"registrationTimeUTC": 1694229466011,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [
{
"value": "scheme",
"variable": true
},
{
"value": "://",
"variable": false
},
{
"value": "address",
"variable": true
},
{
"value": ":",
"variable": false
},
{
"value": "port",
"variable": true
}
]
}
}


