springcloud微服務(wù)實戰(zhàn) 學(xué)習(xí)筆記八 消息總線

springboot整合RabbitMQ

  • 安裝rabbitmq
  • 進(jìn)入cmd進(jìn)入D:\RabbitMQ Server\rabbitmq_server-3.6.10\sbin
  • 執(zhí)行rabbitmq-plugins enable rabbitmq_management
  • 打開瀏覽器并訪問:http://localhost:15672/
  • 默認(rèn)賬戶密碼都為guest

創(chuàng)建項目
依賴

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.4.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

配置文件

spring.application.name=rabbitmq-demo
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456

消息生產(chǎn)者

@Component
public class Sender {
    @Autowired
    private AmqpTemplate rabbitTemplate;
    public void send() {
        String context = "hello " + new Date();
        System.out.println("Sender : " + context);
        this.rabbitTemplate.convertAndSend("hello", context);
    }
}

消息消費者

@Component
@RabbitListener(queues = "hello")
public class Receiver {
    @RabbitHandler
    public void process(String hello) {
        System.out.println("Receiver : " + hello);
    }
}

rabbit配置

@Configuration
public class RabbitConfig {
    @Bean
    public Queue helloQueue() {
        return new Queue("hello");
    }
}

Application

@SpringBootApplication
public class HelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class, args);
    }
}

測試類

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {
    @Autowired
    private Sender sender;
    @Test
    public void hello() throws Exception {
        sender.send();
    }
}

springcloud整合RabbitMQ使用消息總線更新配置文件

添加依賴

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

配置文件添加

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456

發(fā)送post請求到localhost:2001/bus/refresh便可以刷新所有服務(wù)的配置

原理分析

我們通過使用Spring Cloud Bus與Spring Cloud Config的整合,并以RabbitMQ作為消息代理,實現(xiàn)了應(yīng)用配置的動態(tài)更新。


abc
abc

整個方案的架構(gòu)如上圖所示,其中包含了Git倉庫、Config Server、以及微服務(wù)“Service A”的三個實例,這三個實例中都引入了Spring Cloud Bus,所以他們都連接到了RabbitMQ的消息總線上。

當(dāng)我們將系統(tǒng)啟動起來之后,“Service A”的三個實例會請求Config Server以獲取配置信息,Config Server根據(jù)應(yīng)用配置的規(guī)則從Git倉庫中獲取配置信息并返回。

此時,若我們需要修改“Service A”的屬性。首先,通過Git管理工具去倉庫中修改對應(yīng)的屬性值,但是這個修改并不會觸發(fā)“Service A”實例的屬性更新。我們向“Service A”的實例3發(fā)送POST請求,訪問/bus/refresh接口。此時,“Service A”的實例3就會將刷新請求發(fā)送到消息總線中,該消息事件會被“Service A”的實例1和實例2從總線中獲取到,并重新從Config Server中獲取他們的配置信息,從而實現(xiàn)配置信息的動態(tài)更新。

而從Git倉庫中配置的修改到發(fā)起/bus/refresh的POST請求這一步可以通過Git倉庫的Web Hook來自動觸發(fā)。由于所有連接到消息總線上的應(yīng)用都會接受到更新請求,所以在Web Hook中就不需要維護所有節(jié)點內(nèi)容來進(jìn)行更新,從而解決了通過Web Hook來逐個進(jìn)行刷新的問題。

指定刷新范圍

上面的例子中,我們通過向服務(wù)實例請求Spring Cloud Bus的/bus/refresh接口,從而觸發(fā)總線上其他服務(wù)實例的/refresh。但是有些特殊場景下(比如:灰度發(fā)布),我們希望可以刷新微服務(wù)中某個具體實例的配置。

Spring Cloud Bus對這種場景也有很好的支持:/bus/refresh接口還提供了destination參數(shù),用來定位具體要刷新的應(yīng)用程序。比如,我們可以請求/bus/refresh?destination=customers:9000,此時總線上的各應(yīng)用實例會根據(jù)destination屬性的值來判斷是否為自己的實例名,若符合才進(jìn)行配置刷新,若不符合就忽略該消息。

destination參數(shù)除了可以定位具體的實例之外,還可以用來定位具體的服務(wù)。定位服務(wù)的原理是通過使用Spring的PathMatecher(路徑匹配)來實現(xiàn),比如:/bus/refresh?destination=customers:**,該請求會觸發(fā)customers服務(wù)的所有實例進(jìn)行刷新。

架構(gòu)優(yōu)化

既然Spring Cloud Bus的/bus/refresh接口提供了針對服務(wù)和實例進(jìn)行配置更新的參數(shù),那么我們的架構(gòu)也相應(yīng)的可以做出一些調(diào)整。在之前的架構(gòu)中,服務(wù)的配置更新需要通過向具體服務(wù)中的某個實例發(fā)送請求,再觸發(fā)對整個服務(wù)集群的配置更新。雖然能實現(xiàn)功能,但是這樣的結(jié)果是,我們指定的應(yīng)用實例就會不同于集群中的其他應(yīng)用實例,這樣會增加集群內(nèi)部的復(fù)雜度,不利于將來的運維工作,比如:我們需要對服務(wù)實例進(jìn)行遷移,那么我們不得不修改Web Hook中的配置等。所以我們要盡可能的讓服務(wù)集群中的各個節(jié)點是對等的。

因此,我們將之前的架構(gòu)做了一些調(diào)整,如下圖所示:

我們主要做了這些改動:

  • 在Config Server中也引入Spring Cloud Bus,將配置服務(wù)端也加入到消息總線中來。
  • /bus/refresh請求不在發(fā)送到具體服務(wù)實例上,而是發(fā)送給Config Server,并通過destination參數(shù)來指定需要更新配置的服務(wù)或?qū)嵗?/li>

通過上面的改動,我們的服務(wù)實例就不需要再承擔(dān)觸發(fā)配置更新的職責(zé)。同時,對于Git的觸發(fā)等配置都只需要針對Config Server即可,從而簡化了集群上的一些維護工作。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容