为什么与 Redis 的单一连接性能不佳以及如何使其更快

why single connection to redis perform bad and how to make it faster

我最近在对 redis 进行基准测试,这是我得到的结果:

ubuntu 13.10 x86_64 with kernel version 3.11, 
Intel® Core™ i5 CPU M 430 @ 2.27GHz × 4
8GB Memory

因此,在负载相同的情况下,多个连接到 Redis 的速度比单个连接快 8 倍。我在这里不考虑流水线,我已经在测试中尝试了很多优化方法。 (使用taskset使redis单核运行,使用unix domain socket)

两个问题:

  1. 为什么到 redis 的多个连接可以比单个连接更快地执行此操作?

  2. 有没有其他方法(除了管道)可以提高单连接下的性能?

这几天针对这个问题做了一些性能测试,这里得到了一些结果。

关键是找出单连接情况下额外延迟的来源。我的第一个假设是它们来自 epoll。为了找出答案,我使用 systemtap and the script to determine epoll latency。结果(上图:1个连接结果,下图:10个连接结果。抱歉,图中单位应该是纳秒):

从结果可以看出,epoll 的平均停留时间几乎相同,分别为 8655 纳秒和 10254 纳秒。但是,总数存在显着差异。对于 10 个连接,我们调用 epoll 等待 444528 次,但在单个连接的情况下我们将调用它 2000054 次,即 4x,这就是导致额外时间使用的原因。

下一个问题是为什么我们在多重连接期间调用 epoll 的时间这么少。通过redis源码稍微摸索了一下,找到了原因。每次 epoll returns,它将 return 它要处理的事件数。 presudo 代码就像(隐藏大部分细节):

fds = epoll_wait(fds_we_are_monitoring);
for fd in fds:
    handle_event_happening_in(fd);

return值fds是所有发生IO的事件的集合,例如从socket读取输入。对于单连接基准,fds_we_are_monitoring为1,因为只有一个连接,那么每次#fd都会为1。但是对于10连接的情况,fds可以return任何小于10、然后一起处理for loop中的事件。我们一次从 epoll return 获取的事件越多,我们获取的速度就越快。因为请求总数是固定的,本例中,1M设置请求。

为了验证这一点,我使用 systemtap 绘制函数 return 值的分布。 aeProcessEvents,其中 return 是它处理的事件数。

我们可以看到平均:单连接情况下为 1 vs 10 连接情况下为 7。这证明了我们的假设,即 epoll returns 一次的事件数量越多,我们处理请求的速度就越快,直到它成为 CPU 绑定。

我想我得到了第一个问题的答案:为什么到 redis 的多个连接可以比单个连接更快地执行此操作。但是,我仍然想知道是否有任何其他方法(除了管道)可以提高单连接下的性能。如果其他人可以分享一些对此的想法,我将不胜感激。