PHP操作redis集群

一. 概述

目前我们用到的 php 的 redis 扩展 主要有2个,

二. phpredis(PHP扩展)方式

1. phpredis单机方式

<?php
$client = new Redis();
$client->connect('10.30.5.163', '7000');
echo $client->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

2. phpredis集群使用

https://github.com/phpredis/phpredis/blob/feature/redis_cluster/cluster.markdown

<?php
$redis_list = ['10.30.5.162:7000','10.30.5.163:7000','10.30.5.163:7001'];
$client = new RedisCluster(NUll,$redis_list);
echo $client->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');
  • 代码说明
    第一个参数传NULL 别问我,我也不知道为啥。反正文档没找到,这篇也没看懂。
    第二个参数是我们需要连接的redis cluster的master服务器列表。我们有3个master,就填3个, 填一个主节点也行, 甚至填一个从节点也行, 但是性能有差异, 见第四部分

3. 集群原理

为甚么填入任何一个节点地址都可以操作redisCluster呢?

  • 在集群模式下,Redis接收任何键相关命令时首先计算键对应的槽,
    假如初始化的是从节点, 首先会向从节点发送redis命令,
    从节点根据槽找出所对应的节点,如果节点是自身,则处理键命令;
    如果不是自身, 则MOVED重定向错误,通知客户端请求正确的节点。这个过程称为MOVED重定向


    redis开发和运维.png
  • 重定向信息包含了键所对应的槽以及负责该槽的节点地址,根据这些信
    息客户端就可以向正确的节点发起请求
  • phpredis客户端可以根据重定向信息直接再次向键所在节点发起请求, 从而获取数据

图片来源: <<redis开发和运维>>

4. 设定超时

<?php
$redis_list = ['10.30.5.162:7000','10.30.5.163:7000','10.30.5.163:7001', 1.5, 1.5];
$client = new RedisCluster(NUll,$redis_list);
echo $client->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

timeout和read_timeout功能。就是加到master列表的后面。

timeout表示连接redis的最长时间,这里设为1.5秒,表示超过1.5秒要是还没连接成功就返回false 。

read_timeout表示连接redis成功后,读取一个key的超时时间,有时候读取一个key 可能value比较大,读取需要很长时间,这里设置1.5秒,表示要是过了1.5秒还没读取到数据就返回false。

三. PRedis方式

predis是一套用php代码写的php连接redis的扩展

<?php
use Predis\Client;
require __DIR__ . '/../vendor/autoload.php';

// 写一个节点也可以
$redis_list = [
        'tcp://10.30.5.163:7000',
        'tcp://10.30.5.163:7001',
        'tcp://10.30.5.162:7000'
];

$redis = new Client($redis_list, ['cluster'=>'redis']);

echo $redis->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

四. phpredis和Predis性能对比

  • 使用ab压测, 获取key
    /usr/local/apache2/bin/ab -n10000 -c100 http://10.30.5.162/redis.php

  • key:
    new_item_key:d89b561fb759fd533a8c2781ef15dd5f
    分布在10.30.5.163:7000节点

  • php.ini开启opcache

realpath_cache_size = 2M
[opcache]
zend_extension=opcache.so
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
opcache.fast_shutdown=1
opcache.validate_timestamps=1
opcache.revalidate_freq=60
opcache.use_cwd=1
opcache.max_accelerated_files=100000
opcache.max_wasted_percentage=5
opcache.memory_consumption=128
opcache.consistency_checks=0
opcache.huge_code_pages=1

1. phpredis填入三个主节点

<?php
$redis_list = ['10.30.5.162:7000','10.30.5.163:7000','10.30.5.163:7001',1.5,1.5]; 
$client = new RedisCluster(NUll,$redis_list);
echo $client->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

测试结果

Concurrency Level:      100
Time taken for tests:   2.203 seconds
Complete requests:      10000
Failed requests:        12
   (Connect: 0, Receive: 0, Length: 12, Exceptions: 0)
Total transferred:      2506988 bytes
HTML transferred:       509388 bytes
Requests per second:    4539.89 [#/sec] (mean)
Time per request:       22.027 [ms] (mean)
Time per request:       0.220 [ms] (mean, across all concurrent requests)
Transfer rate:          1111.47 [Kbytes/sec] received


吞吐量4500左右

2. phpredis只填入一个从节点

<?php
$redis_list = ['10.30.5.161:7000'];

$client = new RedisCluster(NUll,$redis_list);
echo $client->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

每次都会重定向

Concurrency Level:      100
Time taken for tests:   9.726 seconds
Complete requests:      10000
Failed requests:        77
   (Connect: 0, Receive: 0, Length: 77, Exceptions: 0)
Total transferred:      2490673 bytes
HTML transferred:       506073 bytes
Requests per second:    1028.14 [#/sec] (mean)
Time per request:       97.263 [ms] (mean)
Time per request:       0.973 [ms] (mean, across all concurrent requests)
Transfer rate:          250.07 [Kbytes/sec] received


吞吐量1028(有点低啊)

3. 使用单机模式连接

<?php
$redis_list = 'tcp://10.30.5.163:7000';

$client = new Redis();
$client->connect('10.30.5.163', '7000');
echo $client->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

结果

Concurrency Level:      100
Time taken for tests:   1.238 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      2510000 bytes
HTML transferred:       510000 bytes
Requests per second:    8078.76 [#/sec] (mean)
Time per request:       12.378 [ms] (mean)
Time per request:       0.124 [ms] (mean, across all concurrent requests)
Transfer rate:          1980.24 [Kbytes/sec] received

4. 使用predis集群模式

<?php
use Predis\Client;
require __DIR__ . '/../vendor/autoload.php';

$redis_list = [
        'tcp://10.30.5.163:7000',
        'tcp://10.30.5.163:7001',
        'tcp://10.30.5.162:7000'
];

$redis = new Client($redis_list, ['cluster'=>'redis']);

echo $redis->get('new_item_key:d89b561fb759fd533a8c2781ef15dd5f');

结果

Concurrency Level:      100
Time taken for tests:   5.380 seconds
Complete requests:      10000
Failed requests:        0
Total transferred:      2510000 bytes
HTML transferred:       510000 bytes
Requests per second:    1858.68 [#/sec] (mean)
Time per request:       53.802 [ms] (mean)
Time per request:       0.538 [ms] (mean, across all concurrent requests)
Transfer rate:          455.59 [Kbytes/sec] received

性能和phpredis差一倍, 但是是在开启opcache的情况下, 因为加载predis的client, 需要使用psr-4查找文件, 不开启opcache, 性能会差挺多, 有兴趣可以自己尝试

  • 总结
    使用phpredis操作集群性能和单机相差一倍左右, predis和phpredis差距有点大, 在实际编程中可以按需要去选择

  • 在java操作redis集群的库使用jedis, 可以为每一个节点设置一个连接池, 在发送请求前, 先计算槽, 根据本地缓存的槽和节点映射缓存就可以直接去请求数据保存的节点获取数据, 当槽和节点映射关系不正确, 会触发重试机制, 将最新的映射关系更新到缓存中
    php一次请求过后, 变量的生命周期就结束了, 无法设置连接池以及使用槽节点缓存机制, 命令如果和请求节点不对应, 就会MOVED重定向, 产生性能损耗.

附录 redis扩展安装

~ git clone git@github.com:phpredis/phpredis.git

~ cd phpredis

~ git fetch

~ git checout feature/redis_cluster #切换到cluster分支

~ phpize

~ ./configure

~ make

~ make install

这样就可以用了。如果你是第一次安装redis扩展,还需要在php.ini中加上:

extension=redis.so

文档部分引用
http://www.php.cn/blog/detail/6690.html
http://www.laruence.com/2016/12/18/3137.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354