持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第12天,点击查看活动详情
前言
你是不是经常能在redis日志里面发现报错:
[2489] 02 Jun 10:43:42 # Error allocating resoures for the client
错误是无法为客户端分配资源,查看redis连接数:
# redis-cli info | grep connected
connected_clients:5036
connected_slaves:0
客户端的连接竟然有达到5000多
其实最高的时候我发现有达到9000多的情况🐶
查看客户端连接情况:
redis 127.0.0.1:22151> client list
addr=10.247.64.115:52834 fd=5 idle=21 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=rpush
addr=127.0.0.1:38484 fd=7 idle=0 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=blpop
addr=10.105.1.2:53125 fd=8 idle=21 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=rpush
addr=10.105.1.3:32639 fd=9 idle=21 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=rpush
addr=10.105.1.4:57134 fd=10 idle=21 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=rpush
addr=10.105.1.5:53126 fd=11 idle=21 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=rpush
addr=10.105.1.7:8887 fd=12 idle=21 flags=N db=0 sub=0 psub=0 qbuf=0 obl=0 oll=0 events=r cmd=rpush
每个字段含义如下:
addr:客户端的地址和端口
fd:套接字所使用的文件描述符
idle:以秒计算的空闲时长
flags:客户端 flag
db:该客户端正在使用的数据库 ID
sub:已订阅频道的数量
psub:已订阅模式的数量
multi:在事务中被执行的命令数量
qbuf:查询缓冲区的长度(字节为单位, 0 表示没有分配查询缓冲区)
qbuf-free:查询缓冲区剩余空间的长度(字节为单位, 0 表示没有剩余空间)
obl:输出缓冲区的长度(字节为单位, 0 表示没有分配输出缓冲区)
oll:输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里)
omem:输出缓冲区和输出列表占用的内存总量
events:文件描述符事件
cmd:最近一次执行的命令
一开始我也考虑过,是否是因为客户端的idle空闲时间太长导致连接池维持了太多的无效连接,那么把不用的连接及时的释放就可以,比如:
redis 127.0.0.1:22151> CONFIG SET timeout 30
OK
但是实际上我们的超时已经设置过了,并且我们通过上面的记录可以发现,客户端idle空闲的时间其实并不长
于是我们继续查询客户端连接数的分布情况
netstat -an |grep 22151|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c
大致可以得到:
12:15
1 0.0.0.0
1 10.153.192.4
5 10.153.206.85
205 10.25.172.208
490 10.26.95.96
469 10.27.226.222
461 10.27.228.69
400 10.31.132.250
479 10.45.52.79
431 10.47.110.98
481 10.47.77.34
分析下来,因为我们的业务基本全是使用hash的方式存储,并且有大量用到hgetall的场景,入口处的并发也高,所以redis备机连接数过高,导致读取、连接超时
于是我想到了twemproxy
twemproxy(nutcracker)
twemproxy(nutcracker) 是 Twitter开源的轻量级 memcached / redis 代理服务器,本质就是一个集群管理工具,主要用来弥补 Redis和 Memcached对集群管理的不足,非常适合我们目前所遇到的场景
常规步骤
下载压缩包到服务器的目录中 我的全部包都在 /home/source 文件夹中
github地址:
- github版本:
git clone <https://github.com/twitter/twemproxy.git>
cd twemproxy
autoreconf -fvi
./configure --prefix=/usr/local/webserver/nutcracker
make && make install
如果中间进行不下去报错啦,注意一下,服务器上是否安装了
autoreconf、autoconf、automake、libtool
用 -h 检查一下,找不到的话用 yum install xxx(缺少的环境)
安装一下然后重新继续上次报错停止的步骤就行了
- tar.gz 包版本: 进入 github.com/twitter/twe…
下载一个最新的:如下图
然后用 rz || rz -y 上传到服务器的 /home/source 文件夹中
配置 nutcracker 以及[做一个连接(相当于快捷方式)]
配置 nutcracker.yml 文件代码(推荐在 /etc/ 中自建一个配置文件)
alpha:
listen: 127.0.0.1:22151
hash: fnv1a_64
distribution: ketama
auto_eject_hosts: true
redis: true
server_retry_timeout: 2000
server_failure_limit: 1
servers:
- 10.25.68.40:22151:1
beta:
listen: 127.0.0.1:22152
hash: fnv1a_64
distribution: ketama
auto_eject_hosts: true
timeout: 400
redis: true
servers:
- 10.28.254.194:22151:1
建立连接: ln -n 源启动文件 名为nutcracker的快捷启动文件
ln -n /usr/local/webserver/nutcracker/sbin/nutcracker /usr/bin/nutcracker
启动
如何启动 nutcracker 并可以使其断开后自动重新连接并输出日志
写一个脚本,并在一个死循环内部的写运行 nutcracker 的方法: nutcracker(由于上面做过连接可以在任何地方直接调用) -c (配置文件 nutcracker.yml 的位置),为了便于记录进程死的次数,再输出一份重启的日志并记录时间,最后通过 screen 的方式挂在服务器上跑就行了
脚本代码:
while true
do
day=`date "+%y-%m-%d %H:%M:%S"`
echo -e "nutcracker Restart "$day"\n" >> ~/logs/nutcracker.log
nutcracker -c /etc/nutcracker.yml
done
screen -S nutcracker (新建一个名为nutcracker的窗口)
cd /data/auto (脚本放置位置)
./脚本.sh
control + a + d (将screen挂在后台运行)
总结
再检查一下 启动日志是否在正常输出
tail -f ~/logs/nutcracker.log