Java Spring boot 整合RabbitMQ(二):工作佇列(Work queues)-B2B2C小程式電子商務
現在,我們將傳送一些字串,把這些字串當作複雜的任務。我們並沒有一個真實的複雜任務,類似於圖片大小被調整或 pdf 檔案被渲染,所以我們透過 sleep () 方法來模擬這種情況。我們在字串中加上點號(.)來表示任務的複雜程度,一個點(.)將會耗時 1 秒鐘。比如 “Hello…” 就會耗時 3 秒鐘。
如果您尚未設定專案,請參閱第一個教程中的設定。我們將遵循與第一個教程相同的模式:建立一個包(tut2)並建立 Tut2Config、Tut2Receiver 和 Tut2Sender。
程式碼整合
首先建立一個新的包(tut2),我們將在這裡放置我們的三個類。在配置類 Tut2Config 中,我們設定了兩個配置檔案 ——tut2 和 work-queues。我們利用 Spring 來將佇列 Queue 暴露為一個 bean。我們配置消費者,並定義兩個 bean 以對應於上圖中的工作程式 receiver1 和 receiver2。
配置類
@Profile({"tut2", "work-queues"}) @Configuration public class Tut2Config { @Bean public Queue queue() { return new Queue("work-queues"); } /** * 定義兩個消費者,並且給了他們不同的標識 */ @Profile ("receiver") private static class ReceiverConfig { @Bean public Tut2Receiver receiver1() { return new Tut2Receiver(1); } @Bean public Tut2Receiver receiver2() { return new Tut2Receiver(2); } } @Profile("sender") @Bean public Tut2Sender sender() { return new Tut2Sender(); } }
生產者
我們簡單修改一下生產者的程式碼,以新增點號(.)的方式來人為的增加該任務的時長,字串中的每個點號(.)都會增加 1s 的耗時。
public class Tut2Sender { @Autowired private AmqpTemplate template; @Autowired private Queue queue; int dots = 0; int count = 0; @Scheduled(fixedDelay = 1000, initialDelay = 500) public void send(){ StringBuilder builder = new StringBuilder("Hello"); if (dots++ == 3) { dots = 1; } for (int i = 0; i < dots; i++) { builder.append('.'); } builder.append(Integer.toString(++count)); String message = builder.toString(); template.convertAndSend(queue.getName(), message); System.out.println(" [x] Sent '" + message + "'"); } }
消費者
我們的消費者 Tut2Receiver 透過 doWork () 方法模擬了一個耗時的虛假任務,它需要為訊息體中每一個點號(.)模擬 1 秒鐘的操作。並且我們為消費者增加了一個例項編號,以知道是哪個例項消費了訊息和處理的時長。
@RebbitListener(queues = "work-queues") public class Tut2Receiver { private int instance; public Tut2Receiver(int instance) { this.instance = instance; } @RabbitHandler public void receive(String in) throws InterruptedException { StopWatch watch = new StopWatch(); watch.start(); System.out.println("instance " + this.instance + " [x] Received '" + in + "'"); doWork(in); watch.stop(); System.out.println("instance " + this.instance + " [x] Done in " + watch.getTotalTimeSeconds() + "s"); } private void doWork(String in) throws InterruptedException { for (char ch : in.toCharArray()) { if (ch == '.') { Thread.sleep(1000); } } } }
執行
maven 編譯
mvn clean package -Dmaven.test.skip=true
執行
java -jar target/rabbitmq-tutorial-0.0.1-SNAPSHOT.jar --spring.profiles.active=tut2,sender --tutorial.client.duration=60000
java -jar target/rabbitmq-tutorial-0.0.1-SNAPSHOT.jar --spring.profiles.active=tut2,receiver --tutorial.client.duration=60000
輸出
// Sender
Ready … running for 10000ms
[x] Sent ‘Hello.1’
[x] Sent ‘Hello…2’
[x] Sent ‘Hello…3’
[x] Sent ‘Hello.4’
[x] Sent ‘Hello…5’
[x] Sent ‘Hello…6’
[x] Sent ‘Hello.7’
[x] Sent ‘Hello…8’
[x] Sent ‘Hello…9’
// Receiver
Ready … running for 10000ms
instance 1 [x] Received ‘Hello.1’
instance 2 [x] Received ‘Hello…2’
instance 1 [x] Done in 1.005s
instance 1 [x] Received ‘Hello…3’
instance 2 [x] Done in 2.007s
instance 2 [x] Received ‘Hello.4’
instance 2 [x] Done in 1.005s
instance 1 [x] Done in 3.01s
instance 1 [x] Received ‘Hello…5’
instance 2 [x] Received ‘Hello…6’
instance 1 [x] Done in 2.006s
instance 1 [x] Received ‘Hello.7’
instance 1 [x] Done in 1.002s
instance 1 [x] Received ‘Hello…9’
instance 2 [x] Done in 3.01s
instance 2 [x] Received ‘Hello…8’
prefetch
從消費者這端的輸出可以看出來,instance 1 得到的任務編號始終是奇數(Hello.1,Hello…3,Hello…5,Hello.7),而 instance 2 得到的任務編號始終是偶數。瞭解springcloud架構可以加求求:三五三六二四七二五九
如果感覺這次的輸出只是巧合,可以多試幾次或透過 --tutorial.client.duration= 調整時長得到更多的輸出,而結果肯定都是一樣的。
這裡設計的問題就是之前在基礎概念裡講到的排程策略的問題了。要實現公平排程(Fair dispatch)就是設定 prefetch 的值,實現方式有兩種。
全域性設定
在 application.yml 中設定 spring.rabbitmq.listener.simple.prefetch=1 即可,這會影響到本 Spring Boot 應用中所有使用預設 SimpleRabbitListenerContainerFactory 的消費者。
網上很多人說改配置 pring.rabbitmq.listener.prefetc,實測已經無效,應該是版本的問題。我所使用的版本(RabbitMQ:3.7.4,Spring Boot: 2.0.1.RELEASE),除了 spring.rabbitmq.listener.simple.prefetch,還有一個 spring.rabbitmq.listener.direct.prefetch 可以配置。
改了配置後再執行,可以看到 instance 1 可以獲取到”Hello…6”、”Hello…12” 了。
Ready … running for 60000ms
instance 1 [x] Received ‘Hello.1’
instance 2 [x] Received ‘Hello…2’
instance 1 [x] Done in 1.004s
instance 1 [x] Received ‘Hello…3’
instance 2 [x] Done in 2.008s
instance 2 [x] Received ‘Hello.4’
instance 2 [x] Done in 1.004s
instance 2 [x] Received ‘Hello…5’
instance 1 [x] Done in 3.012s
instance 1 [x] Received ‘Hello…6’
instance 2 [x] Done in 2.007s
instance 2 [x] Received ‘Hello.7’
instance 2 [x] Done in 1.004s
instance 2 [x] Received ‘Hello…8’
instance 1 [x] Done in 3.011s
instance 1 [x] Received ‘Hello…9’
instance 2 [x] Done in 2.007s
instance 2 [x] Received ‘Hello.10’
instance 2 [x] Done in 1.006s
instance 2 [x] Received ‘Hello…11’
instance 1 [x] Done in 3.01s
instance 1 [x] Received ‘Hello…12’
特定消費者
上邊是改了全域性的消費者,如果只針對特定的消費者的話,又怎麼處理呢?
我們可以透過自定義 RabbitListenerContainerFactory 來實現。
@Bean public RabbitListenerContainerFactory<SimpleMessageListenerContainer> prefetchOneRabbitListenerContainerFactory(ConnectionFactory rabbitConnectionFactory) { SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory(); factory.setConnectionFactory(rabbitConnectionFactory); factory.setPrefetchCount(1); return factory; }
然後在特定的消費者上指定 containerFactory
@RebbitListener(queues = "hello", containerFactory = "prefetchTenRabbitListenerContainerFactory") public void receive(String in) { System.out.println(" [x] Received '" + in + "'") }
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952307/viewspace-2678699/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Java Spring boot 整合RabbitMQ(三):(Publish/Subscribe)-B2B2C小程式電子商務JavaSpring BootMQ
- Java Spring Boot 整合RabbitMQ(一):Hello World -B2B2C小程式電子商務JavaSpring BootMQ
- Java Spring boot 整合RabbitMQ(五):主題(Topics)-B2B2C小程式電子商務JavaSpring BootMQ
- RabbitMQ(二)JavaClient SpringBoot整合 Work queuesMQJavaclientSpring Boot
- Java Springboot整合RabbitMQ(六):(RPC)-b2b2c小程式電子商務JavaSpring BootMQRPC
- Java Springboot 整合RabbitMQ(四):路由(Routing)-B2B2C小程式電子商務JavaSpring BootMQ路由
- 每日一學:你知道如何在 RabbitMQ 中實現 Work queues工作佇列模式嗎?MQ佇列模式
- JAVA spring cloud boot b2b2c電子商務分散式微服務JavaSpringCloudboot分散式微服務
- java Spring Cloud b2b2c o2o 電子商務 Eureka【Finchley 版】-b2b2c小程式電子商務JavaSpringCloud
- Spring Boot(十四)RabbitMQ延遲佇列Spring BootMQ佇列
- RabbitMQ學習筆記-Work QueuesMQ筆記
- SpringCloud分散式微服務b2b2c電子商務(十三)Springboot整合RabbitMQGCCloud分散式微服務Spring BootMQ
- java版 spring cloud spring boot mybatis實現 b2b2c 多商戶電子商務平臺JavaCloudSpring BootMyBatis
- java B2B2C Springboot電子商城系統-訊息佇列之 RabbitMQJavaSpring Boot佇列MQ
- Spring Boot整合rabbitmqSpring BootMQ
- Spring Boot 整合 rabbitmqSpring BootMQ
- Laravel RabbitMQ 工作佇列LaravelMQ佇列
- JAVA商城 B2B2C商城系統 小程式 電子商務 springcloud商城JavaSpringGCCloud
- java B2B2C springmvc mybatis電子商務平臺原始碼-訊息佇列之RocketMQJavaSpringMVCMyBatis原始碼佇列MQ
- spring cloud spring boot 構建java版 分散式微服務 b2b2c o2o電子商務雲商平臺CloudSpring BootJava分散式微服務
- 電子商務Java微服務 SpringBoot整合SpringSecurityJava微服務Spring BootGse
- Springcloud分散式微服務b2b2c電子商務一整合Hystrix(二)SpringGCCloud分散式微服務
- spring boot-整合RabbitMq(RabbitMq基礎)Spring BootMQ
- Spring Boot 整合 RabbitMQ 訊息事務(消費者)Spring BootMQ
- RabbitMQ 入門 - 工作佇列MQ佇列
- SpringCloud分散式微服務b2b2c電子商務-Spring Boot配置檔案詳解GCCloud分散式微服務Spring Boot
- (十四)JAVA springboot微服務b2b2c電子商務系統- Spring Cloud構建分散式電子商務平臺JavaSpring Boot微服務Cloud分散式
- spring cloud構建java版 b2b2c電子商務雲商平臺SpringCloudJava
- spring cloud+spring boot 電子商務-spring boot 引用方式${}和@@用法與區別CloudSpring Boot
- JAVA b2b2c電子商務SpringCloud分散式微服務spring-security-基本JavaSpringGCCloud分散式微服務
- RabbitMQ(三):RabbitMQ與Spring Boot簡單整合MQSpring Boot
- spring cloud+spring boot 電子商務spring boot獲取配置檔案的屬性CloudSpring Boot
- spring-boot-route(十三)整合RabbitMQSpringbootMQ
- java B2B2C電子商務平臺分析之七-Spring Cloud ConfigJavaSpringCloud
- java B2B2C原始碼電子商務平臺---大話Spring CloudJava原始碼SpringCloud
- Spring Boot 揭祕與實戰(六) 訊息佇列篇 – RabbitMQSpring Boot佇列MQ
- Next.js+Spring boot開源電子商務專案JSSpring Boot
- java B2B2C springmvc mybatis電子商務平臺原始碼-Spring Cloud SecurityJavaSpringMVCMyBatis原始碼Cloud