3--SpringCloud 和 Zookeeper周阳老师
2021:3--SpringCloud 和 Zookeeper
https://www.cnblogs.com/coderD/p/14350076.html SpringCloud
https://www.cnblogs.com/coderD/p/14350073.html SpringCloud 和 Eureka
https://www.cnblogs.com/coderD/p/14350082.html SpringCloud 和 Zookeeper
https://www.cnblogs.com/coderD/p/14350086.html SpringCloud-Ribbon/OpenFeign
https://www.cnblogs.com/coderD/p/14350091.html SpringCloud:Hystrix 断路器
https://www.cnblogs.com/coderD/p/14350097.html SpringCloud:服务网关 gateway
https://www.cnblogs.com/coderD/p/14350099.html SpringCloud:Config/Bus
https://www.cnblogs.com/coderD/p/14350103.html SpringCloud:Stream/Sleuth
https://www.cnblogs.com/coderD/p/14350110.html SpringCloud Alibaba:Nacos
https://www.cnblogs.com/coderD/p/14350114.html SpringCloud Alibaba:Sentinel
https://www.cnblogs.com/coderD/p/14350119.html SpringCloud Alibaba:Seata
代码:https://gitee.com/xue--dong/spring-cloud
阳哥脑图:https://gitee.com/xue--dong/spring-cloud
主要内容
1. 服务注册中:Zookeeper代替Eureka
2. Consul服务注册与发现
复制代码
1. 注册中心 Zookeeper
zookeeper是一个分布式协调工具,可以实现注册中心功能
关闭linux服务器防火墙后,启动zookeeper服务器
systemctl stop firewalld
zookeeper服务器取代Eureka服务器,zk作为服务注册中心
复制代码
2. 服务提供者
2.1 新建 cloud-provider-payment8004
1. 新建cloud-provider-payment8004
复制代码
2.2 pom
2. pom
复制代码
<dependencies>
<!--SpringBoot整合zookeeper客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<!--引入我们自定义的公共api jar包-->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--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>
<!--Mybatis和SpringBoot的整合-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</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>
复制代码
2.3 yml
3. yml
复制代码
server:
port: 8004
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 192.168.92.130:2181
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 数据源
driver-class-name: com.mysql.cj.jdbc.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
复制代码
2.4 主启动类
4. 主启动类
复制代码
@SpringBootApplication
@EnableDiscoveryClient //开启服务发现
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class, args);
}
}
复制代码
2.5 controller
5. controller
复制代码
@RestController
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();
}
}
复制代码
2.6 测试:解决 jar 包冲突
6. 启动测试
这里视频会出现一个jar冲突的异常
复制代码
分析思路:
找到代码中出错的地方,向启动入口处的报错,肯定是环境引起的。
注意到提示zookeeper-3.5.6-beta。
再想到我们自己安装的zookeeper版本,那就可能是jar包的冲突了。
很可能是某个整合包自带的zookeeper包和我们服务器上的zookeeper版本不一样。
发现我们导入的spring-zookeeper的整合包,包含了zookeeper-3.5.6-beta,我们要将其排除掉
复制代码
怎么做:
一般不会卸载zookeeper,因为其他系统可能正在使用这个zookeeper。
所以我们排除掉包含的这个冲突的zookeeper包,引入一个服务器对应的jar包
7. 我这里没报错。
不知道是不是我的版本(3.6.1)比较高的原因
我试着将整合包中的3.5.3版本的zookeeper剔除掉,引入3.6.1
复制代码
<!--SpringBoot整合zookeeper客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--排除掉自带的zookeepr3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入对应服务器版本的zookeeper-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
</dependency>
复制代码
8. 启动:报错
添加了3.6.1的zookeeper后,会报错:
复制代码
那么很显然了,根据上面的分析,出错误在主启动类,关键词slf4j,logback。
查看引入的3.6.1的zookeeper包:
复制代码
我导入的slf4j:
复制代码
我选择排除掉其中的3.6.1的zookeeper包其中的三个日志相关的jar包,用自己的。
复制代码
成功排除掉。
注意:groupId和artifactId的对应。
重启服务:启动成功!!!
9. 查看一下服务是否注册成功
1. 进入zookeeper容器中
docker exec -it 66805aa71339 /bin/bash
2. 客户端连接
./bin/zkCli.sh
复制代码
3. 查看服务
ls /
ls /services
复制代码
注册成功!!!
继续进去看:
ls /services/cloud-provider-payment
ls /services/cloud-provider-payment/e3d40a33-8de3-4bc6-b560-d1b510211045
复制代码
4. 几个概念
1. /services/cloud-provider-payment/e3d40a33-8de3-4bc6-b560-d1b510211045
这整个东西就是zookeeper的zNode节点。
2. 我们通过get命令,获取zookeeper中的节点信息
复制代码
这一大串,就是我们服务存在zookeeper的基本信息--JSON串。
3. 我们在线解析一下这个json串
复制代码
2.7 思考
10. 思考
注册到zookeeper的微服务是一个zNode节点,这个服务节点时临时节点还是持久节点?
我们注册进zookeeper的服务,会自动生成一个流水号id
复制代码
1. 关闭掉8004服务
2. 查看zookeeper中是否还有该微服务。
复制代码
发现刚断开连接时zookeeper还保存着该服务,等待一段时间剔除了断开连接的微服务。
3. 所以注册到zookeeper的微服务节点是临时节点。
4. 再重新启动8004的微服务
复制代码
服务又注册了进来,但是流水id换了。
5. zookeeper比eureka更加心狠干脆。
复制代码
3. 服务消费者
3.1 新建 cloud-consumerzk-order80
1. 新建cloud-consumerzk-order80
复制代码
3.2 pom
<dependencies>
<!--SpringBoot整合zookeeper客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--排除掉自带的zookeepr3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入对应服务器版本的zookeeper-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.6.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入我们自定义的公共api jar包-->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--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>
<!--Mybatis和SpringBoot的整合-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</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>
复制代码
3.3 yml
server:
port: 80
spring:
application:
name: cloud-consumerzk-order
cloud:
zookeeper:
connect-string: 192.168.92.130:218
复制代码
3.4. 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderZKMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderZKMain80.class, args);
}
}
复制代码
3.5. 业务类
package com.atguigu.springcloud.config;
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //开启默认的负载均衡机制:赋予了RestTemplate负载均衡的能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
package com.atguigu.springcloud.controller;
@RestController
@Slf4j
public class OrderZKController {
//由于在ApplicationContextConfig开启了负载均衡,这里可以通过服务名访问到微服务
public static final String INVOKE_URL = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
//返回String测试一下:不交互数据库了
@GetMapping("/consumer/payment/zk")
public String paymentInfo(){
String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk", String.class);
return result;
}
}
复制代码
3.6. 测试
1. 服务注册进zookeeper成功
复制代码
2. 服务调用成功
复制代码
4 Consul 服务注册与发现
4.1 Consul 简介
1. 是什么:微服务的服务注册中心
复制代码
Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司采用Go语言开发
提供了微服务系统中心的服务治理,配置中心,控制总线等功能。这些功能中的每一个都可以根据需要
单独使用,也可以一起使用,以构建全方位的服务网格。
总之Consul提供了一种完整的服务网格解决方案。
它具有很多优点:
包括,基于raft协议,比较简洁;支持健康检查,同时支持HTTP和DNS协议支持跨数据中心的WAN集群。
提供图形界面 跨平台,支持Linux,MAC,Windows
2. 能干嘛:The key features of Consul are:
Service Discovery:服务发现,提供HTTP和DNS两种发现方式
Health Checking: 健康检查,支持多种方式,HTTP,TCP,Docker,Shell脚本定制化
KV Store: Key,Value的存储方式
Secure Service Communication: 安全的服务交流
Multi Datacenter:多数据中心
可视化web界面
3. 下载
复制代码
4. 怎么用
复制代码
4.2 安装并运行 Consul
1. 下载完成后只有一个consul.exe文件
硬盘路径下双击运行
2. cmd:
查看版本: D:\Developer_Tools\Consul>consul --version
使用开发者模式启动: D:\Developer_Tools\Consul>consul agent -dev
3. 可视化web页面:localhost:8500
复制代码
5. 生产者服务注册:consul
5.1 新建 Module 支付服务:cloud-providerconsul-payment8006
5.2 pom
<dependencies>
<!--consul和SpringCloud的整合-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--引入我们自定义的公共api jar包-->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--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>
<!--Mybatis和SpringBoot的整合-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
</dependency>
<!--mysql-connector-java-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--jdbc-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</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>
复制代码
5.3 yml
# 微服务端口号
server:
port: 8006
# 微服务名称
spring:
application:
name: cloud-provider-payment
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 数据源
driver-class-name: com.mysql.cj.jdbc.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: root
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
mybatis:
mapper-locations: classpath:mapper/*.xml # 扫描类路径下mapper文件夹下的.xml配置文件
type-aliases-package: com.atguigu.springcloud.entities # 该包所有Entity类,取默认别名
复制代码
5.4 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class, args);
}
}
复制代码
5.5 controller
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping(value="/payment/consul")
public String paymentConsul(){
return "springcloud with consul: "+serverPort+"\t"+ UUID.randomUUID().toString();
}
}
复制代码
5.6 测试
启动8006服务
复制代码
注册成功
复制代码
6. 消费者服务注册:consul
6.1 新建 module
新建module cloud-consumerconsul-order80
复制代码
6.2 pom
<dependencies>
<!--consul和SpringCloud的整合-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--引入我们自定义的公共api jar包-->
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--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>
<!--热部署-->
<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>
复制代码
6.3 yml
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
复制代码
6.4 主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class, args);
}
}
复制代码
6.5 controller 和 config
config
复制代码
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //开启默认的负载均衡机制:赋予了RestTemplate负载均衡的能力
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
复制代码
controller
复制代码
@RestController
@Slf4j
public class OrderConsulController {
//由于在ApplicationContextConfig开启了负载均衡,这里可以通过服务名访问到微服务
public static final String INVOKE_URL = "http://consul-provider-payment";
@Resource
private RestTemplate restTemplate;
//返回String测试一下:不交互数据库了
@GetMapping("/consumer/payment/consul")
public String paymentInfo(){
String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);
return result;
}
}
复制代码
6.6 启动测试
7. 三个注册中心的异同点
CAP:理论
Eureka主要保证高可用:AP
Zookeeper/Consul主要保证数据的一致:CP
web界面:
Eureka/Consul都有一个web界面。
Zookeeper只有一个linux客户端。
复制代码
7.1
从CAP理论分析一下异同:
Eureka主要满足AP
Zookeeper/Consul主要满足CP
C:Consistency 强一致性
A:Avaliability 可用性
P: Partition tolerance 分区容错性
P在分布式中永远都要保证。
所以要么是CP,要么是AP。
三个只能占2个。
CAP理论关注粒度是数据,而不是整体系统设计的角度。
1. 最多只能同时较好的满足两个
CAP理论的核心:一个分布式系统不可能同时很好的满足三个需求。因此根据CAP原理将
NOSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类。
CA:单点集群,满足一致性,可用性的系统,通常扩展性不强大。
CP:满足一致性,分区容错性的系统,对数据一致性要求高,所以性能负担大。
Zookeeper/Consul
要求数据必须一致性。
AP:满足可用性,分许容错性的系统,通常可能对一致性要求低一些。
Eureka
场景:商场,暂时不一致错一点没关系,只要能正常访问下单即可。
Eureka通过设置一些属性,也可以通过牺牲高可用性实现一致性的要求。
2. 分布式必须满足:P: Partition tolerance 分区容错性
复制代码