前段时间基础架构组、DBA还有云盘团队一起推广了phpredis的RedisCluster的线上使用,目前线上业务已经稳定,单业务的规模水平是:Qps平均15W,数据量在700G左右。现对这段时间的工作和所遇到的一些常见问题进行简单总结:
现象:最开始试水phpredis的Cluster功能时,总是遇到’Couldn’t map cluster keyspace using any provided seed’的错误
原因:这是由于早期phpredis驱动的fd泄漏问题造成的。每新建一个RedisCluster客户端,客户端会向给定的Seeds节点获取Redis集群的Slots分布信息,但是为了获取slots信息而向Seeds节点建立的连接是不用于后期发送命令使用的,所以在获取slots信息结束后应该释放掉改连接,而phpredis没有释放,这样在新建若干次RedisCluster客户端后,就fd泄漏了,导致连接建立失败,slots信息也就无法获取了,从而报错。
解决办法:更新phpredis的驱动,后期的phpredis驱动已经修复这个问题 (是我们提交的, wakaka……!)
现象:客户机上timewait端口数量比较多时,‘Timed out…’报错量比较
分析:我们观察到,当timewait端口数量较多时,会存在两个线程进程绑定绑定到同一个端口,但是却只有一个进程的连接建立成功了,另一个进程的连接建立要在已建立连接断开3s(SYN重试时间)后才能成功,而3s的时间延迟,而3s的延迟在业务方看来是不能容忍的,一般肯定会报“Time out…”的错误。而且随着timewait的数量的增加,这种情况发生的频率也递增;
解决办法:使用长连接,或者限制timewait端口数
问题:获取Slots信息比较耗性能
原因:因为每新建一个RedisCluster客户端都会向给定的Seeds节点拉去Redis集群的Slots信息,因为要建立连接和命令的特殊性,这个过程是相当耗时的(局域网内测试:2ms左右),当在新建RedisCluster的比较频繁的场景下,是比较的耗性能的
解决办法:修改phpredis驱动,在本地缓存住Redis集群的的Slots信息,把它放在持久性资源内。这样每次新建一个RedisCluster客户端时就不用再走网络获取Slots信息,直接在本地缓存中就可以拿到这些信息了。
备注:
a. 在我们的推动下,作者也出了一个这样的功能,在cache-slots分支上;
b. 驱动在拉去Slots信息时,总是按顺序选择依次选择第一个,第二个……这样第一个Seed节点的压力就会比较大,所以如果在新建RedisCluster客户端比较频繁的场景下,应该使用Qconf这样的工具或者修改驱动,以随机选择Seed节点,达到均衡负载的目的。
/*
#define CLUSTER_SEND_PAYLOAD(sock, buf, len) \
(sock && sock->stream && !redis_check_eof(sock, 1 TSRMLS_CC) && \
php_stream_write(sock->stream, buf, len)==len)
*/
#define CLUSTER_SEND_PAYLOAD(sock, buf, len) \
((sock && sock->stream && !redis_check_eof(sock, 1 TSRMLS_CC) && \
php_stream_write(sock->stream, buf, len)==len) || \
((sock->stream == NULL ? : redis_stream_close(sock)), \
sock->lazy_connect = 1, \
sock->status = REDIS_SOCK_STATUS_DISCONNECTED, \
0))
鉴于我们遇到的大部分问题都和驱动内发送命令的逻辑相关,所以最后贴一张phpredis驱动向主节点发送命令逻辑的流程图:
a. 根据key所对应的slot找出负责该slot的Redis主节点
b. 若是与给定节点还没有建立链接,则先建立链接
c. 发送命令:不成功则转向下一个redis主节点,然后从b重新开始
d. 读取返回值:若正常返回,则结束;
e. 判断是否超时:超时了则抛出超时异常;
f. 判断是否发生moved错误:是则转向所moved错误所提示的redis节点,并从b重新开始;
g. 继续从b开始重试
说明:
上面判断的超时,循环之间是叠加的,不是每次循环开始又重新开始计时;
超时异常的产生主要有两个:一个是与负责给定slot的redis节点的连接一直建立失败,导致不断循环,然后超过时间限制;另一个,在给定时间限制内,没有从服务端读到返回值,直接超时,抛出异常。
redis常用数据结构strig、list、hash、set、zset,这是最常用的5中redis数据结构,其实还有些不太常用的数据结构比如:HyperLogLog、GeoHash、PubSub等
redis 是当前非常流行的缓存数据库,得益于其简单的 key-value 模式的数据存储和丰富的数据类型与事件机制使得 redis 成为当前后端开发中不可或缺的利器。下面推荐一些好用的 redis 的管理工具
前段时间组内有个投票的产品,上线前考虑欠缺,导致被刷票严重。后来,通过研究,发现可以通过 redis lua 脚本实现限流,这里将 redis lua 脚本相关的知识分享出来,讲的不到位的地方还望斧正。
Redis在Php项目中的实际应用场景:商品维度计数、用户维度计数、存储社交关系、用作缓存代替memcached、反spam系统、用户Timeline/Feeds、最新列表&排行榜、消息通知、将Redis用作消息队列
php调用redis进去读写操作,大并发下会出现:读取key1,没有内容则写入内容,但是大并发下会出现同时多个php进程写入的情况,这个时候需要加一个锁,即获取锁的php进程有权限写。
Redis配置成主从模式,主库(Master)只负责写数据,从库(Slave)只负责读数据。一个主库可以拥有多个从库,但一个从库只能隶属于一个主库。
连接操作命令,持久化,远程服务控制,对value操作的命令,String,List,Set,Hash,Redis 发布订阅命令,Redis 事务命令,查看keys个数,清空数据库
目前有很多成熟的缓存产品,包括Redis,memcached等。这里以Redis为例来分析下使用缓存实现分布式锁的方案。主要的实现方式是使用Jedis.setNX方法来实现。以上实现方式同样存在几个问题:
说到分布式缓存,可能大多数人脑海浮现的就是redis了,为什么redis能够在竞争激烈的缓存大战中脱颖而出呢?原因无非有一下几点:性能好,丰富的特性跟数据结构,api操作简单。但是用的人多了,就会出现很多不规范或者疏忽的地方,严重的时候甚至会导致生产事故
Redis是一个由Salvatore Sanfilippo写的key-value存储系统。Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!