持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
前言
redis的一个优点就是快,但是对于甲方爸爸来说,只是快还不够,要更快一点,要最快。所以,redis性能调优你必须了解,让你的redis快到飞起。
设置键值的过期时间(惰性删除)
我们应该根据实际的业务情况,对键值设置合理的过期时间,这样 Redis 会帮你自动清除过期的键 值对,以节约对内存的占用,以避免键值过多的堆积,频繁的触发内存淘汰策略。 相关命令如下:
- EXPlRE 命令用于将键key 的生存时间设置为ttl 秒。
- PEXPIRE 命令用于将键key 的生存时间设置为ttl 毫秒。
- EXPIREAT < timestamp> 命令用于将键key 的过期时间设置为timestamp所指定的秒数时间戳。
- PEXPIREAT < timestamp > 命令用于将键key 的过期时间设置为timestamp所指定的毫秒数时间戳。
使用lazy free特性
lazy free 特性是 Redis 4.0 新增的一个非常使用的功能,它可以理解为惰性删除或延迟删除。意思是在 删除的时候提供异步延时释放键值的功能,把键值释放操作放在 BIO(Background I/O) 单独的子线程处 理中,以减少删除删除对 Redis 主线程的阻塞,可以有效地避免删除 big key 时带来的性能和可用性问题。 lazy free对应了4种场景,默认都是关闭的:
- lazyfree-lazy-eviction no
- lazyfree-lazy-expire no
- lazyfree-lazy-server-del no
- slave-lazy-flush no 它们代表的含义如下:
- lazyfree-lazy-eviction:表示当 Redis 运行内存超过最大内存时,是否开启 lazy free 机制删除;
- lazyfree-lazy-expire:表示设置了过期时间的键值,当过期之后是否开启 lazy free 机制删除;
- lazyfree-lazy-server-del:有些指令在处理已存在的键时,会带有一个隐式的 del 键的操作,比如 rename 命令,当目标键已存在,Redis 会先删除目标键,如果这些目标键是一个 big key,就会 造成阻塞删除的问题,此配置表示在这种场景中是否开启 lazy free 机制删除;
- slave-lazy-flush:针对 slave(从节点) 进行全量数据同步,slave 在加载 master 的 RDB 文件前, 会运行 flushall 来清理自己的数据,它表示此时是否开启 lazy free 机制删除。 建议开启其中的 lazyfree-lazy-eviction、lazyfree-lazy-expire、lazyfree-lazy-server-del 等配置,这样 就可以有效的提高主线程的执行效率。
限制 Redis 内存大小,设置内存淘汰策略
没有指定最大缓存,如果有新的数据添加,超过最大内存,则32位会使redis崩溃,所以一定要设置。 最佳设置是物理内存的75% ,写操作比较多 60% 相关参数:
- maxmemory 1048576
- maxmemory 1048576B
- maxmemory 1000KB
- maxmemory 100MB
- maxmemory 1GB
- maxmemory 1000K
- maxmemory 100M
- maxmemory 1G 设置内存淘汰策略:
- noeviction:不淘汰任何数据,当内存不足时,新增操作会报错,Redis 默认内存淘汰策略;
- allkeys-lru:淘汰整个键值中最久未使用的键值;
- allkeys-random:随机淘汰任意键值;
- volatile-lru:淘汰所有设置了过期时间的键值中最久未使用的键值;
- volatile-random:随机淘汰设置了过期时间的任意键值;
- volatile-ttl:优先淘汰更早过期的键值。
- volatile-lfu:淘汰所有设置了过期时间的键值中,最少使用的键值;
- allkeys-lfu:淘汰整个键值中最少使用的键值。
禁用长耗时的查询命令
Redis 绝大多数读写命令的时间复杂度都在 O(1) 到 O(N) 之间,其中 O(1) 表示可以安全使用的,而 O(N) 就应该当心了,N 表示不确定,数据越大查询的速度可能会越 慢。因为 Redis 只用一个线程来做数据查询,如果这些指令耗时很长,就会阻塞 Redis,造成大量延 时。 要避免 O(N) 命令对 Redis 造成的影响,可以从以下几个方面入手改造:
- 决定禁止使用 keys 命令;
- 避免一次查询所有的成员,要使用 scan 命令进行分批的,游标式的遍历;
- 通过机制严格控制 Hash、Set、Sorted Set 等结构的数据大小;
- 将排序、并集、交集等操作放在客户端执行,以减少 Redis 服务器运行压力;
- 删除 (del) 一个大数据的时候,可能会需要很长时间,所以建议用异步删除的方式 unlink,它会启 动一个新的线程来删除目标数据,而不阻塞 Redis 的主线程
使用 slowlog 优化耗时命令
我们可以使用 slowlog 功能找出最耗时的 Redis 命令进行相关的优化,以提升 Redis 的运行速度, 慢查询有两个重要的配置项:
- slowlog-log-slower-than :用于设置慢查询的评定时间,也就是说超过此配置项的命令,将会 被当成慢操作记录在慢查询日志中,它执行单位是微秒 (1 秒等于 1000000 微秒);
- slowlog-max-len :用来配置慢查询日志的最大记录数。
避免大量数据同时失效
如果在大型系统中有大量缓存在同一时间同时过期,那么会导致 Redis 循环多次持续扫描删除过期字 典,直到过期字典中过期键值被删除的比较稀疏为止,而在整个执行过程会导致 Redis 的读写出现明显 的卡顿,卡顿的另一种原因是内存管理器需要频繁回收内存页,因此也会消耗一定的 CPU。 为了避免这种卡顿现象的产生,我们需要预防大量的缓存在同一时刻一起过期,就简单的解决方案就是 在过期时间的基础上添加一个指定范围的随机数。
使用 Pipeline 批量操作数据
Pipeline (管道技术) 是客户端提供的一种批处理技术 可以批量执行一组指令,一次性返回全部结果, 可以减少频繁的请求应答
客户端使用优化
在客户端的使用上我们除了要尽量使用 Pipeline 的技术外,还需要注意要尽量使用 Redis 连接池,而不 是频繁创建销毁 Redis 连接,这样就可以减少网络传输次数和减少了非必要调用指令。
使用分布式架构来增加读写速度
Redis 分布式架构有重要的手段:
- 主从同步
- 哨兵模式
- Redis Cluster 集群
使用物理机而非虚拟机
在虚拟机中运行 Redis 服务器,因为和物理机共享一个物理网口,并且一台物理机可能有多个虚拟 机在运行,因此在内存占用上和网络延迟方面都会有很糟糕的表现,我们可以通过 ./redis-cli -- intrinsic-latency 100 命令查看延迟时间,如果对 Redis 的性能有较高要求的话,应尽可能在物理 机上直接部署 Redis 服务器。
禁用 THP 特性
当开启了 THP 时,fork 的速度会变慢,fork 之后每个内存页从原来 4KB 变为 2MB,会大幅增加重写 期间父进程内存消耗。同时每次写命令引起的复制内存页单位放大了 512 倍,会拖慢写操作的执行时 间,导致大量写操作慢查询。例如简单的 incr 命令也会出现在慢查询中,因此 Redis 建议将此特性进 行禁用,禁用方法如下:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
为了使机器重启后 THP 配置依然生效,可以在 /etc/rc.local 中追加 echo never > /sys/kernel/mm/transparent_hugepage/enabled 。
结束
此次分享的redis性能调优旧这么多了,需要交流学习可以关注公众号【温故知新之java】,互相学习,一起进步