如何进行Redis性能优化?这一篇就够了( 二 )


另外,我们还可以从资源使用率层面来分析 , 如果你的应用程序操作 Redis 的 OPS 不是很大 , 但 Redis 实例的 CPU 使用率却很高,那么很有可能是使用了复杂度过高的命令导致的 。
3.操作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 bytesBiggestlist found 'mylist:004' has 40 itemsBiggestset found 'myset:2386' has 38 membersBiggesthash found 'myhash:3574' has 37 fieldsBiggestzset found 'myzset:2704' has 42 members36313 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)这里我需要提醒你的是 , 当执行这个命令时 , 要注意 2 个问题:
1)对线上实例进行 bigkey 扫描时,Redis 的 OPS 会突增,为了降低扫描过程中对 Redis 的影响 , 最好控制一下扫描的频率 , 指定 -i 参数即可 , 它表示扫描过程中每次扫描后休息的时间间隔,单位是秒 。
2)扫描结果中,对于容器类型(List、Hash、Set、ZSet)的 key,只能扫描出元素最多的 key 。但一个 key 的元素多,不一定表示占用内存也多,你还需要根据业务情况 , 进一步评估内存占用情况 。
4.集中过期
如果你发现,平时在操作 Redis 时,并没有延迟很大的情况发生,但在某个时间点突然出现一波延时,其现象表现为:变慢的时间点很有规律,例如某个整点,或者每间隔多久就会发生一波延迟 。
如果是出现这种情况,那么你需要排查一下,业务代码中是否存在设置大量 key 集中过期的情况 。
如果有大量的 key 在某个固定时间点集中过期,在这个时间点访问 Redis 时,就有可能导致延时变大 。
Redis 的过期数据采用被动过期 + 主动过期两种策略:
1)被动过期:只有当访问某个 key 时,才判断这个 key 是否已过期,如果已过期,则从实例中删除 。
2)主动过期:Redis 内部维护了一个定时任务,默认每隔 100 毫秒(1秒10次)就会从全局的过期哈希表中随机取出 20 个 key,然后删除其中过期的 key,如果过期 key 的比例超过了 25%,则继续重复此过程,直到过期 key 的比例下降到 25% 以下,或者这次任务的执行耗时超过了 25 毫秒,才会退出循环 。
注意,这个主动过期 key 的定时任务,是在 Redis 主线程中执行的 。
也就是说如果在执行主动过期的过程中,出现了需要大量删除过期 key 的情况,那么此时应用程序在访问 Redis 时,必须要等待这个过期任务执行结束,Redis 才可以服务这个客户端请求 。
如果此时需要过期删除的是一个 bigkey,那么这个耗时会更久 。而且 , 这个操作延迟的命令并不会记录在慢日志中 。
因为慢日志中只记录一个命令真正操作内存数据的耗时 , 而 Redis 主动删除过期 key 的逻辑,是在命令真正执行之前执行的 。
5.实例内存达到上限
当我们把 Redis 当做纯缓存使用时 , 通常会给这个实例设置一个内存上限 maxmemory,然后设置一个数据淘汰策略 。
当 Redis 内存达到 maxmemory 后,每次写入新的数据之前,Redis 必须先从实例中踢出一部分数据,让整个实例的内存维持在 maxmemory 之下,然后才能把新数据写进来 。
这个踢出旧数据的逻辑也是需要消耗时间的,而具体耗时的长短,要取决于你配置的淘汰策略: