04-Consul服务注册与发现

1.为什么要引入服务注册中心

1.1 原因

public static final String PAYMENT_SRV_URL = "http://localhost:8001";//硬编码

微服务所在的IP地址和端口号硬编码到订单微服务中,会存在非常多的问题

(1)如果订单微服务和支付微服务的IP地址或者端口号发生了变化,则支付微服务将变得不可用,需要同步修改订单微服务中调用支付微服务的IP地址和端口号。

(2)如果系统中提供了多个订单微服务和支付微服务,则无法实现微服务的负载均衡功能。

(3)如果系统需要支持更高的并发,需要部署更多的订单微服务和支付微服务,硬编码订单微服务则后续的维护会变得异常复杂。

所以,在微服务开发的过程中,需要引入服务治理功能,实现微服务之间的动态注册与发现,从此刻开始我们正式进入SpringCloud实战。

1.2 注册中心在SpringCloud体系的位置

2.为什么不再使用Eureka

2.1 Enreka停更维护

https://github.com/Netflix/eureka/wiki

2.2 注册中心独立且和微服务功能解耦

目前主流服务中心,希望单独隔离出来而不是作为一个独立微服务嵌入到系统中。

按照Netflix之前的思路,注册中心Eureka也是作为一个微服务且需要程序员自己开发部署(cloud2020的教程,eureka需要单独引入依赖,做为一个服务启动)。

实际情况,希望微服务和注册中心分离解耦,注册中心和业务无关的,不要混为一谈。提供类似tomcat一样独立的组件,微服务注册上去使用,是个成品。

.3 阿里巴巴Nacos的崛起

一个集成了Service discovery and configuration management的独立组件。在配置文件的持久化上,使用起来比Consul要简单。后面教程会讲解到。

3.Consul简介

3.1 是什么

3.1.1 consul官网地址

https://www.consul.io/

3.1.2 What is Consul?

Consul 是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司用Go语言开发。

提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。它具有很多优点。包括: 基于raft协议,比较简洁; 支持健康检查, 同时支持HTTPDNS协议支持跨数据中心的 WAN集群,提供图形界面 跨平台,支持 Linux、Mac、Windows。

https://developer.hashicorp.com/consul/docs/intro

3.1.3 禁止使用问题

HashiCorp是一家非常知名的基础软件提供商,很多人可能没听过它的名字,但是其旗下的6款主流软件,Terraform、Consul、Vagrant、Nomad、Vault,Packer 相信不少程序员都听说或使用过,尤其是Consul使用者不尽其数。截止目前为止,从HashiCorp官网上的声明来看,开源项目其实还是“安全”的,被禁用的只是Vault企业版(并且原因是Vault产品目前使用的加密算法在中国不符合法规,另一方面是美国出口管制法在涉及加密相关软件上也有相应规定。因此这两项原因使得HashiCorp不得不在声明中说明风险)而非其他所有开源产品(Terraform、Consul等)。因此,大家可以暂时放下心来,放心使用!

3.1.4 Spring Cloud Consul

https://docs.spring.io/spring-cloud-consul/reference/index.html

3.2 能干嘛

3.2.1 服务发现

提供HTTP和DNS两种发现方式。

3.2.2 健康检测

支持多种方式,HTTP,TCP,Docker,Shell脚本定制化监控。

3.2.3 KV存储

Key,Value的存储方式。

3.2.4 多数据中心

Consul多数据中心

3.2.5 可视化WEB界面

3.3 下载地址

https://developer.hashicorp.com/consul/install

3.4 快速开始

https://docs.spring.io/spring-cloud-consul/reference/quickstart.html

4.下载并运行Consul

下载,注意选择版本,和对应操作系统,以及如果是,Windows下的CPU架构。

找到下载文件,移动到合适的目录,解压即可,因为是一个可执行的consul.exe文件

#查看版本信息,注意在consul.exe目录下执行
D:\Develop\consul>consul -version

开发者模式启动

D:\Develop\consul>consul agent -dev

通过http://localhost:8500,访问页面

5.服务注册与发现

5.1 服务提供者8001

支付服务provider8001注册进consul

5.1.1 引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    <exclusions>
        <!--这个因为包含了多余的日志依赖,这个是排除的。否则控制台,会有警告信息。-->
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

为什么这么引入,见官网

5.1.2 配置文件修改
spring:
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name} 
5.1.3 主启动

@EnableDiscoveryClient注解,开启服务发现(作为一个服务,注册到consul,也可以从consul中,获取其他服务的ip和端口信息)。

5.2 服务消费者80

5.2.1 引入依赖
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
    <exclusions>
        <!--这个因为包含了多余的日志依赖,这个是排除的。否则控制台,会有警告信息。-->
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
5.2.2 修改配置
server:
  port: 8080

spring:
  application:
    name: cloud-consumer-order
  ####Spring Cloud Consul for Service Discovery
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true #优先使用服务ip进行注册
        service-name: ${spring.application.name}
5.2.3 主启动

@EnableDiscoveryClient注解,开启服务发现。

5.2.4 Controller类修改
@RestController
@RequestMapping("/consumer")
public class OrderController {

    //public static final String PAYMENT_SRV_URL = "http://localhost:8001";//硬编码

    public static final String PAYMENT_SRV_URL = "http://cloud-payment-service";//服务注册中心上的微服务名称

    @Resource
    private RestTemplate restTemplate;
	
    ...
}
5.2.5 启动测试

5.2.6 修改RestTemplateConfig类
@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced//新增的,因为注册中心 ,必须要有负载均衡。
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

5.3 注册中心异同点

5.3.1 CAP理论

C:Consistency(强一致性)

A:Availablility(可用性)

P:Partition tolerance(分区容错性)

5.3.2 经典CAP图


中间件,一般能支持CAP中的两项特性,就不错了。

5.3.3 AP(Eureka/Nacos)

AP架构

当网络分区出现后,为了保证可用性,系统B可以返回旧值,保证系统的可用性。

当数据出现不一致时,虽然A, B上的注册信息不完全相同,但每个Eureka节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求A查不到,但请求B就能查到。如此保证了可用性但牺牲了一致性结论:违背了一致性C的要求,只满足可用性和分区容错,即AP。

5.3.4 CP(Zookerper/Consul)

CP架构

当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性,Consul 遵循CAP原理中的CP原则,保证了强一致性和分区容错性,且使用的是Raft算法,比zookeeper使用的Paxos算法更加简单。虽然保证了强一致性,但是可用性就相应下降了,例如服务注册的时间会稍长一些,因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功 ;在leader挂掉了之后,重新选举出leader之前会导致Consul 服务不可用。结论:违背了可用性A的要求,只满足一致性和分区容错,即CP。

6.服务配置与刷新

6.1 分布式系统面临的->配置问题

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可少的。比如某些配置文件中的内容大部分都是相同的,只有个别的配置项不同。就拿数据库配置来说吧,如果每个微服务使用的技术栈都是相同的,则每个微服务中关于数据库的配置几乎都是相同的,有时候主机迁移了,我希望一次修改,处处生效。

当下我们每一个微服务自己带着一个application.yml,上百个配置文件的管理....../(ㄒoㄒ)/~~

6.2 官网说明

Consul可作为注册中心和配置中心。

作为配置中心介绍。

6.3 服务使用配置中心

既然可以使用全局配置信息,直接注册进Consul服务器,从Consul获取。但是要遵守Consul的配置规则要求。

6.3.1 引入依赖
<!--SpringCloud consul config-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-config</artifactId>
    <exclusions>
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

为什么需要引入注册中心,和bootstrap依赖。见官网

6.3.2 修改配置

Consul配置规则说明

You can change the data key using spring.cloud.consul.config.data-key.可以使用该属性key修改配置文件和其分组间使用的分隔符。

例如Consul中默认','作为分隔符,application,dev.yml 设置了属性为'-' ,就可以使用该方式,application-dev.yml。

新增bootstrap.yml配置文件

applicaiton.yml是用户级的资源配置项。

bootstrap.yml是系统级的,优先级更加高。

Spring Cloud会创建一个“Bootstrap Context”,作为Spring应用的Application Context的父上下文。初始化的时候,Bootstrap Context负责从外部源加载配置属性并解析配置。这两个上下文共享一个从外部获取的Environment

Bootstrap属性有高优先级,默认情况下,它们不会被本地配置覆盖。 Bootstrap contextApplication Context有着不同的约定,所以新增了一个bootstrap.yml文件,保证Bootstrap ContextApplication Context配置的分离。

applicaiton.yml文件改为bootstrap.yml,这是很关键的或者两者共存。因为bootstrap.yml是比applicaiton.yml先加载的。bootstrap.yml优先级高于applicaiton.ymlymlproperties只是文件名后缀,以及配置是,相同前缀的key是否省略不同(写法上),优先级方面无区别。

6.3.3 配置文件内容

bootstrap.yml

spring:
  application:
    name: cloud-payment-service
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        service-name: ${spring.application.name}
      config:
        profile-separator: '-' # default value is ",",we update '-'
        format: YAML

applicaiton.yml

server:
  port: 8001

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3307/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: xxx
    password: xxx
  profiles:
    active:  # 多环境配置加载内容dev/prod,不写就是默认default配置


# ========================mybatis===================
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.cloud.entities
  configuration:
    map-underscore-to-camel-case: true
6.3.4 consul服务器Key/Value配置填写

1.参考规则

config/cloud-payment-service/data //没写就是默认default
config/cloud-payment-service-dev/data
config/cloud-payment-service-prod/data

2.创建config文件夹,以/结尾

打开,consul的web管理界面,Key/value菜单,Create按钮新建即可。

3.在config文件夹下创建其他3个文件夹,以/结尾

4.在上述3个文件夹下分别创建data内容,data不再是文件夹

6.3.5 测试配置中心配置的方法
    @Value("${server.port}")
    private String port;

    @GetMapping(value = "/get/info")
    private String getInfoByConsul(@Value("${info}") String info) {//要和data文件中写入的配置信息相同
        return "Info: " + info + "\t" + "port: " + port;
    }

通过修改application.yml里面的激活配置部分,进行内容的验证。

6.3.6 测试

6.3.7 使用ConfigUtil静态获取系统配置的类

一般情况下,开发时,都会使用一个工具类静态的获取系统配置,见博文

6.4 动态刷新

在周阳老师视频中,修改了data中的配置内容,不会立刻刷洗,但是我学习,操作过程中,会自动刷新,且不用配置或者,在主启动类上加@RefreshScope注解。

周洋老师视频中,需要在主启动类,加@RefreshScope注解,修改spring.cloud.consul.config.watch.wait-time配置,改项配置默认值是55秒。

6.5 思考

存在问题,在Key/Value新增的配置,在consul重启后,就没了。Consul的配置持久化...

只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。