窥探redis为什么会变慢

当今分布式服务大行其道,微服务,微应用解耦的需求层层推动,这个时候,咱们常常会用到redis这款中间件做为分布式系统的缓存来使用,以提升系统应用的响应速度,或者说下降服务器的负载难度。那么问题来了,redis速度快的flag是直接写官网的公屏上,那咱们不妨来推演一下,redis变慢的缘由,知其然而知其因此然。html

窥探redis为什么会变慢

你们之言

Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库。官方提供的数据是能够达到100000+的QPS(每秒内查询次数),数据结构简单,对数据操做也简单,Redis中的数据结构是专门进行设计的。使用多路I/O复用模型,非阻塞IO。前端

问题1:redis真的只是单进程单线程吗?redis

问题2:redis数据结构真的简单吗?数据库

不可能单线程

从表面上看采用单线程,这样避免了没必要要的上下文切换和竞争条件,也不存在多进程或者多线程致使的切换而消耗 CPU,甚至不用去考虑各类锁的问题,所以不存在加锁释放锁操做,没有由于可能出现死锁而致使的性能消耗。然而当咱们在启用rdb的时候,当咱们在启用scan的时候,都是会启用一个子进程来完成任务,而原来的主进程任务仍是在正常进行,对于系统来讲可能会存在响应时间长一点的感知。只看表面的话,对于redis的认知是远远不够的。后端

redis的数据结构很简单?

嗯,redis的数据结构说简单的话,纯粹是菜鸟教程看多了缓存

窥探redis为什么会变慢

redis的结构有挺多的,主要是一下三种:服务器

  • 常见的数据结构:string、hash、set、sortset、list
  • 特殊结构:HyperLogLog、Geo、Pub/Sub
  • redis modult:BloomFilter,RedisSearch,Redis-ML

经过分类咱们一来知道这玩意由浅入深的复杂,二来知道经过不通的结构能够处理不一样的业务场景。对于业务场景的探讨后续能够展开讲讲,此次主要是想推演一下,在全部场景中挺常见的现象——变慢。网络

redis为什么会变慢

随着时间的堆积,数据的累增,系统很直观的会感受的变慢的现象,对于大型程序来讲,主要是内存碎片啊、堆栈溢出啊等等这些关于垃圾回收机制致使的,另外的仍是跟其余组件在配合中,网络开销致使的现象,此次咱们主要是从redis自身进行分析。数据结构

基本性能

咱们应该先知道设备的基本性能,有数据比较才有调优的依据,刚上线的设备性能应该是最优秀的,以后就须要考虑,上线的服务数据的分布问题。多线程

基准性能

Redis 在一台负载正常的机器上,其最大的响应延迟和平均响应延迟分别是怎样的?

Redis 在不一样的软硬件环境下,它的性能是各不相同的。

指令

为了获取这些性能的数据,咱们可使用如下指令来获取数据。

Redis 的最小、最大、平均访问延迟

redis-cli -h 127.0.0.1 -p 6379 --latency-history -i 1

窥探redis为什么会变慢

60 秒内的最大响应延迟

redis-cli -h 127.0.0.1 -p 6379 --intrinsic-latency 60

窥探redis为什么会变慢

测试步骤

  1. 在相同配置的服务器上,测试一个正常 Redis 实例的基准性能
  2. 找到你认为可能变慢的 Redis 实例,测试这个实例的基准性能
  3. 若是你观察到,这个实例的运行延迟是正常 Redis 基准性能的 2 倍以上,便可认为这个 Redis 实例确实变慢了

发现问题

  1. 业务服务器到 Redis 服务器之间的网络存在问题,例如网络线路质量不佳,网络数据包在传输时存在延迟、丢包等状况
  2. Redis 自己存在问题,须要进一步排查是什么缘由致使 Redis 变慢

分析问题

分析问题的三把斧,链路追踪,看日志,大胆猜想

链路追踪

这里的链路追踪可能有点离题,由于是从整个系统全组件中,进行链路质量追踪,在这个过程当中能够发现某个环节出现时延太高的现象。常见的工具好比OpenTracing

看日志

目的是想知道在什么时间点,执行了哪些命令比较耗时,这个也是有指令来执行的。

Redis 的慢日志slowlog

查看Redis慢日志以前,你须要设置慢日志的阈值,让redis知道何时就是慢。例如,设置慢日志的阈值为 5 毫秒,而且保留最近 500 条慢日志记录

只记录一个命令真正操做内存数据的耗时

# 命令执行耗时超过 5 毫秒,记录慢日志
CONFIG SET slowlog-log-slower-than 5000
# 只保留最近 500 条慢日志
CONFIG SET slowlog-max-len 500

大胆猜想

这些其实都是日常积累到的状况,也是相关指令自己的问题致使的慢现象。

常用 O(N) 以上复杂度的命令,例如 SORT、SUNION、ZUNIONSTORE 聚合类命令

Redis 在操做内存数据时,时间复杂度太高,要花费更多的 CPU 资源。

所以对于数据的聚合操做,放在客户端作,也就是带着强计算能力的终端,redis本质是前端数据到后端数据过渡用的中间件,计算本不是他的强项,过分使用O(n)级别的指令,会致使redis消耗大量的cpu,所以尽可能把相关的开销负载到强cpu 的终端上。

使用 O(N) 复杂度的命令,但 N 的值很是大

Redis 一次须要返回给客户端的数据过多,更多时间花费在数据协议的组装和网络传输过程当中,为了不这种现象,应该须要避免大数据的传输,大象流改老鼠流。执行O(N) 命令,保证N 尽可能的小(推荐N <= 300),每次获取尽可能少的数据,让 Redis 能够及时处理返回

操做bigkey

若是一个key 写入的value 很是大,那么 Redis 在分配内存时就会比较耗时。一样的,当删除这个key 时,释放内存也会比较耗时,这种类型的key 咱们通常称之为bigkey

指令
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 0.01

窥探redis为什么会变慢

  1. 对线上实例进行 bigkey 扫描时,Redis 的 OPS 会突增,为了下降扫描过程当中对 Redis 的影响,最好控制一下扫描的频率,指定 -i 参数便可,它表示扫描过程当中每次扫描后休息的时间间隔,单位是秒
  2. 扫描结果中,对于容器类型(List、Hash、Set、ZSet)的 key,只能扫描出元素最多的 key。但一个 key 的元素多,不必定表示占用内存也多,你还须要根据业务状况,进一步评估内存占用状况
优化
  1. 业务应用尽可能避免写入 bigkey
  2. 若是你使用的 Redis 是 4.0 以上版本,用 UNLINK 命令替代 DEL,此命令能够把释放 key 内存的操做,放到后台线程中去执行,从而下降对 Redis 的影响
  3. 若是你使用的 Redis 是 6.0 以上版本,能够开启 lazy-free 机制(lazyfree-lazy-user-del = yes),在执行 DEL 命令时,释放内存也会放到后台线程中执行

集中过时,redis雪崩的现象

变慢的时间点颇有规律,例如某个整点,或者每间隔多久就会发生一波延迟

参考资料

  1. https://redis.io/topics/introduction
  2. https://www.runoob.com/redis/redis-data-types.html
  3. https://zhuanlan.zhihu.com/p/58358264
  4. https://medium.com/rahasak/kafka-with-etcd3-d04f438aa639
  5. https://www.jianshu.com/p/a036405f989c
  6. https://tianbin.org/learning/HyperLogLog/
  7. https://juejin.cn/post/6844903791590916109
  8. https://juejin.cn/post/684490386207200052
相关文章
相关标签/搜索