上一篇文章,留了一個懸念,Config Client
實現配置的實時更新,咱們可使用 /refresh
接口觸發,若是全部客戶端的配置的更改,都須要手動觸發客戶端 /refresh
,當服務愈來愈多的時候,那豈不是維護成本很高,顯然不太合適,而使用Spring Cloud Bus
消息總線實現方案,能夠優雅的解決以上問題,那就是經過消息代理中間件RabbitMQ
加 Git
的Webhooks
來觸發配置的更新,那具體是怎麼實現的,我會經過圖文形式介紹。node
Spring Cloud Bus
將分佈式系統的節點經過輕量級消息代理鏈接起來。用於在集羣中傳播狀態更改(例如配置更改事件)或其餘管理指令。Spring Cloud Bus
的一個核心思想是經過分佈式的啓動器對 Spring Boot
應用進行擴展,也能夠用來創建一個或多個應用之間的通訊頻道。目前惟一實現的方式是用 AMQP
消息代理做爲通道,可是相同的基本功能集(還有一些取決於傳輸)在其餘傳輸的路線圖上git
消息總線是一種通訊工具,能夠在機器之間互相傳輸消息、文件等。消息總線扮演着一種消息路由的角色,擁有一套完備的路由機制來決定消息傳輸方向。發送段只須要向消息總線發出消息而不用管消息被如何轉發。Spring cloud bus
經過輕量消息代理鏈接各個分佈的節點。管理和傳播全部分佈式項目中的消息,本質是利用了MQ的廣播機制在分佈式的系統中傳播消息,目前經常使用的有Kafka
和RabbitMQ
。
下面是一個配置中心刷新配置的例子github
[圖片來源於網絡若有侵權請私信刪除]web
post
請求給bus/refresh
server
端接收到請求併發送給Spring Cloud Bus
Spring Cloud bus
接到消息並通知給其它客戶端Server
端獲取最新配置消息代理(Message Broker
)是一種消息驗證、傳輸、路由的架構模式。消息代理是一箇中間件產品,它的核心是一個消息的路由程序,用來實現接收和分發消息,並根據設定好的消息處理流來轉發給正確的應用。它包括獨立的通訊和消息傳遞協議,可以實現組織內部和組織間的網絡通訊。設計代理的目的就是爲了可以從應用程序中傳入消息,並執行一些特別的操做。spring
和組織間的網絡通訊。設計代理的目的就是爲了可以從應用程序中傳入消息,並執行一些特別的操做。
現有的消息代理開源產品:json
ActiveMQ
Kafka
RabbitMQ
RocketMQ
目前Spring Cloud Bus
支持 RabbitMQ
和 Kafka,spring-cloud-starter-bus-amqp
、spring-cloud-starter-bus-kafka
segmentfault
RabbitMQ是一個開源的AMQP實現,服務器端用Erlang語言編寫,支持多種客戶端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP
等,支持AJAX
。用於在分佈式系統中存儲轉發消息,在易用性、擴展性、高可用性等方面表現不俗。瀏覽器
AMQP
,即Advanced message Queuing Protocol
,高級消息隊列協議,是應用層協議的一個開放標準,爲面向消息的中間件設計。消息中間件主要用於組件之間的解耦,消息的發送者無需知道消息使用者的存在,反之亦然。安全
AMQP
的主要特徵是面向消息、隊列、路由(包括點對點和發佈/訂閱)、可靠性、安全。服務器
Github:https://github.com/rabbitmq
官網地址:http://www.rabbitmq.com
安裝RabbitMQ 能夠參考以前的文章
CentOs7.3 搭建 RabbitMQ 3.6 單機服務:
http://www.javashuo.com/article/p-hghklenn-mw.html
CentOs7.3 搭建 RabbitMQ 3.6 Cluster 集羣服務:
http://www.javashuo.com/article/p-mlnirdgd-gc.html
Spring Boot 中使用 RabbitMQ:
http://www.javashuo.com/article/p-ckhyrgdn-d.html
如下項目修改不作過多解釋,部分代碼再也不展現,請閱讀上篇文章,Spring Cloud(十)高可用的分佈式配置中心 Spring Cloud Config 中使用 Refresh:http://www.ymq.io/2017/12/23/spring-cloud-config-eureka-refresh/
把上一篇,示例代碼下載,才能夠進行一下的操做,下載地址在文章末尾
spring-cloud-eureka-service
spring-cloud-config-server
spring-cloud-eureka-provider-1
spring-cloud-eureka-provider-2
spring-cloud-eureka-provider-3
spring-cloud-feign-consumer
在項目spring-cloud-config-server
進行如下操做
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
在 application.properties
添加如下配置.關閉安全認證
RabbitMQ 的 ymq
用戶是手動建立的,具體閱讀上面 安裝RabbitMQ
部分
#關閉刷新安全認證 management.security.enabled=false spring.rabbitmq.host=192.168.252.126 spring.rabbitmq.port=5672 spring.rabbitmq.username=ymq spring.rabbitmq.password=123456
修改第上一篇文章項目
spring-cloud-eureka-provider-1
spring-cloud-eureka-provider-2
spring-cloud-eureka-provider-3
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
在 application.properties
添加如下配置.關閉安全認證
spring.rabbitmq.host=192.168.252.126 spring.rabbitmq.port=5672 spring.rabbitmq.username=ymq spring.rabbitmq.password=123456
啓動MQ服務
$ service rabbitmq-server start Redirecting to /bin/systemctl start rabbitmq-server.service
查看MQ狀態
$ service rabbitmq-server status
[root@node6 rabbitmq]# service rabbitmq-server status Redirecting to /bin/systemctl status rabbitmq-server.service ● rabbitmq-server.service - RabbitMQ broker Loaded: loaded (/usr/lib/systemd/system/rabbitmq-server.service; disabled; vendor preset: disabled) Active: active (running) since Fri 2017-12-29 17:44:10 CST; 9min ago Process: 2814 ExecStop=/usr/sbin/rabbitmqctl stop (code=exited, status=0/SUCCESS) Main PID: 2948 (beam) Status: "Initialized" CGroup: /system.slice/rabbitmq-server.service ├─2948 /usr/lib64/erlang/erts-8.0.3/bin/beam -W w -A 64 -P 1048576 -t 5000000 -stbt db -zdbbl 32000 -K true -- -root /usr/lib64/erlang -progname erl -- -home /var/lib/rabbitmq -- -pa /usr... ├─3131 /usr/lib64/erlang/erts-8.0.3/bin/epmd -daemon ├─3233 erl_child_setup 1024 ├─3240 inet_gethost 4 └─3241 inet_gethost 4 Dec 29 17:44:08 node6 rabbitmq-server[2948]: RabbitMQ 3.6.10. Copyright (C) 2007-2017 Pivotal Software, Inc. Dec 29 17:44:08 node6 rabbitmq-server[2948]: ## ## Licensed under the MPL. See http://www.rabbitmq.com/ Dec 29 17:44:08 node6 rabbitmq-server[2948]: ## ## Dec 29 17:44:08 node6 rabbitmq-server[2948]: ########## Logs: /var/log/rabbitmq/rabbit@node6.log Dec 29 17:44:08 node6 rabbitmq-server[2948]: ###### ## /var/log/rabbitmq/rabbit@node6-sasl.log Dec 29 17:44:08 node6 rabbitmq-server[2948]: ########## Dec 29 17:44:08 node6 rabbitmq-server[2948]: Starting broker... Dec 29 17:44:10 node6 rabbitmq-server[2948]: systemd unit for activation check: "rabbitmq-server.service" Dec 29 17:44:10 node6 systemd[1]: Started RabbitMQ broker. Dec 29 17:44:10 node6 rabbitmq-server[2948]: completed with 6 plugins. [root@node6 rabbitmq]#
按照順序依次啓動項目
spring-cloud-eureka-service
spring-cloud-config-server
spring-cloud-eureka-provider-1
spring-cloud-eureka-provider-2
spring-cloud-eureka-provider-3
spring-cloud-feign-consumer
啓動該工程後,訪問服務註冊中心,查看服務是否都已註冊成功:http://127.0.0.1:8761/
任何發送到Fanout Exchange
的消息都會被轉發到與該Exchange
綁定(Binding
)的全部springCloudBus
隊列Queue
上。
瀏覽器打開 :http://192.168.252.128:15672/
修改Git
倉庫配置,在 content=hello dev
後面加上 Spring Cloud Bus Test
經過 Postman
發送 GET
請求到:http://localhost:8888/springCloudConfig/dev/master 查看 Config Server
是不是最新的值
命令窗口,經過curl http://127.0.0.1:9000/hello
訪問服務,或者在瀏覽器訪問http://127.0.0.1:9000/hello
F5 刷新
發現沒有獲得最新的值
由於咱們沒有主動觸發Config Server bus/refresh
接口
經過 Postman
發送 POST
請求到:http://localhost:8888/bus/refresh ,咱們能夠看到如下內容:
注意是 PSOT
請求
三個Config Client
客戶端控制檯,分別會打印如下內容意思就是,收到遠程更新請求,config.client,KEYS
刷新, key
是 content
2017-12-29 18:38:49.023 INFO 28944 --- [jeTgrKRGzgj9g-1] o.s.cloud.bus.event.RefreshListener : Received remote refresh request. Keys refreshed [config.client.version, content] 2017-12-29 18:38:49.025 INFO 28944 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_EUREKA-PROVIDER/localhost:eureka-provider:8081: registering service... 2017-12-29 18:38:49.035 INFO 28944 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_EUREKA-PROVIDER/localhost:eureka-provider:8081 - registration status: 204 2017-12-29 18:38:49.067 INFO 28944 --- [jeTgrKRGzgj9g-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: SpringAMQP#31e87320:0/SimpleConnection@39151d4e [delegate=amqp://ymq@192.168.252.126:5672/, localPort= 64885]
訪問:http://localhost:8081/ ,http://localhost:8082/ ,http://localhost:8083/ 已經刷新了配置
如今雖然能夠不用重啓服務就更新配置了,但仍是須要咱們手動操做,這樣仍是不可取的。因此,這裏就要用到Git的webhooks來達到自動更新配置。
打開git上配置倉庫的地址,添加webhooks
,上面Payload URL
我寫的域名,固然我沒有部署,上面的Payload URL
就填寫咱們的配置中心觸發刷新的地址,固然這裏不能寫localhost
啦,要外網訪問地址才行。
還有這裏面有個Secret的祕鑰驗證,若是這裏填寫的話,在配置文件上要寫上encrypt.key
與之對應。
某些場景下(例如灰度發佈),咱們可能只想刷新部分微服務的配置,此時可經過/bus/refresh
端點的destination
參數來定位要刷新的應用程序。
例如:/bus/refresh?destination=customers:8000
,這樣消息總線上的微服務實例就會根據destination
參數的值來判斷是否須要要刷新。其中,customers:8000
指的是各個微服務的ApplicationContext ID
。
destination
參數也能夠用來定位特定的微服務。例如:/bus/refresh?destination=customers:**
,這樣就能夠觸發customers
微服務全部實例的配置刷新。
一些場景下,咱們可能但願知道Spring Cloud Bus
事件傳播的細節。此時,咱們能夠跟蹤總線事件(RemoteApplicationEvent
的子類都是總線事件)。
跟蹤總線事件很是簡單,只需設置spring.cloud.bus.trace.enabled=true
,這樣在/bus/refresh
端點被請求後,訪問/trace
端點就可得到相似以下的結果:
發送 GET
請求到:http://localhost:8888/trace
[ { "timestamp": 1514543931362, "info": { "method": "GET", "path": "/eureka-provider/dev/master", "headers": { "request": { "accept": "application/json, application/*+json", "user-agent": "Java/1.8.0_112", "host": "localhost:8888", "connection": "keep-alive" }, "response": { "X-Application-Context": "config-server:8888", "Content-Type": "application/json;charset=UTF-8", "Transfer-Encoding": "chunked", "Date": "Fri, 29 Dec 2017 10:38:51 GMT", "status": "200" } }, "timeTaken": "6002" } }, { "timestamp": 1514543927451, "info": { "method": "GET", "path": "/eureka-provider/dev/master", "headers": { "request": { "accept": "application/json, application/*+json", "user-agent": "Java/1.8.0_112", "host": "localhost:8888", "connection": "keep-alive" }, "response": { "X-Application-Context": "config-server:8888", "Content-Type": "application/json;charset=UTF-8", "Transfer-Encoding": "chunked", "Date": "Fri, 29 Dec 2017 10:38:47 GMT", "status": "200" } }, "timeTaken": "4927" } }, { "timestamp": 1514543925254, "info": { "method": "GET", "path": "/eureka-provider/dev/master", "headers": { "request": { "accept": "application/json, application/*+json", "user-agent": "Java/1.8.0_112", "host": "localhost:8888", "connection": "keep-alive" }, "response": { "X-Application-Context": "config-server:8888", "Content-Type": "application/json;charset=UTF-8", "Transfer-Encoding": "chunked", "Date": "Fri, 29 Dec 2017 10:38:45 GMT", "status": "200" } }, "timeTaken": "2862" } }, { "timestamp": 1514543923565, "info": { "method": "POST", "path": "/bus/refresh", "headers": { "request": { "cache-control": "no-cache", "postman-token": "0e497ec1-0c03-4dc2-bb61-ce2a266227d3", "user-agent": "PostmanRuntime/7.1.1", "accept": "*/*", "host": "127.0.0.1:8888", "accept-encoding": "gzip, deflate", "content-length": "0", "connection": "keep-alive" }, "response": { "X-Application-Context": "config-server:8888", "status": "200" } }, "timeTaken": "6616" } } ]
GitHub:https://github.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-config-bus-rabbitMQ
碼雲:https://gitee.com/souyunku/spring-cloud-examples/tree/master/spring-cloud-config-bus-rabbitMQ