Redis

关注公众号 jb51net

关闭
首页 > 数据库 > Redis > Redis性能

Redis常见性能问题及解决方案

作者:程序员Seven

本文给大家介绍Redis常见性能问题及解决方案,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

常见性能问题和解决方案?

使用批量操作减少网络传输

一个 Redis 命令的执行可以简化为以下 4 步:

其中,第 1 步和第 4 步耗费时间之和称为 Round Trip Time (RTT,往返时间) ,也就是数据在网络上传输的时间。

使用批量操作可以减少网络传输次数,进而有效减小网络开销,大幅减少 RTT。

另外,除了能减少 RTT 之外,发送一次命令的 socket I/O 成本也比较高(涉及上下文切换,存在read()write()系统调用),批量操作还可以减少 socket I/O 成本。这个在官方对 pipeline 的介绍中有提到:https://redis.io/docs/manual/pipelining/ 。

Redis 中有一些原生支持批量操作的命令,比如:

不过,在 Redis 官方提供的分片集群解决方案 Redis Cluster 下,使用这些原生批量操作命令可能会存在一些小问题需要解决。就比如说 MGET 无法保证所有的 key 都在同一个 hash slot(哈希槽)上,MGET可能还是需要多次网络传输,原子操作也无法保证了。不过,相较于非批量操作,还是可以节省不少网络传输次数。

整个步骤的简化版如下(通常由 Redis 客户端实现,无需我们自己再手动实现):

如果想要解决这个多次网络传输的问题,比较常用的办法是自己维护 key 与 slot 的关系。不过这样不太灵活,虽然带来了性能提升,但同样让系统复杂性提升。

pipeline的作用?与原生批命令(mset和mget)的区别?

redis客户端执行一条命令分4个过程: 发送命令、命令排队、命令执行、返回结果。使用pipeline可以批量请求,批量返回结果,执行速度比逐条执行要快。

使用pipeline组装的命令个数不能太多,不然数据量过大,增加客户端的等待时间,还可能造成网络阻塞,可以将大量命令的拆分多个小的pipeline命令完成。

原生批命令(mset和mget)与pipeline对比:

pipeline 和 Redis 事务的对比?

事务可以看作是一个原子操作,但其实并不满足原子性。当我们提到 Redis 中的原子操作时,主要指的是这个操作(比如事务、Lua 脚本)不会被其他操作(比如其他事务、Lua 脚本)打扰,并不能完全保证这个操作中的所有写命令要么都执行要么都不执行。这主要也是因为 Redis 是不支持回滚操作。

说说为什么Redis过期了为什么内存没释放?

第一种情况,可能是覆盖之前的key,导致key过期时间发生了改变。

当一个key在Redis中已经存在了,但是由于一些误操作使得key过期时间发生了改变,从而导致这个key在应该过期的时间内并没有过期,从而造成内存的占用。

第二种情况是,Redis过期key的处理策略导致内存没释放。

一般Redis对过期key的处理策略有两种:惰性删除和定时删除。

先说惰性删除的情况

当一个key已经确定设置了xx秒过期同时中间也没有修改它,xx秒之后它确实已经过期了,但是惰性删除的策略它并不会马上删除这个key,而是当再次读写这个key时它才会去检查是否过期,如果过期了就会删除这个key。也就是说,惰性删除策略下,就算key过期了,也不会立刻释放内容,要等到下一次读写这个key才会删除key。

而定时删除会在一定时间内主动淘汰一部分已经过期的数据,默认的时间是每100ms过期一次。因为定时删除策略每次只会淘汰一部分过期key,而不是所有的过期key,如果redis中数据比较多的话要是一次性全量删除对服务器的压力比较大,每一次只挑一批进行删除,所以很可能出现部分已经过期的key并没有及时的被清理掉,从而导致内存没有即时被释放。

Redis突然变慢,有哪些原因?

什么是大key?

通常我们会将含有较大数据或含有大量成员、列表数的Key称之为大Key。
以下是对各个数据类型大key的描述:

上述的定义并不绝对,主要是根据value的成员数量和大小来确定,根据业务场景确定标准。

大Key造成的问题?

大 key 造成的阻塞问题还会进一步影响到主从同步和集群扩容。

大key怎么处理?

什么是 hotkey?

如果一个 key 的访问次数比较多且明显多于其他 key 的话,那这个 key 就可以看作是 hotkey(热 Key)。例如在 Redis 实例的每秒处理请求达到 5000 次,而其中某个 key 的每秒访问量就高达 2000 次,那这个 key 就可以看作是 hotkey。

hotkey 出现的原因主要是某个热点数据访问量暴增,如重大的热搜事件、参与秒杀的商品。

hotkey 有什么危害?

处理 hotkey 会占用大量的 CPU 和带宽,可能会影响 Redis 实例对其他请求的正常处理。此外,如果突然访问 hotkey 的请求超出了 Redis 的处理能力,Redis 就会直接宕机。这种情况下,大量请求将落到后面的数据库上,可能会导致数据库崩溃。

因此,hotkey 很可能成为系统性能的瓶颈点,需要单独对其进行优化,以确保系统的高可用性和稳定性。

如何解决 hotkey?

hotkey 的常见处理以及优化办法如下(这些方法可以配合起来使用):

慢查询命令

经常使用O(n)以上复杂度的命令,由于Redis是单线程执行命令,因此这种情况Redis处理数据时就会很耗时。例如

解决方案就是,不使用这些复杂度较高的命令,并且一次不要获取太多的数据,每次尽量操作少量的数据,让Redis可以及时处理返回

keys命令存在的问题?如何高效安全的遍历所有key?

redis的单线程的。keys指令会导致线程阻塞一段时间,直到执行完毕,服务才能恢复。scan采用渐进式遍历的方式来解决keys命令可能带来的阻塞问题,每次scan命令的时间复杂度是O(1),但是要真正实现keys的功能,需要执行多次scan。

scan的缺点:在scan的过程中如果有键的变化(增加、删除、修改),遍历过程可能会有以下问题:新增的键可能没有遍历到,遍历出了重复的键等情况,也就是说scan并不能保证完整的遍历出来所有的键。

什么是内存碎片?为什么会有 Redis 内存碎片?

可以将内存碎片简单地理解为那些不可用的空闲内存。

当数据删除后,Redis 释放的内存空间会由内存分配器管理,并不会立即返回给操作系统。所以,操作系统仍然会记录着给 Redis 分配了大量内存。而Redis 释放的内存空间可能并不是连续的,那么,这些不连续的内存空间很有可能处于一种闲置的状态。也就产生了内存碎片

举个例子:Redis 默认使用 jemalloc 作为内存分配器,它是按照固定大小来分配内存的,比如实际需要 8kb 的内存,分配器给了 12kb。那么多余的 4kb 其实就无法被利用上了,它就叫内存碎片。

Redis 内存碎片虽然不会影响 Redis 性能,但是会增加内存消耗。

如何清理 Redis 内存碎片?

直接通过 config set 命令将 activedefrag 配置项设置为 yes 即可。

config set activedefrag yes

具体什么时候清理需要通过下面两个参数控制:

# 内存碎片占用空间达到 500mb 的时候开始清理
config set active-defrag-ignore-bytes 500mb
# 内存碎片率大于 1.5 的时候开始清理
config set active-defrag-threshold-lower 50

通过 Redis 自动内存碎片清理机制可能会对 Redis 的性能产生影响,我们可以通过下面两个参数来减少对 Redis 性能的影响:

# 内存碎片清理所占用 CPU 时间的比例不低于 20%
config set active-defrag-cycle-min 20
# 内存碎片清理所占用 CPU 时间的比例不高于 50%
config set active-defrag-cycle-max 50

Redis的Key和Value的设计原则有哪些?

Key 设计原则

Value 设计原则

Redis 性能瓶颈时如何处理?

如果 Redis 无法承受当前的负载的话,可以考虑从以下几个解决方法去解决:

到此这篇关于Redis常见性能问题及解决方案的文章就介绍到这了,更多相关Redis性能内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文