樓主在項目中需要實現分佈式lucene查詢,由於lucene的索引是存放在本地的。網上有很多方案實現起來相對比較複雜,故樓主爲了簡單化針對索引同步問題採用的方案是,如果某一結點發生索引的增刪改,通過rabbitmq通知所有lucene節點也進行本地的索引的更改。
fanout類型的exchange雖然可以通知所有隊列,但一個隊列只能綁定一個消費者(如果綁定多個消費者,只要有一個消費者消費了這個消息,其他的消費者就獲得不到這個消息了,至於手動ask經測試不行,具體原因沒有細看),然後受spring cloud bus的啓發,每個lucene實例都綁定一個獨立的隊列,所有的隊列綁定到同一個exchange,從而實現一對多通知的功能。
同時,考慮到上線和拓展的便捷性,要求隊列的添加和綁定全部動態自動完成。代碼邏輯不復雜,只是有些類不常用,網上的資料相對較少,故把完整源碼貼出來,供大家學習交流。代碼質量不高,如有錯誤歡迎大家及時指正!
package com.unionpay.wash.lucene_service.MQListener;
import com.rabbitmq.http.client.domain.QueueInfo;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.core.RabbitManagementTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.UUID;
@Component
public class MQListener implements CommandLineRunner {
@Autowired
private RabbitTemplate template;
@Autowired
private AmqpAdmin admin;
private static String queueName;
@Override
public void run(String... args) throws Exception {
RabbitManagementTemplate managementTemplate = new RabbitManagementTemplate();
String exchangeName = "lucene_exchange";
Exchange exchange = managementTemplate.getExchange(exchangeName);
if (exchange == null) {
managementTemplate.addExchange(new FanoutExchange(exchangeName));
}
List<QueueInfo> queues = managementTemplate.getClient().getQueues();
for (QueueInfo queueInfo : queues){
String s = queueInfo.getName();
String idleSince = queueInfo.getIdleSince();
if (queueInfo.getConsumerCount() == 0 && s.contains("lucene_index") && idleSince != null){
managementTemplate.deleteQueue(new Queue(s));
}
}
queueName = "lucene_index_"+UUID.randomUUID();
managementTemplate.addQueue(new Queue(queueName));
Binding binding = BindingBuilder.bind(new Queue(queueName)).to(new FanoutExchange(exchangeName));
admin.declareBinding(binding);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
while (true){
try{
Object o = template.receiveAndConvert(queueName,100);
if (o == null){
Thread.sleep(1000);
}else{
//TODO
}
}catch (InterruptedException e){
e.printStackTrace();
}catch (AmqpException e){
managementTemplate.addQueue(new Queue(queueName));
BindingBuilder.bind(new Queue(queueName)).to(new FanoutExchange(exchangeName));
}
}
}
});
thread.start();
}
}