概念
服务注册中心:
服务注册中心是服务实现服务化管理的核心组件, 主要用来存储服务信息。类似于目录服务的作用,比如提供者 url 串、路由信息等。是 SOA 架构中基础之一。
服务注册中心的作用:
服务的注册
服务的发现
常见的注册中心
Zookeeper、Eureka、consul、还有阿里的Nacos
服务注册中心解决的痛点:
服务与服务之间依赖关系管理难的问题。
因为Eureka 2.0已经停更了,如果非要使用Eureka的话,那需要自己维护,这对于追求效率的那是不可接受的,或者就换其他方案。使用其他服务组件来代替,如上面所说到的几个(推荐使用阿里的Nacos),这是将服务的注册与发现替换为Zookeeper。 Zookeeper是一个分布式协调工具,实现了注册中心的功能。
Zookeeper的安装
zookeeper版本:3.4.9 系统坏境:Contos8 Docker版本:Docker version 19.03.12, build 48a66213fe 使用docker拉取镜像:不带后面的版本号就是默认拉取最新的版本
docker pull zookeeper:3.4.9
启动zookeeper: 这就不解释这些参数是啥了。想了解的可以去学习下docker
docker run -d -p 2181:2181 -p 2888:2888 -p 3888:3888 --restart always zookeeper:3.4.9
查看运行中的镜像
docker ps
可以看到zookeeper已经启动了,将2181端口映射到宿主机的2181端口上
服务提供者
项目的构建:采用聚合工程演示(不细说项目的构建步骤)
父工程POM文件(篇幅有限,只列出关键代码)
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
<mysql.version>8.0.18</mysql.version>
<druid.verison>1.1.16</druid.verison>
<mybatis.spring.boot.verison>1.3.0</mybatis.spring.boot.verison>
</properties>
<dependencyManagement>
<dependencies>
<!--Spring Boot 2.2.2-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.2.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--Spring Cloud Hoxton.SR1-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--MySQL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!--Druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.verison}</version>
</dependency>
<!--mybatis-springboot整合-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.verison}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<!--log4j-->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
在该父工程下新建Moudle,项目名尽量起的有意义些。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>SpringCloud2020</artifactId>
<groupId>com.tianye</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8003</artifactId>
<dependencies>
<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.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</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>
1、在该工程的resource下新建application.yml配置文件,如下
server:
port: 8003 #端口号
spring:
application:
name: cloud-provider-service # 应用名称
cloud:
zookeeper:
connect-string: 192.168.110.129:2181
上面的spring.application.name建议一定要配置,默认它就是微服务名。
spring.cloud.zookeeper.connect-string:值也就是安装zookeeper的ip加端口号.
注意:可以关闭防火墙或开放该端口
2、添加启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8003 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8003.class,args);
}
}
@EnableDiscoveryClient:让注册中心发现,并扫描到该服务(项目),注意:从Spring Cloud Edgware版本开始, @EnableDiscoveryClient 是可以省略的。只要加上相关依赖,并进行对应配置,即可将微服务注册到服务发现组件上面。
3、编写controller:也就是一个简单的请求,返回当前端口号
@Slf4j
@RestController
public class PaymentController {
@Value("${server.port}")
private String port;
@GetMapping(value = "/payment/zookeeper")
public String zookeeperTest(){
return "Zookeeper:"+ port ;
}
}
4、启动主程序
注:我这里启动抛出了一个错
就是jar冲突导致的,原因是因为spring-cloud-starter-zookeeper-discovery中会自动引入zookeeper-3.5.3-beta版本,但这里使用的是3.4.9版本。
解决方案:修改pom.xml,将3.5.3-beta排除掉,手动加入3.4.9版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<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>
进入Docker的zookeeper中,使用如下命令 ae5de827ad6c 是zookeeper的容器id
docker exec -it ae5de827ad6c zkCli.sh
进行如下操作
可以看到服务提供者已经注册到zookeeper上了。
其中使用get /services/cloud-provider-service/3c1d4251-e80f-409d-a83e-36a5553f11f2 命令得到该微服务的详细信息。复制该json字符串格式化可以看到以下
编写的controller也可以正常访问
如果将该服务提供者停止,过一会再到容器中查看zookeeper上的服务,会发现该服务节点变没了,所以zookeeper的服务节点是临时的。也就是zookeeper只保证CAP理论中的CP(数据的一致性以及分区的容错性)。至于什么是CAP,CAP理论是分布式系统的一个概念,C是Consistency(一致性),A是Availability(可用性),P是Partition tolerance(分区容错性),CAP 理论关注细粒度是数据,而不是整体系统设计的。一个分布式系统不可能同时很好的满足一致性、可用和分区容错性三个需求,只能满足其中的两个。因为在分布式系统中,分区容错性是必须要保证的,那么可用性和一致性就能二选一了,一般都是保证AP或CP。(Eureka保证AP, Consul保证CP,Nacos可以进行AP或CP的切换)
服务停止后服务给剔除 主流注册中心产品比较
服务消费者
项目的创建:再新建一个module,pom文件依赖跟上面一致 application.yml文件
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
zookeeper:
connect-string: 192.168.110.129:2181
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ZKOrderConsumerMain80 {
public static void main(String[] args) {
SpringApplication.run(ZKOrderConsumerMain80.class, args);
}
}
配置类 @LoadBalanced 让RestTemplate 支持负载均衡除了负载均衡,它还有将服务名转换成IP的功能,也就是根据服务名cloud-provider-payment,找到192.168.110.129地址
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
编写controller,通过RestTemplate,使用应用名称访问Zookeeper中注册地址,实现调用。
@RestController
@Slf4j
public class ZKOrderController {
private final String baseUrl = "http://cloud-provider-service";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/zookeeper/get")
public String get(){
return restTemplate.getForObject(baseUrl+"/payment/zookeeper",String.class);
}
}
启动服务提供者和服务消费者,可以看到服务提供者和服务消费者已经成功注册到zookeeper中去。 测试 访问http://localhost/consumer/zookeeper/get
http://cloud-provider-payment/payment/zookeeper,其中cloud-provider-payment是服务名,从Zookeeper中找到真实的地址,发送/payment/zookeeper请求,此时,就发送到了提供者的controller上面,这样就完成了请求。