当前位置:网站首页>Redis的最佳实践?看完不心动,算我输!!
Redis的最佳实践?看完不心动,算我输!!
2022-06-26 10:23:00 【BigTree的学习之路】
Redis的最佳实践?看完不心动,算我输!!
一、Redis键值设计
1、优雅的key结构
Redis的key虽然可以自定义,但是最好遵循几个最佳实战约定:
- 遵循基本格式:[业务名称]:[数据名]:[id]
login:user:10 - 不包含特殊字符
- value长度不超过44字节 (4版本之前是39)
优点:
- 阅读性强
- 避免key冲突
- 方便管理。比如:删除该业务下所有的key
- 更节省内存
1.为什么value长度不尽量不超过44字节
key是String类型,底层编码包括:int、embstr、raw三种:
- int:全部是数值的情况下,采用int编码。将字符串当成数值存储。
- embstr:小于44字节使用,是连续的内存空间,内存占用更小。
- raw:大于44字节使用,是通过指针,指向不同的内存空间。 由于内存不连续,所以访问的时候性能收到影响。
# 测试value,是纯数字。底层编码是int
127.0.0.1:6379> set name 123
OK
127.0.0.1:6379> object encoding name
"int"
# 测试44个字节,底层编码是embstr
127.0.0.1:6379> set name 12345678912345678912345678912345678912345678
OK
127.0.0.1:6379> object encoding name
"embstr"
# 测试45个字节,底层编码是raw
127.0.0.1:6379> set name 123456789123456789123456789123456789123456789
OK
127.0.0.1:6379> object encoding name
"raw"
2、拒绝BigKey
1.什么是BigKey
虽然一个key,最大能存放512,但是5MB的就是很大的key了
BigKey通常以key的大小和key中成员变量来综合判定,例如:
- key本身的数据量过大:一个String类型的key,它的值是5MB
- key中的成员变量过多:一个ZSET类型的key,他的成员变量10,000个
- key中的成员数据量过大:一个Hash类型的key,它的成员变量虽然只有1000个,但是这些成员变量的value总大小为100MB
推荐值:
- 对于String类型的单个key,建议value小于10KB
- 对于集合类型的key,建议元素数量小于1000
2.BigKey的危害
- 网络阻塞
对BigKey执行读请求时,少量的QPS就可能导致带宽使用率被占满,导致redis实例,乃至所在物理机变慢
例如一个key的大小5MB,并发20次请求,那么就是100MB的带宽。如果服务器只有100MB的带宽,那么就是全部占用了。
数据倾斜
BigKey所在的Redis实例内存使用率远超其他实例,无法使数据分片的内存资源达到均衡Redis阻塞
对元素较多的hash、list、zset等做运算会比较耗时,从而主线程阻塞CPU压力
对BigKey的数据序列化和反序列化会导致CPU的使用率飙升,影响Redis实例和本机其他应用
3.如何发现BigKey
redis-cli bigkeys
利用Redis-cli提供的–bigkeys参数,可以遍历分析所有key,并返回Key的整体统计信息与每个数据的TOP1的bigkey。
缺点:
只能看到第一名,有可能第一名并不是bigkey。也有可能第一第二第三都是bigkey。scan扫描
自己编程,利用scan扫描Redis中的所有key,利用strlen和hlen等命令判断key的长度。(不建议使用memory usage,因为是主线程操作)
1.并不是主线程去操作
2.并且用的是迭代器逐步扫描
3.每次扫描一小部分第三方工具
利用第三方工具,如Redis-Rdb-Tools分析RDB快照文件,全面分析内存使用情况网络监控
自定义工具,监控进出Redis的网络数据,超出预警值时主动告警
4.如何删除BigKey
BigKey由于内存占用较多,即使删除这样的key也需要耗时很长时间,导致Redis主线程阻塞,引发一系列问题。
Redis3.0及以下版本
如果是集合类型,则用(扫描的方法)遍历Bigkey的元素,先逐个删除子元素,最后删除BigKeyRedis 4.0以后
Redis在4.0后提供了异步删除的命令:unlik
3、恰当的数据类型
string类型存储了一个123,会占用48个字节。有很多源信息。
1.存储User对象
可以使用Hash类型。
- hash的entry数量小于500时,底层使用ziplist,空间占用小,可以灵活访问对象的任意字段。
- hash的entry数量超过500时,会使用哈希表,内存占用比较多。一百万数据,占用内存大小是62.23M

方法一:导致BigKey问题
可以通过hash-max-ziplist-entries配置entry上限。但是如果entry过多就会导致BigKey问题。`
方法二:
拆分为小的hash,将id/100作为key,将id%100作为field,这样每100个元素为一个hash
例如:有100万条数据,不拆分是1个哈希,拆分成1万个哈希。将100万数据放到1万个哈希里面,每个哈希只有100个数据。
内存占用:
二、批处理优化
单个命令执行的流程:
N次命令的响应时间=N次往返的网络传输耗时+N次Redis执行命令耗时。
- 测试案例一:每次执行一次set命令,十万条数据,大概需要44秒。
1、N条命令批处理执行
N次命令的响应时间=1次往返的网络传输耗时+N次Redis执行命令耗时。
- 测试案例二:批处理MSET命令,十万条数据,大概需要182毫秒
优点:速度最快,具有原子性
缺点:数据类型受限制
不要在一次批处理中传输太多命令,否则单次命令占用带宽过多,会导致网络阻塞。
2、Pipeline
MSET虽然可以批处理,但是却只能操作部分数据类型(String和Hash类型),因此如果有对复杂数据类型的批处理需要,建议使用Pipeline功能:
优点:数据类型不收限制
缺点:速度略微低于M操作,并不是原子操作。
- 测试案例三:批处理Pipeline,十万条数据,大概需要250毫秒
@Resource
private Jedis jedis;
@Test
void testPipeline() {
// 创建管道
Pipeline pipelined = jedis.pipelined();
// 获取当前时间
long l = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
//放入命令到管道
pipelined.set("test_key:"+i,"value_"+i);
if (i % 1000 == 0 ){
//每放入一千条命令,批量执行一次
pipelined.sync();
}
long l1 = System.currentTimeMillis();
System.out.println("time====>"+(l1-l));
}
}
3、集群下的批处理
如MSET或Pipeline这样的批处理需要再一次请求中携带多条命令,而此时如果Redis是一个集群,那批处理命令的多个key必须落在一个插槽中,否则会导致执行失败。
mset name jack age12 sex male
(error)CROSSLOT Keys in request don't hash to the same solt
# 翻译:在这次请求中是:跨域多次槽的key,没有办法去做hash。没有办法到一个槽内。
四种处理方式:

并行solt(推荐使用)
计算每个key的插槽,将存在相同插槽的key,存放在同一组中。从而分出多个组。 在通过多线程的方式同时执行各组的命令。
@Test
void testMSetInCluster(){
HashMap<String, String> map = new HashMap<>(3);
map.put("name","zhangsan");
map.put("age","21");
map.put("sex","male");
stringRedisTemplate.opsForValue().multiSet(map);
}
三、服务端优化
1、持久化配置
Redis的持久化虽然可以保证数据安全,但也会带来很多额外的开销,因此持久化请遵循下列建议:
- 用来做缓存的Redis实例尽量不要开启持久化功能。
- 建议关闭RDB持久化功能,使用AOF持久化。
- 利用脚本定期在slave从节点做RDB,实现数据备份。
- 设置合理的rewrite阈值,避免频繁的bgrewrite
超过上一次rewrite的大小的百分百。并且超过64兆
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
- 配置no-appendfsync-on-rewrite=yes,进制在rewrit期间做aof,避免因aof引起的阻塞
部署有关建议:
- Redis实例的物理机要预留足够内存,应对fork和rewrite
- 单个Redis实例内存上限不要太大,例如4G或者8G。可以加快fork速度、减少主从同步、数据迁移的压力。
- Redis实例不要和CPU密集型应用部署在一起。例如ES
- 不要与高硬盘负载应用一起部署。例如数据库、消息队列。
2、慢查询
慢查询:在redis执行时耗时超过某个阈值的命令。称为慢查询
慢查询的阈值可以通过配置指定:
- 默认阈值是10毫秒,redis执行命令是微妙级别,建议是1毫秒。
slowlog-log-slower-than 10000 - 慢查询会放入慢查询日志中,日志的长度有上限,可以通过配置指定:建议长度是1000
slowlog-max-len 128
3、命令及安全配置
- Redis一定要设置密码
- 进制线上使用下面的命令:keys、flushall、flushdb、config set 等命令。可以利用rename-command禁用或者另起名字。
- bind:限制网卡,进制外网网卡访问
- 开启防火墙
- 不要使用Root账户启用Redis
- 尽量不是有默认的端口
四、集群最佳实践
集群虽然具备高可用特性,能实现自动故障恢复,但是如果使用不当,也会存在一些问题。
- 集群完整性问题
- 集群带宽问题
- 数据倾斜问题。hash_tag
- 客户端性能问题
- 命令的集群兼容性问题
- 集群下不支持lua和事务问题。
所以要不要使用集群?
单体的Redis(主从Redis)已经达到万级别的QPS,并且也具备很强的高可用特性。如果主从能满足业务需求的情况下,尽量不搭建Redis集群。
1、集群完整性问题
集群要不要全部覆盖。也就说插槽数量一个都不能少。当有插槽不能使用时,整个redis集群都不可用。默认是开启的。cluster-require-full-coverage yes
为了保证高可用性,建议将此配置改为 false
2、集群带宽问题
集群节点之间会不断的互相ping来确定集群中其他节点的状态。每次ping携带的信息至少包括:
- 插槽信息
- 集群状态信息
集群中节点越多,集群状态信息数据量也越大,10各节点的相关信息可能达到1kb,此时每次集群互通需要的带宽会非常高。
解决途径:
- 避免大集群,集群节点数不要太多,最好少于1000,如果业务庞大,则建立多个集群
- 避免在单个物理机中运行多个redis实例
- 配置合适的cluster-nodetimeout值。 集群节点客观下线的超时时间。15秒

边栏推荐
- 【北邮果园微处理器设计】10 Serial Communication 串口通信笔记
- 最强swarm集群一键部署+氢弹级容器管理工具介绍
- Server single and two-way adjustable one key mutual trust script!
- How does unity prevent other camera positions and rotations from being controlled by steamvrplugin when using steamvrplugin
- Is it safe to use flush mobile phones to speculate in stocks? How to fry stocks with flush
- 一键部署属于自己的社区论坛
- laravel 安装报错 Uncaught ReflectionException: Class view does not exist
- 互联网对抗神器之漏洞扫描与反渗透
- MySQL backup and restore command
- Moore vote, leetcode169, leetcode229
猜你喜欢

4、 Stacks and queues
![[Beiyou orchard microprocessor design] 10 serial communication serial communication notes](/img/61/b4cfb0500bbe39ed6a371bb8672a2f.png)
[Beiyou orchard microprocessor design] 10 serial communication serial communication notes

Machine Learning Clustering - Experimental Report

Grain Mall - distributed Foundation

Code specification & explain in detail the functions and uses of husky, prettier, eslint and lint staged

c语言 --- 运算符和表达式

滑动窗口

matlab 编程实例: 如何统计元胞数组中元素的数量

3、 Linked list exercise

C language -- operators and expressions
随机推荐
PC qq Hall upload Update Modifying versioninfo
ISO 26262 - 2 functional safety concept
Group by is used in laravel to group and query the quantity
That is to say, "live broadcast" is launched! One stop live broadcast service with full link upgrade
Bit operation n & (n-1), leetcode231, interview question 05.06
Jasperreports - print PDF (project tool)
Concise course of probability theory and statistics in engineering mathematics second edition review outline
3、 Linked list exercise
Win10 start FTP service and set login authentication
Detailed explanation of MySQL fuzzy query
Origin of b+ tree index
Sqli labs range 1-5
Consumer microservice Governance Center stepping on the pit
最牛X的CMDB系统
MySQL 30 military regulations
Easyx-----c语言实现2048
sliding window
工作汇报(2)
Redis (basic) - learning notes
代码规范 & 详细解释 husky、prettier、eslint、lint-staged 的作用和使用