前端系统推送大批量数据进入我方系统进行处理, 为了减轻我方系统的压力, 并且充分发挥服务器的性能, 提高处理效率, 于是使用 Rabbit 做了限流处理, 同时有多线程运行多个消费者处理任务, 来提高效率
Rabbit配置类, 其余的基础配置配置都维护在配置文件或者配置中心
/***
* Rabbit配置类
* @author yanqiang.jiang
* @version 1.0
* @date 2019/08/26
**/
@Configuration
@Slf4j
public class RabbitConfig {
@Autowired
private CachingConnectionFactory connectionFactory;
@Autowired
private SimpleRabbitListenerContainerFactoryConfigurer factoryConfigurer;
/**
* 数据队列
*
* @return 队列
*/
@Bean
public Queue accoflowHs() {
return new Queue("testQueue");
}
/**
* 单一消费者
*
* @return SimpleRabbitListenerContainerFactory
*/
@Bean(name = "singleListenerContainer")
public SimpleRabbitListenerContainerFactory listenerContainer() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factory.setConnectionFactory(connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
factory.setConcurrentConsumers(1);
factory.setMaxConcurrentConsumers(1);
factory.setPrefetchCount(1);
factory.setTxSize(1);
factory.setAcknowledgeMode(AcknowledgeMode.AUTO);
return factory;
}
/**
* 多个消费者
*
* @return SimpleRabbitListenerContainerFactory
*/
@Bean(name = "multiListenerContainer")
public SimpleRabbitListenerContainerFactory multiListenerContainer() {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
factoryConfigurer.configure(factory, connectionFactory);
factory.setMessageConverter(new Jackson2JsonMessageConverter());
// 多消费者进行手工确认
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
// 默认消费者数量
factory.setConcurrentConsumers(10);
// 最大消费者数量
factory.setMaxConcurrentConsumers(15);
// 最大投递数
factory.setPrefetchCount(5);
return factory;
}
/**
* RabbitTemplate 配置
*
* @return RabbitTemplate
*/
@Bean
public RabbitTemplate rabbitTemplate() {
connectionFactory.setPublisherConfirms(true);
connectionFactory.setPublisherReturns(true);
RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
rabbitTemplate.setMandatory(true);
rabbitTemplate.setConfirmCallback((CorrelationData correlationData, boolean ack, String cause) -> {
log.info("消息发送成功:correlationData({}),ack({}),cause({})", correlationData, ack, cause);
}
);
rabbitTemplate.setReturnCallback((Message message, int replyCode, String replyText, String exchange, String routingKey) -> {
log.info("消息丢失:exchange({}),route({}),replyCode({}),replyText({}),message:{}", exchange, routingKey, replyCode, replyText, message);
}
);
return rabbitTemplate;
}
}
此处注意点:
factory.setMessageConverter(new Jackson2JsonMessageConverter());
发送的消息将会使用它来序列化
factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
必须开启手动确认模式
factory.setConcurrentConsumers(10);
和 factory.setMaxConcurrentConsumers(15);
这个表示消费者的数量, 也就是消费多线程运行的线程数目.
factory.setPrefetchCount(5);
每次取的消息的数目, 数目大效率高, 但是顺序越得不到保证
/***
* rabbit 生产者
* @author yanqiang.jiang
* @version 1.0
* @date 2019/08/26
**/
@Component
@Slf4j
public class AccoflowHsProducer {
@Autowired
private AmqpTemplate rabbitTemplate;
/**
* 发送信息
*
* @param batchNum 流水号
*/
public void stringSend(String batchNum) {
log.info("消息队列:{},发布消息:{}", "testQueue", batchNum);
// 第一个参数为刚刚定义的队列名称
this.rabbitTemplate.convertAndSend("testQueue",
MessageBuilder.withBody(batchNum.getBytes(StandardCharsets.UTF_8)).build());
}
}
/***
* rabbit 消费者
* @author yanqiang.jiang
* @version 1.0
* @date 2019/08/26
**/
@Component
@Slf4j
public class AccoflowHsConsumer {
@Autowired
private AccoflowInfHsHandler accoflowInfHsHandler;
/**
* 监听消费用户日志
*
* @param msg 消息
*/
@RabbitListener(queues = "testQueue" containerFactory = "multiListenerContainer")
public void recievedString(Message msg, Channel channel) throws Exception {
try {
log.info("来源事务落地通用消费者{}收到消息", channel.getChannelNumber());
PaTransactionTask task = JSON.parseObject(msg.getBody(), PaTransactionTask.class);
log.info("来源事务落地通用消费者{}解析消息:{}", channel.getChannelNumber(), task.getPlanControlId());
// 这里最好添加重复执行判断
// 处理来源事务
runner.excuteTransaction(task);
} catch (Exception e) {
log.info("来源事务落地通用消费者{}出错", channel.getChannelNumber());
e.printStackTrace();
}
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), true);
log.info("来源事务落地通用消费者{}确认消", channel.getChannelNumber());
}
}
注意:
channel.basicAck(msg.getMessageProperties().getDeliveryTag(), true);
处理完毕后一定要确认消息, 不然不会继续处理下个消息. 同时考虑异常的情况,也要手工确认
采取手动确认后处理完成后才会确认,这里处理时间可能比较长, 这个时候消息超时server会向消费者再次发送消息, 所以这里建议添防重复处理。防止重复消费消息。