SpringCloud学习笔记【五】:Zookeeper代替Eureka实现服务注册与发现

Zookeeper的服务注册与发现

安装Zookeeper环境

Zookeeper的3.4.9

Windows和Linux环境皆可,这里介绍一下使用Docker启动Zookeeper。

直接看这篇文章就好了:Docker安装Zookeeper以及Zk常用命令

创建Zk服务提供者模块

引入依赖

<!--SpringBoot整合zookeeper客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>

配置yml

#8004表示注册到zookeeper服务器的支付服务提供者端口号
server:
  port: 8004
#服务别名----注册zookeeper到注册中心名称
spring:
  application:
    name: cloud-provider-payment
  cloud:
    zookeeper:
      connect-string: 121.199.16.31:2181

添加注解@EnableDiscoveryClient

/**
 * @author summerday
 *
 * //@EnableDiscoveryClient该注解用于向使用consul或者zookeeper作为注册中心时注册服务
 */
@SpringBootApplication
@EnableDiscoveryClient
public class Payment8004Application {
    public static void main(String[] args) {
        SpringApplication.run(Payment8004Application.class,args);
    }
}

编写Controller

@RestController
@Slf4j
public class PaymentController {
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/payment/zk")
    public String paymentZk() {
        return "spring cloud with zookeeper: " + serverPort + "\t" + UUID.randomUUID().toString();
    }
}

我们希望将这个模块注册进Zookeeper注册中心。

测试,发现jar包冲突

启动程序,我们发现程序直接报错,并且戛然而止。

经过排查,可以发现是jar包发生了冲突,原来我们引入的依赖自带着一个zookeeper-3.5.3-beta.jar,而我们的zookeeper是3.4.9的。

解决jar包冲突

zookeeper版本

方法一、卸载现有的zookeeper,安装3.5.3版本的即可

当然,这个方法可以解决冲突,但是好好地把已安装的zk卸载了,不够妥当。

方法二、排除jar包依赖,引入3.4.9包

<!--SpringBoot整合zookeeper客户端-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <!--先排除自带的zookeeper3.5.3-->
    <exclusions>
        <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.9</version>
</dependency>

日志框架多绑定

如果这样你以为就成功了,非也,因为还有存在冲突的情况,如日志冲突:

SLF4J: Class path contains multiple SLF4J bindings.

同理,我们排除掉slf4j-log4j12就行了。

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
            <!--排除slf4j-log4j12-->
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

继续测试

在zookeeper中执行命令:

[zk: localhost:2181(CONNECTED) 7] ls / # 查看根目录下的节点
[services,zookeeper]
[zk: localhost:2181(CONNECTED) 8] ls /services  # 查看/services目录下的节点,成功入驻
[cloud-provider-payment] # yml中配置的spring.application.name
[zk: localhost:2181(CONNECTED) 9] ls /services/cloud-provider-payment
[b780fc19-2823-4420-9937-3959de87720b] # 流水号
[zk: localhost:2181(CONNECTED) 10] get /services/cloud-provider-payment/b780fc19-2823-4420-9937-3959de87720b # 获取znode结构
{"name":"cloud-provider-payment","id":"b780fc19-2823-4420-9937-3959de87720b","address":"DESKTOP-QFK0MBG","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"cloud-provider-payment","metadata":{"instance_status":"UP"}},"registrationTimeUTC":1605873188009,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address",{"value":":",{"value":"port","variable":true}]}}
cZxid = 0x31
ctime = Fri Nov 20 11:53:09 GMT 2020
mZxid = 0x31
mtime = Fri Nov 20 11:53:09 GMT 2020
pZxid = 0x31
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x175e40811430010
dataLength = 558
numChildren = 0

此时,我们的服务已经成功注册进zookeeper注册中心。

Zookeeper注册的服务是临时节点

我们直到Eureka默认是开启自我保护机制的:宁可同时保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例

而Zookeeper不同,一旦你服务停止,在下一次心跳的时候,服务会被剔除,服务可以再次连接,但流水号会发生改变。

创建Zk服务消费者模块

pom,yml,启动类注解差不太多,这里就不赘述了,感兴趣可以查看仓库代码:https://gitee.com/tqbx/spring-cloud-learning,以标签的形式详细区分每个步骤。

@RestController
@Slf4j
public class OrderZKController
{
    public static final String INVOKE_URL = "http://cloud-provider-payment";

    @Resource
    private RestTemplate restTemplate;

    @LoadBalanced // 不加该注解,会导致:java.net.UnknownHostException: cloud-provider-payment
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

    @GetMapping(value = "/consumer/payment/zk")
    public String paymentInfo()
    {
        return restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
    }
}

当我们同时启动消费者和提供者,zookeeper中就会注册进两个service。消费者访问localhost/consumer/payment/zk,将会调用提供者的接口,完成需求。

源码下载

本系列文章为《尚硅谷SpringCloud教程》的学习笔记【版本稍微有些不同,后续遇到bug再做相关说明】,主要做一个长期的记录,为以后学习的同学提供示例,代码同步更新到Gitee:https://gitee.com/tqbx/spring-cloud-learning,并且以标签的形式详细区分每个步骤,这个系列文章也会同步更新。

相关文章

这篇文章主要介绍了spring的事务传播属性REQUIRED_NESTED的原...
今天小编给大家分享的是一文解析spring中事务的传播机制,相...
这篇文章主要介绍了SpringCloudAlibaba和SpringCloud有什么区...
本篇文章和大家了解一下SpringCloud整合XXL-Job的几个步骤。...
本篇文章和大家了解一下Spring延迟初始化会遇到什么问题。有...
这篇文章主要介绍了怎么使用Spring提供的不同缓存注解实现缓...