发布订阅(pub/sub)是一种消息通信模式,主要的目的是解耦消息发布者和消息订阅者之间的
耦合,这点和设计模式中的观察者模式比较相似。pub/sub 不仅仅解决发布者和订阅者直接代码级别耦合也解决两者在物理部署上的耦合。redis 作为一个pub/sub 的server,在订阅者和发布者之间起到了消息路由的功能。订阅者可以通过subscribe 和psubscribe 命令向redisserver 订阅自己感兴趣的消息类型,redis 将消息类型称为通道(channel)。当发布者通过publish 命令向redis server 发送特定类型的消息时。订阅该消息类型的全部client 都会收到此消息。这里消息的传递是多对多的。一个client 可以订阅多个channel,也可以向多个channel发送消息。下面做个实验。这里使用3 不同的client, client1 用于订阅tv1 这个channel 的消息,client2用于订阅tv1 和tv2 这2 个chanel 的消息,client3 用于发布tv1 和tv2 的消息。Client1:
Client2:
Client3:
下面看Client1和Client2的接收情况:
Client1和Client2都收到了tv1的消息,然后我们再使用Client3发布一条消息:
看看Clien1,Client2的接收情况
下面将详细的解释一下上面的例子
1、client1 订阅了tv1 这个channel 这个频道的消息,client2 订阅了tv1 和tv2 这2 个频道的消息2、client3 是用于发布tv1 和tv2 这2 个频道的消息发布者3、接下来我们在client3 发布了一条消息”publish tv1 program1”,大家可以看到这条消息是发往tv1 这个频道的4、理所当然的client1 和client2 都接收到了这个频道的消息5、 然后client3 又发布了一条消息”publish tv2 program2”,这条消息是发往tv2 的,由于client1 并没有订阅tv1,所以client1 的结果中并没有显示出任何结果,但client2 订阅了这个频道,所以client2 是会有返回结果的。我们也可以用psubscribe tv*的方式批量订阅以tv 开头的频道的内容。看完这个小例子后应该对pub/sub 功能有了一个感性的认识。需要注意的是当一个连接通过subscribe 或者psubscribe 订阅通道后就进入订阅模式。在这种模式除了再订阅额外的通道或者用unsubscribe 或者punsubscribe 命令退出订阅模式,就不能再发送其他命令。另外使用psubscribe 命令订阅多个通配符通道,如果一个消息匹配上了多个通道模式的话,会多次收到同一个消息。
Pipeline 批量发送请求
redis 是一个cs 模式的tcp server,使用和http 类似的请求响应协议。一个client 可以通过一
个socket 连接发起多个请求命令。每个请求命令发出后client 通常会阻塞并等待redis 服务处理,redis 处理完后请求命令后会将结果通过响应报文返回给client。基本的通信过程如下:Client: INCR XServer: 1Client: INCR XServer: 2Client: INCR XServer: 3Client: INCR XServer: 4
基本上四个命令需要8 个tcp 报文才能完成。由于通信会有网络延迟,假如从client 和server
之间的包传输时间需要0.125 秒。那么上面的四个命令8 个报文至少会需要1 秒才能完成。这样即使redis 每秒能处理100 个命令,而我们的client 也只能一秒钟发出四个命令。这显示没有充分利用redis 的处理能力,怎么样解决这个问题呢? 我们可以利用pipeline 的方式从client 打包多条命令一起发出,不需要等待单条命令的响应返回,而redis 服务端会处理完多条命令后会将多条命令的处理结果打包到一起返回给客户端。通信过程如下Client: INCR XClient: INCR XClient: INCR XClient: INCR XServer: 1Server: 2Server: 3Server: 4
假设不会因为tcp 报文过长而被拆分。可能两个tcp 报文就能完成四条命令,client 可以将四
个incr 命令放到一个tcp 报文一起发送,server 则可以将四条命令的处理结果放到一个tcp报文返回。通过pipeline 方式当有大批量的操作时候,我们可以节省很多原来浪费在网络延迟的时间,需要注意到是用pipeline 方式打包命令发送,redis 必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。具体多少合适需要根据具体情况测试。具体是否使用pipeline 必须要基于大家手中的
网络情况来决定,不能一切都按最新最好的技术来实施,因为它有可能不是最适合你的。