服务注册中心
- 一、Eureka服务注册与发现 (×)
- 二、Zookeeper服务注册与发现 (√)
- 三、Consul服务注册与发现 (√)
- 🔺 Consul简介
- (1) 是什么
- (2) 能干嘛
- (3) 在哪下 (本机:windows版本)
- (4) 怎么玩
- 🔺 安装并运行Consul
- (1) 官网说明
- (2) 安装
- (3) 使用开发模式启动
- 🔺 服务提供者
- (1) 新建模块 cloud-providerconsul-payment8006
- (2) 配置 pom.xml
- (3) 配置 application.yml
- (4) 创建主启动类
- (5) 创建 PaymentController
- (6) 测试
- 🔺 服务消费者
- (1) 新建模块 cloud-consumerconsul-order80
- (2) 配置 pom.xml
- (3) 配置 application.yml
- (4) 创建主启动类
- (5) 配置bean:ApplicationContextConfig
- (6) 创建 OrderConsulMain80
- (7) 测试
- 三个注册中心异同点
一、Eureka服务注册与发现 (×)
🔺 单机Eureka构建步骤
(1) EurekaServer 服务端搭建
① 新建模块 cloud-eureka-server7001
② 配置 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.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.lun.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--boot 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>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
③ 配置 application.yml
server:
port: 7001
eureka:
instance:
hostname: locathost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己。
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
④ 主启动类
@SpringBootApplication
@EnableEurekaServer // 表示为EurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
⑤ 测试
eureka服务有了,但是没有客户(有server但是client没有注册进去)
(2) 将支付微服务8001注册到 EurekaServer
① 添加依赖到pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
② 添加配置到 application.yml
eureka:
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
③ 主启动类上加注解 @EnableEurekaClient
@EnableEurekaClient // 表明是EurekaClient
④ 测试
(3) 将订单微服务80注册到 EurekaServer
① 添加依赖到 pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
② 添加配置到 application.yml
spring:
application:
name: cloud-order-service
eureka:
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
③ 主启动类上加注解 @EnableEurekaClient
@EnableEurekaClient // 表明是EurekaClient
④ 测试
🔺 集群Eureka构建步骤
Eureka 集群
解决办法: 搭建Eureka注册中心集群,实现负载均衡+故障容错
(1) Eureka集群环境构建步骤
① 新建模块 cloud-eureka-server7002
pom中依赖和7001相同
② 修改映射配置
找到C:\Windows\System32\drivers\etc路径下的hosts文件
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
通过命令:ipconfig /flushdns 刷新hosts文件
③ 7001的 application.yml
server:
port: 7001
spring:
application:
name: cloud-eureka-service
eureka:
instance:
# eureka服务端的实例名称
hostname: eureka7001.com
client:
# false表示不向注册中心注册自己
register-with-eureka: false
# false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要检索服务
fetch-registry: false
service-url:
# 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/
④ 7002的 application.yml
server:
port: 7002
spring:
application:
name: cloud-eureka-service2
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
⑤ 7002的主启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class, args);
}
}
⑥ 测试
(2) 将支付服务8001,和订单服务80微服务发布到上面2台Eureka集群配置中
① 修改二者 yaml 即可
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
② 测试
(3) 支付服务提供者8001集群环境搭建
① 新建模块 cloud-provider-payment8002
pom文件的依赖和8001相同
yaml文件除了server-port为8002,其他与8001的都相同
主启动类
业务类也与8001相同
② 修改8001和8002的controller
取出yaml中的servre-port,便于测试时的分析
@Value("${server.port}")
private String serverPort;
③ 修改80客户端的 PAYMENT_URL
订单服务的访问地址不能写si,之前是指定的8001,现在支付服务是集群环境,所以需要用服务名进行访问
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
由于一个集群中有多个服务,所以此时使用客户80访问时,会报错,因为不知道具体访问的是集群中的哪个服务,所以需要在 getRestTemplate上添加一个注解@LoadBalanced均衡负载,循环访问集群中的每个服务
④ 测试
🔺 actuator微服务信息完善
(1) 主机名称:服务名称修改
修改yaml文件
eureka:
instance:
instance-id: payment8001 #修改服务名称
(2) 访问信息有IP信息提示
此时没有IP信息显示
修改yaml文件
prefer-ip-address: true # 访问路径可以显示ip信息
🔺 服务发现Discovery
对于注册eureka里面的微服务,可以通过服务发现来获得该服务的信息
(1) 修改cloud-provider-payment8001的Controller
注意discoveryClient的包时spring的那个,如果没有.getServices(),可以看看是不是包导错了
// 服务发现 获取服务信息
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/payment/discover")
public DiscoveryClient discover() {
// 获取注册中心的服务列表
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("****服务:" + service);
}
// 获取某个服务的实例
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("服务cloud-payment-service中有: " + "\t" + instance.getServiceId() + "\t" + instance.getInstanceId() + "\t" + instance.getHost());
}
return this.discoveryClient;
}
(2) 8001的启动类添加@EnableDiscoveryClient
就用原来的@EnableEurekaClient似乎也是可以的
@SpringBootApplication
// 表明是EurekaClient,且只适用于Eureka注册中心
@EnableEurekaClient
// 二者都是可以让注册中心发现,扫描到该服务,区别在于EnableEurekaClient只适用于Eureka注册中心,而EnableDiscoveryClient可以为其他注册中心
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
(3) 测试
🔺 eureka自我保护
(1) 故障现象
(2) 导致原因
(3) 如何禁止自我保护
① 7001的yaml中关闭自我保护模式
enable-self-preservation: false # 禁止eureka的自我保护,服务一旦没有"心跳",就会被剔除
② 8001中修改配置,方便测试查看效果
lease-renewal-interval-in-seconds: 1 # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)e
lease-expiration-duration-in-seconds: 2 # Eureka服务端在收到最后一次心跳后等待时间上限 ,单位为秒(默认是90秒),超时剔除服务
③ 测试
可以同时启动 7001(禁用自我保护) 和 7002(默认开启自动保护),然后启动8001,再stop 8001,就可以看到 7001中很快剔除8001,而7002中还有
二、Zookeeper服务注册与发现 (√)
🔺 注册中心Zookeeper
Zookeeper是一个分布式协调工具,可以实现注册中心功能
Zookeeper服务器 取代 Eureka服务器,zk作为服务注册中心
🔺 服务提供者
(1) 新建模块 cloud-provider-payment8004
(2) 配置 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.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8004</artifactId>
<dependencies>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</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>
</project>
(3) 配置 application.yml
server:
port: 8004 # 8004表示注册到zookeeper服务器的支付服务提供者端口号
spring:
application:
name: cloud-provider-payment # 服务别名---注册zookeeper到注册中心的名称
cloud:
zookeeper:
connect-string: 192.168.44.129:2181 # 默认localhost:2181
(4) 创建主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class, args);
}
}
(5) 启动8004注册进zookeeper
【 PS: 由于zookeeper的半数机制,最少必须启动三个server,一开始只启动了一个,然后启动了一会儿就一直报错。】
① 启动 zookeeper
bin/zkServer.sh start
② 启动后问题
jar 包冲突
③ 问题出现的原因
调整 pom.xml
<!--SpringBoot整合Zookeeper客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<!--先排除自带的zookeeper3.5.3-->
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加zookeeper3.4.10版本-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.10</version>
</dependency>
④ 测试
此时关闭8004后,zookeeper中的节点不在了,由此可见,创建的服务节点是临时节点。
🔺 服务消费者
(1) 新建模块 cloud-consumerzk-order80
(2) 配置 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.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumerzk-order80</artifactId>
<dependencies>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
<exclusions>
<!--先排除自带的zookeeper3.5.3-->
<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.10</version>
</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>
</project>
(3) 配置 application.yml
server:
port: 80
spring:
application:
name: cloud-consumer-order # 服务别名
cloud:
zookeeper:
connect-string: 192.168.44.129:2181 # 注册到zookeeper地址
(4) 创建主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderZkMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderZkMain80.class, args);
}
}
(5) 业务类
① 配置bean:ApplicationContextConfig
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
② 创建 OrderZkController
@RestController
@Slf4j
public class OrderZkController {
private String url = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/zk")
public String paymentInfo() {
return restTemplate.getForObject(url+"/payment/zk", String.class);
}
}
(6) 测试
三、Consul服务注册与发现 (√)
🔺 Consul简介
(1) 是什么
https://www.consul.io/intro/index.html
(2) 能干嘛
- 服务发现:提供HTTP/DNS两种发现方式
- 健康检测:支持多种方式,HTTP、TCP、Docker、shell脚本定制化
- KV存储: Key、Value的存储方式
- 多数据中心:Consul支持多数据中心
- 可视化界面
(3) 在哪下 (本机:windows版本)
https://www.consul.io/downloads.html
(4) 怎么玩
https://www.springcloud.cc/spring-cloud-consul.html
🔺 安装并运行Consul
(1) 官网说明
https://learn.hashicorp.com/consul/getting-started/install.html
(2) 安装
(3) 使用开发模式启动
consul agent -dev
http://localhost:8500/ui/dc1/services
🔺 服务提供者
(1) 新建模块 cloud-providerconsul-payment8006
(2) 配置 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.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-providerconsul-payment8006</artifactId>
<dependencies>
<!--SpringCloud consul-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</project>
(3) 配置 application.yml
server:
port: 8006 # consul服务端口
spring:
application:
name: cloud-provider-payment
cloud:
consul: # consul注册中心地址
host: localhost
port: 8500
discovery:
hostname: 127.0.0.1
service-name: ${spring.application.name}
(4) 创建主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class, args);
}
}
(5) 创建 PaymentController
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping("/payment/consul")
public String paymentConsul() {
return "SpringCloud with consul:" + serverPort + "\t" + UUID.randomUUID().toString();
}
}
(6) 测试
🔺 服务消费者
(1) 新建模块 cloud-consumerconsul-order80
(2) 配置 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.atguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumerconsul-order80</artifactId>
<dependencies>
<!--SpringCloud consul-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.atguigu.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<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>
</project>
(3) 配置 application.yml
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
consul:
host: localhost
port: 8500
discovery:
hostname: 127.0.0.1
service-name: ${spring.application.name}
(4) 创建主启动类
@SpringBootApplication
@Slf4j
public class OrderConsulMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class, args);
}
}
(5) 配置bean:ApplicationContextConfig
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
(6) 创建 OrderConsulMain80
@RestController
@Slf4j
public class OrderConsulController {
@Resource
private RestTemplate restTemplate;
private String INVOKE_URL = "http://cloud-provider-payment";
@GetMapping("/consumer/payment/consul")
public String paymentInfo() {
return restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);
}
}
(7) 测试
三个注册中心异同点
分区容错性要保证, 所以要么是CP, 要么是AP
- C: Consistency(强一致性)
- A: Availability(可用性)
- P: Parttition tolerance(分区容错性)
- CAP理论关注粒度是否是数据,而不是整体系统设计的策略
AP:eureka
CP(Zookeeper/Consul)
当网络分区出现后,为了保证一致性,就必须拒绝请求,否则无法保证一致性
结论:违背了可用性A的要求,只满足一致性和分区容错,即CP