2020:0709--3--SpringCloud和Zookeeper

1,005 阅读7分钟

主要内容

1.  服务注册中:Zookeeper代替Eureka

2.   Consul服务注册与发现

1. 注册中心Zookeeper

zookeeper是一个分布式协调工具,可以实现注册中心功能

关闭linux服务器防火墙后,启动zookeeper服务器
systemctl stop firewalld

zookeeper服务器取代Eureka服务器,zk作为服务注册中心

2. 服务提供者

2.1 新建cloud-provider-payment8004

1.  新建cloud-provider-payment8004

2.2 pom

2.  pom
<dependencies>

        <!--SpringBoot整合zookeeper客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
        </dependency>
        <!--引入我们自定义的公共api jar包-->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--web/actuator这两个一般一起使用,写在一起-->
        <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>

        <!--Mybatis和SpringBoot的整合-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
        </dependency>

        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</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>

2.3 yml

3.  yml
     server:
      port: 8004
    
    spring:
      application:
        name: cloud-provider-payment
      cloud:
        zookeeper:
          connect-string: 192.168.92.130:2181
    
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource      # 数据源
        driver-class-name: com.mysql.cj.jdbc.Driver     # mysql驱动包
        url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root

2.4 主启动类

4.  主启动类
    @SpringBootApplication
    @EnableDiscoveryClient //开启服务发现
    public class PaymentMain8004 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8004.class, args);
        }
    }

2.5 controller

5.  controller
    @RestController
    public class PaymentController {
    
        @Value("${server.port}")
        private String serverPort;
    
        @RequestMapping(value="/payment/zk")
        public String paymentzk(){
            return "springcloud with zookeeper: "+serverPort+"\t"+ UUID.randomUUID().toString();
        }
    }

2.6 测试:解决jar包冲突

6.  启动测试

    这里视频会出现一个jar冲突的异常

    分析思路:
        
        找到代码中出错的地方,向启动入口处的报错,肯定是环境引起的。
        
        注意到提示zookeeper-3.5.6-beta。
        
        再想到我们自己安装的zookeeper版本,那就可能是jar包的冲突了。
        
        很可能是某个整合包自带的zookeeper包和我们服务器上的zookeeper版本不一样。
        
        发现我们导入的spring-zookeeper的整合包,包含了zookeeper-3.5.6-beta,我们要将其排除掉

    怎么做:
    
        一般不会卸载zookeeper,因为其他系统可能正在使用这个zookeeper。
        
        所以我们排除掉包含的这个冲突的zookeeper包,引入一个服务器对应的jar包
        
7.  我这里没报错。

    不知道是不是我的版本(3.6.1)比较高的原因
    
    我试着将整合包中的3.5.3版本的zookeeper剔除掉,引入3.6.1
        <!--SpringBoot整合zookeeper客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <!--排除掉自带的zookeepr3.5.3-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--引入对应服务器版本的zookeeper-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.6.1</version>
        </dependency>
8.  启动:报错
    
    添加了3.6.1的zookeeper后,会报错:

    那么很显然了,根据上面的分析,出错误在主启动类,关键词slf4j,logback。
    
    查看引入的3.6.1的zookeeper包:

    我导入的slf4j:

    我选择排除掉其中的3.6.1的zookeeper包其中的三个日志相关的jar包,用自己的。

    成功排除掉。
    
    注意:groupId和artifactId的对应。
 
    重启服务:启动成功!!!

9.  查看一下服务是否注册成功

    1.  进入zookeeper容器中
    
        docker exec -it 66805aa71339 /bin/bash
        
    2.  客户端连接
    
        ./bin/zkCli.sh

    3.  查看服务
    
        ls /
        ls /services

        注册成功!!!
        
        继续进去看:
        
        ls /services/cloud-provider-payment
        
        ls /services/cloud-provider-payment/e3d40a33-8de3-4bc6-b560-d1b510211045

    4.  几个概念
    
        1.  /services/cloud-provider-payment/e3d40a33-8de3-4bc6-b560-d1b510211045
        
        这整个东西就是zookeeper的zNode节点。
        
        
        2.  我们通过get命令,获取zookeeper中的节点信息

            这一大串,就是我们服务存在zookeeper的基本信息--JSON串。
            
        3.  我们在线解析一下这个json串

2.7 思考

10. 思考

        注册到zookeeper的微服务是一个zNode节点,这个服务节点时临时节点还是持久节点?
        
        我们注册进zookeeper的服务,会自动生成一个流水号id

        1.  关闭掉8004服务
        
        2.  查看zookeeper中是否还有该微服务。

            发现刚断开连接时zookeeper还保存着该服务,等待一段时间剔除了断开连接的微服务。
            
        3.  所以注册到zookeeper的微服务节点是临时节点。
        
        
        4.  再重新启动8004的微服务

            服务又注册了进来,但是流水id换了。
            
        5.  zookeeper比eureka更加心狠干脆。

3. 服务消费者

3.1 新建cloud-consumerzk-order80

    1.  新建cloud-consumerzk-order80

3.2 pom

        <dependencies>
    
            <!--SpringBoot整合zookeeper客户端-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
                <!--排除掉自带的zookeepr3.5.3-->
                <exclusions>
                    <exclusion>
                        <groupId>org.apache.zookeeper</groupId>
                        <artifactId>zookeeper</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
            <!--引入对应服务器版本的zookeeper-->
            <dependency>
                <groupId>org.apache.zookeeper</groupId>
                <artifactId>zookeeper</artifactId>
                <version>3.6.1</version>
                <exclusions>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-log4j12</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-api</artifactId>
                    </exclusion>
                    <exclusion>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
    
    
            <!--引入我们自定义的公共api jar包-->
            <dependency>
                <groupId>com.atguigu.springcloud</groupId>
                <artifactId>cloud-api-commons</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <!--web/actuator这两个一般一起使用,写在一起-->
            <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>
    
            <!--Mybatis和SpringBoot的整合-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
            </dependency>
    
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
            </dependency>
    
            <!--mysql-connector-java-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!--jdbc-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</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>

3.3 yml

    server:
      port: 80
    
    spring:
      application:
        name: cloud-consumerzk-order
      cloud:
        zookeeper:
          connect-string: 192.168.92.130:218

3.4. 主启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    public class OrderZKMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderZKMain80.class, args);
    
        }
    }

3.5. 业务类

    package com.atguigu.springcloud.config;
    
    @Configuration
    public class ApplicationContextConfig {
    
        @Bean
        @LoadBalanced //开启默认的负载均衡机制:赋予了RestTemplate负载均衡的能力
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
  
    package com.atguigu.springcloud.controller; 
    
    @RestController
    @Slf4j
    public class OrderZKController {
    
        //由于在ApplicationContextConfig开启了负载均衡,这里可以通过服务名访问到微服务
        public static final  String INVOKE_URL = "http://cloud-provider-payment";
    
        @Resource
        private RestTemplate restTemplate;
    
        //返回String测试一下:不交互数据库了
        @GetMapping("/consumer/payment/zk")
        public String paymentInfo(){
            String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk", String.class);
    
            return result;
        }
    }

3.6. 测试

    1.  服务注册进zookeeper成功

    2.  服务调用成功

4 Consul服务注册与发现

4.1 Consul简介

1.  是什么:微服务的服务注册中心

官网

    Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司采用Go语言开发
    
    提供了微服务系统中心的服务治理,配置中心,控制总线等功能。这些功能中的每一个都可以根据需要
    单独使用,也可以一起使用,以构建全方位的服务网格。
    
    总之Consul提供了一种完整的服务网格解决方案。
    
    它具有很多优点:
        包括,基于raft协议,比较简洁;支持健康检查,同时支持HTTP和DNS协议支持跨数据中心的WAN集群。
        
        提供图形界面 跨平台,支持Linux,MAC,Windows

2.  能干嘛:The key features of Consul are:

        Service Discovery:服务发现,提供HTTP和DNS两种发现方式
        
        Health Checking: 健康检查,支持多种方式,HTTP,TCP,Docker,Shell脚本定制化
        
        KV Store:   Key,Value的存储方式
        
        Secure Service Communication: 安全的服务交流
        
        Multi Datacenter:多数据中心
        
        可视化web界面
        
        
3.  下载

下载

4.  怎么用

中文文档

4.2 安装并运行Consul

    1.  下载完成后只有一个consul.exe文件
        
        硬盘路径下双击运行
    
    2.  cmd:
        查看版本:   D:\Developer_Tools\Consul>consul --version
        
        使用开发者模式启动:  D:\Developer_Tools\Consul>consul agent -dev
        
    3.  可视化web页面:localhost:8500

5. 生产者服务注册:consul

5.1 新建Module支付服务:cloud-providerconsul-payment8006

5.2 pom

<dependencies>
        <!--consul和SpringCloud的整合-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!--引入我们自定义的公共api jar包-->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--web/actuator这两个一般一起使用,写在一起-->
        <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>

        <!--Mybatis和SpringBoot的整合-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <!--如果没写版本,从父层面找,找到了就直接用,全局统一-->
        </dependency>

        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</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>

5.3 yml

    # 微服务端口号
    server:
      port: 8006
    
    # 微服务名称
    spring:
      application:
        name: cloud-provider-payment
    
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource      # 数据源
        driver-class-name: com.mysql.cj.jdbc.Driver     # mysql驱动包
        url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8
        username: root
        password: root
      cloud:
        consul:
          host: localhost
          port: 8500
          discovery:
            service-name: ${spring.application.name}
    
    
    
    mybatis:
      mapper-locations: classpath:mapper/*.xml                # 扫描类路径下mapper文件夹下的.xml配置文件
      type-aliases-package: com.atguigu.springcloud.entities  # 该包所有Entity类,取默认别名

5.4 主启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    public class PaymentMain8006 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8006.class, args);
        }
    }

5.5 controller

    @RestController
    @Slf4j
    public class PaymentController {
    
        @Value("${server.port}")
        private String serverPort;
    
        @RequestMapping(value="/payment/consul")
        public String paymentConsul(){
            return "springcloud with consul: "+serverPort+"\t"+ UUID.randomUUID().toString();
        }
    }

5.6 测试

    启动8006服务

    注册成功

6. 消费者服务注册:consul

6.1 新建module

新建module cloud-consumerconsul-order80

6.2 pom

<dependencies>

        <!--consul和SpringCloud的整合-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!--引入我们自定义的公共api jar包-->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!--web/actuator这两个一般一起使用,写在一起-->
        <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.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>

6.3 yml

    server:
      port: 80
    
    spring:
      application:
        name: cloud-consumer-order
    
      cloud:
        consul:
          host: localhost
          port: 8500
          discovery:
            service-name: ${spring.application.name}

6.4 主启动类

    @SpringBootApplication
    @EnableDiscoveryClient
    public class OrderConsulMain80 {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderConsulMain80.class, args);
        }
    }

6.5 controller和config

config
    @Configuration
    public class ApplicationContextConfig {
    
        @Bean
        @LoadBalanced //开启默认的负载均衡机制:赋予了RestTemplate负载均衡的能力
        public RestTemplate getRestTemplate(){
            return new RestTemplate();
        }
    }
controller
    @RestController
    @Slf4j
    public class OrderConsulController {
    
        //由于在ApplicationContextConfig开启了负载均衡,这里可以通过服务名访问到微服务
        public static final  String INVOKE_URL = "http://consul-provider-payment";
    
        @Resource
        private RestTemplate restTemplate;
    
        //返回String测试一下:不交互数据库了
        @GetMapping("/consumer/payment/consul")
        public String paymentInfo(){
            String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);
    
            return result;
        }
    }

6.6 启动测试

7. 三个注册中心的异同点

    CAP:理论
    
        Eureka主要保证高可用:AP
        
        Zookeeper/Consul主要保证数据的一致:CP
        
        
    web界面:
        Eureka/Consul都有一个web界面。
        Zookeeper只有一个linux客户端。

7.1

    从CAP理论分析一下异同:
    
        Eureka主要满足AP
        
        Zookeeper/Consul主要满足CP
        
        C:Consistency 强一致性
        A:Avaliability 可用性
        P: Partition tolerance 分区容错性
        
            P在分布式中永远都要保证。
            所以要么是CP,要么是AP。
            三个只能占2个。
        
        CAP理论关注粒度是数据,而不是整体系统设计的角度。
        
    
    1.  最多只能同时较好的满足两个
    
        CAP理论的核心:一个分布式系统不可能同时很好的满足三个需求。因此根据CAP原理将
        NOSQL数据库分成了满足CA原则,满足CP原则和满足AP原则三大类。
        
        CA:单点集群,满足一致性,可用性的系统,通常扩展性不强大。
        
        CP:满足一致性,分区容错性的系统,对数据一致性要求高,所以性能负担大。
            Zookeeper/Consul
            
            要求数据必须一致性。
        
        AP:满足可用性,分许容错性的系统,通常可能对一致性要求低一些。
            Eureka
            
            场景:商场,暂时不一致错一点没关系,只要能正常访问下单即可。
        
        Eureka通过设置一些属性,也可以通过牺牲高可用性实现一致性的要求。
            
    2.  分布式必须满足:P: Partition tolerance 分区容错性