知方号

知方号

RedisRedis最佳实践:键值设计<快狐的激活码是多少>

RedisRedis最佳实践:键值设计

Redis最佳实践:键值设计

在Redis中,良好的键值设计可以达成事半功倍的效果,而不好的键值设计可能会带来Redis服务停滞,网络阻塞,CPU使用率飙升等一系列问题,今天就教大家如何设计一个良好的key-value

1 优雅的key结构

Redis的Key虽然可以自定义,但最好遵循下面的几个最佳实践约定:

遵循基本格式:[业务名称]:[数据名]:[id],例如我们的登录业务,需要保存用户信息,其key可以设计成如下格式

这种设计的好处不仅在于可读性强,还在于可以避免key的冲突问题,而且方便管理

Key的长度不超过44字节

无论是哪种数据类型, key都是string类型,string类型的底层编码包含int、embstr和raw三种。如果key中全是数字,那么就会直接以int类型去存储,而int占用的空间也是最小的,当然出于业务需求,我们不可能将key设计为一个全数字的,而如果不是纯数字,底层存储的就是SDS内容,如果小于44字节,就会使用embstr类型,embstr在内存中是一段连续的存储空间,内存占用相对raw来说较小,而当字节数大于44字节时,会转为raw模式存储,在raw模式下,内存空间不是连续的,而是采用一个指针指向了另外一段内存空间,在这段空间里存储SDS内容,这样空间不连续,访问的时候性能也就会收到影响,还有可能产生内存碎片

需要注意的是,如果你的redis版本低于4.0,那么界限是39字节而非44字节

Key中不包含一些特殊字符

2 拒绝BigKey 2.1 判断BigKey

BigKey顾名思义就是一个很大的Key,这里的大并不是指Key本身很大,而是指包括这个Key的Value在内的一整个键值对很大

BigKey通常以Key-Value的大小或者Key中成员的数量来综合判定,例如:

Key的Value过大:例如一个String类型的Key,它的Value为5MB Key中的成员数过多:例如一个ZSET类型的Key,它的成员数量为10000个 Key中成员的Value过大:例如一个Hash类型的Key,它的成员数量虽然只有1000个,但这些成员的Value总大小为100 MB

那么如何判断元素的大小呢?redis中为我们提供了相应的命令,语法如下:

memory usage 键名

这条命令会返回一条数据占用内存的总大小,这个大小不仅包括Key和Value的大小,还包括数据存储时的一些元信息,因此可能你的Key与Value只占用了几十个字节,但最终的返回结果是几百个字节

但是我们一般不推荐使用memory指令,因为这个指令对CPU的占用率是很高的,实际开发中我们一般只需要衡量Value的大小或者Key中的成员数即可

例如如果我们使用的数据类型是String,就可以使用以下命令,返回的结果是Value的长度

strlen 键名

如果我们使用的数据类型是List,就可以使用以下命令,返回的结果是List中成员的个数

llen 键名

一般我们推荐,单个key的value小于10KB,集合类型的key元素数量小于1000

2.2 BigKey的危害

网络阻塞

当我们对一个BigKey发起读请求时,只需少量的QPS就可能导致带宽使用率被占满,导致Redis实例乃至所在物理机变慢,例如一个bigkey占用5M内存,只需要QPS达到20,那么1秒钟就会占100M的带宽

数据倾斜

集群环境下,由于所有插槽一开始都是均衡分配的,因此BigKey所在的Redis实例内存使用率会远超其他实例,从而无法使数据分片的内存资源达到均衡,最后不得不手动重新分配插槽,增加运维人员的负担

Redis阻塞

对元素较多的hash、list、zset等做运算会耗时较久,而且由于Redis是单线程的,在运算过程中会导致服务阻塞,无法接收其他用户请求

CPU压力

对BigKey的数据进行序列化或反序列化都会导致CPU的使用率飙升,影响Redis实例和本机其它应用

2.3 如何发现BigKey

既然我们知道了什么叫BigKey以及BigKey的危害,那么如何去快速发现Redis中所有的BigKey呢?这里为大家提供以下几种方案:

1)利用Redis本身提供的命令

利用以下命令,可以遍历分析所有key,并返回Key的整体统计信息与每种数据类型中Top1的BigKey

redis-cli -a 密码 --bigkeys

演示如下(这里我的redis没有设置密码,如果你的redis设置了密码,则需要使用 -a 密码 进行连接)

2)自己手动编写程序进行扫描

我们可以通过自己编写程序,将Redis中所有的数据查询出来并一一统计长度来找出BigKey,这里不建议使用keys *来查询所有数据,因为keys * 是一次将所有的数据全部查找出来,如果数据量很大,key *一次可能要几十秒甚至几分钟,在如此长的时间内,Redis的主线程会因为执行该命令而被阻塞。

这里建议使用redis提供的scan命令,语法如下:

scan 起始位置 count 数量

scan扫描有点类似于分页查询,而被分页的对象是redis中所有的数据,scan命令调用一次只会从指定的起始位置开始返回指定数量的数据,以及此次扫描结束时光标所在的位置,下一次扫描时就需要从这个光标开始继续往下扫描

这里提供一个已经编写好的查找BigKey的测试类,大家可以参考一下

import com.heima.jedis.util.JedisConnectionFactory;import org.junit.jupit

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。