SpringCould-Zookeeper服务注册与发现

概念

服务注册中心:服务注册中心是服务实现服务化管理的核心组件, 主要用来存储服务信息。类似于目录服务的作用,比如提供者 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:也就是一个简单的请求,返回当前端口号,

  1. @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

/consumer/zookeeper请求会调用http://cloud-provider-payment/payment/zookeeper,其中cloud-provider-payment是服务名,从Zookeeper中找到真实的地址,发送/payment/zookeeper请求,此时,就发送到了提供者的controller上面,这样就完成了请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值