兔哥的前一篇文章介绍了Redis MULTI 和 EXEC的时候讨论过它们的"事务"性质——被 MULTI 和 EXEC包裹
的命令在执行时不会被其他客户端打扰。而使用事务的其中一个好处就是底层的客户端会通过使用流水线来提高事务
执行时的性能。本篇文章兔哥将介绍如何在不使用事务的情况下,通过使用流水线来进一步提升命令的执行性能。
使用过Redis 朋友都知道一些可以接受多个参数的添加命令和更新命令,如MGET、MSET、HMGET、 HMSET、RPUSH 和LPUSH、SADD、ZADD 等。这些命令简化了那些需要重复执行相同命令的操作,并且极大地提升了性能。尽管效果可能没有以上提到的命令那么显著,但使用非事务型流水线(non-transactional pipeline)同样可以获得相似的性能提升,并且可以让用户同时执行多个不 同的命令。
在需要执行大量命令的情况下,即使命令实际上并不需要放在事务里面执行,但是为了通过一次发送所有命令来减少通信次数并降低延迟值,用户也可能会将命令包裹在 MULTT 和 EXEC里面执行。遗憾的是,MULTI和 EXEC并不是免费的——它们也会消耗资源,并且可能会导致其他重要的命令被延迟执行。不过好消息是,我们实际上可以在不使用MULTI 和ExEc的情况下,获得流水线带来的所有好处。兔哥前一篇文章使用了以下语句来在Python 中执行MULTI和 EXEC 命令∶ pipe=conn.pipeline() 如果用户在执行pipeline()时传入True 作为参数,或者不传入任何参数,那么客户端将使用MULTI 和EXEC包裹起用户要执行的所有命令。另一方面,如果用户在执行 pipeline()时传入False 为参数,那么客户端同样会像执行事务那样收集起用户要执行的所有命令,只是不再使用MULTI 和 EXEC 包裹这些命令。如果用户需要向 Redis 发送多个命令,并且对于这些命令来说,一个命令的执行结果并不会影响另一个命令的输入,而且这些命令也不需要以事务的方式来执行的话,那么我们可以通过向pipeline()方法传人False来进一步提升Redis的整体性能。让我们来看一个这方面的例子。
兔哥前面的 文章中曾经编写并更新过一个名为update_token()的函数,它负责记录用户最近浏览过的商品以及用户最近访问过的页面,并更新用户的登录cookie。以下展示的是之前文章中展示过的更新版 update_token()函数,这个函数每次执行都会调用2个或者 5个Redis命令,使得客户端和 Redis之间产生2次或者5次通信往返。
如果Redis 和 Web服务器通过局域网进行连接,那么它们之间的每次通信往返大概需要耗费一两毫秒,因此需要进行2次或者5次通信往返的update_token()函数大概需要花费2~10毫秒来执行,按照这个速度计算,单个Web服务器线程每秒可以处理100~500个请求。尽管这种速度已经非常可观,但我们还可以在这个速度的基础上更进一步∶通过修改update_token()函数,│让它创建一个非事务型流水线,然后使用这个流水线来发送所有请求,这样我们就得到了下面代码展示的update_token_pipeline ()函数。
通过将标准的 Redis 连接替换成流水线连接,程序可以将通信往返的次数减少至原来的与到,并将 update_token_pipeline()函数的预期执行时间降低至 1~2 毫秒。按照这个速度来计算的话,如果一个Web服务器只需要执行update_token_pipeline()来更新商品的浏览信息,那么这个Web服务器每秒可以处理500~1000个请求。从理论上来看,update_token_pipeline()函数的效果非常棒,但是它的实际运行速度又是怎样的呢?
为了回答这个问题,兔哥将对 update_token()函数和 update_token_pipeline()函数进行一些简单的测试。兔哥将分别通过快速低延迟网络和慢速高延迟网络来访问同一台机器,并测试运行在机器上面的Redis每秒可以处理的请求数量。下面的代码展示了进行性能测试的函数,这个函数会在给定的时限内重复执行update_token()函数或者 update_token_pipeline()函数,然后计算被测试的函数每秒执行了多少次。
下表展示了不同宽带以及不同延迟值的网络上进行性能测试函数的到的数据。
在不同类型的网络上执行流水线和非流水线连接∶对于高速网络,测试程序几乎达到了单核处理器可以编码/解码 Redis 命令的极限;而对于低速网络,测试程序的运行则受到网络带宽和延迟值的影响
现在我们已经知道如何在不使用事务的情况下,通过使用流水线来提升Redis的性能了,那么除了流水线之外,还有其他可以提升Redis性能的常规(standard)方法吗?下一篇文章兔哥详细介绍 根据上表数据显示,高延迟网络使用流水线时的速度要比不使用流水线时的速度快5倍,低延迟网络使用流水线也可以带来接近4倍的速度提升,而本地网络的测试结果实际上已经达到了Python在单核环境下使用 Redis 协议发送和接收短命令序列的性能极限(下篇文章将更详细地说明这个问题)。