我对Redis事务和管道之间的区别以及最终如何在Booksleeve中使用管道有点混淆。我看到Booksleeve支持Redis transaction feature(MULTI
/ EXEC
),但其API /测试中没有提及流水线功能。但是,在其他实现中很明显,管道和事务之间存在区别,即在atomicity中,如下面的redis-ruby版本所示,但在某些places中,这些术语似乎可以互换使用
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的管道或对如何实现它们有任何想法?
答案 0 :(得分:6)
在BookSleeve中,一切始终是流水线的。没有同步操作。不是一个人。因此,每个操作都返回某种形式的Task
(可能是一个香草Task
,可能是Task<string>
,Task<long>
等等,其中在某些时候在将来(即当redis响应时)将有一个值。您可以在调用代码中使用Wait
执行同步等待,或使用ContinueWith
/ await
(C#5语言功能)执行异步回调。
交易没有什么不同;它们是流水线的。事务的唯一微妙变化是它们在呼叫站点被额外缓冲直到完成(因为它是一个多路复用器,在我们有一个完整的工作单元之前,我们无法开始管道与事务相关的消息,因为它会对同一多路复用器上的其他呼叫者产生不利影响。)
所以:没有明确.pipelined
的原因是 所有 都是流水线和异步的。
答案 1 :(得分:4)
Pipelining是一种协议级别的通信策略,与原子性无关。它与“交易”的概念完全正交。 (例如,您可以在流水线连接中使用MULTI .. EXEC
。)
什么是流水线?
redis的最基本连接器是以请求 - 回复方式进行交互的同步客户端。客户端发送请求,然后在发送下一个请求之前等待Redis的响应。
在流水线操作中,客户端可以继续发送请求而不会暂停以查看每个请求的Redis响应。当然,Redis是单线程服务器和自然序列化点,因此请求顺序被保留并反映在响应顺序中。这意味着,客户端可以有一个线程发送请求(通常通过从请求队列中出队),另一个线程正在不断处理来自Redis的响应。请注意,您当然仍然可以使用单线程客户端进行流水线操作,但确实会失去一些效率。双线程模型允许充分利用本地CPU和网络带宽(例如饱和度)。
如果你到目前为止这样做,你必须问自己:那么,客户端的请求和响应如何匹配?好问题!有很多方法可以解决这个问题。在JRedis中,我将请求包装在(java)Future
对象中,以处理请求/响应处理的异步。每次发送请求时,相应的Future对象都会被挂起的响应对象包装并排队。响应侦听器一次只从队列1项中出列,并解析响应(流)并更新未来对象。
现在,客户端的最终用户可以暴露给同步或异步接口。如果接口是同步的,那么实现自然必须阻止Future的响应。
如果你已经关注到目前为止,那么应该清楚的是,使用带有流水线技术的同步语义的单线程应用程序会破坏流水线操作的整个目的(因为应用程序阻止响应并且不忙于向客户端提供其他请求。但是,如果应用程序是多线程的,则管道的同步接口允许您在处理N个客户端应用程序线程时使用单一连接。 (所以在这里,它是一种帮助构建线程安全连接的实现策略。)
如果管道接口是异步的,那么即使是单线程客户端应用程序也可以从中受益。吞吐量至少增加一个数量级。
(使用流水线的注意事项:编写容错的流水线客户端是非常重要的。)
理想情况下我应该使用图表,但要注意剪辑结尾处发生的事情: http://www.youtube.com/watch?v=NeK5ZjtpO-M
答案 2 :(得分:1)
以下是Redis Transactions Documentation
的链接关于BookSleeve,请参阅Marc的this post。
“CreateTransaction()创建一个暂存区域来构建命令(使用完全相同的API)并捕获未来的结果。然后,当调用Execute()时,缓冲的命令被组装到MULTI / EXEC单元并在连续的块(多路复用器将显然将所有这些一起发送)。“
如果您在交易中创建命令,它们将自动“流水线化”。