redis优化系列(十一)集群常见问题及客户端操作

客户端操作

注:这里的操作客户端语言,使用的是PHP语言。


搭建好了 Redis 集群并且理解了通信和伸缩细节,但还没有使用客户端去操作集群。Redis 集群对客户端通信协议做了比较大的修改,为了追求性能最大化,并没有采用代理的方式而是采用客户端直连节点的方式。


可以直接用predis类库 使用composer require predis/predis进行安装。 安装后可以使用基于predis的类库提供的相关类和方法来直接操作redis集群,但是该类库功能不够完善。也可以使用phpredis的C扩展,这个功能基本都提供了。


predis类库是基于php进行封装的类库,phpredis的C扩展是使用C语言进行封装的php扩展。


predis类库的相关资料可参看如下链接:

https://packagist.org/packages/predis/predis

https://github.com/nrk/predis


phpredis的C扩展相关资料可参考如下链接:

https://github.com/phpredis/phpredis


phpredis的C扩展操作redis集群可参考如下链接:

https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#readme


集群的常见问题

集群功能的常见限制

Redis 集群相对单机在功能上存在一些限制,需要开发人员提前了解,在使用时做好规避。限制如下:

①、key 批量操作支持有限。如 mset、mget,目前只支持具有相同 slot 值的 key 执行批量操作。对于映射为不同 slot 值的 key 由于执行 mget、mset、delete 等操作可能存在于多个节点上因此不被支持。

②、key 事务操作支持有限。同理只支持多 key 在同一节点上的事务操作,当多个 key 分布在不同的节点上时无法使用事务功能。

③、不支持多数据库空间。单机下的 Redis 可以支持16个数据库,集群模式下只能使用一个数据库空间,即 db0。

④、复制结构只支持一层,从节点只能复制主节点,不支持嵌套树状复制结构。(也就是说不支持类似redis主从的树状结构)


解决:

利用redis的C扩展解决

安装:


1、使用源码编译方式安装

wget http://pecl.php.net/get/redis-3.1.5.tgz
tar -xvf  redis-3.1.5.tgz
cd  redis-3.1.5.tgz
phpize
./configure
make
make install


2、直接使用pecl扩展库方式进行安装

pecl install http://pecl.php.net/get/redis-3.1.5.tgz


redis的C扩展的简单使用示例,假设你已经安装了。:

//第一个NULL参数表示可以指定redis的一个.ini的配置文件,这里不需要,给NULL参数即可
$obj_cluster = new RedisCluster(NULL, array('119.3.220.26:6391', '119.3.220.26:6392', '119.3.220.26:6393'));

$data = $obj_cluster->mget(['name1','name2','name3']); //批量获取key的值

//print_r($data); //成功获取到值

在上面的简单示例中 发现redis的C扩展支持批量获取key的值,同时支持mset等批量操作。该扩展除了支持集群模式下的mset、mget等批量操作外。同时支持超时时间、事务等相关支持。


predis的使用示例,假设你已经将predis类库都下载下来了。composer require predis/predis

require  "vendor/autoload.php";

//这里不一定要将所有的redis节点ip写上去,一般来说只需要给集群中的master节点的1-2台ip地址即可
$parameters = ['119.3.220.26:6391', '119.3.220.26:6392', '119.3.220.26:6393'];

//选项设置为:集群模式
$options = ['cluster' => 'redis'];

$client = new Predis\Client($parameters, $options);

//设置值
$client->set('name1', '1');
$client->set('name2', '2');
$client->set('name3', '3');

echo $client->get('name2'); //获取值

//试一下predis的批量获取值
$client->mget(['name1','name2','name3']);  //运行报错:predis不支持批量获取值

predis类库支持的模式很多,除了cluster集群外,也支持sentinel和redis主从等操作,但是在上面的示例中,我们发现predis不支持批量获取值等类似的操作。


一般情况下使用phpredis的C扩展即可,不过也要看项目和个人了


集群实现批量操作的原理

r1.png

流程:

1)计算 slot 并根据 slots 缓存获取目标节点连接,发送命令。

2)如果出现连接错误,使用随机连接重新执行键命令,每次命令重试对 $retryLimit 参数减1。

3)如果捕获到 MOVED 重定向错误,使用 cluster slots 命令更新 slots 缓存,调用缓存更新方法。

4)重复执行1)~3)步,直到命令执行成功,或者当 $retries<=0 时抛出异常。


集群常见问题:

1、移除节点之后,因为被移除节点,还保留节点信息,所以必须先删除之前的配置信息,否则有可能出现如下报错

r1.png


2、重定向问题

在集群模式下,Redis 接收任何键相关命令时 首先计算键对应的槽,再根据槽找出所对应的节点,如果节点是自身,则处理键命令;否则回复 MOVED 重定向错误,通知客户端请求正确的节点。

r2.jpg


如下提示:

r3.png



ASK 重定向问题

客户端 ASK 重定向流程:

Redis 集群支持在线迁移槽(slot)和数据来完成水平伸缩,当 slot 对应的数据从源节点到目标节点迁移过程中,客户端需要做到智能识别,保证键命令可正常执行。例如当一个 slot 数据从源节点迁移到目标节点时,期间可能出现一部分数据在源节点,而另一部分在目标节点。


如果键对象不存在,则可能存在于目标节点,这时源节点会回复 ASK 重定向异常。格式如下:(error)ASK{slot}{targetIP}:{targetPort}。


客户端从 ASK 重定向异常提取出目标节点信息,发送 asking 命令到目标节点打开客户端连接标识,再执行键命令。如果存在则执行,不存在则返回不存在信息。

r1.jpg


ASK 与 MOVED 虽然都是对客户端的重定向控制,但是有着本质区别。ASK 重定向说明集群正在进行 slot 数据迁移,客户端无法知道什么时候迁移完成,因此只能是临时性的重定向,客户端不会更新本地的slots 缓存。但是 MOVED 重定向说明键对应的槽已经明确指定到新的节点,因此需要更新 slots 缓存。



有人说恋爱最美的时期 就是暧昧不清的阶段  -->【那些年,我们一起追过的女孩】




声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

精彩评论

全部回复12人评论7,777人参与