RabbitMQ池化方案
private void sendKernel(Message message){
//使用线程池进行异步提交
AsyncBaseQueue.submit(new Runnable() {
@Override
public void run() {
String topic=message.getTopic();
String routingKey=message.getRoutingKey();
CorrelationData correlationData=new CorrelationData(
String.format("%s#%s", message.getMessageId(), System.currentTimeMillis())
);
rabbitTemplate.convertAndSend(topic,routingKey,message,null,correlationData);
log.info("#RabbitBrokerImpl.sendKernel# send to rabbitmq, messageid: {}",
message.getMessageId());
}
});
}
虽然实现了线程池,完成了多线程,但是RabbitTemplate是由Spring帮我们注入的,默认是单例的。所以,我们还需要把RabbitTemplate池化
@Slf4j
@Component
public class RabbitTemplateContainer implements RabbitTemplate.ConfirmCallback {
private Map<String /* TOPIC */, RabbitTemplate> rabbitMap = Maps.newConcurrentMap();
private Splitter splitter=Splitter.on("#");
/* 连接工厂 */
@Autowired
private ConnectionFactory connectionFactory;
public RabbitTemplate getTemplate(Message message) throws MessageRuntimeException {
Preconditions.checkNotNull(message);
String topic = message.getTopic();
RabbitTemplate rabbitTemplate = rabbitMap.get(topic);
if (rabbitTemplate != null) {
return rabbitTemplate;
}
log.info("#RabbitTemplateContainer.getTemplate# topic: {} is not exist, create one",topic);
RabbitTemplate newRabbitTemplate=new RabbitTemplate(connectionFactory);
newRabbitTemplate.setRetryTemplate(new RetryTemplate());
newRabbitTemplate.setRoutingKey(message.getRoutingKey());
newRabbitTemplate.setExchange(topic);
// TODO: 2020-02-27 对message的序列化方式
// newRabbitTemplate.setMessageConverter();
String messageType=message.getMessageType();
if(!MessageType.RAPID.equals(messageType)){
//需要设置callback
newRabbitTemplate.setConfirmCallback(this);
}
rabbitMap.put(topic,newRabbitTemplate);
return rabbitMap.get(topic);
}
@Override
public void confirm(CorrelationData correlationData, boolean b, String s) {
// TODO: 2020-02-27 具体的应答
List<String> strings=splitter.splitToList(correlationData.getId());
String messageId=strings.get(0);
long sendTime=Long.parseLong(strings.get(1));
if (b){
log.info("send message is OK, confirm messageId: {}, send time: {}",messageId,sendTime);
}else{
log.error("send message is Failed, confirm messageId: {}, send time: {}",messageId,sendTime);
}
}
}
实现消息异步提交的线程池
@Slf4j
public class AsyncBaseQueue {
public static final int THREAD_SIZE = Runtime.getRuntime().availableProcessors();
public static final int QUEUE_SIZE = 10000;
public static ExecutorService executorService =
new ThreadPoolExecutor(THREAD_SIZE, THREAD_SIZE, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(QUEUE_SIZE), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread();
t.setName("rabbitmq_client_async_sender");
return t;
}
}, new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
log.error("async sender is error rejected, runnable:{}, executor:{}",
r, executor);
}
});
public static void submit(Runnable r){
executorService.submit(r);
}
}
ThreadLocal实现RabbitMQ消息的批量发送
首先实现一个ThreadLocal类:
public class MessageHolder {
private List<Message> messages= new ArrayList<>();
@SuppressWarnings({"rawtypes","unchecked"})
public static final ThreadLocal<MessageHolder> holder=new ThreadLocal(){
@Override
protected Object initialValue() {
return new MessageHolder();
}
};
public static void add(Message message){
holder.get().messages.add(message);
}
public static List<Message> clear(){
List<Message> tmp=new ArrayList<>(holder.get().messages);
holder.remove();
return tmp;
}
}
# ProducerClient.class
@Override
public void send(List<Message> messages) throws MessageRuntimeException {
messages.forEach(message -> {
message.setMessageType(MessageType.RAPID);
MessageHolder.add(message);
});
rabbitBroker.sendMessages();
}
# RabbitBrokerImpl.class
@Override
public void sendMessages() {
List<Message> messages=MessageHolder.clear();
messages.forEach(message -> {
sendKernel(message);
});
}
之前的版本
把批量消息直接放到参数变量里
# ProducerClient.class
@Override
public void send(List<Message> messages) throws MessageRuntimeException {
messages.forEach(message -> {
message.setMessageType(MessageType.RAPID);
});
rabbitBroker.sendMessages(messages);
}
# RabbitBrokerImpl.class
@Override
public void sendMessages(List<Message> messages) {
messages.forEach(message -> {
sendKernel(message);
});
}