Twemproxy https://github.com/twitter/twemproxy 可以说是最古老的 Redis 代理软件了, 一般来说, 引入代理后性能会比没有引入代理时低一些, 毕竟代理会导致一些额外的性能损耗, 可是 Twemproxy 却会提升性能, 这主要得益于它的 Pipelining https://github.com/twitter/twemproxy#pipelining 功能可以实现打包请求, 简单点说: 当代理收到多个并发请求时, 它会把这些请求打包成一个请求发送给后端服务器, 从而减少不必要的 RTT. 关于 Pipelining 本文不 做过多讨论, 实际上我想说的是它的另一个功能: 连接池! 下面看看如何通过 Twemproxy 提升 PHP/Redis 的性能.
众所周知, PHP 的运行方式很难实现真正的连接池, 不过通过本地的 Unix Domain Socket, 我们可以绕开连接池, 实现曲线救国, 具体介绍大家可以参考我以前写的旧文: 史上最 LOW 的 PHP 连接池解决方案 https://huoding.com/2017/09/10/635 , 在那篇文章里, 我借助 Nginx 的 Stream 模块, 实现了一个 Redis 代理, 通过它来实现连接池功能, 然后 PHP 通过本地的 Unix Domain Socket 来连接 Redis 代理, 从而达到连接池的效果, 不过在本文里, 我不再自己编写 Redis 代理, 而是直接使用 Twemproxy, 让我们看看效果如何.
假设你已经安装好了 Twemproxy, 设置一下配置文件 /etc/redis.yml:
- instance:
- listen: /var/run/nutcracker.sock
- redis: true
- redis_auth: ...
- preconnect: true
- servers:
- - 127.0.0.1:6379:1
让我们把服务运行起来, So easy:
shell> /path/to/nutcracker -c /etc/redis.yml
下面让我们压测看看性能怎么样:
不使用 Twemproxy 的测试脚本 without_twemporxy.php 如下:
- <?php
- $redis = new Redis;
- $redis->connect('127.0.0.1', 6379);
- $redis->auth('...');
- $redis->set('foo', 'bar');
- echo $redis->get('foo');
- ?>
使用 Twemproxy 的测试脚本 with_twemproxy.php 如下:
- <?php
- $redis = new Redis;
- $redis->connect('/var/run/nutcracker.sock');
- $redis->auth('...');
- $redis->set('foo', 'bar');
- echo $redis->get('foo');
- ?>
通过 ab 模拟一个高并发的场景, 压测看看性能有没有提升:
- shell> ab -k -n 10000 -c 100 http://test/without_twemproxy.php
- shell> ab -k -n 10000 -c 100 http://test/with_twemproxy.php
一开始, 结果让人非常沮丧, 使用 Twemproxy, 没有带来任何性能上的提升. 这是为什么呢? 原来是因为 Twemproxy 是单线程的, 缺省情况下只能使用一个 CPU, 这个问题好解决, 我们只要按 CPU 个数启动多个进程 (假设有 4 个 CPU) 即可.
首先, 创建多个配置文件 /etc/nutcracker[1-4].yml:
- instance:
- listen: /var/run/nutcracker[1-4].sock
- redis: true
- redis_auth: ...
- preconnect: true
- servers:
- - 127.0.0.1:6379:1
然后, 启动多个 Twemproxy 进程:
- shell> /path/to/nutcracker -c /etc/redis1.yml -m 512 -s 11111 -d
- shell> /path/to/nutcracker -c /etc/redis2.yml -m 512 -s 22222 -d
- shell> /path/to/nutcracker -c /etc/redis3.yml -m 512 -s 33333 -d
- shell> /path/to/nutcracker -c /etc/redis4.yml -m 512 -s 44444 -d
相应的, 使用 Twemproxy 的测试脚本也要做出适当的调整:
- <?php
- $redis = new Redis;
- $redis->connect('/var/run/nutcracker' . rand(1, 4) . '.sock');
- $redis->auth('...');
- $redis->set('foo', 'bar');
- echo $redis->get('foo');
- ?>
再执行压测, 结果发现使用 Twemproxy 后, 性能整整提升了 100%! 如果你在压测过程中通过 top 命令观察 CPU 情况的时候, 会发现所有 CPU 都被吃满了, 基本上没有 idle, 此外, 如果你在压测过程中通过 MONITOR 观察 Redis 执行的命令, 你会观察到 Pipelining 现象, 还会观察到 AUTH 被省略了, 这些都是性能提升的原因.
说明: 为什么 mbuf-size 在高并发的时候推荐设置为 512, 参考 https://github.com/twitter/twemproxy/blob/master/notes/recommendation.md .
此外, 有时候系统可能会偏爱 CPU0, 此时在运行多个 Twemproxy 进程的时候, 可以考虑通过 taskset 命令绕开 CPU0, 避免 CPU0 成为性能瓶颈.
来源: http://www.tuicool.com/articles/BzaeieV