35

通过Twemproxy提升PHP/Redis的性能

 5 years ago
source link: https://huoding.com/2018/06/23/673?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Twemproxy 可以说是最古老的 Redis 代理软件了,一般来说,引入代理后性能会比没有引入代理时低一些,毕竟代理会导致一些额外的性能损耗,可是 Twemproxy 却会提升性能, 这主要得益于它的 Pipelining 功能可以实现打包请求,简单点说:当代理收到多个并发请求时,它会把这些请求打包成一个请求发送给后端服务器,从而减少不必要的 RTT。关于 Pipelining 本文不 做过多讨论,实际上我想说的是它的另一个功能:连接池!下面看看如何通过 Twemproxy 提升 PHP/Redis 的性能。

众所周知,PHP 的运行方式很难实现真正的连接池,不过通过本地的 Unix Domain Socket,我们可以绕开连接池,实现曲线救国,具体介绍大家可以参考我以前写的旧文: 史上最LOW的PHP连接池解决方案 ,在那篇文章里,我借助 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,参考 recommendation

此外,有时候系统可能会偏爱 CPU0,此时在运行多个 Twemproxy 进程的时候,可以考虑通过taskset 命令绕开 CPU0,避免 CPU0 成为性能瓶颈。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK