一 观察指标
1 cpu 性能监控图 关注 user 和system的使用率
2 network 性能监控图
出口流量如果很大的话代表可能存在大key或者高并发查询(get)
进口流量如果很大的话代表可能存在高并发写入(set)
3 IOPS 性能监控图
备份机制导致 频繁的AOF操作和间隔性的RDB操作都可能导致IO升高
4 内存性能监控图
redis本身内存在配置文件中有定制 ,如果超过了报警的阈值就需要减少key的量或者给服务器内存扩容
5 key相关
1 hits/misses key的命中问题,如果大量没有命中,会导致缓存穿透
2 expiring/not-expiring key key的失效问题,如果过期的值瞬间升高,会导致缓存失效
3 command-calls 各种操作类型的统计,排查哪个动作耗费的cpu过高
4 clients 总的连接数大小统计,排查现在整体的连接水平
5 evicted_keys 由于 maxmemory 限制,而被回收内存的 key 的总数 被回收的key
- evicted_keys属性就是被回收的keys的数量
- 如果evicted_keys增加速度比较快,说明一部分CPU被征用来回收Key
6 QPS
1 常见查询操作
字符串类型->get
hash类型 hget 单个(select one)
hmget 多个(select manay)
hgetall 所有(select all)
list类型 lrange key start stop select manay
lindex key index select one
2 常见写入操作
字符串类型-> set setnx(SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写)
hash类型->hset(如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。如果字段已经存在于哈希表中,旧值将被覆盖)
集合 ->sadd 多个元素写入集合
列表->lpop lset
3 常见删除操作
删除类型->del
4 通用操作 1 确认value是否存在 exits 有些程序是先exists确定key是否存在 再进行访问,所以有可能出现exists统计量很高的情况
2 查看key类型 type 系统
3 健康检测 ping 系统
4 设置过期时间 expire 程序 主动设置过期时间,但是频率不高
5 配置文件 config 系统
6 整体查看 info 系统
二 Redis参数
1 maxclients 最大连接数
redis-cli -p port client list|grep -Evi "name=sentinel-|addr=127.0.0.1"|awk -F'=|:' '{print $3}'|sort -n|uniq -c|sort -nr 分组统计连接数
redis-cli -p port info|grep list 统计总连接数
2 maxmemory 最大内存
、 根据监控图-内存 进行分析数据内存占用
3 实时观察入库命令
redis Monitor
4 慢日志 slowlog get N
5 config get maxmemory-policy 查看默认的淘汰机制
三 具体问题分析
1 redis连接超时
可能原因
1 到达了redis设置的maxclients数量
2 程序本身redis配置有问题
3 redis本身服务不可用
4 redis本身服务处于高负载状态,导致阻塞无法处理新的连接
补充 redis 超时问题有可能是C/S两头的问题,不一定问题只出现在redis-server 这里要注意
redis-cli -h {host} -p {port} --latency 延时测试
redis-cli -h {host} -p {port} --latency-history 延时采样测试 15S 一次
2 redis key不淘汰的问题
现象: redis key 的内存占用一直升高,默认设置了淘汰策略没有起作用
可能原因
1 由于人为或者程序更改了淘汰策略,进行手动查看 redis info|grep maxmemory_policy,进行对比即可,我们线上用的是allkeys-lru(allkeys-lru: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key) 这也是3.0以上版本默认的淘汰机制
3 出口流量问题
1 通过 iftop -i eth0 -nNB -m 10M 过滤出出口流量大于10M的应用IP,确定具体应用服务
2 获取PMM监控数据
1 总的命令数是否有异常
2 具体的命令排行 要着重观察get hgetall
3 观察慢日志的异常操作
slowlog get num
4 分析server.log是否有异常
5 内存碎片问题
定义
1 相关指标 mem_fragmentation_ratio 计算方式 Redis向操作系统申请的内存/REDIS数据在内存的占用比例 可以这样理解 相差不要太多两者.大于或者小于太多都不合适
2 对于内存碎片率,一般保持在 1~1.5 之间是最合理的。 如果大于1.5 就代表超过50%的碎片产生,需要清理 如果小于1 代表需要进行扩容内存
3 Redis 中,最常用的是写入、修改、删除数据。这些操作在执行后都会产生 一定程度的内存碎片
解决
1 重启redis服务,重新读取RDB数据文件
2 Redis 中有专门的参数设置用来进行自动清理内存碎片:activedefrag yes 适用于版本大于4.0的方式
active-defrag-ignore-bytes 100mb:
碎片达到100MB时,开启清理。
active-defrag-threshold-lower 10:
当碎片超过 10% 时,开启清理。
active-defrag-threshold-upper 100:
内存碎片超过 100%,尽最大清理。mb
active-defrag-cycle-min 5:
清理内存碎片占用 CPU 时间的比例不低于此值,保证清理能正常开展。
active-defrag-cycle-max 75:
清理内存碎片占用 CPU 时间的比例不高于此值。一旦超过则停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致其它请求延迟。
四 一些其他通用操作
1 配置设置相关
1 config get "*" 2 config set "maxmemory" "8000000000" 3 config rewrite(保存)
五 基础
单线程
1 多路复用和非阻塞 I/O:Redis 使用 I/O 多路复用功能来使用多线程监听多个 socket 连接客户端,这样就可以使用一个线程连接来处理多个请求,减少线程切换带来的开销,同时也避免了 I/O 阻塞操作,从而大大提高了 Redis 的性能;
比如当 socket 中有数据时,Redis 会通过调用先将数据从内核态空间拷贝到用户态空间,再交给 Redis 调用,而这个拷贝的过程就是阻塞的,当数据量越大时拷贝所需要的时间就越多,而这些操作都是基于单线程完成的。
2 避免上下文切换:因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的消耗,而且单线程不会导致死锁问题的发生。
3 内存操作而并非硬盘 数据结构简单
4 多线程改进
1 4.0 多线程对于大key和清理全量key的异步操作 利用多线程(属于不常用的后台操作)
2 6.0 多线程对于读写的多线程提供 将 I/O 读写变成了多线程,而命令的执行依旧是由主线程串行执行的,因此在多线程下操作 Redis 不会出现线程安全的问题
5 总结
1 6.0 处理请求(多线程)-> IO读写(多线程)->命令执行(单线程)
2 在redis的多线程模式下,获取、解析命令,以及输出结果着两个过程,可以配置成多线程执行的,因为它毕竟是我们定位到的主要耗时点 但是大部分命令执行都是单线程 针对用户请求
六 补充
1 redis的rdb备份属于冷文件 可以实时进行拷贝
2 耗时相关
redis相关耗时总结
1 发送命令网络传输时间(网络稳定性)->命令在Redis服务端队列中等待的时间(队列等待,因为是串行),命令执行的时间(Redis中的slowlog检测命令执行时间),结果返回的Redis客户端的时间(结果检测集的大小)。
八 相关名词
缓存穿透 查询一个并不存在的key,直接穿透redis 最常用的方式是程序中采用 布隆过滤器
缓存击穿 大量的请求同时查询一个 key 时,此时这个key正好失效了,就会导致大量的请求都打到数据库上面去。这种现象我们称为缓存击穿。
1 用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上
2 还有一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降
缓存雪崩 当某一时刻发生大规模的缓存失效的情况,比如你的缓存服务宕机了,会有大量的请求进来直接打到DB上面。结果就是DB 称不住,挂掉。进行高可用使用redis-clister
缓存并发 高并发量的key访问 进行拆分
分布式锁