I. Introduction
We (six) distribution center (Git version and dynamic refresh) mentioned, if the client needs to get the latest configuration information needed to perform refresh
, we can use every mechanism Webhook code sends a request submitted to refresh the client, when the client end more and more, the need for each client to perform again, this program not for you. Use Spring Cloud Bus can be the perfect solution to this problem.
Spring Cloud Bus
Each distribution node via Spring Cloud Bus lightweight message broker. This change in status with the broadcast (e.g., configuration change) command, or other messages. Spring Bus a core idea is to extend the Spring Boot application distributed by the starter, it can also be used to establish a communication channel between multiple applications. The only way to achieve is to use Amqp message broker as a channel, the same set of characteristics (some depending on the channel settings) in the document more channels.
Spring Cloud Bus have been translated into many domestic message bus, but also very image. It can be understood as all distributed project management and dissemination of information can, in fact, the essence is to use a broadcast mechanism MQ spread messages in a distributed system, currently used have Kafka and RabbitMQ. The use of Bus mechanism can do a lot of things, where the configuration center client refresh one is a typical application scenarios, we Bus mechanisms used in the configuration center by a diagram to describe.
Second, combat
You need to download and install rabbit.
We chose the article (vii) distribution center (of service and high availability) sample code version to transform, MQ do we use RabbitMQ example.
Server
Add in pom.xml, the four is a must
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
application.yml follows
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/liazhan/test-cloud # 配置git仓库的地址
search-paths: config-repo # git仓库地址下的相对地址,可以配置多个,用,分割。
bus:
enabled: true
trace:
enabled: true
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
server:
port: 12000
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
management:
endpoints:
web:
exposure:
include: bus-refresh
Start class plus @EnableConfigServer
notes
package com.example.configservergit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@EnableConfigServer
@SpringBootApplication
public class ConfigServerGitApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerGitApplication.class, args);
}
}
Client
Add the following in the pom.xml dependency, the first five is a must, the last webflux you can use to replace the web
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
Here it is easy to miss spring-boot-starter-actuator
, if the lack of this, when executed on the server /actuator/bus-refresh
when the client can not receive information, Console will display the following information in (I'm trapped in here for a long time ......)
2018-04-19 18:50:05.711 INFO 39762 --- [vOu-GI8c8mJtQ-1] o.s.a.r.c.CachingConnectionFactory : Attempting to connect to: [localhost:5672]
2018-04-19 18:50:05.739 INFO 39762 --- [vOu-GI8c8mJtQ-1] o.s.a.r.c.CachingConnectionFactory : Created new connection: rabbitConnectionFactory.publisher#2bc15b3b:0/SimpleConnection@14eb0d5e [delegate=amqp://[email protected]:5672/, localPort= 60107]
2018-04-19 18:50:05.749 INFO 39762 --- [vOu-GI8c8mJtQ-1] o.s.amqp.rabbit.core.RabbitAdmin : Auto-declaring a non-durable, auto-delete, or exclusive Queue (springCloudBus.anonymous.bOoVqQuSQvOu-GI8c8mJtQ) durable:false, auto-delete:true, exclusive:true. It will be redeclared if the broker stops and is restarted while the connection factory is alive, but all messages will be lost.
application.yml follows
spring:
application:
name: config-git
cloud:
bus:
trace:
enabled: true
enabled: true
server:
port: 13000
bootstrap.yml follows
spring:
cloud:
config:
name: config-client # 对应 {application} 部分
profile: dev # 对应 {profile} 部分
label: master # 对应 {label} 部分,即 Git 的分支。如果配置中心使用的是本地存储,则该参数无用
discovery:
enabled: true
service-id: config-server
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
controller as follows
package com.example.configclient.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
@RestController
@RefreshScope
public class HelloController {
@Value("${neo.hello:error}")
private String profile;
@GetMapping("/info")
public Mono<String> hello(){
return Mono.justOrEmpty(profile);
}
}
@RefreshScope
Must be added, otherwise the client will receive an update message server, but can not be updated, because they do not know where the update.
As to start the main class, do not change the default generated, not posted.
Third, the test
We do not profile with rabbit-related configuration, springboot default configuration of the local rabbit.
Each start eureka, config-server and two config-client (13000,13001).
After starting, RabbitMQ will automatically create a topic and two types of Exchange at springCloudBus.anonymous.
the beginning of the anonymous Queue
We open HTTP: // localhost: 15672 , can be seen in the following figure
We visit http: // localhost: 13000 / info and http: // localhost: 13001 info / returns the contents are dev
.
Git configuration information in the dev
read dev bus
and executed
POST http://localhost:12000/actuator/bus-refresh/
If the reported 405 errors, you can be exposed to the configuration file configuration change it, do not know why. . . . To "*" on it
management:
endpoints:
web:
exposure:
include: "*"
Another visit http: // localhost: 13000 / info and http: // localhost: 13001 / info after then returns the content is modified dev bus
, indicating a success.
It is worth mentioning that, as long as the open Spring Cloud Bus, or whether it is config-server config-client performs /actuator/bus-refresh
all updates can all be configured.
Fourth, the partial refresh
Under certain scenarios (eg gray-release), we may want to refresh the configuration section micro services, this time through /actuator/bus-refresh/{destination}
to locate the application you want to refresh the destination endpoint parameters.
For example: /actuator/bus-refresh/customers:8000
such micro service instance on the message bus will be based on the value of the parameter to determine whether the destination need to be refreshed. Wherein, customers:8000
referring to each micro ApplicationContext ID services.
destination parameters may also be used to locate specific widget service. For example: /actuator/bus-refresh/customers:**
so that you can trigger micro-services customers all instances of configuration refresh.
Fifth, the tracking bus event
Under some scenarios, we may want to know the details of Spring Cloud Bus event propagation. At this point, we can track bus event (RemoteApplicationEvent subclasses are bus event).
Trace Bus event is very simple, just set spring.cloud.bus.trace.enabled=true
, so that /actuator/bus-refresh
the endpoint is requested, access to /actuator/httptrace
the endpoint should obtain results similar to the following:
{
"timestamp": 1495851419032,
"info": {
"signal": "spring.cloud.bus.ack",
"type": "RefreshRemoteApplicationEvent",
"id": "c4d374b7-58ea-4928-a312-31984def293b",
"origin": "stores:8002",
"destination": "*:**"
}
},
{
"timestamp": 1495851419033,
"info": {
"signal": "spring.cloud.bus.sent",
"type": "RefreshRemoteApplicationEvent",
"id": "c4d374b7-58ea-4928-a312-31984def293b",
"origin": "spring-cloud-config-client:8001",
"destination": "*:**"
}
},
{
"timestamp": 1495851422175,
"info": {
"signal": "spring.cloud.bus.ack",
"type": "RefreshRemoteApplicationEvent",
"id": "c4d374b7-58ea-4928-a312-31984def293b",
"origin": "customers:8001",
"destination": "*:**"
}
}
The log shows spring-cloud-config-client:8001
issued RefreshRemoteApplicationEvent event, broadcast to all the services, was customers:8001
and stores:8002
received a. Want message received customize your approach, you can add @EventListener
annotations AckRemoteApplicationEvent and SentApplicationEvent type into your own applications. TraceRepository class or to directly process the data.
In this way, we can clearly know the details of the incident spread.
but. . .
In my tests, it was found that the following results:
There is no information. . .
Learn from https://windmt.com/2018/04/19/spring-cloud-9-config-eureka-bus/