consul
简介、环境搭建
之前服务注册中心使用的是 Eureka,当前已经停止更新了,取而代之的是 Consul 和 Alibaba Nacos。
并且 Eureka 其实作为服务注册中心是有点奇怪的,它本身作为一个微服务,但是他又要求其他微服务耦合进去,所以很奇怪。
Consul 可以做服务发现、配置管理,主要功能有:
- 服务发现:提供 HTTP、DNS 两种发现方式
- 健康监测:支持多种方式,包括 HTTP、TCP、Docker、Shell
- KV 存储:Key、Value 存储方式
- 多数据中心:Consul 支持多数据中心
- 可视化 WEB 界面
注册中心的异同点
注册中心的异同,主要是从三个方面考虑:CAP,即:
- C: Consistency(强一致性)
- A: Availability(可用性)
- P: Partition tolerance(分区容错性)
CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求
因此,根据 CAP 原理将 NoSQL 数据库分成了满足 CA 原则、满足 CP 原则和满足 AP 原则三大类:
CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大
CP - 满足一致性,分区容忍性的系统,通常性能不是特别高
当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性
Consoul 使用 CP 原则保证了强一致性和分区容错性,且使用的是 Raft 算法,比 zookeeper 使用的 Paxos 算法更加简单
虽然保证了强一致性,但是可用性就相应下降了,例如服务注册的时间会稍长一些
因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功
在 leader 挂掉了之后,重新选举出 leader 之前会导致 Consul 服务不可用
结论:违背了可用性 A 的要求,只满足一致性和分区容错,即 CP
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些
当网络分区出现后,为了保证可用性,系统 B 可以返回旧值,保证系统的可用性
当数据出现不一致时,虽然 A、B 上的注册信息不完全相同,但每个节点依然能够正常对外提供服务
Eureka 就使用了这种方式,这会出现查询服务信息时如果请求 A 查不到,但请求 B 就能查到
如此保证了可用性但牺牲了一致性结论:违背了一致性C的要求,只满足可用性和分区容错,即 AP
服务注册与发现
cloud-provider-payment8001服务提供者模块增加依赖<!--SpringCloud consul discovery --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>spring: # Spring Cloud Consul for Service Discovery cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name}之后在主启动类中增加注解
@EnableDiscoveryClient激活服务发现功能重新启动服务提供者,可以看到已经注册到了 Consul
cloud-consumer-order80服务消费者模块增加依赖<!--SpringCloud consul discovery --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-discovery</artifactId> </dependency>spring: application: name: cloud-consumer-order ####Spring Cloud Consul for Service Discovery cloud: consul: host: localhost port: 8500 discovery: #优先使用服务ip进行注册 prefer-ip-address: true service-name: ${spring.application.name}主启动类中添加注解
@EnableDiscoveryClientcontroller 中,硬编码的
http://localhost:8001改为使用 Consol 中服务注册的名称cloud-payment-service,即http://cloud-payment-service,这样解决了硬编码问题启动,发现已经注册成功了
尝试调用 controller 之后,发现出现报错,这是因为我们的 Consul 天生支持负载均衡,所以调用的时候它不知道具体需要找哪一个微服务,所以需要再加上一个负载均衡的配置,也就是在 RestTemplate 上加一个
@LoadBalanced我们的 RestTemplate 都是用的同一个,所以在 bean 中加上即可
@Configuration public class RestTemplateConfig { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }加上之后重启 tomcat 后再次访问成功。
服务配置与刷新
微服务意味着每一个服务都需要进行配置,但如果像传统服务一样每一个服务都需要一个 application.yaml 那将是一个管理的灾难。
所以可以使用 Consol 的 KV 功能,同时配合定义的配置文件来获取配置信息
修改
cloud-provider-payment8001,服务提供者增加 pom 依赖<!--SpringCloud consul config--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-consul-config</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>创建
bootstrap.yml从官网上看,如果要使用则需要设置
bootstrap.yml来代替application.yml,本次我们主要修改cloud-provider-payment8001模块作为案例但是虽然说是
bootstrap.yml可以替代,但是一般来说我们可将通用配置放到bootstrap.yml中,将特殊配置放到application.yaml中注意,上图中的
config/testApp,dev/data,其中的逗号指的是文件所在路径使用逗号,对于国人而言有点太超前了所以我们之后在配置文件中使用后面的
spring.cloud.consul.config.profile-separator修改文件路径(环境分隔符),改为-,这样在创建文件夹(不同环境)就会是xxx-xx的形式创建
bootstrap.ymlspring: application: name: cloud-payment-service ####Spring Cloud Consul for Service Discovery cloud: consul: host: localhost port: 8500 discovery: service-name: ${spring.application.name} config: # default value is ",",we update '-' profile-separator: '-' format: YAML修改
application.yaml,删除了 consul 中的内容,增加了spring.profiles.active: dev,这代表我们使用的环境是 dev,也就代表着我们将会在 consul 中创建一个 dev 的文件夹作为环境server: port: 8001 # ==========applicationName + druid-mysql8 driver=================== spring: application: name: cloud-payment-service jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8 datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver url: jdbc:mysql://hadoop101:3306/db2024?useUnicode=true&characterEncoding=UTF-8&useSSL=false username: root password: root profiles: active: dev # ========================mybatis=================== mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.causes.cloud.entities configuration: map-underscore-to-camel-case: true在 consul 中增加对应的配置信息
新建文件夹和文件,其中三个目录中,dev 代表开发、prod 代表生产、啥也不带就是默认
config/cloud-payment-service/data config/cloud-payment-service-dev/data config/cloud-payment-service-prod/data三个文件夹下面分别有三个 data 文件,其中分别是
修改 controller
@Value("${server.port}") private String port; @GetMapping(value = "/pay/get/info") private String getInfoByConsul(@Value("${causes.info}") String info) { return String.format("info: %s, port: %s", info, port); }动态刷新
动态刷新的意思是,在项目运行的过程中修改 consul 中的配置文件,会不会随着修改而进行动态调整,结果并不会
要进行动态调整的方式也很简单,直接在启动类中加上
@RefreshScope即可动态刷新时间默认为
55s,可以通过spring.cloud.consul.config.watch.wait-time调整,生产按需即可
consul 配置持久化
虽然建立了多个环境和配置,但是这些配置会随着 consul 服务的重启而消失,为了保证容错必须进行持久化配置
我们可以通过命令 consul agent -server -data-dir xxx 指定文件路径
但是为了方便,通过下列 consul_start.bat 脚本将 consul 配置为 windows 服务,每次开机的时候自动启动 consul,同时实现了持久化服务,一举多得
打开时使用管理员权限
@echo.服务启动......
@echo off
@sc create Consul binpath= "D:\soft\Cloud\consul\consul.exe agent -server -ui -bind=127.0.0.1 -client=0.0.0.0 -bootstrap-expect 1 -data-dir D:\soft\Cloud\consul\mydata"
@net start Consul
@sc config Consul start= AUTO
@echo.Consul start is OK......success
@pause
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。