1.redis自带的发布订阅模式
缺点:
首先这些消息并没有持久化机制,属于即发即弃模式。也就是说它们不能像ActiveMQ中的消息那样保证持久化消息订阅者不会错过任何消息,无论这些消息订阅者是否随时在线。最重要的是在应用开发中如何保证双发都在线的长连接状态?因为Redis的监听其实是打开了一个长连接操作的。任何网络波动都会断开的。
也是由于即发即弃的消息模式,所以Redis也没有必要专门对使用订阅/发布功能的客户端连接进行识别,用来明确该客户端连接的ID是否在之前已经连接过Redis服务了。ActiveMQ中保持持续通知的功能的前提,就是能够识别客户端连接ID的历史连接情况,以便确定哪些订阅消息这个客户端还没有处理。
分布式消息系统中,如何避免消息重复?
造成消息重复的根本原因是:网络不可靠。只要通过网络交换数据,就无法避免这个问题。所以解决这个问题的办法就是绕过这个问题。那么问题就变成了:如果消费端收到两条一样的消息,应该怎样处理?
a. 消费端处理消息的业务逻辑保持幂等性;
b. 保证每条消息都有唯一编号且保证消息处理成功与去重表的日志同时出现。
通过幂等性,不管来多少条重复消息,可以实现处理的结果都一样。再利用一张日志表来记录已经处理成功的消息的ID,如果新到的消息ID已经在日志表中,那么就可以不再处理这条消息,避免消息的重复处理。
/**
*发布
*/
@Service("publishToRedisService")
public class PublishToRedisServiceImpl implements PublishToRedisService {
private static final Logger LOGGER = LoggerFactory.getLogger(PublishToRedisServiceImpl.class);
@Autowired
private RedisTemplate<Serializable, Serializable> redisTemplate;
@Override
public void publish(String topic, JSONObject message) {
LOGGER.info("PublishToRedisServiceImpl.publish topic={}, message={}",topic,JSONObject.toJSONString(message));
RedisTemplate<Serializable, Serializable> redisTemplate = this.redisTemplate;
String json = JSONObject.toJSONString(message);
try{
redisTemplate.convertAndSend(topic, json);
redisTemplate.
}catch (Exception e){
LOGGER.error("redisTemplate.convertAndSend error",e);
}
}
}
/**
*接收
*/
public class SubscribeService implements MessageListener {
private static final Logger logger = LoggerFactory.getLogger(SubscribeService.class);
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public void onMessage(final Message message, final byte[] pattern ) {
logger.info("=====================>>>>>>>>>>>>>>>>>>>>>>");
logger.info("Message received: " + message.toString());
}
}
2.队列的方法
用redis的list数据结构 实现先进先出队列
//如果队列为空,阻塞等待数据
List<String> list = jedis.blpop(0,topic);
启动队列
/**
* 程序启动后执行该方法
*
*/
@Component
public class PollQueueInit implements CommandLineRunner {
@Autowired
private PollQueueService pollQueueService;
@Override
public void run(String... args) {
new Thread(()->
pollQueueService.pollQueue()
).start();
}
}