Redis优化及问题点

  1. 阻塞点

1、集合全量查询和聚合操作;

2、bigkey 删除;(删除key时,需要释放内存,为了高效管理,释放的内存需要加到内存管理链表,方便后续分配。)

3、清空数据库;

4、AOF 日志同步写;(rdb和aof重写都是子线程操作不会阻塞主线程,aof同步写大量key会造成redis阻塞)

5、从库加载 RDB 文件。

我们通过关键点和客户端需要返回的数据来判断,读取操作是不能异步进行的,所以集合全量查询和聚合操作不能进行异步处理;从库加载RDB文件不能进行异步操作。

Bigkey删除、AOF日志同步写、清空数据库这三个都可以进行异步处理:当redis启动时,操作系统会给redis创建三个线程,负责AOF日志同步写、键值对删除以及文件管理。Redis主线程当接到上面三种情况时,会将命令封装成一个任务,然后将任务放到链表形式的任务队列中,主线程返回操作完成,等待子线程进行处理。

  1. Cpu优化redis

Cpu的两种架构:

单处理器多核:服务器上只有一个处理器,但是有多个物理核,每个物理核上有两个逻辑核。(处理器上有L1、L2、L3这三级缓存,L1、L2是每个物理核自己私有的,L3是整个处理共有的)

多处理器架构(NUMA 架构):服务器上有多个处理器,每个处理器有多个物理核,每个物理核上有两个逻辑核。多个处理器之间通过总线进行连接。

Cpu多核对于redis影响:当redis在多核服务器上运行时,会出现上下文切换的情况。例如:redis在A物理核上运行,然后被cpu调度到B物理核上去运行,这时候我们L1、L2的缓存数据就没有办法使用了,需要重新加载L1、L2缓存数据及命令。这样就造成了redis的处理速度变慢。这时候我们将redis绑定一个物理核,不让他进行切换操作,这样就能提升redis的处理速度了。(不要绑在逻辑核上,redis会有rdb、Aof重写等操作,需要开辟新的子线程,会出现竞争,绑定在物理核上,就可以相对减少竞争)

多cpu(NUMA架构)对redis的影响:当网络中断处理程序从网卡读取数据,存储到操作系统内核的内存缓冲区。内存通过epoll机制触发事件,通知 Redis 实例,Redis 实例再把数据从内核的内存缓冲区拷贝到自己的内存空间

如果网络中断处理程序和 Redis 实例各自所绑的 CPU 核不在同一个 CPU Socket 上,那么,Redis 实例读取网络数据时,就需要跨 CPU Socket 访问内存,这个过程会花费较多时间。

为了避免 Redis 跨 CPU Socket 访问网络数据,我们最好把网络中断程序和 Redis 实例绑在同一个 CPU Socket 上,这样一来,Redis 实例就可以直接从本地内存读取网络数据了

  1. redis变慢

  1. 通过响应时间来判断redis当前状况

  1. 通过当前环境下的基线性能:./redis-cli --intrinsic-latency 120(redis-cli 命令提供了–intrinsic-latency 选项,可以用来监测和统计测试期间内的最大延迟,这个延迟可以作为 Redis 的基线性能。)把运行时延迟和基线性能进行对比,如果你观察到的 Redis 运行时延迟是其基线性能的 2 倍及以上,就可以认定 Redis 变慢了。

  1. 通过判断执行命令的时间复杂度O(1)或者O(N),来减少redis操作的消耗。

  1. 用其他高效命令代替。比如说,如果你需要返回一个SET 中的所有成员时,不要使用 SMEMBERS 命令,而是要使用 SSCAN 多次迭代返回,避免一次返回大量数据,造成线程阻塞。

  1. 当你需要执行排序、交集、并集操作时,可以在客户端完成,而不要用SORT、SUNION、SINTER 这些命令,以免拖慢 Redis 实例。

  1. Keys命令不要再生产使用,他会遍历所有的键值对。

  1. 定期删除:过期key的删除也会影响到redis的性能。正常的删除操作会阻塞redis线程,当有大量的过期key需要处理的时候会操作redis性能下降,所以设置过期key的时候时间不能有大量相同过期时间。(redis4.0之后删除key操作可以做异步处理。)

  1. AOF模式引起的变慢:redis AOF写日志的配置分为no、everysec、always。No是由操作系统周期性写入磁盘;everysec是每秒写入一次通过后台子线程写入,主线程在写入内存后就直接返回,不会等待aof写入磁盘;always是每次都会写入到磁盘,主线程会等待写入完成后才会返回。

当redis触发AOF重写的时候,如果需要比较大的IO处理,有可能会阻塞aof正常的写入磁盘,导致redis也被阻塞。(everysec的情况是主线程会监控写入情况,当第二次写入磁盘时,发现上一次还没有写完,redis会阻塞主线程)

我们可以通过设置AOF重写时,不进行redis写入数据库操作:no-appendfsync-on-rewrite yes。

  1. 操作系统swap机制:

操作系统将内存数据在内存和磁盘之间换入和换出的操作。(redis数据写入或读取磁盘,造成磁盘io,redis主线程直接被影响)

  1. 当服务器可用内存不足会导致系统触发swap机制

  1. Redis实例服务器有其他服务,其他服务使用大量内存导致redis内存不足。

  1. 内存大页:正常在Linux系统上我们的内存页是4kB,在Linux版本更新后支持2MB。Redis触发写时复制,客户端只修改100B的数据,我们就需要将2MB的内存页复制一份,相反原有的小页我们只需要复制4KB就行。所以内存大页有可能会导致redis出现问题。我们需要关闭内存大页。

查看内存大页:cat /sys/kernel/mm/transparent_hugepage/enabled

关闭内存大页:echo never /sys/kernel/mm/transparent_hugepage/enabled

  1. 内存碎片

Redis出现内存碎片的原因:

  1. 内存分配器不能按需分配,一般是按固定大小分配的。比如需要申请10字节的空间,但是内存分配器会给你16字节。

  1. 键值对会发生删除修改等操作导致的碎片。

保存ABCD四个键值,分别是3、1、2、4个字节,当D删除修改了变小了一个字节,就会有碎片;修改A为4字节的时候,会将B拷贝到其他位置,保证A的空间连续,然后C删除两个字节,D删除一个字节。这样剩下了3个字节的空间,但是redis存储3个字节没有办法使用上图的空间,这样就造成了空间使用率下降。

  1. 怎么查看空间碎片

Redis命令INFO memory

Used_memory:redis为了保存数据实际申请的空间

Used_memory_rss:操作系统实际分配给redis的物理内存空间

mem_fragmentation_ratio = used_memory_rss/ used_memory(空间利用率)

当空间利用率大于1.5的时候我们就应该想办法去除空间碎片了。

  1. 清理空间碎片

  1. 重启redis,空间会重新分配。但是代价太大了不建议。

  1. 4.0版本后,redis自己提供了自动清理空间碎片,但是清理空间碎片也是需要消耗资源的,redis单线程运行,如果清理时间很长有可能导致redis阻塞。

开启自动清理空间:config set activedefrag yes

触发条件设置:active-defrag-ignore-bytes 100mb:**表示内存碎片的字节数达到 100MB 时,开始清理;

active-defrag-threshold-lower 10:**表示内存碎片空间占操作系统分配给 Redis 的总空间比例达到 10% 时,开始清理。

自动清理限制防止侵占redis性能:

active-defrag-cycle-min 25: 表示自动清理过程所用 CPU 时间的比例不低于 25%,保证清理能正常开展;

active-defrag-cycle-max 75:**表示自动清理过程所用 CPU 时间的比例不高于 75%,一旦超过,就停止清理,从而避免在清理时,大量的内存拷贝阻塞 Redis,导致响应延迟升高。

  1. 内存缓冲

  1. 客户端输入输出缓冲区

为了避免客户端和服务器端的请求发送和处理速度不匹配,服务器端给每个连接的客户端都设置了一个输入缓冲区和输出缓冲区,我们称之为客户端输入缓冲区和输出缓冲区。

客户端输入缓冲区溢出:

  1. 当客户端发送bigkey的时候,导致输入缓冲区溢出

  1. 服务器端间歇性阻塞,导致redis处理速度不足,导致输入缓冲区溢出

查询redis内存缓冲区使用情况

命令:CLIENT LIST

id=5 addr=127.0.0.1:50487 fd=9 name= age=4 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=32742 obl=0 oll=0 omem=0 events=r cmd=client

Cmd:客户端最新的执行命令

Qbuf:输入缓冲区使用大小 26字节

qbuf-free:输入缓冲区剩余大小 32742字节

输入缓冲区大小就是Qbuf+qbuf-free 32768字节,也就是32kb。

Redis默认允许每一个客户端最多暂存1GB的数据和命令。

解决方案:避免客户端写入bigkey,以及避免 Redis 主线程阻塞。

Redis输出缓冲区:

每个客户端设置的输出缓冲区也包括两部分:一部分,是一个大小为 16KB 的固定缓冲空间,用来暂存 OK 响应和出错信息;另一部分,是一个可以动态增加的缓冲空间,用来暂存大小可变的响应结果。

普通客户端缓冲大小设置:client-output-buffer-limit normal 0 0 0

normal 表示当前设置的是普通客户端,第 1 个 0 设置的是缓冲区大小限制,第 2 个 0 和第 3 个 0 分别表示缓冲区持续写入量限制和持续写入时间限制。

因为普通客户端请求获取数据get命令等都是阻塞式请求,所以我们对这类输出缓冲区不做限制。

订阅发布客户端缓冲大小设置:client-output-buffer-limit pubsub 8mb 2mb 60

pubsub 参数表示当前是对订阅客户端进行设置;8mb 表示输出缓冲区的大小上限为 8MB,一旦实际占用的缓冲区大小要超过 8MB,服务器端就会直接关闭客户端的连接;2mb 和 60 表示,如果连续 60 秒内对输出缓冲区的写入量超过 2MB 的话,服务器端也会关闭客户端连接。

  1. 主从集群缓冲区

全量复制(主节点生产RDB发送从节点)时,主节点还能接受到客户端的写命令,会写入到复制缓冲区。

增量复制,主节点执行完直接写入到复制缓冲区中发送给从节点。

当从节点接收和加载RDB文件时,从节点是阻塞状态,那么主节点的命令都需要放到复制缓冲区中,如果从节点处理速度比较慢的话,有可能会造成复制缓冲区溢出,主从节点断连,导致全量同步失败。

解决方案:

  1. 控制全量同步RDB文件大小,2~4GB左右

  1. 设置复制缓冲区大小:config set client-output-buffer-limit slave 512mb 128mb 60

slave 参数表明该配置项是针对复制缓冲区的。512mb 代表将缓冲区大小的上限设置为 512MB;128mb 和 60 代表的设置是,如果连续 60 秒内的写入量超过 128MB 的话,也会触发缓冲区溢出。

注意:主节点的复制缓冲区是多个从节点输入缓冲区之和。(所以从节点不建议过多)

复制积压缓冲区(repl_backlog_size ):主从节点断连,造成主节点积压数据和命令。一个大小有限的环形缓冲区,如果发生覆盖情况,从节点还没有同步这些旧命令数据,就会造成主从节点间重新开始执行全量复制。

所以我们需要合理的设置repl_backlog_buffer的大小。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值