首页 > 数据库 >Redis 内存是如何划分的?

Redis 内存是如何划分的?

时间:2024-03-18 11:02:10浏览次数:20  
标签:Redis 碎片 划分 内存 memory 缓冲区 客户端

查询内存命令

info memory

查询Redis自身使用内存的统计数据。通过这个命令,可以了解 Redis 实例的内存分配情况、内存碎片、键空间使用情况等

  1. 内存分配情况:

    • used_memory:Redis 实例当前使用的内存总量(以字节为单位)。

    • used_memory_human:以人类可读格式显示的内存使用量。

    • used_memory_rss:Redis 占用的物理内存总量(包括操作系统使用的内存)。

    • used_memory_peak:Redis 实例历史上使用的最大内存总量。

    • used_memory_peak_human:以人类可读格式显示的历史内存使用的最大值。

  2. 内存碎片情况:

    • mem_fragmentation_ratio:内存碎片比率,表示内存碎片与已分配内存的比率。

    • mem_allocator:Redis 使用的内存分配器。

  3. 键空间相关信息:

    • keyspace_hits:成功查找键的次数。

    • keyspace_misses:未能查找键的次数。

    • expired_keys:过期的键的数量。

    • evicted_keys:因为内存满而被驱逐的键的数量。

  4. 持久化相关信息:

    • rdb_changes_since_last_save:上次 RDB 快照以来的更改数量。

    • rdb_last_save_time:上次成功创建 RDB 快照的时间戳。

    • rdb_last_bgsave_time_sec:最近一次创建 RDB 快照所花费的秒数。

  5. 客户端和对象相关信息:

    • connected_clients:当前连接到服务器的客户端数量。

    • client_longest_output_list:客户端输出缓冲区中最长的等待时间(以字节为单位)。

需要重点关注的指标有: used_memory_rssused_memory以及它们的比值mem_fragmentation_ratio

  • mem_fragmentation_ratio>1时, 说明used_memory_rss-used_memory多出的部分内存并没有用于数据存储, 而是被内存碎片所消耗, 如果两者相差很大, 说明碎片率严重。
  • mem_fragmentation_ratio<1时, 这种情况一般出现在操作系统把Redis内存交换(Swap) 到硬盘导致, 出现这种情况时要格外关注, 由于硬盘速度远远慢于内存, Redis性能会变得很差, 甚至僵死。

内存划分

Redis进程内消耗主要包括: 自身内存+对象内存+缓冲内存+内存碎片

对象内存

对象内存是Redis内存占用最大的一块, 存储着用户所有的数据。 Redis 所有的数据都采用key-value数据类型, 每次创建键值对时, 至少创建两个类型对象: key对象和value对象。 对象内存消耗可以简单理解为sizeof(keys)+sizeof(values) 。 键对象都是字符串, 在使用Redis时很容易忽略键对内存消耗的影响, 应当避免使用过长的键。

缓冲内存

缓冲内存主要包括: 客户端缓冲、 复制积压缓冲区、 AOF缓冲区。客户端缓冲指的是所有接入到Redis服务器TCP连接的输入输出缓冲。输入缓冲无法控制, 最大空间为1G, 如果超过将断开连接。 输出缓冲通过参数client-output-buffer-limit控制 。

客户端缓冲
普通客户端

除了复制和订阅的客户端之外的所有连接, Redis的默认配置是: client-output-buffer-limit normal000

Redis并没有对普通客户端的输出缓冲区做限制, 一般普通客户端的内存消耗可以忽略不计, 但是当有大量慢连接客户端接入时这部分内存消耗就不能忽略了, 可以设置maxclients做限制

从客户端

主节点会为每个从节点单独建立一条连接用于命令复制,默认配置是: client-output-buffer-limit slave256mb64mb60。 当主从节点之间网络延迟较高或主节点挂载大量从节点时这部分内存消耗将占用很大一部分, 建议主节点挂载的从节点不要多于2个

订阅客户端

当使用发布订阅功能时, 连接客户端使用单独的输出缓冲区, 默认配置为: client-output-buffer-limit pubsub32mb8mb60, 当订阅服务的消息生产快于消费速度时, 输出缓冲区会产生积压造成输出缓冲区空间溢出。

复制积压缓冲区

Redis在2.8版本之后提供了一个可重用的固定大小缓冲区用于实现部分复制功能, 根据repl-backlog-size参数控制, 默认1MB。 对于复制积压缓冲区整个主节点只有一个, 所有的从节点共享此缓冲区, 因此可以设置较大的缓冲区空间, 如100MB, 这部分内存投入是有价值的, 可以有效避免全量复制, 更多细节见第6.4节。

AOF缓冲区

这部分空间用于在Redis重写期间保存最近的写入命令,具体细节见5.2节。 AOF缓冲区空间消耗用户无法控制, 消耗的内存取决于AOF重写时间和写入命令量,这部分空间占用通常很小。

碎片

Redis默认的内存分配器采用jemalloc, 可选的分配器还有: glibc、tcmalloc。 内存分配器为了更好地管理和重复利用内存, 分配内存策略一般采用固定范围的内存块进行分配。 例如jemalloc在64位系统中将内存空间划分为: 小、 大、 巨大三个范围。 每个范围内又划分为多个小的内存块单位, 如下所示:

  • 小: [8byte], [16byte, 32byte, 48byte, ..., 128byte], [192byte,428256byte, ..., 512byte], [768byte, 1024byte, ..., 3840byte]

  • 大: [4KB, 8KB, 12KB, ..., 4072KB]

  • 巨大: [4MB, 8MB, 12MB, ...]

比如当保存5KB对象时jemalloc可能会采用8KB的块存储, 而剩下的3KB空间变为了内存碎片不能再分配给其他对象存储。 内存碎片问题虽然是所有内存服务的通病, 但是jemalloc针对碎片化问题专门做了优化, 一般不会存在过度碎片化的问题, 正常的碎片率( mem_fragmentation_ratio) 在1.03左右。 但是当存储的数据长短差异较大时, 以下场景容易出现高内存碎片问题:

  • 频繁做更新操作, 例如频繁对已存在的键执行append、 setrange等更新操作。

  • 大量过期键删除, 键对象过期删除后, 释放的空间无法得到充分利用, 导致碎片率上升。

出现高内存碎片问题时常见的解决方式如下:

  • 数据对齐: 在条件允许的情况下尽量做数据对齐, 比如数据尽量采用数字类型或者固定长度字符串等, 但是这要视具体的业务而定, 有些场景无法做到。

  • 安全重启: 重启节点可以做到内存碎片重新整理, 因此可以利用高可用架构, 如Sentinel或Cluster, 将碎片率过高的主节点转换为从节点, 进行安全重启。

子进程内存消耗

子进程内存消耗主要指执行AOF/RDB重写时Redis创建的子进程内存消耗。 Redis执行fork操作产生的子进程内存占用量对外表现为与父进程相同,理论上需要一倍的物理内存来完成重写操作。 但Linux具有写时复制技术(copy-on-write) , 父子进程会共享相同的物理内存页, 当父进程处理写请求时会对需要修改的页复制出一份副本完成写操作, 而子进程依然读取fork时整个父进程的内存快照。

  • Redis产生的子进程并不需要消耗1倍的父进程内存, 实际消耗根据期间写入命令量决定, 但是依然要预留出一些内存防止溢出。

  • 需要设置sysctl vm.overcommit_memory=1允许内核可以分配所有的物理内存, 防止Redis进程执行fork时因系统剩余内存不足而失败。

  • 排查当前系统是否支持并开启THP, 如果开启建议关闭, 防止copy-onwrite期间内存过度消耗。

标签:Redis,碎片,划分,内存,memory,缓冲区,客户端
From: https://blog.csdn.net/weixin_42576071/article/details/136802850

相关文章

  • Redis 产生阻塞的原因,如何找到阻塞的原因
    如何发现慢查询slowlogget{n} 获取最近的n条慢查询命令,默认对于执行超过10毫秒的命令都会记录到一个定长队列中调整方法修改为低算法度的命令,如hgetall改为hmget等,禁用keys、sort等命令。调整大对象:缩减大对象数据或把大对象拆分为多个小对象如何发现大对象r......
  • Redis作为缓存,MySQL数据库如何与Redis保持一致性(双写一致性)?
    Redis作为缓存,MySQL数据库如何与Redis保持一致性(双写一致性)?双写一致性:​ 修改了数据库中的数据的同时,也要更新缓存的数据,保证数据库和缓存中的数据保持一致。请求数据的执行流程:​ 请求去访问Redis,如果Redis缓存中有数据则返回数据,如果Redis缓存中没有数据则去查数据库,数......
  • 内存函数(C语言)
    文章目录内存函数memcpymemmovememsetmemcmp内存函数使用内存函数需要包含头文件<string.h>memcpy将内存的数据拷贝到新空间void*memcpy(void*destination,constvoid*source,size_tnum);memcpy函数能将源地址后num个字节的数据拷贝到目标空间区别内存......
  • redis-server.exe 双击闪退还显示未连接
    Redis下运行cmd:D:\Redis-x64-3.0.504>redis-server.exeredis.windows.conf报错:[7672]13Mar21:29:36.738#CreatingServerTCPlisteningsocket*:6379:bind:Noerror执行客户端(可以在下载的地方双击redis-cli.exe,也可以执行命令):D:\Redis-x64-3.0.504>red......
  • Redis缓存和MyBaits整合
    目录一.基础知识1.Redis缓存2.特点二.使用Redis1.下载redis2.安装RedisDesktopManager软件3.连接Redis三.Redis缓存和MyBaits整合1.加入依赖2.配置文件3.配置类4.创建数据库和实体类5.使用四.练习一.基础知识1.Redis缓存缓存(*Cache),就是数据交换的*缓......
  • 【C语言——浮点数在内存中的存储(补充篇)】
    一.概况     根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数都可以表示为以下形式:V=(-1)^s*M*2^E1.(-1)^表示符号位,当s=0时,V为正数;当s=1,V为负数。2.M表示有效数字,M是大于等于1,小于2的。3.2^E表示指数。  二.存储过程IEEE754对有效数字M......
  • 内存泄漏调试工具
    asan、valgrind、coverity和gpertools都是用于帮助开发人员发现和调试代码中的各种问题的工具,但它们在特定方面有着不同的重点和功能。ASan(AddressSanitizer):ASan常用于C/C++代码的静态和动态内存访问错误检测,通过在编译时注入额外的代码来对内存进行访问监控,包括缓冲区溢......
  • 整数和浮点数在内存中储存的形式
    整数整数的二进制表示法有三种,即原码、反码、补码。三种表示方式均有符号位和数值位符号位位于数值位最高位的那一位,分别用0和1表示,0表示正数,1表示负数。数值位,除最高位的那一位外其他都是数值位。正整数的原码、反码和补码都相同,负整数不同,负整数的反码等于原码二进制......
  • BcLinux-Redis-集群(cluster)模式安装配置
    IP:192.168.0.28081、8082IP:192.168.0.3 8081、8082IP:192.168.0.4 8081、80821、三个节点同样操作[root@server-1setup]#yuminstalltcl或者:wgethttp://downloads.sourceforge.net/tcl/tcl8.6.1-src.tar.gztarxzvftcl8.6.1-src.tar.gz-C/home/local/cd/home/loc......
  • 14_redis哨兵机制
    redis哨兵(sential)哨兵人巡查监控后后台master主机是否故障,如果故障了根据投票数自动将某一个从机转换为主机,继续对外提供服务。哨兵的作用监控redis主机的运行状态,包括主机master和slave。当主机宕机后,能自动将从机切slave换成新的主机master注意哨兵不使用集群,仅仅是和......