REDIS 集群安装运维调优及常见问题处理
上篇详细阐述了 redis 集群的安装搭建以及集群监控变更相关运维操作,本篇继续对 redis 集群调优和常见问题的解决进行介绍。
一、集群调优
1.1 Linux 内存内核参数优化:
Vm.overcommit_memory
参数说明: 文件指定了内核针对内存分配的策略,其值可以是 0、1、2。
0:表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存, 内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
1:表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
2:表示内核允许分配超过所有物理内存和交换空间总和的内存。
建议该参数设置为 1
1.2 网络参数优化:
系统打开最大文件数设置:
fs.file-max:系统所有进程一共可以打开的文件数量
Fs.file-nr:这个是一个状态指示的文件,一共三个值:
第一个代表全局已经分配的文件描述符数量
第二个代表自由的文件描述符(待重新分配的)
第三个代表总的文件描述符的数量。
swap 设置:
为提高 redis 整体性能 ,避免 redis 内部的热数据被在内存不足的情况被交换到磁盘,读取数据的时候相应缓慢,建议尽量不使用 swap 或者禁用 swap。对于内部不足 最好的方法还是扩大内存。
临时生效:
sysctl -w vm.swappiness=0
永久生效:
echo "vm.swappiness = 0">> /etc/sysctl.conf(尽量不使用交换分区,注意不不是禁用)
刷新 SWAP:可以执行命令刷新一次 SWAP(将 SWAP 里的数据转储回内存,并清空 SWAP 里的数据)
swapoff -a && swapon -a
sysctl -p (执行这个使其生效,不用重启)
或者直接关闭 swap
swapoff -a
并修改文件 /etc/fstab 注释掉 swap 行,并重启永久生效
关闭透明大页(Transparent Huge Pages):
在 redis 实例启动时候会报如下警告:
WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
意思是:你使用的是透明大页,可能导致 redis 延迟和内存使用问题
执行以下命令可修复该问题:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
永久解决方案:
修改内核参数 /boot/grub/grub.conf
添加 transparent_hugepage=never numa=off
重启生效
open-file:
用户会话级别的文件打开的最大数
1.3 Redis 配置参数调优:
禁用 rdb 持久化
rdb 持久化会导致 redis 实例频繁的做 fork 操作,fork 创建一个子进程,比较耗费资源。
在访问量比较大的系统中(特别是更新/插入比较频繁的系统中),会产生大量的增量数据,系统刷新大量的增量数据到磁盘会严重导致性能波动。
rdb 会丢数据
建议设置为 save “”
设置 maxmemory
默认值是 0,表示不限制内存使用,会导致系统资源被耗尽。建议根据项目系统需求设置一个最大值,但不建议单实例超过 20gb。
设置 timeout 超时时间
防止大量空闲链接占用大量资源 ,建议设置将超时链接设置为 3600s Timeout 3600
slowlog-max-len
设置 1000,记录慢查询的条数,默认 128 ,增加该值,方便排查系统异常等问题。
tcp-backlog 默认
TCP 接收队列长度,受以下两个内核参数的影响:
/proc/sys/net/core/somaxconn
tcp_max_syn_backlog
在高并发的环境下,你需要把这个值调高以避免客户端连接缓慢的问题。
数据持久化策略
数据持久化策略 ,以场景为主
appendonly: 是否开启 appendonlylog,开启的话每次写操作会记一条 log,这会提高数据抗风险能力,但影响效率。
appendfsync: appendonlylog 如何同步到磁盘(三个选项,分别是每次写都强制调用 fsync、每秒启用一次 fsync、不调用 fsync 等待系统自己同步)。可以设置为 no,everysec,always
no:只需让操作系统在需要时刷新数据。速度快。
everysec (默认):fsync 每秒只有一次。折中。
always:每次写入仅附加日志后的 fsync。慢,最安全。
发送使用 fsync 的默认策略,每秒写入性能仍然很好(使用后台线程执行 fsync,并且当没有 fsync 正在进行时,主线程将努力执行写入。)建议设置为 everysec.
数据淘汰策略 待确认
maxmemory-policy 六种方式 :
volatile-lru:只对设置了过期时间的 key 进行 LRU(默认值)
allkeys-lru :是从所有 key 里 删除 不经常使用的 key
volatile-random:随机删除即将过期 key
allkeys-random:随机删除
volatile-ttl:删除即将过期的
noeviction:永不过期,返回错误
建议设置为 volatile-ttl
repl-diskless-sync 启用无盘复制
复制过程中产生的 rdb 文件不落盘,避免造成过大的 io,影响性能 该参数默认 no
建议设置为 no
repl-disable-tcp-nodelay
是否启用 TCP_NODELAY,如果启用则会使用少量的 TCP 包和带宽去进行数据传输到 slave 端,当然速度会比较慢;如果不启用则传输速度比较快,但是会占用比较多的带宽。
no-appendfsync-on-rewrite
bgrewriteaof 机制,在一个子进程中进行 aof 的重写,从而不阻塞主进程对其余命令的处理,同时解决了 aof 文件过大问题。
现在问题出现了,同时在执行 bgrewriteaof 操作和主进程写 aof 文件的操作,两者都会操作磁盘,而 bgrewriteaof 往往会涉及大量磁盘操作,这样就会造成主进程在写 aof 文件的时候出现阻塞的情形。
现在 no-appendfsync-on-rewrite 参数出场了:如果该参数设置为 no,是最安全的方式,不会丢失数据,但是要忍受阻塞的问题。如果设置为 yes 呢?这就相当于将 appendfsync 设置为 no,这说明并没有执行磁盘操作,只是写入了缓冲区,因此这样并不会造成阻塞(因为没有竞争磁盘),但是如果这个时候 redis 挂掉,就会丢失数据。
丢失多少数据呢?在 linux 的操作系统的默认设置下,最多会丢失 30s 的数据。因此,如果应用系统无法忍受延迟,而可以容忍少量的数据丢失,则设置为 yes。如果应用系统无法忍受数据丢失,则设置为 no。
tcp-keepalive
发送 redis 服务端主动向空闲的客户端发起 ack 请求,以判断连接是否有效 ,默认值为 0 ,表示禁用,可以通过 tcp-keepalive 配置项来进行设置,单位为秒。假如设置为 60 秒,则 server 端会每 60 秒向连接空闲的客户端发起一次 ACK 请求,以检查客户端是否已经挂掉,对于无响应的客户端则会关闭其连接。所以关闭一个连接最长需要 120 秒的时间。如果设置为 0,则不会进行保活检测。默认为 0
cluster-slave-validity-factor
设置 slave 断开 master 的时间因子在进行故障转移的时候全部 slave 都会请求申请为 master,但是有些 slave 可能与 master 断开连接一段时间了导致数据过于陈旧,不应该被提升为 master。该参数就是用来判断 slave 节点与 master 断线的时间是否过长。
判断方法是:比较 slave 断开连接的时间和(node-timeout * slave-validity-factor)+ repl-ping-slave-period 如果节点超时时间为三十秒, 并且 slave-validity-factor 为 10,假设默认的 repl-ping-slave-period 是 10 秒,即如果超过 310 秒 slave 将不会尝试进行故障转移。
cluster-node-timeout
Cluster 集群中节点互联超时时间 ,默认 15s
cluster-require-full-coverage
默认是 yes
集群所有主节点状态为 ok 才提供服务。建议设置为 no,可以在 slot 没有全部分配的时候提供服务。
cluster-migration-barrier
cluster-migration-barrier 默认值
只有当一个主节点至少拥有其他给定数量个处于正常工作中的从节点的时候,才会分配从节点给集群中孤立的主节点。这个给定数量就是 migration barrier。migration barrier 是 1 意味着一个从节点只有在其主节点另外至少还有一个正常工作的从节点的情况下才会被分配...
注:孤立的主节点:原本有 slave,但 slave 离线的 master,本身没有 slave 的 master 不属于孤立主节点。
min-slaves-to-write 默认
master 必须最少拥有的 slave ,否则不允许写入 ,默认值为 0 ,表示禁用此特性
min-slaves-max-lag 默认
限制 slave 延迟的最大时间,如超过这个时间,master 拒绝写入
slave-serve-stale-data
设置从库是否可对外提供服务
slave-serve-stale-data 参数设置成 yes,主从复制中,从服务器可以响应客户端请求;
slave-serve-stale-data 参数设置成 no,主从复制中,从服务器将阻塞所有请求,有客户端请求时返回“SYNC with master in progress”
二、常见问题
2.1 redis 链接超时
异常现象:
redis 应用链接超时,zabbix 监控链接超时获取不到监控数据 ,Linux 系统层面,redis 进程所在的 cpu 节点 ,cpu 使用率 100% ,可用内存比较多(free 比较小 ,cache 比较多),磁盘写比较高,cpu sys 时间占比非常高。
磁盘现象:
Cpu 现象:
内存状态:
分析:
通过查看 redis 错误日志,发现 redis 6443 实例正在执行 aof rewrite 操作。通过对比之前 zabbix 监控和 aof rewrite 时间点,几乎 redis6443 实例每次进行 aof 操作的时候 Linux 出现以上现象(链接超时,cpu 高) 。
从日志中分析可以看出,在进行 aof rewrite 的时,Linux 额外分配了差不多 60G 的内存给 redis 的 fork 进程,而此时 free 内存不足 60g 理论上应该使用 cache,但是从表象上看,并没有直接使用 cache,而是在使用 cache 之前做了部分清理工作(cpu sys 时间比较高),腾出部分空闲空间 。
临时解决方案:清理 cache
echo 1 > /proc/sys/vm/drop_caches
问题得到临时解决
永久解决方案:关掉 Linux 的透明大页
临时关闭:
echo never > /sys/kernel/mm/redhat_transparent_hugepage/enabled
永久关闭
2.2 io 报错
I/O error reading bulk count from MASTER: Operation now in progress
调整 client-output-buffer-limit 解决
127.0.0.1:9003> config get client-output-buffer-limit
"client-output-buffer-limit"
"normal 0 0 0 slave 0 0 0 pubsub 33554432 8388608 60"
对于普通客户端来说,限制为 0,也就是不限制。因为普通客户端通常采用阻塞式的消息应答模式,何谓阻塞式呢?如:发送请求,等待返回,再发送请求,再等待返回。这种模式下,通常不会导致 Redis 服务器输出缓冲区的堆积膨胀;
对于 Pub/Sub 客户端(也就是发布/订阅模式),大小限制是 8M,当输出缓冲区超过 8M 时,会关闭连接。持续性限制是,当客户端缓冲区大小持续 60 秒超过 2M,则关闭客户端连接;3. 对于 slave 客户端来说,大小限制是 256M,持续性限制是当客户端缓冲区大小持续 60 秒超过 64M,则关闭客户端连接。
2.3 aof 文件损坏
出错过程:
实例在将 aof 文件读取到内存时,中断,redis 进程自动关闭
日志报错:
WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. [2716] 28 Apr 10:17:27.915 # Bad file format reading the append only file: make a backup of your AOF file, then use./redis-check-aof --fix <filename> [2761] 28 Apr 10:19:40.866 * Increased maximum number of open files to 10032 (it was originally set to 1024)
解决方法:
使用 redis-check-aof 修复 aof 文件,操作命令如下:
$:redis-check-aof --fix appendonly.aof
然后重新启动 redis
2.4 新增节点至 redis 集群时报错
报错信息:
[ERR] Node 10.1.193.209:8006 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
原因:
新增节点不为空 解决:删除新增节点的 node.file,aof 文件,flushdb 或者 kill 进程重新建立节点(有时候/var/run/下面没有进程文件,导致进程没有关闭)。到这里 redis 系列文章就暂时完结了,感谢大家的阅读和支持,后续将持续更新其他系列技术文章。
程序员的核心竞争力其实还是技术,因此对技术还是要不断的学习,关注 “IT 巅峰技术” 公众号 ,该公众号内容定位:中高级开发、架构师、中层管理人员等中高端岗位服务的,除了技术交流外还有很多架构思想和实战案例。
作者是 《 消息中间件 RocketMQ 技术内幕》 一书作者,同时也是 “RocketMQ 上海社区”联合创始人,曾就职于拼多多、德邦等公司,现任上市快递公司架构负责人,主要负责开发框架的搭建、中间件相关技术的二次开发和运维管理、混合云及基础服务平台的建设。
版权声明: 本文为 InfoQ 作者【IT巅峰技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/1e6c3b6b14baeb971cfd67195】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论