发布与订阅
Redis提供了"发布、订阅"模式的消息机制,其中消息订阅者与发布者不直接通信,发布者向指定的频道(channel)发送消息,订阅者从频道拿取消息。
pubsub简单命令介绍
-
publish [频道] [消息] 如 publish test yu
-
subscribe [频道] 订阅某个频道的消息
-
pubsub numsub [频道] 查看订阅数
-
unsubscribe [频道] 取消订阅
-
psubscribe ch* 按模式订阅
-
punsubscribe ch* 按模式取消订阅
注意:这种方式是一种发送既忘的原则,如果发送时没有消费者订阅,消息就会丢失,pub/sub作为消息中间件时不能保证消息的可靠。保证消息的可靠性时,不能作为选择。Redis后续推出了Stream的发布订阅功能。
基于stream的发布与订阅
可以使用消费者群组来消费,last_delivered_id来标识该消费者群组消费到了消息的哪个位置。一个消费者群组内部消费者可以有多个,且一个消息仅能被一个消费者群组下面的一个消费者消费。消息的确认ACK,确保消息一定被消费成功。pending_ids[]标识消息已经被消费者拿到了,但是消费者还没有做应答,如果一直不做应答,这个pending_ids(Pending Entries List)会越来越长,不支持消费超时,死信队列。
消息id: 毫秒时间戳-序号 表示消息是在这个时间戳产生的第几个。
Message Conent: 消息内容,String
基于Stream的操作
-
xadd [stream] * [key] [value]…
*表示消息id由redis生成 stream 为stream名称,返回值为消息id,即使出现了时钟回拨,Last_generated_id 记录最大的id,会使-后面的数字+1,也不会导致重复。
-
xlen [stream] 查看stream中消息个数
-
xrange [stream] - + 查看stream中所有消息
-和+可以替换为对应的消息id
-
xdel [stream] [消息id] 删除stream中的指定消息
支持消费者群组,同时也支持单消费者,单消费者用来保证消息的顺序性。 -
xread count 1 streams [stream] 0-0 表示从头开始消费一条消息
-
xread count 1 streams [stream] 消息id 指定id开始
-
xread count 1 streams [stream] $ 从尾部读取消息
-
xread block 0 count 1 streams [stream] $ 阻塞式从尾部读取
消费者群组 -
xgroup create [stream] [group] 0-0
-
xgroup create [stream][group] $
-
xinfo groups [stream]
查看消费者群组的信息 -
xreadgroup GROUP [group] [consumer] count [n] streams [stream] >
创建一个消费者 group 消费者群组名称 , consumer 消费者名称 stream stream名称 > 从哪一个开始读取
xreadgroup GROUP cg1 c1 block 0 count 1 streams stream:test > 阻塞式读取
xinfo consumers [stream] [group]
查看消费者群组中的信息
-
xack [stream] [consumer] [消息id]
确认一条消息
-
xclaim 把消息在多个消费者之间转移
-
xpending [stream] [group] 查看未ack的消息
redis实现消息队列的方式
- 可通过队列实现 lpush brpop
@Component
public class ListVer {
public static final String RS_LIST_MQ_NS = "rs:list:mq";
@Autowired
private JedisPool jedisPool;
/**
* 发送消息
* @param key
* @param message
*/
public void put(String key, String message) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.lpush(RS_LIST_MQ_NS+key, message);
} catch (Exception ex) {
throw new RuntimeException("发送消息失败");
} finally {
jedis.close();
}
}
/**
* 获取消息
* @param key
* @return
*/
public List<String> get(String key){
Jedis jedis = null;
try{
jedis = jedisPool.getResource();
return jedis.brpop(0,RS_LIST_MQ_NS+key);
}catch (Exception ex){
throw new RuntimeException("获取消息失败");
}finally {
jedis.