Redis Java客户端:我是否需要将命令缓冲到管道中以提高性能?

时间:2016-09-29 10:57:11

标签: java design-patterns redis jedis spring-data-redis

所以我只是在排序集中增加分数。这是我运行的唯一命令,使用Jedis客户端从Java应用程序每秒大约10-30个命令。由于我只是更新分数,我也不关心回应。我担心的是每个ZINCRBY命令都被放入自己的TCP数据包中,并在允许我的线程发送下一个ZINCRBY线程之前等待下一个回复。

所以,我想实现管道衬里,一次批量说50个命令。这里是我看到代码/设计模式气味的地方:这种设计模式不是很常见,驱动程序应该处理它吗?看来.net“StackExchange.redis”驱动程序会自动命令批处理,但Java驱动程序没有此功能?我的想法是创建一个自定义的redis命令缓冲类,它将传入的命令放入管道并在50个项目之后调用sync(),真的需要吗?

另外,我在日志中注意到这一点,因为我通过Spring Data Redis使用Jedis:

20160929 06:48:27.393 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.393 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.393 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.393 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.393 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.394 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.394 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.629 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.630 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.630 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.631 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.631 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.631 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.631 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.631 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.632 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.632 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.632 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.632 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.632 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.633 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.633 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.633 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection
20160929 06:48:27.633 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Opening RedisConnection
20160929 06:48:27.633 [Twitter4J Async Dispatcher[0]] DEBUG o.s.d.r.c.RedisConnectionUtils # Closing Redis Connection

所以它似乎正在关闭每个天真执行的命令的连接(通过Spring提供的模板模式)。我认为关闭连接会强制TCP缓冲区为每个数据包发送一个命令,所以这似乎对我来说效率很低,因为套接字占用了相当多的CPU。虽然Spring Data Redis API允许直接访问Jedis客户端,但如果管道当前处于打开状态,则不会关闭连接,因此编写“管道缓冲区”是一个选项。

简而言之,我应该创建/利用写入redis管道的缓冲区以及X命令后的刷新吗?我根本不喜欢浪费所有这些CPU周期(更高的AWS账单)天真地运行每个命令的想法,并且好奇我的场景是否有更好的设计模式。或者,如果切换到其他Java Redis客户端可以解决此问题。或者,如果有一些Java库已经在redis管道中缓冲命令。

2 个答案:

答案 0 :(得分:2)

我认为我们需要在这里详细了解细节,因为你在这里提到了不同的方面。

通常,默认情况下,所有Java Redis客户端(JedisLettuceRedisson等等)都会直接将命令写入TCP通道。因此,每个命令都作为一个或多个TCP数据包发送。生菜和Redisson作为它们的操作模式,因为两个客户端都使用异步/事件驱动的编程模型来将Redis命令写入TCP通道。 Jedis强制您等待命令结果,因为它暴露了阻塞API。 Redisson和Lettuce暴露不同种类的API(使用Futures异步或使用RxJava / Reactive Streams反应),不会强迫您等待命令结果。

批处理/缓冲是另一种在客户端内存中收集命令并将命令作为批处理发送到Redis的技术。这适用于LettuceRedisson客户端。 Jedis将流水线模式中的命令直接写入TCP通道。

命令批处理会带来一些影响。可以自动批处理命令(例如大小为10或50),但这需要用户注意。批处理始终需要进行一些最终同步,以避免命令在队列中停留并且尚未发送,因为尚未达到批处理大小。

Spring Data Redis使用Jedis和Lettuce来展示其功能,因此需要Spring Data Redis来应对两个驱动程序的共同内容。您可以将Spring Data Redis设置为使用与Jedis的连接池,这样您就可以从每次与Redis交互时未关闭的池连接中受益。

答案 1 :(得分:0)

流水线是Redis的常见模式,可以降低通信成本。 Jedis是redis的推荐Java驱动程序,它支持管道传输。 Lettuce是另一种选择,它也支持pipelining