栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

微服务注册中心eureka,zookeeper和consul

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

微服务注册中心eureka,zookeeper和consul

B站尚硅谷P15~P35
代码Gitee地址
虽然eureka已经过去了,但仍然需要学习。

1.eureka

传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,所以需要使用服务器治理,管理服务与服务之间的依赖关系。可以实现服务调用、负载均衡、容错等,实现服务发现于注册。
eureka就是Spring Cloud 封装了 Netflix 公司的eureka来实现服务治理。

1.1 概念

eureka采用CS架构设计,作为服务注册功能的服务器,它是服务注册中心。系统中的其它微服务使用eureka的客户端连接到eureka server 并维持心跳连接。这样系统的维护人员就可以通过eureka server 来监控系统各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会以别名的形式把当前自己服务器的信息注册到注册中心上。另一方可以去注册中心获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在注册中心上,因为注册中心管理每个服务与服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心存放服务地址信息。

1.2 组件
  • Eureka Server:提供服务注册
    各个微服务节点通过配置启动后,会在Eureka Server中进行注册,这样Eureka Server中的服务注册表将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观看到。
  • Eureka Client:通过注册中心访问
    是一个Java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询的负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认30秒),如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
1.3 单机eureka搭建
  • 新建maven的module:cloud-eureka-server7001

  • 加入依赖

    
    
        
            org.example
            cloud-api-commons
            1.0-SNAPSHOT
        
    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
        
    
        
            org.springframework.boot
            spring-boot-starter-web
        
    
        
            org.springframework.boot
            spring-boot-starter-actuator
        
    
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    
        
            junit
            junit
        
    
        
            org.springframework.boot
            spring-boot-devtools
            runtime
            true
        
    
    
    
    
  • 新增yml配置文件:

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: localhost # 实例名称
      client:
        register-with-eureka: false # 不向注册中心自己
        fetch-registry: false # 不检索自己
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ # 配置地址
    
    • 新建启动类
    @SpringBootApplication
    @EnableEurekaServer
    public class EurekaMain7001 {
        public static void main(String[] args) {
            SpringApplication.run(EurekaMain7001.class,args);
        }
    }
    
  • 启动测试:

1.4 将cloud-provider-payment8001注册进eureka
  • 切换到cloud-provider-payment8001模块。

  • 加入依赖:

            
                org.springframework.cloud
                spring-cloud-starter-netflix-eureka-client
            
    
  • 新增yaml配置

    eureka:
      client:
        register-with-eureka: true # 将自己注册进eurekaServer
        fetch-registry: true # 从eurekaServer抓取注册信息,多节点必须开启才能配合ribbon
        service-url:
          defaultZone: http://localhost:7001/eureka
    
    
  • 修改主启动类:

    @SpringBootApplication
    @EnableEurekaClient
    public class PaymentMain8001 {
        public static void main(String[] args) {
            SpringApplication.run(PaymentMain8001.class,args);
        }
    }
    
  • 先启动注册中心,在启动当前模块,可以看到注册成功。

1.5 将cloud-consumer-order80注册进eureka

操作流程与上方相同。

  • 切换到cloud-consumer-order80模块。

  • 新增依赖:

            
                org.springframework.cloud
                spring-cloud-starter-netflix-eureka-client
            
    
  • 修改yaml

    spring:
      application:
        name: cloud-order-service
    
    eureka:
      client:
        register-with-eureka: true # 将自己注册进eurekaServer
        fetch-registry: true # 从eurekaServer抓取注册信息,多节点必须开启才能配合ribbon
        service-url:
          defaultZone: http://localhost:7001/eureka
    
  • 修改主启动类

    @SpringBootApplication
    @EnableEurekaClient
    public class OrderMain80 {
        public static void main(String[] args) {
            SpringApplication.run(OrderMain80.class,args);
        }
    }
    
  • 启动测试:

1.6 eureka集群概念

微服务RPC远程调用最核心的就是高可用,如果只有一个注册中心,如果它出现故障会导致整个服务环境直接挂掉。

  • 注册原理:互相注册,相互守望。,即多个eureka server之间是相互注册的,当前eureka server中需要有其它所有的eureka server信息。
1.7 eureka集群搭建
  • 以单机方式新建一个module:cloud-eureka-server7002,依赖,启动类也相同。

  • 修改本机的hosts文件:C:WindowsSystem32driversetc

    ## cloud-22-06 ##
    127.0.0.1 eureka7001.com
    127.0.0.1 eureka7002.com
    
  • 修改7001的yml配置文件:

    server:
      port: 7001
    
    eureka:
      instance:
        hostname: eureka7001.com # 实例名称
      client:
        register-with-eureka: false # 不向注册中心自己
        fetch-registry: false # 不检索自己
        service-url:
          defaultZone: http://eureka7002.com:7002/eureka/ # 注入7002
    
    
  • 修改7002的yml配置文件:

    server:
      port: 7002
    
    eureka:
      instance:
        hostname: eureka7002.com # 实例名称
      client:
        register-with-eureka: false # 不向注册中心自己
        fetch-registry: false # 不检索自己
        service-url:
          defaultZone: http://eureka7001.com:7001/eureka/ # 注入7001
    
    
  • 分别启动两个eureka测试:
    通过映射的域名+端口访问,可以看到其它的注册中心。

1.8 将80配置和8001进eureka集群

分别修改两配置文件中的defaultZone:

defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/, # 注入7002 和 7001
  • 查看两个eureka中注册情况。

1.9 搭建服务提供者集群
  • 新建module:cloud-provider-payment8002,除了配置文件的端口是8002之外其余都相同(名字都是将8001改为8002)。

  • 修改8001和8002的controller:

    @Slf4j
    @RestController
    @RequestMapping("/payment")
    public class PaymentController {
    
        @Autowired
        private PaymentService paymentService;
    
        @Value("${server.port}")
        private String serverPort;
    
        
        @PostMapping("/create")
        public CommonResult create(@RequestBody Payment payment){
            boolean result = paymentService.create(payment) > 0;
            log.info("插入结果:" + result);
            return result ?
                    new CommonResult(200,"插入成功,端口:" + serverPort):
                    new CommonResult(444,"插入失败");
        }
    
        
        @GetMapping("/{id}")
        public CommonResult create(@PathVariable("id") Long id){
            Payment payment = paymentService.getPaymentById(id);
            log.info("查询结果:" + payment);
            return !Objects.isNull(payment) ?
                    new CommonResult(200,"查询成功,端口:" + serverPort,payment):
                    new CommonResult(444,"没有当前id=" + id + "对应数据");
        }
    
    }
    
  • 搭建完成

1.10 配置负载均衡

根据上方的集群可以发现,使用80端口访问时,只能访问到8001服务。

  • 修改cloud-consumer-order80的ApplicationContextConfig:

    @Configuration
    public class ApplicationContextConfig {
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    
    }
    
    
  • 修改cloud-consumer-order80的controller:

    @Slf4j
    @RestController
    @RequestMapping("/consumer")
    public class OrderController {
    
        private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
    
        @Autowired
        private RestTemplate restTemplate;
    
        @PostMapping("/payment/create")
        public CommonResult create(@RequestBody Payment payment){
            return restTemplate.postForObject(PAYMENT_URL+"/payment/create" ,
                    payment ,
                    CommonResult.class);
        }
    
        @GetMapping("/payment/{id}")
        public CommonResult getPaymentById(@PathVariable("id") Long id){
            return restTemplate.getForObject(PAYMENT_URL+"/payment/" + id ,
                    CommonResult.class);
        }
    
    }
    
  • 测试:可以看出两个端口轮询出现。

1.11 完善配置信息
  • 修改8001和8002的yml配置文件:

    server:
      port: 8001
    
    spring:
      application:
        name: cloud-payment-service
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: org.gjt.mm.mysql.Driver
        url: jdbc:mysql://localhost:3306/jm-cloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
        username: root
        password: root
    
    eureka:
      client:
        register-with-eureka: true # 将自己注册进eurekaServer
        fetch-registry: true # 从eurekaServer抓取注册信息,多节点必须开启才能配合ribbon
        service-url:
    #      defaultZone: http://localhost:7001/eureka,
          defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/, # 注入7002 和 7001
      instance:
        instance-id: payment8001
        
    mybatis:
      mapper-locations: classpath:mapper
    	    @PostMapping("/create")
    	    public CommonResult create(@RequestBody Payment payment){
    	        boolean result = paymentService.create(payment) > 0;
    	        log.info("插入结果:" + result);
    	        return result ?
    	                new CommonResult(200,"插入成功,端口:" + serverPort):
    	                new CommonResult(444,"插入失败");
    	    }
    	
    	    
    	    @GetMapping("/{id}")
    	    public CommonResult create(@PathVariable("id") Long id){
    	        Payment payment = paymentService.getPaymentById(id);
    	        log.info("查询结果:" + payment);
    	        return !Objects.isNull(payment) ?
    	                new CommonResult(200,"查询成功,端口:" + serverPort,payment):
    	                new CommonResult(444,"没有当前id=" + id + "对应数据");
    	    }
    	
    	    @GetMapping("/discovery")
    	    public Object discovery() {
    	        List services = discoveryClient.getServices();
    	        services.forEach(System.out::println);
    	
    	        List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    	        instances.forEach(instance -> {
    	            System.out.println(instance.getServiceId() + "t" + instance.getHost() + "t" + instance.getPort() + "t" + instance.getUri());
    	        });
    	
    	        return this.discoveryClient;
    	    }
    	
    	}
    
    • 修改启动类:

      @SpringBootApplication
      @EnableEurekaClient
      @EnableDiscoveryClient
      public class PaymentMain8001 {
          public static void main(String[] args) {
              SpringApplication.run(PaymentMain8001.class,args);
          }
      }
      
    • 访问测试:

    1.13 eureka自我保护

    保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册中的数据,即某时刻某个微服务不能用了,Eureka不会立即清理,依然会对该服务信息进行保存。

    出现图中的红字表示进入模式。


    宁可保留错误的,也不会盲目的注销任何可能健康的服务实例。可以让eureka集群更加的健壮、稳定。

    1.14 禁用eureka自我保护
    • 修改7001和7002的yml配置文件:

      eureka:
        server:
          enable-self-preservation: false # 关闭自我保护机制
          eviction-interval-timer-in-ms: 2000 # 检测时间
      
    • 启动查看:表示已经关闭自我保护。

    • 修改8001配置文件:

    eureka:
      instance:
        lease-renewal-interval-in-seconds: 1 # 向客户端发送心跳的时间间隔。
        lease-expiration-duration-in-seconds: 1 # 客户端等待收到最后一次心跳的时间上限。
    
    
    • 配置之后,当8001出现故障时马上就会被eureka客户端剔除。
    2.zookeeper

    由于eureka2.0版本胎死腹中,且1.0不再更新,因此需要更多的来替代它。

    2.1 使用docker安装zookeeper
    • 拉镜像

      docker pull zookeeper3.4.9
      
    • 运行

      docker run --name zookeeper -p 2181:2181 --restart always -d zookeeper:3.4.9
      
    • 查看docker ps

    2.2 支付服务注入zookeeper
    • 新建服务提供者:cloud-provider-payment8003作为注册到zookeeper中的服务提供者。

    • 修改pom:

          
              
                  org.example
                  cloud-api-commons
                  1.0-SNAPSHOT
              
      
              
                  org.springframework.cloud
                  spring-cloud-starter-zookeeper-discovery
      
                  
                      
                          org.apache.zookeeper
                          zookeeper
                      
                  
              
      
      
              
                  org.apache.zookeeper
                  zookeeper
                  3.4.9
      
                  
                      
                          org.slf4j
                          slf4j-log4j12
                      
                  
              
      
              
                  org.springframework.boot
                  spring-boot-starter-web
              
      
              
                  org.springframework.boot
                  spring-boot-starter-actuator
              
      
              
                  org.mybatis.spring.boot
                  mybatis-spring-boot-starter
              
      
              
                  mysql
                  mysql-connector-java
              
      
              
                  org.springframework.boot
                  spring-boot-starter-jdbc
              
      
              
                  org.springframework.boot
                  spring-boot-starter-test
                  test
              
      
              
                  com.alibaba
                  druid-spring-boot-starter
                  1.2.9
              
      
              
                  org.springframework.boot
                  spring-boot-devtools
                  runtime
                  true
              
      
          
      
    • 以同样的方式将8001中的dao、controller、service、mapper.xml复制过来。

    • 主启动类:

      @SpringBootApplication
      @EnableDiscoveryClient  // 向zookeeper或者consul注入
      public class PaymentMain8003 {
          public static void main(String[] args) {
              SpringApplication.run(PaymentMain8003.class,args);
          }
      }
      
    • 修改yml

      server:
        port: 8003
      
      spring:
        application:
          name: cloud-payment-service
        datasource:
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: org.gjt.mm.mysql.Driver
          url: jdbc:mysql://localhost:3306/jm-cloud?useUnicode=true&characterEncoding=utf-8&useSSL=false
          username: root
          password: root
        cloud:
          zookeeper:
            connect-string: ip:2181
      
      mybatis:
        mapper-locations: classpath:mapper
          @PostMapping("/create")
          public CommonResult create(@RequestBody Payment payment){
              boolean result = paymentService.create(payment) > 0;
              log.info("插入结果:" + result);
              return result ?
                      new CommonResult(200,"插入成功,端口:" + serverPort):
                      new CommonResult(444,"插入失败");
          }
      
          
          @GetMapping("/{id}")
          public CommonResult create(@PathVariable("id") Long id){
              Payment payment = paymentService.getPaymentById(id);
              log.info("查询结果:" + payment);
              return !Objects.isNull(payment) ?
                      new CommonResult(200,"查询成功,端口:" + serverPort,payment):
                      new CommonResult(444,"没有当前id=" + id + "对应数据");
          }
      
          
          @GetMapping("/zk")
          public CommonResult paymentZK(){
             return new CommonResult(200, serverPort + "t" + UUID.randomUUID().toString());
          }
      
      }
      
    • 启动测试:在服务器中使用docker命令:

      1. 进入zookeeper
      docker exec -it 容器id /bin/bash
      
      1. 进入zookeeper客户端
       zkCli.sh -server 127.0.0.1:2181
      
      1. 查看运行的服务
       ls /services
      
      1. 可以看到刚才启动的服务
    2.3 支付消费者注入zookeeper
    • 新建module:cloud-consume-zk-order80,将原先80模块代码复制过来。

    • 修改pom:

              
      
          
              org.example
              cloud-api-commons
              1.0-SNAPSHOT
          
      
          
              org.springframework.cloud
              spring-cloud-starter-zookeeper-discovery
              
              
                  
                      org.apache.zookeeper
                      zookeeper
                  
              
          
      
          
          
              org.apache.zookeeper
              zookeeper
              3.4.9
              
              
                  
                      org.slf4j
                      slf4j-log4j12
                  
              
          
      
      
          
              org.springframework.boot
              spring-boot-starter-web
          
      
          
              org.springframework.boot
              spring-boot-starter-actuator
          
      
          
              org.springframework.boot
              spring-boot-starter-test
              test
          
      
          
              org.springframework.boot
              spring-boot-devtools
              runtime
              true
          
      
      
      
    • 修改配置文件:

      server:
        port: 80
      
      spring:
        application:
          name: cloud-order-service
        cloud:
          zookeeper:
            connect-string: 8.140.23.138:2181
      
      
    • 启动测试:可以看到了。

    2.4 bug记录

    无论是注入到zookeeper中的服务者还是消费者都无法调用dao中的接口,总是说找不到方法,但是测试可以通过。不晓得啥问题。

    3. consul

    一套分布式服务发现和配置管理系统,是HashiCorp公司用Go语言开发。
    提供了微服务系统的服务治理、配置中心、控制总线等功能。每一个功能都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格。

    特点:

    1. 服务发现:提供HTTP和DNS两种发现方式;
    2. 健康检测:支持多种方式,HTTP、TCP、Docker、Sheel脚本定制化;
    3. KV存储:类似于redis的k、v存储方式;
    4. 多数据中心:consul支持多数据中心;
    5. 可视化Web界面。
    3.1 安装consul
    • 下载:consul官网,这里使用的是1.6.1版本。
    • 配置环境变量到exe的父文件夹。
    • 在cmd下运行consul agent -dev
    • 访问测试:可以看到ui就可以了。
    3.2 将服务提供者注入consul
    • 新建moudl:cloud-provider-consul-payment8006

    • pom:

          
      
              
                  org.example
                  cloud-api-commons
                  1.0-SNAPSHOT
              
      
              
                  org.springframework.cloud
                  spring-cloud-starter-consul-discovery
              
      
              
                  org.springframework.boot
                  spring-boot-starter-web
              
      
              
                  org.springframework.boot
                  spring-boot-starter-actuator
              
      
              
                  org.springframework.boot
                  spring-boot-starter-test
                  test
              
      
              
                  junit
                  junit
              
      
              
                  org.springframework.boot
                  spring-boot-devtools
                  runtime
                  true
              
      
          
      
    • 配置yml:

      server:
        port: 8006
      
      spring:
        application:
          name: consul-provider-payment
        cloud:
          consul:
            host: localhost
            port: 8500
            discovery:
              server-name: ${spring.application.name}
      
      
    • 主启动类

      @SpringBootApplication
      @EnableDiscoveryClient
      public class PaymentMainConsul8006 {
          public static void main(String[] args) {
              SpringApplication.run(PaymentMainConsul8006.class,args);
          }
      }
      
    • 测试controller

      @Slf4j
      @RestController
      @RequestMapping("/payment")
      public class PaymentConsulController {
      
          @Value("${server.port}")
          private String serverPort;
      
          
          @GetMapping("/consul")
          public String paymentConsul(){
              return  serverPort + "t" + UUID.randomUUID().toString();
          }
      
      }
      
    • 启动测试:可以看到刚才启动的服务。

      访问controller也可以看到对应接口情况。

    3.3 将服务消费者注入consul
    • 新建moudle: cloud-consumer-consul-order80

    • pom:

          
              
                  org.springframework.cloud
                  spring-cloud-starter-consul-discovery
              
      
      
              
                  org.example
                  cloud-api-commons
                  1.0-SNAPSHOT
              
      
              
                  org.springframework.boot
                  spring-boot-starter-web
              
      
              
                  org.springframework.boot
                  spring-boot-starter-actuator
              
      
              
                  org.projectlombok
                  lombok
                  true
              
      
              
                  org.springframework.boot
                  spring-boot-starter-test
                  test
              
      
          
      
    • 配置文件:

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

      @Configuration
      public class ApplicationContextConfig {
      
          @Bean
          @LoadBalanced
          public RestTemplate restTemplate(){
              return new RestTemplate();
          }
      
      }
      
    • 主启动类

      @SpringBootApplication
      @EnableDiscoveryClient
      public class OrderMainConsul80 {
          public static void main(String[] args) {
              SpringApplication.run(OrderMainConsul80.class,args);
          }
      }
      
    • 测试接口

      @Slf4j
      @RestController
      @RequestMapping("/consumer")
      public class OrderController {
      
          private static final String PAYMENT_URL = "http://consul-provider-payment";
      
          @Autowired
          private RestTemplate restTemplate;
      
          @GetMapping("/payment/consul")
          public String paymentConsul(){
              return restTemplate.getForObject(PAYMENT_URL+"/payment/consul" , String.class);
          }
      
      }
      
    • 启动测试:可以看到新启动的服务,接口也可以访问成功。

    4. 总结 4.1 CAP

    CAP:

    1. C(consistdency):强一致性;
    2. A(Availability):高可用性;
    3. P(Partititon tolerance):分区容错性;

    最多只能同时较好的满住两个。
    CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性三个需求。
    根据CAP原理将NoSQL数据库分成满足CA、CP和AP原则的三大类:

    1. CA:单点集群,满足一致性,可用性的系统,通常在可扩展性上不强大;
    2. CP:满足一致性,分区容错性的系统,性能不是特别高;
    3. AP:满足可用性,分区容错性的系统,对一致性的要求较低。

    4.2 此时系统架构如下

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/967076.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号