[英]How to run spring batch jobs simultaneously which share same readers and writers instances?
這就是我現有系統的工作方式。
我有使用spring batch編寫的批處理,該批處理將消息異步地寫入隊列。 編寫者一旦將一定數量的消息發送到隊列,就開始收聽LINKED_BLOCKING_QUEUE以獲取相同數量的消息。
我有spring amqp偵聽器,它使用消息並對其進行處理。 處理后,使用者將回復返回到回復隊列。 有一些偵聽器,它們偵聽答復隊列以檢查消息是否被成功處理。 回復偵聽器檢索響應並將其添加到LINKED_BLOCKING_QUEUE中,然后由編寫者獲取。 一旦作者獲取所有答復,便完成批處理。 如果有異常,它將停止該批處理。
這是我的工作配置
<beans:bean id="computeListener" class="com.st.symfony.Foundation"
p:symfony-ref="symfony" p:replyTimeout="${compute.reply.timeout}" />
<rabbit:queue name="${compute.queue}" />
<rabbit:queue name="${compute.reply.queue}" />
<rabbit:direct-exchange name="${compute.exchange}">
<rabbit:bindings>
<rabbit:binding queue="${compute.queue}" key="${compute.routing.key}" />
</rabbit:bindings>
</rabbit:direct-exchange>
<rabbit:listener-container
connection-factory="rabbitConnectionFactory" concurrency="${compute.listener.concurrency}"
requeue-rejected="false" prefetch="1">
<rabbit:listener queues="${compute.queue}" ref="computeListener"
method="run" />
</rabbit:listener-container>
<beans:beans profile="master">
<beans:bean id="computeLbq" class="java.util.concurrent.LinkedBlockingQueue" />
<beans:bean id="computeReplyHandler" p:blockingQueue-ref="computeLbq"
class="com.st.batch.foundation.ReplyHandler" />
<rabbit:listener-container
connection-factory="rabbitConnectionFactory" concurrency="1"
requeue-rejected="false">
<rabbit:listener queues="${compute.reply.queue}" ref="computeReplyHandler"
method="onMessage" />
</rabbit:listener-container>
<beans:bean id="computeItemWriter"
class="com.st.batch.foundation.AmqpAsynchItemWriter"
p:template-ref="amqpTemplate" p:queue="${compute.queue}"
p:replyQueue="${compute.reply.queue}" p:exchange="${compute.exchange}"
p:replyTimeout="${compute.reply.timeout}" p:routingKey="${compute.routing.key}"
p:blockingQueue-ref="computeLbq"
p:logFilePath="${spring.tmp.batch.dir}/#{jobParameters[batch_id]}/log.txt"
p:admin-ref="rabbitmqAdmin" scope="step" />
<job id="computeJob" restartable="true">
<step id="computeStep">
<tasklet transaction-manager="transactionManager">
<chunk reader="computeFileItemReader" processor="computeItemProcessor"
writer="computeItemWriter" commit-interval="${compute.commit.interval}" />
</tasklet>
</step>
</job>
</beans:beans>
這是我的作者代碼,
public class AmqpAsynchRpcItemWriter<T> implements ItemWriter<T> {
protected String exchange;
protected String routingKey;
protected String queue;
protected String replyQueue;
protected RabbitTemplate template;
protected AmqpAdmin admin;
BlockingQueue<Object> blockingQueue;
String logFilePath;
long replyTimeout;
// Getters and Setters
@Override
public void write(List<? extends T> items) throws Exception {
for (T item : items) {
Message message = MessageBuilder
.withBody(item.toString().getBytes())
.setContentType(MessageProperties.CONTENT_TYPE_TEXT_PLAIN)
.setReplyTo(this.replyQueue)
.setCorrelationId(item.toString().getBytes()).build();
template.send(this.exchange, this.routingKey, message);
}
for (T item : items) {
Object msg = blockingQueue
.poll(this.replyTimeout, TimeUnit.MILLISECONDS);
if (msg instanceof Exception) {
admin.purgeQueue(this.queue, true);
throw (Exception) msg;
} else if (msg == null) {
throw new Exception("reply timeout...");
}
}
System.out.println("All items are processed.. Command completed. ");
}
}
偵聽器pojo
public class Foundation {
Symfony symfony;
long replyTimeout;
//Getters Setters
public Object run(String command) {
System.out.println("Running:" + command);
try {
symfony.run(command, this.replyTimeout);
} catch (Exception e) {
return e;
}
return "Completed : " + command;
}
}
這是回復處理程序
public class ReplyHandler {
BlockingQueue<Object> blockingQueue;
public void onMessage(Object msgContent) {
try {
blockingQueue.put(msgContent);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
現在,問題是,我想同時運行具有唯一批次ID的多個批次,這將為不同批次處理不同數據(相同類型)。
隨着將來批次數量的增加,我不想為每個批次繼續添加單獨的隊列和答復隊列。
而且,為了同時處理消息,我有多個偵聽器(設置有偵聽器並發性)正在監聽隊列。 如果我為不同批次添加不同的隊列,則會增加正在運行的偵聽器的數量,這可能會使服務器超負荷(CPU /內存使用率很高)。
因此,我不想為要添加的每種批次復制相同的基礎結構。 我想使用相同的基礎結構,只是特定批次的編寫者應該只獲得其響應,而不是同時運行的其他批次的響應。
我們是否可以使用項目編寫器的相同實例,對多個並行運行的批次實例使用相同的阻塞隊列實例?
您可能需要研究JMS消息選擇器 。
根據文檔
使用createConsumer和createDurableSubscriber方法,可以在創建消息使用者時將消息選擇器指定為參數。
然后,消息使用者僅接收其標題和屬性與選擇器匹配的消息。
在AMQP(RabbitMQ)世界中,沒有等效的JMS消息選擇器表達式。
每個使用者都必須有自己的隊列,並且您可以使用發送方設置的路由密鑰,通過交換機將其路由到適當的隊列。
它沒有您想像的那么繁重; 您不必靜態配置代理; 使用者可以使用RabbitAdmin
來RabbitAdmin
聲明/刪除交換,隊列和綁定。
請參閱Spring AMQP文檔中的配置代理 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.