有了这篇你还说你不会redis性能优化、内存分析及优化(1)

4. 考虑操作系统和硬件是否影响性能


Redis 运行的外部环境,也就是操作系统和硬件显然也会影响 Redis 的性能。

CPU

Intel 多种 CPU 都比 AMD 皓龙系列好

虚拟化

实体机比虚拟机好,主要是因为部分虚拟机上,硬盘不是本地硬盘,监控软件导致 fork 指令的速度慢(持久化时会用到 fork),尤其是用 Xen 来做虚拟化时。

内存管理

在 linux 操作系统中,为了让 translation lookaside buffer,即 TLB,能够管理更多内存空间(TLB 只能缓存有限个 page),操作系统把一些 memory page 变得更大,比如 2MB 或者 1GB,而不是通常的 4096 字节,这些大的内存页叫做 huge pages。

同时,为了方便程序员使用这些大的内存 page,操作系统中实现了一个 transparent huge pages(THP)机制,使得大内存页对他们来说是透明的,可以像使用正常的内存 page 一样使用他们。但这种机制并不是数据库所需要的,可能是因为 THP 会把内存空间变得紧凑而连续吧,就像mongodb 的文档[11]中明确说的,数据库需要的是稀疏的内存空间,所以请禁掉 THP 功能。Redis 也不例外,但 Redis 官方博客上给出的理由是:使用大内存 page 会使 bgsave 时,fork 的速度变慢;如果 fork 之后,这些内存 page 在原进程中被修改了,他们就需要被复制(即 copy on write),这样的复制会消耗大量的内存(毕竟,人家是 huge pages,复制一份消耗成本很大)

所以,请禁止掉操作系统中的 transparent huge pages 功能。

交换空间:当一些内存 page 被存储在交换空间文件上,而 Redis 又要请求那些数据,那么操作系统会阻塞 Redis 进程,然后把想要的 page,从交换空间中拿出来,放进内存。这其中涉及整个进程的阻塞,所以可能会造成延时问题,一个解决方法是禁止使用交换空间(Redis Essentials 中如是建议,如果内存空间不足,请用别的方法处理)。

5. 考虑持久化带来的开销


5.1 RDB 全量持久化。

这种持久化方式把 Redis 中的全量数据打包成 rdb 文件放在硬盘上。但是执行 RDB 持久化过程的是原进程 fork 出来一个子进程,而 fork 这个系统调用是需要时间的,根据Redis Lab 6 年前做的实验[12],在一台新型的 AWS EC2 m1.small^13 上,fork 一个内存占用 1GB 的 Redis 进程,需要 700+ 毫秒,而这段时间,redis 是无法处理请求的。

虽然现在的机器应该都会比那个时候好,但是 fork 的开销也应该考虑吧。为此,要使用合理的 RDB 持久化的时间间隔,不要太频繁。

5.2 AOF 增量持久化。

这种持久化方式会把你发到 redis server 的指令以文本的形式保存下来(格式遵循 redis protocol),这个过程中,会调用两个系统调用,一个是 write(2),同步完成,一个是 fsync(2),异步完成。

这两部都可能是延时问题的原因:

write 可能会因为输出的 buffer 满了,或者 kernal 正在把 buffer 中的数据同步到硬盘,就被阻塞了。fsync 的作用是确保 write 写入到 aof 文件的数据落到了硬盘上,在一个 7200 转/分的硬盘上可能要延时 20 毫秒左右,消耗还是挺大的。更重要的是,在 fsync 进行的时候,write 可能会被阻塞。其中,write 的阻塞貌似只能接受,因为没有更好的方法把数据写到一个文件中了。但对于 fsync,Redis 允许三种配置,选用哪种取决于你对备份及时性和性能的平衡:always:当把 appendfsync 设置为 always,fsync 会和客户端的指令同步执行,因此最可能造成延时问题,但备份及时性最好。everysec:每秒钟异步执行一次 fsync,此时 redis 的性能表现会更好,但是 fsync 依然可能阻塞 write,算是一个折中选择。no:redis 不会主动出发 fsync (并不是永远不 fsync,那是不太可能的),而由 kernel 决定何时 fsync。

6. 使用分布式架构 —— 读写分离、数据分片


把慢速的指令发到某些从库中执行 把持久化功能放在一个很少使用的从库上 把某些大 list 分片 其中前两条都是根据 Redis 单线程的特性,用其他进程(甚至机器)做性能补充的方法。

7. reids 内存分析及使用优化


redis内存使用情况:info memory

7.1 内存使用

redis的内存使用分布:自身内存,键值对象占用、缓冲区内存占用及内存碎片占用。redis 空进程自身消耗非常的少,可以忽略不计,优化内存可以不考虑此处的因素。

7.1.1 对象内存

对象内存,也即真实存储的数据所占用的内存。redis k-v结构存储,对象占用可以简单的理解为 k-size + v-size。redis的键统一都为字符串类型,值包含多种类型:string、list、hash、set、zset五种基本类型及基于string的Bitmaps和HyperLogLog类型等。

在实际的应用中,一定要做好kv的构建形式及内存使用预期。

7.1.2 缓冲内存

缓冲内存包括三部分:客户端缓存、复制积压缓存及AOF缓冲区。

  1. 客户端缓存:接入redis服务器的TCP连接输入输出缓冲内存占用,TCP输入缓冲占用是不受控制的,最大允许空间为1G。输出缓冲占用可以通过client-output-buffer-limit参数配置。redis 客户端主要分为从客户端、订阅客户端和普通客户端。

从客户端连接占用:也就是我们所说的slave,主节点会为每一个从节点建立一条连接用于命令复制,缓冲配置为:client-output-buffer-limit slave 256mb 64mb 60。主从之间的间络延迟及挂载的从节点数量是影响内存占用的主要因素。因此在涉及需要异地部署主从时要特别注意,另外,也要避免主节点上挂载过多的从节点(<=2);

订阅客户端内存占用:发布订阅功能连接客户端使用单独的缓冲区,默认配置:client-output-buffer-limit pubsub 32mb 8mb 60。当消费慢于生产时会造成缓冲区积压,因此需要特别注意消费者角色配比及生产、消费速度的监控。

普通客户端内存占用:除了上述之外的其它客户端,如我们通常的应用连接,默认配置:client-output-buffer-limit normal 1000。可以看到,普通客户端没有配置缓冲区限制,通常一般的客户端内存消耗也可以忽略不计。

但是当redis服务器响应较慢时,容易造成大量的慢连接,主要表现为连接数的突增,如果不能及时处理,此时会严重影响redis服务节点的服务及恢复。公众号搜索:[Java学习之道],回复’福利’,3T资料等你来拿!

关于此,在实际应用中需要注意几点:

maxclients最大连接数配置必不可少。合理预估单次操作数据量(写或读)及网络时延ttl。禁止线上大吞吐量命令操作,如keys等。高并发应用情景下,redis内存使用需要有实时的监控预警机制,

  1. 复制积压缓冲区 v2.8之后提供的一个可重用的固定大小缓冲区,用以实现向从节点的部分复制功能,避免全量复制。配置单数:repl-backlog-size,默认1M。单个主节点配置一个复制积压缓冲区。

  2. AOF缓冲区 AOF重写期间增量的写入命令保存,此部分缓存占用大小取决于AOF重写时间及增量。

7.2 redis子进程内存消耗

子进程即redis执行持久化(RDB/AOF)时fork的子任务进程。

  1. 关于linux系统的写时复制机制:父子进程会共享相同的物理内存页,父进程处理写请求时会对需要修改的页复制一份副本进行修改,子进程读取的内存则为fork时的父进程内存快照,因此,子进程的内存消耗由期间的写操作增量决定。

  2. 关于linux的透明大页机制THP(Transparent Huge Page):THP机制会降低fork子进程的速度;写时复制内存页由4KB增大至2M。高并发情境下,写时复制内存占用消耗影响会很大,因此需要选择性关闭。

  3. 关于linux配置:一般需要配置linux系统 vm.overcommit_memory=1,以允许系统可以分配所有的物理内存。防止fork任务因内存而失败。

7.3 redis内存管理

redis的内存管理主要分为两方面:内存上限控制及内存回收管理。

7.3.1 内存上限:maxmemory

目的:缓存应用内存回收机制触发 + 防止物理内存用尽(redis 默认无限使用服务器内存) + 服务节点内存隔离(单服务器上部署多个redis服务节点) 在进行内存分配及限制时要充分考虑内存碎片占用影响。动态调整,扩展redis服务节点可用内存:config set maxmemory {}。

7.3.2 内存回收

「回收时机:键过期、内存占用达到上限」

  1. **「过期键删除:」**redis 键过期时间保存在内部的过期字典中,redis采用惰性删除机制+定时任务删除机制。惰性删除:即读时删除,读取带有超时属性的键时,如果键已过期,则删除然后返回空值。这种方式存在问题是,触发时机,加入过期键长时间未被读取,那么它将会一直存在内存中,造成内存泄漏。

定时任务删除:redis内部维护了一个定时任务(默认每秒10次,可配置),通过自适应法进行删除。删除逻辑如下:

需要说明的一点是,快慢模式执行的删除逻辑相同,这是超时时间不同。

  1. 「内存溢出控制」

当内存达到maxmemory,会触发内存回收策略,具体策略依据maxmemory-policy来执行。

  • noevication:默认不回收,达到内存上限,则不再接受写操作,并返回错误。

  • volatile-lru:根据LRU算法删除设置了过期时间的键,如果没有则不执行回收。

  • allkeys-lru:根据LRU算法删除键,针对所有键。

  • allkeys-random:随机删除键。

  • volatitle-random:速记删除设置了过期时间的键。

  • volatilte-ttl:根据键ttl,删除最近过期的键,同样如果没有设置过期的键,则不执行删除。动态配置:config set maxmemory-policy {} 在设置了maxmemory情况下,每次的redis操作都会检查执行内存回收,因此对于线上环境,要确保所这只的maxmemory>used_memory。

另外,可以通过动态配置maxmemory来主动触发内存回收。

推荐文章

更多项目源码

分享

首先分享一份学习大纲,内容较多,涵盖了互联网行业所有的流行以及核心技术,以截图形式分享:

(亿级流量性能调优实战+一线大厂分布式实战+架构师筑基必备技能+设计思想开源框架解读+性能直线提升架构技术+高效存储让项目性能起飞+分布式扩展到微服务架构…实在是太多了)

其次分享一些技术知识,以截图形式分享一部分:

Tomcat架构解析:

算法训练+高分宝典:

Spring Cloud+Docker微服务实战:

最后分享一波面试资料:

切莫死记硬背,小心面试官直接让你出门右拐

1000道互联网Java面试题:

Java高级架构面试知识整理:

外链图片转存中…(img-2Xgc3p1C-1714728715859)]

算法训练+高分宝典:

[外链图片转存中…(img-LQbtvSmf-1714728715860)]

Spring Cloud+Docker微服务实战:

[外链图片转存中…(img-Eaq6lvDR-1714728715861)]

最后分享一波面试资料:

切莫死记硬背,小心面试官直接让你出门右拐

1000道互联网Java面试题:

[外链图片转存中…(img-VJczI3NS-1714728715861)]

Java高级架构面试知识整理:

[外链图片转存中…(img-NFr01eU0-1714728715862)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值