服务注册与发现 Eureka+zookeeper+consul
服务治理
在传统的rpc
远程框架调用中,管理每个服务于服务之间的依赖关系复杂
,管理复杂
,所以需要服务治理,即管理服务与服务之间的依赖关系,可以实现服务调用
,负载均衡
,容错
等。统称为服务的注册与发现
什么是rpc
:参考这里:https://www.cnblogs.com/Rampant/p/14741363.html#rpc
SpringCloud
封装了 Netflix
公司开发的 Eureka
模块来实现服务治理
(2020年已经停止更新了
)
Eureka
Eureka是Netflix开发的服务发现框架,本身是一个基于REST的服务,主要用于定位运行在AWS域中的中间层服务,以达到负载均衡和中间层服务故障转移的目的。SpringCloud将它集成在其子项目spring-cloud-netflix中,以实现SpringCloud的服务发现功能。
Eureka包含两个组件:Eureka Server
和Eureka Client
。
Eureka Server
提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client
是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。(自我保护机制
:CAP理论的AP
原则,(可用性
和 分区容错性
))
Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
运行原理图
Eureka Server搭建
在学Eueka
,我们需要一个服务提供者
,和服务消费者
,这两个模块如何搭建,参考:https://www.cnblogs.com/Rampant/p/14770855.html
上面环境准备好了,那么我们开始搭建
1、
在父工程下添加一个空的 maven
模块
2、
修改pom.xml
文件,添加以下依赖
<!--
版本解释与说明
在 1.X 版本没有客户端与服务端的区分,统一导入
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
在 2.x 版本后客户端与服务端区别开
客户端
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
服务端
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
-->
<dependencies>
<!--需要使用实体类,导入我们需要的 Api-->
<dependency>
<groupId>com.wyx</groupId>
<artifactId>SpringCloud-API</artifactId>
<version>${project.version}</version>
</dependency>
<!--eureka-server 服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
3、
添加application.yaml
server:
port: 7001
eureka:
instance:
hostname: localhost # eureka 服务端的名称,可以是域名,或者IP,表示注册中心存放到哪台服务器
client:
register-with-eureka: false # 是否向注册中心注册自己,这里就是服务端所以不需要注册
fetch-registry: false # 是否需要检索服务,由于自己就是管理者,所以不需要
service-url:
# 注册服务的访问地址:表示访问 http://localhost:7001/eureka/ 就可以进入服务端
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
4、
创建主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication //SpringBoot启动注解
@EnableEurekaServer //自动装配Eureka Server 的服务
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class);
}
}
5、
访问测试:http://localhost:7001/
出现下图配置成功。
微服务提供者入驻 Eureka Server
这里我们需要微服务的提供者
,搭建流程参考:https://www.cnblogs.com/Rampant/p/14770855.html
修改微服务的提供者:cloud-provider-user-8001
模块
1、
修改pom.xml
,添加如下依赖
<!--eureka-client 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、
修改applicatin.yaml
,其他配置文件不变,添加eureka
的配置信息即可
eureka:
client:
# 将自己注入到 eureka Server (注册中心)
register-with-eureka: true
# 是否从 eureka server 抓取自己的注册信息
fetch-registry: true
service-url:
# 注册到注册中心的地址,也就是我们搭建的 eureka server
defaultZone: http://localhost:7001/eureka
3、
修改主启动类,在主启动
类上添加注解@EnableEurekaClient
// 自动注入EnableEurekaClient 启动时将类的信息,按照配置注入注册中心
@EnableEurekaClient
4、
启动测试:切记
需要先启动注册中心
,在启动这个类
,
访问:http://localhost:7001/ ,如下测试成功
微服务消费者入驻Eureka Server
1、
修改pom.xml
,添加如下依赖
<!--eureka-client 客户端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2、
修改applicatin.yaml
,其他配置文件不变,添加eureka
的配置信息即可
eureka:
client:
# 将自己注入到 eureka Server (注册中心)
register-with-eureka: true
# 是否从 eureka server 抓取自己的注册信息
fetch-registry: true
service-url:
# 注册到注册中心的地址,也就是我们搭建的 eureka server
defaultZone: http://localhost:7001/eureka
3、
修改主启动类,在主启动
类上添加注解@EnableEurekaClient
// 自动注入EnableEurekaClient 启动时将类的信息,按照配置注入注册中心
@EnableEurekaClient
4、
启动测试:切记
需要先启动注册中心
,在启动这个类
,
访问:http://localhost:7001/ ,如下测试成功
Eureka Server集群
搭建
在现实的开发中,一般情况下都需要集群
来实现高可用
,防止在运行过程中,因为网络,或者服务器宕机等原因,照成注册中心不可用的原因。
再次搭建一个Eureka Server
1、
创建cloud-eureka-server-7002
的maven空项目
2、
修改pom.xml
,与cloud-eureka-server-7001
一样
<dependencies>
<!--需要使用实体类,导入我们需要的 Api-->
<dependency>
<groupId>com.wyx</groupId>
<artifactId>SpringCloud-API</artifactId>
<version>${project.version}</version>
</dependency>
<!--eureka-server 服务端-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
3、
编辑C:\Windows\System32\drivers\etc\host文件
后面追加
如下内容
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
3、
添加application.yaml
server:
port: 7002
eureka:
instance:
# 这里不能在填 localhost,因为会映射主机,两台都是localhost,会出错,我们需要修改刚才我们修改的配置映射
hostname: eureka7002.com # eureka 服务端的名称,可以是域名,或者IP,表示注册中心存放到哪台服务器
client:
register-with-eureka: false # 是否向注册中心注册自己,这里就是服务端所以不需要注册
fetch-registry: false # 是否需要检索服务,由于自己就是管理者,所以不需要
service-url:
# 注册服务的访问地址:表示访问 http://localhost:7001/eureka/ 就可以进入服务端
# 注册之间互相监督,所以这里需要把它注入到另外一个 eureka 中
defaultZone: http://eureka7001.com:7001/eureka/
4、
创建主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServer7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer7002.class);
}
}
5、
修改cloud-eureka-server-7001
的 application.yaml
server:
port: 7001
eureka:
instance:
# 这里不能在填 localhost,因为会映射主机,两台都是localhost,会出错,我们需要修改刚才我们修改的配置映射
hostname: eureka7001.com # eureka 服务端的名称,可以是域名,或者IP,表示注册中心存放到哪台服务器
client:
register-with-eureka: false # 是否向注册中心注册自己,这里就是服务端所以不需要注册
fetch-registry: false # 是否需要检索服务,由于自己就是管理者,所以不需要
service-url:
# 注册服务的访问地址:表示访问 http://localhost:7001/eureka/ 就可以进入服务端
# 注册之间互相监督,所以这里需要把它注入到另外一个 eureka 中
defaultZone: http://eureka7002.com:7002/eureka/
6、
启动测试
总结:
Eureka
集群就是利用两个的互相监督功能,来保证是否能正常运行,如果一台Eureka Server
另外一台也能正常工作。保证应用的高可用
微服务入驻 Eureka Server
集群
微服务入驻集群和,入驻单机差不多,只不过,我们要将入驻的地址填写集群的所有Eureka Server
即可。所有我们只需要修改配置文件application.yaml
server:
port: 8001 # 启动端口
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml # 配置别名包扫描路径
type-aliases-package: com.wyx.cloud.pojo # 配置实体类存放路径
configuration:
map-underscore-to-camel-case: true # 数据库的下划线转驼峰命名
spring:
application:
name: springcloud-provider-user # 服务名字
datasource: # 配置数据源和数据库连接配置
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud?useSSL=true&useUnicode=true&charterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: 970699
eureka:
client:
# 将自己注入到 eureka Server (注册中心)
register-with-eureka: true
# 是否从 eureka server 抓取自己的注册信息
fetch-registry: true
service-url:
# 注册到注册中心的地址,也就是我们搭建的 eureka server
# defaultZone: http://localhost:7001/eureka 单机
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群
对应微服务的消费者
也是一样,我们一并修改。
server:
port: 80
spring:
application:
name: consumer-order
eureka:
client:
# 将自己注入到 eureka Server (注册中心)
register-with-eureka: true
# 是否从 eureka server 抓取自己的注册信息
fetch-registry: true
service-url:
# 注册到注册中心的地址,也就是我们搭建的 eureka server
# defaultZone: http://localhost:7001/eureka 单机
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群
微服务提供者集群搭建
已经有了cloud-provider-user-8001
所以我们还需要一个微服务的提供者,我们开始创建。
1、
创建cloud-provider-user-8002
的maven空项目
2、
修改pom.xml
与 cloud-provider-user-8001
的相同
3、
添加application.yaml
;与cloud-provider-user-8001
的相同,只是端口不一样
server:
port: 8002 # 启动端口
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml # 配置别名包扫描路径
type-aliases-package: com.wyx.cloud.pojo # 配置实体类存放路径
configuration:
map-underscore-to-camel-case: true # 数据库的下划线转驼峰命名
spring:
application:
name: springcloud-provider-user # 服务名字
datasource: # 配置数据源和数据库连接配置
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/springcloud?useSSL=true&useUnicode=true&charterEncoding=utf8&serverTimezone=GMT%2B8
username: root
password: 970699
eureka:
client:
# 将自己注入到 eureka Server (注册中心)
register-with-eureka: true
# 是否从 eureka server 抓取自己的注册信息
fetch-registry: true
service-url:
# 注册到注册中心的地址,也就是我们搭建的 eureka server
# defaultZone: http://localhost:7001/eureka 单机
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群
4、
创建主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class Provider8002 {
public static void main(String[] args) {
SpringApplication.run(Provider8002.class);
}
}
5、
编写业务代码
和 cloud-provider-user-8001
的相同,复制即可
6、
这里,我们需要对业务代码做一定修改
,因为在业务代码中,我们调用的端口是写死了调用
对 UserController
进行修改,让它在返回结果中附带端口号
,修改如下
package com.wyx.cloud.controller;
import com.wyx.cloud.pojo.CommonResult;
import com.wyx.cloud.pojo.User;
import com.wyx.cloud.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
@Slf4j
public class UserController {
@Resource
private UserService userService;
// 注意注解是spring的 别导错包
@Value("${server.port}")
private String serverPort; //获取启动的端口号
@PostMapping("/addUser")
public CommonResult<Integer> add(@RequestParam("id") Long id,
@RequestParam("name") String name,
@RequestParam("age") Integer age,
@RequestParam("sex") String sex){
int result = userService.add(new User(id,name,age,sex));
if(result > 0){
return new CommonResult<>(200,"插入成功,服务端口:"+serverPort, result);
}else {
return new CommonResult<>(444, "插入失败,服务端口:"+serverPort, null);
}
}
@GetMapping("/User/{id}")
public CommonResult<User> getUser(@PathVariable("id") Long id){
User user = userService.getUserById(id);
if(user != null){
return new CommonResult<>(200,"查询成功,服务端口:"+serverPort, user);
}else {
return new CommonResult<>(444,"查询失败,服务端口:"+serverPort, null);
}
}
}
对服务消费者
中的调用端口,就行修改
, 不能让它写死调用 8001
提供的服务。修改后如下
package com.wyx.cloud.controller;
import com.wyx.cloud.pojo.CommonResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
@RestController
public class OrderController {
/*
* 将微服务的路径不写死,将它修改为 Eureka Server 的实例化Application 名称
* */
//public final static String PROVIDER_URL = "http://localhost:8001"; # 写死
public final static String PROVIDER_URL = "http://SPRINGCLOUD-PROVIDER-USER"; // 未写死
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/createUser")
public CommonResult createUser(@RequestParam("id") Long id,
@RequestParam("name") String name,
@RequestParam("age") Integer age,
@RequestParam("sex") String sex){
return restTemplate.postForObject(PROVIDER_URL+"addUser"+"?id="+id+"&name="+name+
"&age="+age+"&sex="+sex
,null,CommonResult.class);
}
@GetMapping("/consumer/getUser/{id}")
public CommonResult getUser(@PathVariable("id") Long id){
return restTemplate.getForObject(PROVIDER_URL+"/User/"+id,CommonResult.class);
}
}
但是
修改后我们有两台微服务提供者提供了同一个实例,我们并不能确定
我们需要走哪一个提供者
于是我们需要在给我们提供 RestTemplate 的模板(ApplicationConfig 类)
中添加一个注解,让它实现轮询的方式访问。修改后如下
package com.wyx.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 ApplicationConfig {
@Bean
@LoadBalanced // 选择不同的服务提供者,不然会因为不知道走哪一台服务提供者而报错
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
注意:
不用忘记resources
资源目录下的 mybatis
文件夹也要导入。
7、
将所有服务按照 Eureka Server
、服务提供者
、消费者
的顺序启动后测试。
启动测试访问:http://localhost/consumer/getUser/13 后门的13
对应数据库中user
的主键,根据数据库的主键修改。
微服务信息完善
1、
导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2、
添加配置application.yaml
eureka:
instance:
instance-id: provider-user-8001 # 服务名称修改
prefer-ip-address: true # 配置鼠标放到服务名称上显示 ip
访问:http://192.168.137.1:8002/actuator/health 可以查看当前状态是否可以使用
获取注册中心的信息
1、主启动类似添加注解
@EnableDiscoveryClient
2、
添加一个请求路径就可以查看注册在注册中心的信息
@Resource
DiscoveryClient discoveryClient;
@GetMapping("/consumer/discovery")
public DiscoveryClient discoveryClient(){
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info(service);
}
int order = discoveryClient.getOrder();
log.info(order+"");
List<ServiceInstance> instances = discoveryClient.getInstances("SPRINGCLOUD-PROVIDER-USER");
for (ServiceInstance instance : instances) {
log.info(instance.getInstanceId()+"\t"+instance.getHost()+"\t"+instance.getUri()+"\t"+instance.getPort());
}
return discoveryClient;
}
访问测试:http://localhost/consumer/discovery
关闭自我保护机制
推荐在开发时使用,能更快的让我们查询相关信息
只需要修改配置文件即可,在application.yaml
中添加如下配置即可
修改默认的发送心跳间隔,和剔除服务时间
eureka:
instance:
# eureka 向客户端发送信息的时间间隔,默认30秒
lease-expiration-duration-in-seconds: 1
# eureka 消除服务的等待上限时间,默认90秒
lease-renewal-interval-in-seconds: 2
Zookeeper替换 Eureka Server
1、
安装 zookeeperp
并启动,参考:https://www.cnblogs.com/Rampant/p/14741363.html#zookeeper
2、开启防火墙端口
# 开启防火墙端口 2181端口
[root@localhost home]# firewall-cmd --zone=public --add-port=2181/tcp --permanent
success
# 重启防火墙
[root@localhost home]# systemctl restart firewalld.service
服务提供者注册到 zookeeper
3、
新建 maven
空项目 cloud-provider-user-zookeeper-8004
4、
修改pom.xml
,添加如下依赖
<dependencies>
<!--连接 zookeeper 注册中心的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
5、
添加application.yaml
server:
port: 8004
spring:
application:
name: cloud-provider-user-zookeeper-8004 # 提供服务的应用名称应用名称
cloud:
zookeeper:
# zookeeper 注册中心地址,如果是集群用逗号分割即可
connect-string: 192.168.137.129:2181
# connect-string: 192.168.137.129:2181,192.168.137.130:2181
6、
创建主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 主动注入服务的注册与发现
public class ZookeeperMain8004 {
public static void main(String[] args) {
SpringApplication.run(ZookeeperMain8004.class);
}
}
编写业务类
package com.wyx.cloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class ZkController {
@GetMapping("/provider/zk")
public String get(){
return "使用 Zookeeper 注册中心进行注册";
}
}
7、
启动测试:
# 在liunx 下使用 zookeeper 客户端连接 zookeeper.server
./zkCli.sh
# 查看注册的信息,
[zk: localhost:2181(CONNECTED) 0] ls /
[dubbo, services, zookeeper] # services 是注册服务的目录、
# 查看注册的信息,看到,我们编写业务代码的应用名称
[zk: localhost:2181(CONNECTED) 1] ls /services
[cloud-provider-user-zookeeper-8004]
# 查看注册,生成了随机的流水号
[zk: localhost:2181(CONNECTED) 2] ls /services/cloud-provider-user-zookeeper-8004
[44e6e447-ae5a-402f-85e8-b56daac62c46]
# 查看流水号的值
[zk: localhost:2181(CONNECTED) 3] get /services/cloud-provider-user-zookeeper-8004/44e6e447-ae5a-402f-85e8-b56daac62c46
{"name":"cloud-provider-user-zookeeper-8004","id":"44e6e447-ae5a-402f-85e8-b56daac62c46","address":"192.168.137.1","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"cloud-provider-user-zookeeper-8004","name":"cloud-provider-user-zookeeper-8004","metadata":{"instance_status":"UP"}},"registrationTimeUTC":1621139618198,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
将值利用json
转化工具查看:
查看解析后的值信息
正是我们编写微服务
的相关信息。
停止服务
,等 90 秒
左右再次查看注册中心的信息
# 可以发现注册的信息已经消失
[zk: localhost:2181(CONNECTED) 31] ls /
[dubbo, zookeeper]
通过移除
信息可以知道,在zookeeper 下,我们这里满足的是CAP理论的CP
原则,(一致性
和 分区容错性
))
服务消费者入驻 zookeeper
1、
新建 maven
空项目 cloud-consumer-user-zookeeper-80
2、
修改pom.xml
,添加如下依赖
<dependencies>
<!--连接 zookeeper 注册中心的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
5、
添加application.yaml
server:
port: 80
spring:
application:
name: cloud-consumer-user-zookeeper-80 # 提供服务的应用名称应用名称
cloud:
zookeeper:
# zookeeper 注册中心地址,如果是集群用逗号分割即可
connect-string: 192.168.137.129:2181
# connect-string: 192.168.137.129:2181,192.168.137.130:2181
6、
创建主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // 主动注入服务的注册与发现
public class ConsumerZk80 {
public static void main(String[] args) {
SpringApplication.run(ConsumerZk80.class);
}
}
7、
注入 RestTemplate
package com.wyx.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 ApplicationConfig {
@Bean
@LoadBalanced // 选择不同的服务提供者,不然会因为不知道走哪一台服务提供者而报错,这里注意是解决微服务集群的问题
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
8、
编写业务代码
package com.wyx.cloud.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 OrderZookeeper {
// 注册服务的名称
public static final String INVOKE_URL = "http://cloud-provider-user-zookeeper-8004";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/zk")
public String getInfo(){
// 使用 restTemplate 调用服务方接口
return restTemplate.getForObject(INVOKE_URL+"/provider/zk",String.class);
}
}
9、
启动测试,先启动服务端,在启动客户端
访问:http://localhost/consumer/zk
注意:
这里使用的是单机版
,集群的化,只需要配置 zookeeper集群
,注册是修改application.yanl
,多添加集群地址即可,
zookeeper
如何集群:在安装 zookeeper
中有说明:https://www.cnblogs.com/Rampant/p/14741363.html#zookeeper
Consul服务治理
安装
安装Consul
下载地址
Windows版本(1.9.5):https://releases.hashicorp.com/consul/1.9.5/consul_1.9.5_windows_amd64.zip
Linux版本(1.9.5):https://releases.hashicorp.com/consul/1.9.5/consul_1.9.5_linux_amd64.zip
window 启动
,进入目录的文件夹,使用CMD
输入以下命令
consul agent -dev
liunx 解压出来安装,需要修改文件的权限为,可执行文件,然后输入上面命令即可。
执行命令后访问:http://localhost:8500
看见上图启动成功。
服务提供者注册到 Consul
1、
新建cloud-provider-consul-8005
的空maven项目
2、
修改pom.xml
文件
<dependencies>
<!--连接 consul 的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
3、
添加 application.yaml
server:
port: 8005
spring:
application:
name: cloud-provider-consul
cloud:
consul:
# 服务的主机
host: localhost
# 服务的端口号
port: 8500
discovery:
# 注册到服务中心的名称
service-name: ${spring.application.name}
4、
编写主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulMain8005 {
public static void main(String[] args) {
SpringApplication.run(ConsulMain8005.class,args);
}
}
5、
编写业务类
package com.wyx.cloud.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class ConsulController {
@GetMapping("/provider/consul")
public String get(){
return "使用 Consul 注册中心进行注册";
}
}
6、
启动测试,记得启动前需要运行我们安装的 consul
查看业务代码:http://localhost:8005/provider/consul
服务消费者注册到 Consul
1、
新建cloud-consumer-consul-80
的空maven项目
2、
修改pom.xml
文件
<dependencies>
<!--连接 consul 的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--spring-boot-web 模块 常用的3个-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</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.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok 依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
3、
添加 application.yaml
server:
port: 80
spring:
application:
name: cloud-consumer-consul
cloud:
consul:
# 服务的主机
host: localhost
# 服务的端口号
port: 8500
discovery:
# 注册到服务中心的名称
service-name: ${spring.application.name}
4、
编写主启动类
package com.wyx.cloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerConsul80 {
public static void main(String[] args) {
SpringApplication.run(ConsumerConsul80.class,args);
}
}
5、
编写业务类
package com.wyx.cloud.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 OrderConsulController {
// http://注册服务提供者的名称
public static final String INVOKE_URL = "http://cloud-provider-consul";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/consul")
public String getInfo(){
// 使用 restTemplate 调用服务方接口
return restTemplate.getForObject(INVOKE_URL+"/provider/consul",String.class);
}
}
6、
注入restTemplate
模板。
package com.wyx.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 ApplicationConfig {
@Bean
@LoadBalanced // 选择不同的服务提供者,不然会因为不知道走哪一台服务提供者而报错,负载均衡的一个注解
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
7、
启动测试:先启动consul
在启动服务端,在启动客户端
测试业务代码:http://localhost/consumer/consul
三个服务注册中心的比较
组件名 | 语言 | CAP | 服务监控检查 | 对外暴露接口 | Springcloud集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
Consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
Zookeeper | Java | CP | 支持 | 客户端 | 已集成 |
CAP原则
:点击查看 CAP