redis优化的思考

前言

本篇谈一谈笔者对于redis优化的一些思考和方向。


提示:写博客是自己对知识梳理,目前是写给自己看,算是自己学习后的作业,也是为了养成一个良好的习惯。

一、分析

1. 由于redis都是基于内存的操作,CPU不是redis的性能瓶颈,则服务器的内存利用率、
网络IO和磁盘读写是redis主要性能瓶颈点;
2. 由于redis处理请求和指令时是单线程,则它的性能瓶颈点是同步阻塞问题。

综上所述:redis优化应从 网络IO、磁盘读写、内存利用率及同步阻塞点这几个维度来做优化。

二、网络优化

1.客户端---->服务端

请求批处理减少网络IO开销:
1. 原子性m批处理指令
string类型有批量处理时,推荐用mget/mset代替get/set;
hash类型有批量处理时,推荐使用hmget/hmset代替hget/hset。
2. pipeline技术
在使用list、set和zset时有批量操作时可以使用pipeline技术。
3. redis事务
在特殊业务要求保证多个指令的事务时推荐使用redis事务
4. lua脚本
在需要保证多条指令原子性时推荐使用lua脚本,具体案例有分布式解锁、秒杀扣减库存。

2.集群节点—>节点

节点间的网络优化:
1. 在同一个局域网中搭建集群
2. 控制切分集群的节点数
redis实例上分配的哈希槽信息需要在不同实例之间传递,以及负载均衡,实例增删时,数据会在不同实例间传递。
但哈希槽信息不大,而数据迁移是渐进式的,一般不是主要问题。

三、内存利用率

1. 控制key的长度 
建议开发前先定义好规范,保证key在简单、清晰的前提下,尽可能把key按业务缩写。
2. 杜绝bigkey
string类型的大小建议在20KB以内;
hash、list、set和zset建议控制好元素阈值,推荐控制在5000以内。
3. key设置过期时间
除非业务强要求,否则所有key都得设置过期时间,尽可能减少内存的占用。
4. 选择合适的数据结构
string类型,推荐使用整数型,它底层编码会选择整数型编码,内存开销小;
hash类型,推荐控制元素阈值,元素少时底层会用压缩列表数据结构,内存开销小;
list类型,推荐控制元素阈值,元素少时底层会用压缩列表数据结构,内存开销小;
set类型,推荐存储整数型,它底层编码会选择整数型编码,内存开销小;
zset类型,推荐控制元素阈值,元素少时底层会用压缩列表数据结构,内存开销小;
5. 数据压缩
客户端在写入redis前可以采用snappy、gzip 等压缩算法对数据压缩,减少内存占用,
但客户端在读取数据后需要对数据做解压,会消耗更多的CPU。
6. 开启内存淘汰策略
杜绝使用默认的淘汰策略,按照业务特性选择合适淘汰策略。
7. 内存碎片化
原因:
一个是内存分配器的分配策略造成的,内存分配器是按照固定大小分配的,
而不是按照实际申请的大小分配的;
另一个是redis键值对删除之后会释放部分空间带来的内存碎片。
定位:
通过指令INFO memory 来观察 mem_fragmentation_ratio的指标,
当指标在 1-1.5之间则属于正常的(内存分配策略问题);
当指标大于 1.5 时 则表明内存碎片率已经超过了50%,需要处理内存碎片了
方案:
重启Redis实例;
开启redis自动内存碎片清理功能.

四、磁盘优化

1. 部署优化

1. 物理机搭建redis服务
持久化时,redis采用创建子进程的方式进行( 会调用操作系统的 fork 系统 ),而虚拟机环境执行 fork 的耗时,要比物理机慢。

2. 不使用docker方式部署redis
docker安装redis在做迁移时非常方便,但是在做持久化时比直接安装性能要慢很多,且在请求负载大的时候
比真机安装要慢很多。
ps:对于生产环境上redis部署方式需要你从迁移和性能中做抉择,目前大部分生产环境都是真机部署。

3. 实例大小建议不超过6G
redis实例太大在主从同步会有的卡顿现象,严重时会拖垮master;
redis在异常重启时会重放AOF,如果实例过大数据恢复会异常的缓慢。

2. 持久化优化

1. 不开启持久化
redis只做缓存使用,则不需要开启持久化,减少磁盘的开销.
这里建议在业务没有强要求不要开启持久化。
2. AOF优化
如果有业务要求数据不丢失,则需要开启AOF持久化机制,对于AOF持久化优化方案如下:
2.1 后台处理AOF
 配置appendfsync everysec 把数据持久化的刷盘操作,放到后台线程中去执行,
尽量降低 Redis 写磁盘对性能的影响。
2.2 不建高频率的做AOF持久化
AOF持久化默认的频率是每秒1次,不建议将这个修改这个配置,它已经能保证最多丢失1s数据了。
2.3 开启混合持久化
AOF最大问题就是随着实例运行体积会无限膨胀,对于这个问题redis4.0支持混合持久化方式,
 即RDB+增量的AOF 在AOF重写时会大大减小AOF体积,具体可以去参考我之前关于持久化博客。

3. 集群优化

1. salve做持久化
master不做持久化,让salve做持久化,尽可能分摊master磁盘io的压力。
这个要设置master不重启配置,会存在由于master重启后数据清空问题。
2. 主从同步优化
2.1 增量模式
主从同步方式指定为增量模式,不选择全量的RDB模式,全量模式是一个非常消耗性能。
2.2 级联同步
一主多从时,多个salve都来master这里同步数据,会直接拖垮master性能,对于这个问题
redis支持级联同步的方式,即 master只将数据同步给一个salve,然后其他的salve的数据都从这个salve同步,来减缓master压力。

五、性能优化

1. bigkey问题

bigkey危害:
读写bigkey可能会导致超时,而redis是单线程操作数据,严重的会导致阻塞整个redis服务。
而且一个key只会被分片到一个节点,无法分摊读写压力。

bigkey探测:
1. 自带命令redis-cli --bigkeys
redis自带指令,只能找出五种数据类型里最大的key,并没有太大作用,不推荐。
2. python扫描脚本
可以定位到具体key,但准确度不高,不推荐。
3. rdb_bigkeys工具
go写的一款工具,时间执行快且准确度高,还可以可直接导出到csv文件,方便查看,推荐。

bigkey优化:
1. 对于非string类型bigkey,可以对元素集合进行分割,拆分成功多个,如将一个bigkey拆分成1000个key,则key的后缀使用hash取模10002. 使用本地缓存,如redis中只存放业务id+版本号,将具体内容放在本地缓存,每次查询先查redis缓存,再同本地缓存核对版本号;
3. 优化bigkey一般都是伤筋动骨,推荐在开发时就定义好规范,避免bigkey问题。

2. 过期策略优化

过期策略具体细节可以看我之前的博客,有详细介绍,这里就带过了。
redis默认是开启惰性删除+定期删除。

优化方案:
开启lazy-free,释放内存的耗时操作,将会放到后台线程中去执行,redis4.0支持;
开启多线程模式,在redis6.0之前过期策略都是主线程的同步操作,6.0之后采用多线程去处理。

3. 复杂度高指令

优化方案:
1. 推荐使用scan 分批次查询,不要使用keys;
2. 不使用聚合操作;
2.1 redis是单线程模型处理请求,在执行复杂度过高的命令(消耗更多cpu资源)时后面的
请求会排队导致延迟,如SINTER、SINTERSTORE、ZUNIONSTORE、ZINTERSTORE等。
2.2 推荐用scan分批次查出集合中元素,在客户端做聚合计算
3. 关注容器类数据操作
3.1 查询  当容器类元素非常多时,直接查询会存在由于网络网络问题导致的延迟,推荐分批次查询;
3.2 删除 当容器类元素非常多时,直接删除key时有可能会导致redis卡顿,推荐分批次删除。

总结

大纲基本上出来了,各位读者也帮忙核对以上内容是否有错误或需要补充的地方,最后加上我画的思维导图(可能内容和图有些不一样,会不定期更新内容和图)。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ariel小葵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值