专题类网站,成都建设网站,网站dns解析,企业网站备案备注1.是否使用复杂度过高的命令
首先#xff0c;第一步#xff0c;你需要去查看一下 Redis 的慢日志#xff08;slowlog#xff09;。
Redis 提供了慢日志命令的统计功能#xff0c;它记录了有哪些命令在执行时耗时比较久。
查看 Redis 慢日志之前#xff0c;你需要设置慢…1.是否使用复杂度过高的命令
首先第一步你需要去查看一下 Redis 的慢日志slowlog。
Redis 提供了慢日志命令的统计功能它记录了有哪些命令在执行时耗时比较久。
查看 Redis 慢日志之前你需要设置慢日志的阈值。例如设置慢日志的阈值为 5 毫秒并且保留最近 500 条慢日志记录
redis-cli -h 127.0.0.1 -p 6379
# 命令执行耗时超过 5 微秒记录慢日志
CONFIG SET slowlog-log-slower-than 5
# 只保留最近 500 条慢日志
CONFIG SET slowlog-max-len 500
#获取最近的 10 条慢查询命令
redis-cli SLOWLOG GET 10
1查看日志中是否使用 O(N) 以上复杂度的命令例如 SORT、SUNION、ZUNIONSTORE 聚合类命令
2Redis 一次需要返回给客户端的数据过多更多时间花费在数据协议的组装和网络传输过程中。
优化
1对于数据的聚合操作放在客户端做
2每次获取尽量少的数据让 Redis 可以及时处理返回
2. 是否操作 bigkey
如果你查询慢日志发现并不是复杂度过高的命令导致的而都是 SET / DEL 这种简单命令出现在慢日志中那么需要判断实例是否写入了 bigkey
redis-cli -h 127.0.0.1 -p 6379 --bigkeys -i 1
-------- summary -------
Sampled 829675 keys in the keyspace!
Total key length in bytes is 10059825 (avg len 12.13)
Biggest string found key:291880 has 10 bytes
Biggest list found mylist:004 has 40 items
Biggest set found myset:2386 has 38 members
Biggest hash found myhash:3574 has 37 fields
Biggest zset found myzset:2704 has 42 members
36313 strings with 363130 bytes (04.38% of keys, avg size 10.00)
787393 lists with 896540 items (94.90% of keys, avg size 1.14)
1994 sets with 40052 members (00.24% of keys, avg size 20.09)
1990 hashs with 39632 fields (00.24% of keys, avg size 19.92)
1985 zsets with 39750 members (00.24% of keys, avg size 20.03)
3. 数据是否集中过期
当redis中大量数据集中过期时请求穿透到mysql等关系型数据库会导致查询速度变慢从而影响redis响应变慢
在某个时间点突然出现一波延时其现象表现为变慢的时间点很有规律例如某个整点或者每间隔多久就会发生一波延迟。
优化
1集中过期 key 增加一个随机过期时间把集中过期的时间打散降低 Redis 清理过期 key 的压力
# 在过期时间点之后的 5 分钟内随机过期掉
redis.expireat(key, expire_time random(300))
2如果使用的 Redis 是 4.0 以上版本可以开启 lazy-free 机制当删除过期 key 时把释放内存的操作放到后台线程中执行避免阻塞主线程。
# 释放过期 key 的内存放到后台线程执行
lazyfree-lazy-expire yes
4. 实例内存是否达到上限 把 Redis 当做纯缓存使用时通常会给这个实例设置一个内存上限 maxmemory然后设置一个数据淘汰策略。
当 Redis 内存达到 maxmemory 后每次写入新的数据之前Redis 必须先从实例中踢出一部分数据让整个实例的内存维持在 maxmemory 之下然后才能把新数据写进来。
这个踢出旧数据的逻辑也是需要消耗时间的而具体耗时的长短要取决于你配置的淘汰策略 allkeys-lru不管 key 是否设置了过期淘汰最近最少访问的 keyvolatile-lru只淘汰最近最少访问、并设置了过期时间的 keyallkeys-random不管 key 是否设置了过期随机淘汰 keyvolatile-random只随机淘汰设置了过期时间的 keyallkeys-ttl不管 key 是否设置了过期淘汰即将过期的 keynoeviction不淘汰任何 key实例内存达到 maxmeory 后再写入新数据直接返回错误allkeys-lfu不管 key 是否设置了过期淘汰访问频率最低的 key4.0 版本支持volatile-lfu只淘汰访问频率最低、并设置了过期时间 key4.0 版本支持
一般最常使用的是 allkeys-lru / volatile-lru 淘汰策略它们的处理逻辑是每次从实例中随机取出一批 key这个数量可配置然后淘汰一个最少访问的 key之后把剩下的 key 暂存到一个池子中继续随机取一批 key并与之前池子中的 key 比较再淘汰一个最少访问的 key。以此往复直到实例内存降到 maxmemory 之下。
需要注意的是Redis 的淘汰数据的逻辑与删除过期 key 的一样也是在命令真正执行之前执行的也就是说它也会增加我们操作 Redis 的延迟而且写 OPS 越高延迟也会越明显。
优化
1淘汰策略改为随机淘汰随机淘汰比 LRU 要快很多视业务情况调整
2拆分实例把淘汰 key 的压力分摊到多个实例上
5. 是否开启了redis持久化
当 Redis 开启了后台 RDB 和 AOF后在执行时它们都需要主进程fork出一个子进程进行数据的持久化。主进程在 fork 子进程期间整个实例阻塞无法处理客户端请求的时间。因此如果此时磁盘的 IO 负载很高那这个后台线程在执行刷盘操作fsync 系统调用时就会被阻塞住。此时的主线程依旧会接收写请求紧接着主线程又需要把数据写到文件内存中write 系统调用当主线程使用后台子线程执行了一次 fsync需要再次把新接收的操作记录写回磁盘时如果主线程发现上一次的 fsync 还没有执行完那么它就会阻塞。
你可以在 Redis 上执行 INFO 命令查看 latest_fork_usec 项单位微秒。
##上一次 fork 耗时单位微秒
latest_fork_usec:59477
对于AOP还存在着 AOF rewrite操作这个过程也会占用大量的磁盘 IO 资源。此外fork 的耗时也与系统也有关虚拟机比物理机耗时更久。
优化
1当子进程在 AOF rewrite 期间可以让后台子线程不执行刷盘
# AOF rewrite 期间AOF 后台子线程不进行刷盘操作
# 相当于在这期间临时把 appendfsync 设置为了 none
no-appendfsync-on-rewrite yes
2把redis创建到真实物理机上而不是虚拟机
3如果只是把redis作为缓存使用可以关闭RDB 和 AOF持久化功能
4尽量不要把redis 和 其他 i/o 使用率高的创建在同一台机器上让 Redis 运行在独立的机器上。
5SSD磁盘要比机械硬盘读写效率高出许多
6. 是否开启了内存大页
如果采用了内存大页那么即使客户端请求只修改 100B 的数据Redis 也需要拷贝 2MB 的大页。相反如果是常规内存页机制只用拷贝 4KB。两者相比你可以看到当客户端请求修改或新写入数据较多时内存大页机制将导致大量的拷贝这就会影响 Redis 正常的访存操作最终导致性能变慢。
首先我们要先排查下内存大页。方法是在 Redis 实例运行的机器上执行如下命令:
$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never如果执行结果是 always就表明内存大页机制被启动了如果是 never就表示内存大页机制被禁止。
在实际生产环境中部署时我建议你不要使用内存大页机制操作也很简单只需要执行下面的命令就可以了
echo never /sys/kernel/mm/transparent_hugepage/enabled其实操作系统提供的内存大页机制其优势是可以在一定程序上降低应用程序申请内存的次数。
但是对于 Redis 这种对性能和延迟极其敏感的数据库来说我们希望 Redis 在每次申请内存时耗时尽量短所以我不建议你在 Redis 机器上开启这个机制。
7. 最后还要考虑网络及机器配置对 Redis 性能的影响