StackExchange.Redis 系列 3:Pipelines and Multiplexers 说明

  • 本系列博文是“伪”官方文档翻译,并非完全将官方文档进行翻译,而是我在查阅、测试原始文档并转换为自己东西后进行的“准”翻译。
  • 原始文档见此:https://stackexchange.github.io/StackExchange.Redis/
  • 本系列本博文基于 redis 5.0.6,系列中部分博文跟官方文档有出入,有不同见解 / 说明不当的地方,还请大家不吝拍砖。

Pipeline

  • 在使用 Redis 的时候,大部分的耗时会集中在网络延时上,通过 Pipeline,可以把多次网络请求合并为 1 次,提高性能。

当你执行如下同步方法的时候:

string a = db.StringGet("a");
string b = db.StringGet("b");
  • 只有等你得到了 a 的值以后,获取 b 的值的请求才会发出去。

通过 Pipeline 机制,可以让你不需要等待前一次请求的结果后再进行请求。

  • .NET 下,通过 TPL(Tasl/Task) 来实现 Pipeline 效果,如下:

var aPending = db.StringGetAsync("a");
var bPending = db.StringGetAsync("b");
var a = db.Wait(aPending);
var b = db.Wait(bPending);

时序图:

Multiplexing

  • 有的时候我们会存在这样的业务场景:获取 a 的值,根据 a 的结果值再从 redis 服务器上获取 b,对于 Redis 原生命令而言,可以通过 BLPOP,PRPOP,PRPOPLPUSH 之类的命令来实现,但对于 StackExchange.Redis 而言,StackExchange官方并未提供这些原生命令特性,因为这些命令会阻塞整个线程。
  • 鉴于此,StackExchange.Redis 在单个连接上可以达到极高的吞吐量。
  • 如果你想要 BLPOP 这样的命令,可以通过 ”发布/订阅“的方式来变相实现,方式如下:

sub.Subscribe(channel, delegate {
    string work = db.ListRightPop(key);
    if (work != null) Process(work);
});
//...
db.ListLeftPush(key, newWork, flags: CommandFlags.FireAndForget);
sub.Publish(channel, "");
  • 通过这种方式可以实现无阻塞的效果。
    • 数据不是通过 pub/sub 来发送的,pub/sub API 只是用来通知 worker 去检查工作队列。
    • 如果没有 worker,则新项将会保持再缓冲列表中。
    • 只有 worker 可以 pop 值,当消费者数量大于生产者数量的时候,部分消费者虽然会被通知到,但什么事都不会去执行。
    • 当你重启一个 worker 的时候,应假设存在工作项以便可以让你处理挤压项。
    • 除上述外,语义和 BLPOP 相同。
      无论是同步请求还是异步请求,这些请求都会通过 Pipeline 进行

当不同的调用者同时使用它时,它会自动对单独的请求进行管道传输,因此,无论请求使用阻塞访问还是异步访问,工作都将通过管道进行。