微服务之SpringCloud服务注册与发现

目录

一,前言

二,Eureka实现服务注册与发现

单机Eureka服务注册流程

集群模式搭建模拟

Eureka自我保护机制

三,Zookeeper实现服务注册与发现

四,Consul是实现服务注册与发现

基本简介

安装

服务注册测试

​五,三个注册中心的异同点

一,前言

什么是服务治理

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

什么是服务注册与发现

服务注册就是将服务信息注册进注册中心,然后由注册中心来监控系统中微服务的状态。服务发现就是从注册中心上获取服务的信息。通常在管理分布式环境下的各个Spring Boot微服务时,必然存在服务的注册问题。既然是注册,必然有个管理注册中心的服务器,各个在Spring Cloud管理下的Spring Boot应用就是需要注册的client。

二,Eureka实现服务注册与发现

Spring Cloud使用erureka server, 然后所有需要访问配置文件的应用都作为一个erureka client注册上去。eureka是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳,在默认情况下erureka server也是一个eureka client ,必须要指定一个 server。

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

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

单机Eureka服务注册流程

1,准备项目依赖

首先我们使用Idea新建一个SpringBoot工程,由于在为服务项目中,服务模块较多,因此我们采用分模块的构建方式,在父模块的pom中导入主要依赖,并通过dependencyManagement进行依赖管理,方便后续子模块对项目依赖的调用。

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.yy</groupId>
    <artifactId>SpringCloudAlibaba</artifactId>
    <version>1.0.1</version>
    <modules>
        <module>cloud-provider-8001</module>
        <module>cloud-common</module>
        <module>cloud-order-80</module>
        <module>cloud-eureka-server-7001</module>
        <module>cloud-eureka-server-7002</module>
        <module>cloud-eureka-server-7002</module>
        <module>cloud-provider-8002</module>
        <module>cloud-zookeeper-provider-8003</module>
        <module>cloud-consul-provider-8004</module>
        <module>cloud-consul-consumer-80</module>
        <module>cloud-configuration</module>
    </modules>
    <packaging>pom</packaging>
    <name>SpringCloudAlibaba</name>
    <description>SpringCloudAlibaba学习项目构建总项目pom</description>
​
    <properties>
<!--        将父模块版本统一设置-->
        <myproject.version>1.0.1</myproject.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <springcloud.versin>0.9.0.RELEASE</springcloud.versin>
        <springboot.version>2.7.0</springboot.version>
        <fastjson.version>1.2.72</fastjson.version>
        <mybatisplus.version>3.5.1</mybatisplus.version>
        <lombol.version>1.18.24</lombol.version>
        <druid.version>1.2.14</druid.version>
        <junit.version>4.13.2</junit.version>
        <hutool.version>5.8.8</hutool.version>
    </properties>
<dependencyManagement>
    <dependencies>
        <dependency>
<!--            springcloud-alibaba依赖-->
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${springcloud.versin}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
<!--        hutool工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
<!--        springboot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${springboot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
<!--        自配的common模块-->
        <dependency>
            <groupId>com.yy</groupId>
            <artifactId>cloud-common</artifactId>
            <version>${myproject.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version>
        </dependency>
​
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombol.version}</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatisplus.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>
</project>

2,准备服务项目

因为eureka没有单独启动的服务器,因此需要我们自己准备一个服务来作为服务注册中心,所以我们需要准备两个单独的子模块来作为euraka的服务端和客户端。除此以外,为了方便测试,我们另外准备一个消费端的服务来模拟客户消费服务提供方的过程,屏蔽服务提供的接口。通过配置RestTemplate,以RestTemplate来实现功能。

2.1准备eureka服务端

准备一个单独的子模块服务作为eureka的服务端,配置yml文件中的端口号为7001。项目只需要一个SpringBoot启动类支撑就好。作为eureka的服务端。

2.2准备服务提供的客户端

我们准备一个基本的数据库,并且利用MyBatisPlus快速构建出项目服务的基本框架并配置好基本的yml文件,此时端口号为8001。作为客户端的服务提供方。

server:
  port: 8001
spring:
  application:
    name: cloud-payment-service
  datasource:
    druid:
      username: root
      password: 123456
      url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&useSSL=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:mapper/*.xml
  type-aliases-package: com.yy.entity

这里需要注意的是spring.appliction.name一定要配置进去,在微服务项目的服务都需要用命名来标识,这样当服务注册进服务中心后就能查看到对应的服务信息了。

在controller上实现增删改查的功能接口。

package com.yy.controller;



import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yy.entity.Payment;
import com.yy.service.Impl.PaymentServiceImpl;
import com.yy.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;

/**
 * 支付模块数据表(Payment)表控制层
 *
 * @author makejava
 * @since 2022-12-16 15:24:59
 */
@RestController
@Slf4j
@RequestMapping("payment")
public class PaymentController {
    /**
     * 服务对象
     */
    @Resource
    private PaymentServiceImpl paymentService;

    @Resource
    private DiscoveryClient discoveryClient;
    
    @Value("${server.port}")
    private String port;
    /**
     * 分页查询所有数据
     *
     * @param page 分页对象
     * @param payment 查询实体
     * @return 所有数据
     */
    @GetMapping("page")
    public Result<Page<Payment>> selectAll(Page<Payment> page, Payment payment) {
        return Result.ok(this.paymentService.page(page, new QueryWrapper<>(payment)));
    }

    /**
     * 通过主键查询单条数据
     *
     * @param id 主键
     * @return 单条数据
     */
    @GetMapping("{id}")
    public Result<Payment> selectOne(@PathVariable Serializable id) {
        return Result.ok(this.paymentService.getById(id)).message("调用的eureka服务端口号为"+port);
    }

    /**
     * 新增数据
     *
     * @param payment 实体对象
     * @return 新增结果
     */
    @PostMapping("add")
    public Result<Boolean> insert(@RequestBody Payment payment) {
        return Result.ok(this.paymentService.save(payment)).message("调用的eureka服务端口号为"+port);
    }

    /**
     * 修改数据
     *
     * @param payment 实体对象
     * @return 修改结果
     */
    @PutMapping("update")
    public Result<Boolean> update(@RequestBody Payment payment) {
        return Result.ok(this.paymentService.updateById(payment));
    }

    /**
     * 删除数据
     *
     * @param idList 主键结合
     * @return 删除结果
     */
    @DeleteMapping("delete")
    public Result<Boolean> delete(@RequestParam("idList") List<Long> idList) {
        return Result.ok(this.paymentService.removeByIds(idList));
    }
    //查看服务发现的服务信息
    @GetMapping("/discovery")
    public Result<Object> discovery(){
        List<String> services = discoveryClient.getServices();
        for (String service : services) {
            log.info("服务信息为{}",service);
        }

        List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
        for (ServiceInstance instance : instances) {
            log.info("服务id为:{},hostip地址为:{},端口号为:{}",instance.getServiceId(),instance.getHost(),instance.getPort());
        }
        return Result.ok(this.discoveryClient);
    }
}

2.3准备服务消费客户端

准备消费者服务,端口号为80,因为80端口http可以直接通过ip地址访问。

配置RestTemplate

@Configuration
public class ApplicationContextConfig {
    /**
     * 配置restTemplate
     */
    @Bean
    //给restTemplate提供负载均衡效果,用于服务建立集群的时候
    @LoadBalanced   
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }
}

实现消费方的能够调用服务提供方部分功能的接口。

package com.yy.controller;
​
import com.yy.entity.Payment;
import com.yy.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
​
import javax.annotation.Resource;
​
/**
 * @author young
 * @date 2022/12/16 15:46
 * @description: 模拟客户端接口
 */
@RestController
@Slf4j
@RequestMapping("order")
public class OrderController {
    /**
     * 当服务为集群时不能将路径写死
     */
   // public static final String PAYMENT_URL="http://localhost:8001";
    
    @Resource
    private RestTemplate restTemplate;
​
    @GetMapping("/add")
    public Result<Payment> create(Payment payment){
        return restTemplate.postForObject(PAYMENT_URL+"/payment/add",payment,Result.class);
    }
    @GetMapping("/get/{id}")
    public Result<Payment> create(@PathVariable Integer id){
        return restTemplate.getForObject(PAYMENT_URL+"/payment/"+id,Result.class);
    }
}
​

3,引入Eureka

3.1客户端引入

首先我们要在客户端对应的子模块pom中导入eureka客户端依赖。

<!--    引入eureka依赖-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>3.1.3</version>
        <exclusions>
            <exclusion>
                <groupId>org.zenframework.z8.dependencies.servlet</groupId>
                <artifactId>servlet-api-2.5</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>servlet-api-2.5</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

在这里因为导入依赖后出现了一个依赖冲突,因此通过检查后我们直接排除了servlet-api的依赖。然后在yml配置文件中进行eureka客户端的配置,将我们支付服务作为客户端注册进eureka。

#客户端注册进eureka
eureka:
  client:
    register-with-eureka: true #将自己注册进eureka服务
    fetch-registry: true #是否从eureka服务抓取已有的注册信息 默认true
    service-url:
      #单机,指向服务端地址
      defaultZone: http://localhost:7001/eureka

并且在启动类上标注eureka客户端的注解。

@SpringBootApplication
@MapperScan("com.yy.dao")
/*标识eureka客户端*/
@EnableEurekaClient
/*服务发现*/
@EnableDiscoveryClient
public class PayMentApplication {
    public static void main(String[] args) {
        SpringApplication.run(PayMentApplication.class,args);
    }
}

3.2服务端引入

服务端同样在对应的pom文件中引入eureka服务端对应的依赖。

<!--    eureka server-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        <version>3.1.3</version>
        <exclusions>
            <exclusion>
                <groupId>org.zenframework.z8.dependencies.servlet</groupId>
                <artifactId>servlet-api-2.5</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

然后在yml配置文件中配置eureka服务对应的配置信息,表示将这个7001的服务作为eureka服务端。

server:
  port: 7001
eureka:
  instance:
   # hostname: localhost #实例名称 不配置的话默认为电脑名
    #显示ip地址而不是主机名
    prefer-ip-address: true
    #指定服务器ip地址
    ip-address: 192.168.98.128
    #实例id,为主机status命名
    instance-id: ${eureka.instance.ip-address}:${server.port}
  client:
    register-with-eureka: false #不向注册中心注册自己
    fetch-registry: false #表示自己端就是注册中心

最后在启动类上标注上对应的@EnableEurekaServer注解即可。

4,启动测试

准备工作完成后就可以启动项目了,首先启动eureka服务端7001端口,然后启动客户端8001,以及消费端80,将我们准备的支付模块以及消费模块的服务注册进eureka。然后在浏览其上访问服务端端口号即可看见我们的客户端服务已经注册进注册中心了。

 流程总结:

  1. 先启动eurek a主册中心

  2. 启动服务提供者payment支付服务

  3. 支付服务启动后会把自身信息(比如服务地址以别名方式注册进eureka)

  4. 消费者order服务在需要调用接口时,使用服务别名去注册中心获取实际的RPC远程调用地址

  5. 消费者获得调用地址后,底层实际是利用HttpClient技术-实现远程调用

  6. 消费者获得服务地址后会缓存在本地vm内存中,默认每间限30秒更新—次服务调用地址

集群模式搭建模拟

eureka的集群需要注意两个地方:1,为了实现高可用的效果,一个服务端必须与除自己以外所有的服务地址相关联(比如有A,B,C三个服务端,A需要设置B,C的eureka Server交互的地址,同理,B设置A,C,C设置A,B),这样当一个服务宕机后,另外两个也能正常使用。2,客户端上的eureka.client.serveice-url配置所有的服务端地址。

因此我们准备两个服务端7001,7002后,7001的yml配置为:

server:
  port: 7001
eureka:
  instance:
   # hostname: localhost #实例名称 不配置的话默认为电脑名
    #显示ip地址而不是主机名
    prefer-ip-address: true
    #指定服务器ip地址
    ip-address: 192.168.98.128
    #实例id,为主机status命名
    instance-id: ${eureka.instance.ip-address}:${server.port}
  client:
    register-with-eureka: false #不向注册中心注册自己
    fetch-registry: false #表示自己端就是注册中心
    service-url:
      #设置eureka Server交互的地址查询服务和注册服务依赖地址 ,配置集群时地址指向其他服务端口,这里指向7002服务
      defaultZone: http://localhost:7002/eureka/

客户端8001对应的yml配置为:

server:
  port: 8001
spring:
  application:
    name: cloud-payment-service
  datasource:
    druid:
      username: root
      password: 123456
      url: jdbc:mysql://localhost:3306/springcloud?useUnicode=true&useSSL=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:mapper/*.xml
  type-aliases-package: com.yy.entity
​
#客户端注册进eureka
eureka:
  client:
    register-with-eureka: true #将自己注册进eureka服务
    fetch-registry: true #是否从eureka服务抓取已有的注册信息 默认true
    service-url:
      #单机
      #defaultZone: http://localhost:7001/eureka
      #集群式
      defaultZone: http://localhost:7001/eureka,http://localhost:7002/eureka

运行后即使7001挂掉了,其他的服务也能正常使用。

Eureka自我保护机制

为什么会产生Eureka自我保护机制?

为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除。

什么是自我保护模式?

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。

自我保护机制

默认情况下EurekaClient定时向EurekaServer端发送心跳包 如果Eureka在server端在一定时间内(默认90秒)没有收到EurekaClient发送心跳包,便会直接从服务注册列表中剔除该服务,但是在短时间(90秒中)内丢失了大量的服务实例心跳,这时候Eurekaserver会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通但是EurekaClient为出现宕机,此时如果换做别的注册中心如果一定时间内没有收到心跳会将剔除该服务,这样就出现了严重失误,因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的)

在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。

它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。

取消自我保护机制配置方式

Eureka服务端的yml文件中配置

eureka:
  #关闭自我保护机制配置———保证不可用服务被及时清除
  server:
    enable-self-preservation: false #默认为true
    eviction-interval-timer-in-ms: 2000 #时间间隔

运行后就可以看到自我保护模式已取消,如果此时那个服务挂了,就会被服务端给清除掉了。

三,Zookeeper实现服务注册与发现

zookeeper实现比Eureka更容易,因为zookeeper服务是我们通过安装后启动,不需要我们单独去注册服务中心。因此我们只需要启动zookeeper服务后,创建一个单独的测试服务端口8003即可。

首先在子模块的pom文件中引入zookeeper集成springcloud的依赖。

<!--        引入zookeeper依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <version>3.1.3</version>
        </dependency>

然后配置yml文件,并标识zookeeper服务地址。

server:
  port: 8003
​
spring:
  application:
    name: cloud-zookeeper-provider
  #配置zookeeper
  cloud:
    zookeeper:
      connect-string: localhost:2181

最后在启动类上标识服务发现的注解即可。不用向Eureka那样标识服务端或客户端了。

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

这里的zookeeper就下载在win10本地上,因此手动启动zkServer.cmd后启动子模块测试即可。这里不多做演示了。

四,Consul是实现服务注册与发现

基本简介

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

安装

直接在官网进行下载,这块我们就在windows10下进行下载,解压后就即可得到一个consul的启动文件。

一般情况下如果双击进行启动,可能会发生发生闪退情况。但是不要紧我们使用cmd进行启动即可。进入命令行界面后我们可以先查看consul的版本信息。

D:\Program Files (x86)\Java Enviorment\SpringCloud\consul_1.14.3_windows_amd64>consul --version
Consul v1.14.3
Revision bd257019
Build Date 2022-12-13T17:13:55Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)

然后通过consul agent -dev启动consul服务。

D:\Program Files (x86)\Java Enviorment\SpringCloud\consul_1.14.3_windows_amd64>consul agent -dev
==> Starting Consul agent...
              Version: '1.14.3'
           Build Date: '2022-12-13 17:13:55 +0000 UTC'
              Node ID: '868264ff-490e-9834-cf45-39d5ffefcb44'
            Node name: 'DESKTOP-I2SMELA'
           Datacenter: 'dc1' (Segment: '<all>')
               Server: true (Bootstrap: false)
          Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, gRPC-TLS: 8503, DNS: 8600)
         Cluster Addr: 127.0.0.1 (LAN: 8301, WAN: 8302)
    Gossip Encryption: false
     Auto-Encrypt-TLS: false
            HTTPS TLS: Verify Incoming: false, Verify Outgoing: false, Min Version: TLSv1_2
             gRPC TLS: Verify Incoming: false, Min Version: TLSv1_2
     Internal RPC TLS: Verify Incoming: false, Verify Outgoing: false (Verify Hostname: false), Min Version: TLSv1_2
​
==> Log data will now stream in as it occurs:
​
2022-12-18T19:30:51.675+0800 [INFO]  agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:868264ff-490e-9834-cf45-39d5ffefcb44 Address:127.0.0.1:8300}]"
2022-12-18T19:30:51.675+0800 [INFO]  agent.server.raft: entering follower state: follower="Node at 127.0.0.1:8300 [Follower]" leader-address= leader-id=
2022-12-18T19:30:51.676+0800 [INFO]  agent.server.serf.wan: serf: EventMemberJoin: DESKTOP-I2SMELA.dc1 127.0.0.1
2022-12-18T19:30:51.676+0800 [INFO]  agent.server.serf.lan: serf: EventMemberJoin: DESKTOP-I2SMELA 127.0.0.1
2022-12-18T19:30:51.676+0800 [INFO]  agent.router: Initializing LAN area manager
2022-12-18T19:30:51.677+0800 [INFO]  agent.server: Adding LAN server: server="DESKTOP-I2SMELA (Addr: tcp/127.0.0.1:8300) (DC: dc1)"
2022-12-18T19:30:51.677+0800 [INFO]  agent.server.autopilot: reconciliation now disabled
2022-12-18T19:30:51.677+0800 [INFO]  agent.server: Handled event for server in area: event=member-join server=DESKTOP-I2SMELA.dc1 area=wan
2022-12-18T19:30:51.678+0800 [INFO]  agent.server.cert-manager: initialized server certificate management
2022-12-18T19:30:51.678+0800 [DEBUG] agent.server.autopilot: autopilot is now running
2022-12-18T19:30:51.679+0800 [DEBUG] agent.server.autopilot: state update routine is now running
2022-12-18T19:30:51.678+0800 [DEBUG] agent.hcp_manager: HCP manager starting
2022-12-18T19:30:51.680+0800 [INFO]  agent: Started DNS server: address=127.0.0.1:8600 network=udp
2022-12-18T19:30:51.681+0800 [INFO]  agent: Started DNS server: address=127.0.0.1:8600 network=tcp
2022-12-18T19:30:51.682+0800 [INFO]  agent: Starting server: address=127.0.0.1:8500 network=tcp protocol=http
2022-12-18T19:30:51.682+0800 [INFO]  agent: Started gRPC listeners: port_name=grpc address=127.0.0.1:8502 network=tcp
2022-12-18T19:30:51.682+0800 [INFO]  agent: Started gRPC listeners: port_name=grpc_tls address=127.0.0.1:8503 network=tcp
2022-12-18T19:30:51.682+0800 [INFO]  agent: started state syncer
2022-12-18T19:30:51.683+0800 [INFO]  agent: Consul agent running!
2022-12-18T19:30:51.732+0800 [WARN]  agent.server.raft: heartbeat timeout reached, starting election: last-leader-addr= last-leader-id=
2022-12-18T19:30:51.732+0800 [INFO]  agent.server.raft: entering candidate state: node="Node at 127.0.0.1:8300 [Candidate]" term=2
2022-12-18T19:30:51.735+0800 [DEBUG] agent.server.raft: voting for self: term=2 id=868264ff-490e-9834-cf45-39d5ffefcb44
2022-12-18T19:30:51.736+0800 [DEBUG] agent.server.raft: calculated votes needed: needed=1 term=2
2022-12-18T19:30:51.736+0800 [DEBUG] agent.server.raft: vote granted: from=868264ff-490e-9834-cf45-39d5ffefcb44 term=2 tally=1
2022-12-18T19:30:51.737+0800 [INFO]  agent.server.raft: election won: term=2 tally=1
2022-12-18T19:30:51.737+0800 [INFO]  agent.server.raft: entering leader state: leader="Node at 127.0.0.1:8300 [Leader]"
2022-12-18T19:30:51.737+0800 [DEBUG] agent.hcp_manager: HCP triggering status update
2022-12-18T19:30:51.738+0800 [INFO]  agent.server: cluster leadership acquired
2022-12-18T19:30:51.738+0800 [INFO]  agent.server: New leader elected: payload=DESKTOP-I2SMELA
2022-12-18T19:30:51.738+0800 [INFO]  agent.server.autopilot: reconciliation now enabled
2022-12-18T19:30:51.740+0800 [INFO]  agent.leader: started routine: routine="federation state anti-entropy"
2022-12-18T19:30:51.740+0800 [INFO]  agent.leader: started routine: routine="federation state pruning"
2022-12-18T19:30:51.741+0800 [INFO]  agent.leader: started routine: routine="streaming peering resources"
2022-12-18T19:30:51.741+0800 [INFO]  agent.leader: started routine: routine="metrics for streaming peering resources"
2022-12-18T19:30:51.741+0800 [INFO]  agent.leader: started routine: routine="peering deferred deletion"
2022-12-18T19:30:51.742+0800 [DEBUG] connect.ca.consul: consul CA provider configured: id=fb:50:9b:45:1a:65:15:c1:68:57:73:5f:da:cd:b8:0d:0f:e2:26:eb:68:66:43:11:85:9d:67:a9:7a:56:9c:b9 is_primary=true
2022-12-18T19:30:51.744+0800 [INFO]  connect.ca: updated root certificates from primary datacenter
2022-12-18T19:30:51.744+0800 [INFO]  connect.ca: initialized primary datacenter CA with provider: provider=consul
2022-12-18T19:30:51.745+0800 [INFO]  agent.leader: started routine: routine="intermediate cert renew watch"
2022-12-18T19:30:51.745+0800 [INFO]  agent.leader: started routine: routine="CA root pruning"
2022-12-18T19:30:51.745+0800 [INFO]  agent.leader: started routine: routine="CA root expiration metric"
2022-12-18T19:30:51.746+0800 [INFO]  agent.leader: started routine: routine="CA signing expiration metric"
2022-12-18T19:30:51.746+0800 [INFO]  agent.leader: started routine: routine="virtual IP version check"
2022-12-18T19:30:51.746+0800 [INFO]  agent.leader: stopping routine: routine="virtual IP version check"
2022-12-18T19:30:51.747+0800 [INFO]  agent.leader: stopped routine: routine="virtual IP version check"
2022-12-18T19:30:51.747+0800 [DEBUG] agent.server: successfully established leadership: duration=8.2402ms
2022-12-18T19:30:51.748+0800 [INFO]  agent.server: member joined, marking health alive: member=DESKTOP-I2SMELA partition=default
2022-12-18T19:30:51.753+0800 [DEBUG] agent.server.xds_capacity_controller: updating drain rate limit: rate_limit=1
2022-12-18T19:30:52.110+0800 [DEBUG] agent: Skipping remote check since it is managed automatically: check=serfHealth
2022-12-18T19:30:52.110+0800 [INFO]  agent.server: federation state anti-entropy synced
2022-12-18T19:30:52.110+0800 [INFO]  agent: Synced node info
2022-12-18T19:30:52.115+0800 [DEBUG] agent: Node info in sync
2022-12-18T19:30:52.110+0800 [DEBUG] agent.http: Request finished: method=GET url="/v1/internal/ui/services?dc=dc1&index=14" from=127.0.0.1:61977 latency=362.8429ms
2022-12-18T19:30:52.128+0800 [DEBUG] agent.server.cert-manager: got cache update event: correlationID=leaf error=<nil>
2022-12-18T19:30:52.128+0800 [DEBUG] agent.server.cert-manager: leaf certificate watch fired - updating auto TLS certificate: uri=spiffe://d9178c8e-4c84-1ea5-e030-31992e55232d.consul/agent/server/dc/dc1
2022-12-18T19:30:52.690+0800 [DEBUG] agent.server.cert-manager: CA config watch fired - updating auto TLS server name: name=server.dc1.peering.d9178c8e-4c84-1ea5-e030-31992e55232d.consul
2022-12-18T19:30:53.215+0800 [DEBUG] agent: Skipping remote check since it is managed automatically: check=serfHealth
2022-12-18T19:30:53.215+0800 [DEBUG] agent: Node info in sync

当服务服务运行成功后,我们本地访问localhost:/8500即可进入consul服务的可视化界面。

服务注册测试

和zookeeper服务注册测试方式一样,我们构建差不多的一个新module,只有两个地方需要更改:1,pom文件中导入consul对应的依赖

        <!--        引入consul依赖-->
        <dependency>      <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
            <version>3.1.2</version>
        </dependency>

2,在yml文件中配置consul服务的对应信息 

server:
  port: 8004
​
spring:
  application:
    name: consul-provider-server
  #consul注册中心地址
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}

其他业务模块我们基本一致,然后就可以启动服务调用接口查看测试结果。

package com.yy.controller;
​
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
import java.time.LocalDateTime;
​
/**
 * @author young
 * @date 2022/12/18 19:41
 * @description:
 */
@RestController
@Slf4j
@RequestMapping("consul")
public class ConsulController {
    
    @GetMapping("/test")
    public String method(){
    return "consul服务测试注册的时间是"+ LocalDateTime.now();
    }
}

说明提供方的服务已经注册完毕。同样的方法我们将消费方也注册进consul,运行成功后即可看到可视化界面上的两个服务均已在册。

 测试消费接口也没毛病,大致注册过程到这就搞定了。

五,三个注册中心的异同点

组件名开发语言CAP服务健康检查对外暴露接口
EurekaJavaAp可配支持HTTP
ConsulGoCP支持HTTP/DNS
ZookeeperJavaCP支持客户端

Eureka在默认开启自我保护机制的情况下即使服务挂掉,服务也不会立刻被清除掉,因此它在微服务系统中优先保证数据一致性(C)与分区容错性(P)。而Zookeepe和Consul在默认情况,如果服务挂掉,注册中心会立刻清除掉不可用的服务,因此他们两个默认情况下是优先保证服务可用性(A)和分区容错性。

后续对于Nacos的学习服务注册与发现也会陆续总结出来。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值