服务注册与发现 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 ServerEureka 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-7001application.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、启动测试

访问 http://localhost:7001/

访问 http://localhost:7002/

总结: 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.xmlcloud-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:8500

查看业务代码: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:8500

测试业务代码:http://localhost/consumer/consul

三个服务注册中心的比较

组件名 语言 CAP 服务监控检查 对外暴露接口 Springcloud集成
Eureka Java AP 可配支持 HTTP 已集成
Consul Go CP 支持 HTTP/DNS 已集成
Zookeeper Java CP 支持 客户端 已集成

CAP原则点击查看 CAP

posted @ 2021-05-17 09:20  橘子有点甜  阅读(202)  评论(0编辑  收藏  举报