当前位置:首页 > 问答 > 正文

Redis到底能存多少键值对?其实没那么简单,得看这些因素影响

(引用来源:Redis官方文档、多位资深开发者的经验总结、以及像《Redis实战》这类技术书籍中的相关讨论)

很多人刚开始用Redis的时候,可能会有一个简单的想法:我这台服务器内存是8G的,那Redis是不是就能存差不多8个G的键值对?理论上这么想没错,但实际情况要复杂得多,Redis到底能存下多少数据,并不是一个简单的数字能回答的,它更像是一个由好几个因素共同决定的“动态结果”,咱们就来聊聊这些关键因素。

最直接、最硬性的限制就是可用的物理内存大小,这个很好理解,Redis的所有数据都放在内存里,所以服务器有多少空闲内存,基本上就决定了Redis数据存储的上限,如果你的机器总内存是16G,操作系统和其他应用已经用了4G,那留给Redis的大致也就12G左右,这里有个很重要的点,你需要通过Redis的配置文件(redis.conf)里的maxmemory参数来明确告诉Redis最多能用多少内存,如果你不设置这个参数,在64位系统上,Redis会一直用下去直到把系统内存耗光,这很可能导致系统开始使用交换分区(swap),让Redis的性能变得极慢,甚至拖垮整个服务器,设定一个合理的maxmemory是第一步。

你存储的数据的结构和大小对能存多少键值对影响巨大,这可能是新手最容易忽略的一点,举个例子,你存一个简单的字符串键值对,比如user:1001:name对应值"张三",这个键值对本身占用的内存很小,但如果你用Redis的Hash结构来存储一个用户对象,比如user:1001,里面包含了姓名、年龄、城市等好几个字段,那么为了管理这个Hash结构,Redis需要额外的内存来存储它的内部信息(比如指向各个字段的指针等),这些额外的开销,有时候甚至可能比你实际存储的数据本身还要大,存一万个独立的字符串键,和把这一万个键值对塞进一百个Hash结构里,最终占用的总内存是完全不同的,键和值的长度也很关键,一个很长的键名(比如一个几百字节的字符串)配上一个小小的整数值,就显得很不划算,因为存储长键名本身也费内存。

第三个关键因素是你设置的淘汰策略,当Redis占用的内存达到了你设定的maxmemory上限时,它该怎么办?是拒绝写入新数据,还是淘汰掉一些老数据?这个行为就是由淘汰策略决定的,Redis提供了好几种策略,

  • noeviction:默认策略,不淘汰数据,当内存不够时,新来的写入命令会直接报错。
  • allkeys-lru:从所有的键中,挑最近最少使用的那些淘汰掉。
  • volatile-lru:只从设置了过期时间的键中,淘汰最近最少使用的。
  • allkeys-random:从所有键中随机淘汰。
  • volatile-ttl:优先淘汰过期时间更短的键。

你选择的策略不同,Redis在内存满时的行为就不同,如果你用的是noeviction,那你的键数量在达到内存上限后就固定了,如果你用的是allkeys-lru,那么Redis会不断地淘汰旧数据来容纳新数据,此时你能存储的“有效”键值对数量,其实取决于你的数据访问模式,它是一个动态变化的值。

除了以上三点,还有一些不那么直观但确实存在的因素。Redis持久化(数据保存到硬盘)时的开销,当Redis执行RDB快照或AOF重写时,它需要fork一个子进程来操作,在fork的瞬间,虽然子进程和父进程共享内存,但如果父进程有大量的写操作,会触发操作系统的“写时复制”机制,导致内存占用在短时间内几乎翻倍,如果你的内存本来就已经快满了,这个fork过程可能会因为申请不到足够的内存而失败,实际生产中,一般不会让Redis把内存用到100%,会留出一定的余量来应对这种突发情况。

还有,Redis实例的版本和编译配置也有细微影响,不同版本的Redis在内存分配器和数据结构的内部实现上可能有优化,导致存储相同数据时内存占用略有差异。

回到最初的问题:Redis到底能存多少键值对?答案是,它取决于你的可用内存上限、你的数据结构和大小、你的内存淘汰策略、以及你的运维配置,没有一个放之四海而皆准的数字,最靠谱的方法,是在你的业务环境下,用接近真实的数据样本进行测试和监控,观察内存的增长情况,这样才能找到最适合你业务场景的容量规划,你得亲自摸清你自己这个“Redis”的脾气。

Redis到底能存多少键值对?其实没那么简单,得看这些因素影响