解决错误 lombok依赖版本不兼容导致,pojo实体类中的data等注解影响报错
java: java.lang.NoSuchFieldError: Class com.sun.tools.javac.tree.JCTree$JCImport does not have member field ‘com.sun.tools.javac.tree.JCTree qualid’
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
面试题,rocket如何去重
发送放需要给消息写带一个唯一标记(自己业务控制),消费者方需要控制消息的幂等性。
建立一个去重表,对于我们特定的字段加上唯一索引,然后消息一过来,直接插入,如果插入失败就代表已经消费过这个消息了(如果先判断的话,就不能保证原子性了,所以我们直接先新增,如果重复就会失败)
(我们设计一个去重表,对消息的唯一key添加唯一索引,每次消费消息的时候,先插入数据库,如果成功则执行业务逻辑,如果插入失败,则说明消息来过了,直接签收了)
上代码!
@SpringBootTest
class ARocketmqDemo1ApplicationTests {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
void sendMessage() throws Exception {
DefaultMQProducer producer = new DefaultMQProducer("repeatA-producer-group");
producer.setNamesrvAddr("192.168.88.128:9876");
producer.start();
String key = UUID.randomUUID().toString();
Message message = new Message("repeatOptic", null, key, "扣减库存-1".getBytes());
SendResult sendResult = producer.send(message);
System.out.println("发送结果: " + sendResult);
producer.shutdown();
}
@Test
void receiveMessage() throws Exception {
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("repeatA-consumer-group");
consumer.setNamesrvAddr("192.168.88.128:9876");
consumer.subscribe("repeatOptic", "*");
consumer.registerMessageListener((List<MessageExt> msgs, ConsumeConcurrentlyContext context) -> {
for (MessageExt messageExt : msgs) {
System.out.println("收到消息 key: " + messageExt.getKeys());
System.out.println("消息内容: " + new String(messageExt.getBody()));
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
});
consumer.start();
System.in.read(); // 让消费者保持运行
}
}
消费重复
消息的结构:
/**
* 重试机制
* 1.重试的延时间隔:10s,20s,30s,1m,2m,3m,4m,5m,6m,7m,8m,9m,10m,20m,30m,1h,2h,3h,4h,5h,6h,7h,8h,9h,10h,20h,1d,
* 分级别的重试,重试次数为16次(一般五六次)
* 如果重试16次后,还是失败,则进入死信队列(并发模式) 顺序模式下(int最大值次)都是失败的 是一个死信消息
*则会放到一个死信主题中%DLQ%+你的组名
* 2.能否自定义重试次数
*
* 3.当消息重试次数达到16次后,进入死信队列,死信队列可以用来做消息的补偿
*
*------------------
* 重试的次数一般写5次
*/
public class IRetryTest {
@Test
public void retryProducer() throws Exception{
DefaultMQProducer producer = new DefaultMQProducer("retry-producer-group");
producer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
producer.start();
//生产者发送消息,重试次数 2(默认值)
producer.setRetryTimesWhenSendFailed(2);
producer.setRetryTimesWhenSendAsyncFailed(2);
String key = UUID.randomUUID().toString();
System.out.println("key:"+key);
Message message = new Message("retryTopic", "VIP1", key, "我是VIP11111111".getBytes());
producer.send(message);
System.out.println("发送成功");
producer.shutdown();
}
@Test
public void retryConsumer1() throws Exception{
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("retry-consumer-group");//消费者组名,信息会一个组一份
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("retryTopic","*" );//订阅不同的消息
//设定重试次数
consumer.setMaxReconsumeTimes(2);
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt messageExt = msgs.get(0);
System.out.println(new Date());
System.out.println("消费消息:" + new String(messageExt.getBody()));
//打印重试的次数 重试从第二次开始
System.out.println(messageExt.getReconsumeTimes());
//业务报错了 返回null 返回 RECONSUME_LATER 都会重试
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
});
consumer.start();
System.in.read();
}
直接监听死信队列
@Test
public void retryDeadConsumer1() throws Exception{
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("retry-dead-consumer-group");//消费者组名,信息会一个组一份
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("%DLQ%retry-consumer-group","*" );//订阅不同的消息
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt messageExt = msgs.get(0);
System.out.println(new Date());
System.out.println("消费消息:" + new String(messageExt.getBody()));
System.out.println("记录到特别的位置 文件 mysql 通知人工处理");
//业务报错了 返回null 返回 RECONSUME_LATER 都会重试
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.in.read();
}
/**
* 第二种方案 用的多
* @throws Exception
*/
@Test
public void retryConsumer2() throws Exception{
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("retry-consumer-group");//消费者组名,信息会一个组一份
consumer.setNamesrvAddr(MqConstant.NAME_SRV_ADDR);
consumer.subscribe("retryTopic","*" );//订阅不同的消息
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
MessageExt messageExt = msgs.get(0);
System.out.println(new Date());
try {
handleDb();
}catch (Exception e){
//重试
int reconsumeTimes = messageExt.getReconsumeTimes();
if (reconsumeTimes<=3){
//不要重试了
System.out.println("重试次数超过3次了,记录到数据库,人工处理");
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
//业务报错了 返回null 返回 RECONSUME_LATER 都会重试
return ConsumeConcurrentlyStatus.RECONSUME_LATER;
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
private void handleDb() {
int i = 10 / 0;
}
});
consumer.start();
System.in.read();
}
}