本文章就讲讲搭建, 及三个组件的执行流程
总结: 三种统一点都是在yml中配置, 只要配置好, 项目总能跑!!
Spring Cloud Config配置中心
服务端和客户端两部分, 也是一个独立的微服务应用, 凡是链接上来的也要注册到配置中心上
作用: 集中管理配置文件, 不同环境不同配置, 动态化的配置更新
解决的问题: 复杂的配置问题, local环境, 开发环境, 测试环境, 预发环境, 线上环境
一套集中式, 动态的配置管理设施是不可少的, 一处配置, 处处生效
- Config(配置中心服务端): 运维改配置
server:
port: 3344 #端口号
spring:
application:
name: cloud-config-center #注册进Eureka 服务器的微服务名
cloud:
config:
server:
git:
uri: https://gitee.com/ther661/springcloud2021.git #GitHub远程仓库地址
# 搜索目录
search-paths:
- springcloud-config
#读取分支, 读取git上面你定义的分支, 默认是master分支
label: master
#服务注册到eureka
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
##label: 分支(默认是master主分支)
##name:服务名
##profiles:环境(dev/test/prod)
##推荐写法
##域名/分支{label}/文件名{application}-{profile}.yml
##其他都在yml中配置了
- Config(配置中心客户端): bootstrap.yml是客户端中的配置
application.yml 是(用户级)的资源配置项。bootstrap.yml 是(系统级)的资源配置项,优先级更高。
分布式配置的动态刷新问题
当 GitHub 上的配置文件内容有调整,Github中配置变更后,ConfigServer 配置中心会立刻响应,然鹅客户端却没有任何响应,除非客户端重启或者重新加载,才能够获取最新的配置。 难道每次修改配置文件,客户端都需要重启吗??
接下来对客户端进行 动态刷新
配置 (除了网关不加,其他都得加)
通过配置文件来取决于谁是客户端, 而不是用注解的形式
运维要调用POST请求, 可以达到实时刷新的效果
单纯用Config还有什么问题吗?
假设有多个微服务客户端, 每个微服务都要使用实时刷新Post命令?
可否广播, 一次通知, 处处生效
下面就要借用Bus消息总线
Bus(消息总线)
- 作用:
- 如何实现作用
- 简化流程
- 客户端实时刷新(全部刷新)
- 指定通知命令
Spring Cloud Stream 消息驱动
- 作用
它整合了 Java 的事件处理机制和消息中间件的功能。Spring Cloud Bus 目前仅支持 RabbitMQ 和 Kafka。
就是通过 MQ 消息队列的 Topic 机制,达到广播的效果。topic一次性发送给了所有配置中心config客户端
俗称
#### 简化流程
1: 配置文件在git上面修改,
2:配置中心发现了git上面的配置文件修改
3:配置客户端通过手动触发post方式引发实时更新, 发送给消息总线Bus
3.1利用消息总线,触发一个客户端 的 /bus/refresh 端点。
通过客户端向 Bus 总线发送消息,实现刷新所有客户端的配置。
3.2利用消息总线,触发一个服务端 的 /bus/refresh 端点。
通过Config Server 服务端向 Bus 总线发送消息,实现刷新所有客户端的配置。
4:消息总线再把消息发送给其他客户端
客户端实时刷新(全部刷新)
运维命令: WIN+R: **`curl -X POST "http://localhost:3344/actuator/bus-refresh`**
指定通知命令(只通知某一个配置中心客户端, 不全部通知)
curl -X POST http://localhost:3344/actuator/bus-refresh/config-client:3355
## 后面为微服务的名称和端口
指定3355可以实时更新
Spring Cloud Stream 消息驱动
作用
避免不同的MQ, 有了消息驱动, 一视同仁全部当成MQ使用, 解决多部门配合,
MQ差异化带来的联调问题,屏蔽底层 MQ 之间的细节差异,
比如有的用rabbitMQ, kafaka,rocketMq,怎么一视同仁呢?
**说明:**
1. `Source/Sink`:Source 输入消息,Sink 输出消息
2. `Channel`:通道,是队列 Queue 的一种抽象,在消息通讯系统中就是实现存储和转发的媒介,
通过Channel 对队列进行配置;
3. `Binder`:很方便的 **`连接中间件`**,屏蔽 MQ 之间的差异
- 重复消费问题
当集群方式进行消息消费时,就会存在 消息的重复消费问题。比如订单库存相关消息,购物完成库存 -1,消息重复消费就会导致库存不准确问题出现,这显然是不能接受的。这是因为没有进行分组的原因,不同组就会出现重复消费;同一组内会发生竞争关系,只有一个可以消费。 如果我们不指定(8802、8803)集群分组信息,它会默认将其当做两个分组来对待。这个时候,如果发送一条消息到 MQ,不同的组就都会收到消息,就会造成消息的重复消费。
分组后测试结果:
只要是一个组的消费者,就处于竞争关系,一次只能有一个去消费,这就可以解决重复消费的问题了。(项目中,是否分组就视业务情况而定吧)
加配置解决重复消费问题
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
binders: # 在此处配置要绑定的rabbitmq的服务信息;
defaultRabbit: # 表示定义的名称,用于于binding整合(可以自定义名称)
type: rabbit # 消息组件类型
environment: # 设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
input: # 这个名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json,文本则设置“text/plain”
binder: defaultRabbit # 设置要绑定的消息服务的具体设置(需与自定义名称一致)(飘红:Settings->Editor->Inspections->Spring->Spring Boot->Spring Boot application.yml 对勾去掉)
group: stream01 #分组
只要是一个组的消费者,就处于竞争关系,一次只能有一个去消费,这就可以解决重复消费的问题了。解决之后
- 持久化问题
此时去掉 8802 分组属性,8803 分组仍然为 stream01。此时他们是 2 个分组状态。关闭8802 服务,开启 8803 服务。此时生产者8801 开始发送 4 条消息,我们可以发现 8803 能够正常消费到 4条消息,此时开启 8802 服务,发现 8802 一条消息都没有收到,这就是消息持久化的问题。
解决方法:
还是很简单,还是加一个 group 分组属性就行了。所以说 group 分组属性在消息重复消费和消息持久化消费(避免消息丢失)是一个非常重要的属性,推荐你在使用时加上。
两种问题的解决办法: 都是分成一个组里面