我如何实现Redis管道请求与Booksleeve

本文关键字:管道 Redis 请求 Booksleeve 实现 何实现 | 更新日期: 2023-09-27 18:16:47

我对Redis事务和管道之间的区别以及如何在Booksleeve中使用管道感到有点困惑。我看到Booksleeve支持Redis事务特性(MULTI/EXEC),但是在它的API/测试中没有提到流水线特性。然而,在其他实现中很明显,管道和事务之间存在区别,即原子性,如下面的redis-ruby版本所示,但在某些地方,这两个术语似乎可以互换使用。

redis-ruby实现:

r.pipelined {
  # these commands will be pipelined
  r.get("insensitive_key")
}
r.multi {
  # these commands will be executed atomically
  r.set("sensitive_key")
}

我只使用MULTI/EXEC,但他们似乎阻止所有其他用户,直到事务完成(在我的情况下没有必要),所以我担心他们的性能。有人使用管道与Booksleeve或有关于如何实现他们的任何想法?

我如何实现Redis管道请求与Booksleeve

在BookSleeve中,所有始终是流水线的。没有同步操作。一个也没有。因此,每个操作返回某种形式的Task(可能是香草Task,可能是Task<string>, Task<long>等),其中在未来的某个时候(即当redis响应时)将有一个值。您可以在调用代码中使用Wait来执行同步等待,或者使用ContinueWith/await (c# 5语言特性)来执行异步回调。

事务没有什么不同;它们是流水线的。事务唯一微妙的变化是,它们在调用站点被额外缓冲,直到完成(因为它是一个多路复用器,我们不能开始流水线与事务相关的消息,直到我们有一个完整的工作单元,因为它会对同一多路复用器上的其他调用者产生不利影响)。

所以:没有显式.pipelined的原因是所有都是流水线和异步的。

管道是协议级通信策略,与原子性无关。它与"事务"的概念完全无关。(例如,您可以在流水线连接中使用MULTI .. EXEC。)

什么是流水线?

redis最基本的连接器是一个以请求-应答方式交互的同步客户端。客户端发送一个请求,然后等待Redis的响应,然后再发送下一个请求。

在流水线中,客户端可以继续发送请求而不必暂停查看每个请求的Redis响应。当然,Redis是一个单线程服务器和一个自然的序列化点,因此请求顺序被保留并反映在响应顺序中。这意味着,客户端可以有一个线程发送请求(通常是通过从请求队列中退出队列),另一个线程不断地处理来自Redis的响应。请注意,当然您仍然可以在单线程客户端中使用流水线,但是您确实会损失一些效率。双线程模型允许充分利用本地CPU和网络带宽(例如饱和)。

如果到目前为止你还在遵循这个,你必须问自己:请求和响应在客户端是如何匹配的?好问题!有很多方法可以解决这个问题。在JRedis中,我将请求包装在(java) Future对象中,以处理请求/响应处理的异步性。每次发送请求时,对应的Future对象被挂起的响应对象包装并排队。响应侦听器每次只从这个队列中取出一个项目,解析响应(流)并更新未来对象。

现在,客户机的最终用户可以公开给同步接口或异步接口。如果接口是同步的,那么实现自然必须阻塞Future的响应。

如果你已经明白了,那么应该很清楚,使用同步语义和管道的单线程应用程序违背了管道的整个目的(因为应用程序阻塞了响应,并且没有忙着向客户端提供额外的请求)。但是如果应用程序是多线程的,管道的同步接口允许你在处理N个客户端应用程序线程时使用单个连接。(因此,在这里,它是一种帮助构建线程安全连接的实现策略。)

如果管道的接口是异步的,那么即使是单线程的客户端应用程序也可以受益。吞吐量至少增加一个数量级。

(关于管道的注意事项:编写一个容错的管道客户端是非常重要的。)

理想情况下,我应该使用图表,但要注意剪辑结束时发生了什么:http://www.youtube.com/watch?v=NeK5ZjtpO-M

这是Redis Transactions Documentation的链接

关于BookSleeve,请参考Marc的这篇文章。

"CreateTransaction()创建一个临时区域来构建命令(使用完全相同的API)并捕获未来的结果。然后,当调用Execute()时,缓冲的命令被组装到一个MULTI/EXEC单元中,并在一个连续的块中发送(显然,多路复用器将一起发送所有这些命令)。"

如果你在一个事务中创建命令,它们将自动"流水线"。