Springcloud用Zookeeper做注册中心&CAP原则
Springcloud用Zookeeper做注册中心。需要先安装好zookeeper。
1. 支付模块用zookeeper做注册中心
1新建支付模块 cloud-providerzk-payment8084
选择父工程之后新建moudle,GroupId和Version采用继承的即可,如下:
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>cloud</artifactId> <groupId>cn.qz.cloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-providerzk-payment8084</artifactId> <dependencies> <!-- SpringBoot整合zookeeper客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> <!--引入自己抽取的工具包--> <dependency> <groupId>cn.qz.cloud</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.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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
3.新建yml配置文件:
#8084表示注册到zookeeper服务器的支付服务提供者端口号
server:
port: 8084
#服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 127.0.0.1:2181
4.新建启动类:
package cn.qz.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @Author: qlq * @Description * @Date: 22:49 2020/10/14 */ @SpringBootApplication @EnableDiscoveryClient //该注解用于向使用consul或者zookeeper作为注册中心时注册服务 public class PaymentMain8084 { public static void main(String[] args) { SpringApplication.run(PaymentMain8084.class, args); } }
5.新建测试Controller
package cn.qz.cloud.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 @RequestMapping("/pay") @Slf4j public class PaymentController { @Value("${server.port}") private String serverPort; @RequestMapping(value = "/paymentzk") public String paymentzk() { return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString(); } }
6.启动服务后查看zookeeper中注册的服务
是在zookeeper建立了一个/services/appname/UUID这样的节点来存放数据,节点值格式化后如下:
{ "name": "cloud-provider-payment", "id": "ae024e43-703b-4edc-8a73-2cb7758fdb35", "address": "root", "port": 8084, "sslPort": null, "payload": { "@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance", "id": "application-1", "name": "cloud-provider-payment", "metadata": {} }, "registrationTimeUTC": 1602687210606, "serviceType": "DYNAMIC", "uriSpec": { "parts": [ { "value": "scheme", "variable": true }, { "value": "://", "variable": false }, { "value": "address", "variable": true }, { "value": ":", "variable": false }, { "value": "port", "variable": true } ] } }
可以看到上面的zk注册中心的address是主机名称,改为IP:
(1)修改yml文件:
#8084表示注册到zookeeper服务器的支付服务提供者端口号 server: port: 8084 #服务别名----注册zookeeper到注册中心名称 spring: application: name: cloud-provider-payment cloud: zookeeper: connect-string: 127.0.0.1:2181 discovery: enabled: true instance-host: 127.0.0.1
(2)启动后再次查看:
{ "name": "cloud-provider-payment", "id": "8f8a28b8-d154-469e-aef3-7073ebcad93b", "address": "127.0.0.1", "port": 8084, "sslPort": null, "payload": { "@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance", "id": "application-1", "name": "cloud-provider-payment", "metadata": {} }, "registrationTimeUTC": 1602754345242, "serviceType": "DYNAMIC", "uriSpec": { "parts": [ { "value": "scheme", "variable": true }, { "value": "://", "variable": false }, { "value": "address", "variable": true }, { "value": ":", "variable": false }, { "value": "port", "variable": true } ] } }
(3)查看节点的属性如下:ephemeralOwner代表是临时节点,值为会话的ID
2.订单模块调用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>cloud</artifactId> <groupId>cn.qz.cloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumerzk-order80</artifactId> <dependencies> <!-- SpringBoot整合zookeeper客户端 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> </dependency> <!--引入自己抽取的工具包--> <dependency> <groupId>cn.qz.cloud</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.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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
3.修改yml文件:
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
#注册到zookeeper地址
zookeeper:
connect-string: 127.0.0.1:2181
4.新建启动类:
package cn.qz.cloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /** * @Author: qlq * @Description * @Date: 23:05 2020/10/14 */ @SpringBootApplication @EnableDiscoveryClient public class OrderZKMain80 { public static void main(String[] args) { SpringApplication.run(OrderZKMain80.class, args); } }
5.建立业务类:
(1)注册RestTemplate:
package cn.qz.cloud.config; 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 public class ApplicationContextConfig { @Bean @LoadBalanced public RestTemplate getRestTemplate() { return new RestTemplate(); } }
(2)Controller调用注册中心服务:
package cn.qz.cloud.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; @RestController @RequestMapping("/consumer") public class OrderZKController { public static final String INVOKE_URL = "http://cloud-provider-payment"; @Resource private RestTemplate restTemplate; @GetMapping("/pay/paymentzk") public String paymentzk() { String result = restTemplate.getForObject(INVOKE_URL + "/pay/paymentzk", String.class); return result; } }
6.启动服务查看zk信息如下:
7.访问测试结果如下:
补充:Consul简介
Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司用Go语言开发。提供了服务治理、控制总线等功能。
和zookeeper一样,需要安装客户端后使用。
补充:Eureka、zk、Consul三个注册中心的异同点
一张图如下:
分布式环境有个CAP原则,又称为CAP理论,主要思想是在任何一个分布式系统中都无法同时满足CAP。
C(Consistency):表示一致性,所有的节点同一时间看到的是相同的数据。
A(Avaliablity):表示可用性,不管是否成功,确保一个请求都能接收到响应。
P(Partion Tolerance):分区容错性,系统任意分区后,在网络故障时,仍能操作。
(1)由于当前的网络硬件肯定会出现延迟丢包等问题,所以分区容忍性是我们必须需要实现的。所以我们只能在一致性和可用性之间进行权衡。
CA满足的情况下,P不能满足的原因:数据同步需要时间,也要正常的时间内响应(A),那么机器数量就要少,所以P就不满足
CP 满足的情况下,A不能满足的原因:数据同步需要时间, 机器数量也多,但是同步数据需要时间,所以不能再正常时间内响应,所以A就不满足
AP 满足的情况下,C不能满足的原因:机器数量也多,正常的时间内响应(A),那么数据就不能及时同步到其他节点,所以C不满足。
(2)关于三个注册中心满足的原则:
Zookeeper和Consul :CP设计,保证了一致性,集群搭建的时候,某个节点失效,则会进行选举行的leader,或者半数以上节点不可用,则无法提供服务,因此可用性没法满足。
Eureka:AP原则,无主从节点,一个节点挂了,自动切换其他节点可以使用,去中心化。