一、键值设计
1、key设计
在设计Redis的key时,最好遵循以下几个最佳实践约定:
2、value设计
什么是BigKey?
可以通过在Redis中执行memory usage <key> 命令来判断(是否为BigKey),但一般我们会通过预估的方式判断(差不多得了):
BigKey的危害:
发现BigKey的方式(除了memoy usage):
发现BigKey之后,我们要想办法将BigKey拆分成多个数据,把BigKey变成“Small Key”。
首先我们需要删除BigKey,这部分也要注意,由于BigKey太大了,在删除时也可能发生阻塞操作,因此我们通常采取下列方式进行删除:
选择恰当的数据类型(对BigKey进行拆分)
例1:为对象选择数据类型:
方式二中,虽然每个key看上去长度没有多少,但是Redis在存储key的时候还要额外存储一些元信息,因此,key越多,存储的元信息就越多,占用的空间也就越大。
例2:拆分大Hash
hash-max-ziplist-entries用于调整entry上限,默认为500,所以当entry数量超过500时就不再使用ZipList。如果我们将这个值调为1000,则只有当entry数量超过1000时才不使用ZipList。
可以通过命令行设置这个参数:
方案一:通过设置hash-max-ziplist-entries值使Hash的底层使用ZipList结构(ZipList会对内存进行压缩)。
方案二:拆分成多个string。
Redis没有对String字符串做内存优化,而对Hash和ZSet等数据结构做了内存优化(比如内存压缩等)。
方案三:拆分成多个小Hash。
3、总结:
二、批处理优化
1、为什么需要批处理
通过Java执行Redis命令时,单个命令的执行流程
在这个过程中,主要的时间都花费在网络传输耗时上。
如果是N条指令依次执行,那就是:N次命令的响应时间 = N次往返的网络传输耗时+ N次Redis执行命令耗时。可见会花费大量的时间在网络传输上。
N条命令批量执行:
可见效率提高了很多,仅需要进行一次网络往返传输,因此我们通常采用这种“批处理”方式进行“导入大量数据”之类的操作。
2、pipeline
两种方式可以实现N条命令的批量执行:①使用MSET、HMSET等命令。②使用pipeline(管道)。
使用MSET:
使用pipeline:
两种方式的对比:
3、集群下的批处理
上一节中提到的MSET和pipeline等技术,都只能用于单个Redis中。如果Redis是集群的形式,由于每台Redis都分配了不同的插槽,因此当MSET或者pipeline涉及的数据(的插槽)分布在不同Redis上时,Redis就会报错。
为此,有4种方式可以用于集群下的批处理:
这4种方式中,推荐使用第3种方式“并行slot”。
在Spring提供的RedisTemplate,已经帮我们实现了这种功能,仅需调用redisTemplate.opsForValue().multiSet(map)
即可。
二、服务端优化
1、持久化配置
2、慢查询
Redis在接收到命令时,会将这些命令放入一个队列中。如果由于慢查询导致某条命令的执行时间过长,就可能导致其他命令一直在队列中而不被执行,从而导致报错。
通过设置阈值可以确定某些命令为“慢查询”:
慢查询会被放入到慢查询日志中,可以通过读取这个日志文件来获取慢查询的相关信息:
三、命令及安全配置
https://cloud.tencent.com/developer/article/1039000
四、内存配置
五、集群
【lua和事务问题:这两个操作都是为了保证批处理命令的原子性,因此在集群下不能使用lua和事务。】
上图中,插槽不可用指某个集群节点挂掉了,导致分配给该节点的插槽都用不了。将cluster-require-full-coverage配置为false之后,如果要操作的数据(的插槽)不属于挂掉的节点,则可以正常操作;但如果要操作的数据(的插槽)属于挂掉的节点,那么就会报错。
补充:QPS:全名 Queries Per Second,意思是“每秒查询率”,是一台服务器每秒能够响应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。简单的说,QPS = req/sec = 请求数/秒。
--------完结--------