百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

如何以最节省内存的方式在Redis中缓存百亿数据?

nanshan 2024-12-10 18:56 9 浏览 0 评论

先讲一个曾经处理过的真实案例!

业务场景:根据人群标签进行互联网广告的定向投放,我们期望每个请求都能足够快地获取到用户的标签信息,尽快完成处理逻辑并响应。

缓存方案:由于数据量是10亿级别,将来可能会是百亿级别,进程内缓存直接不考虑。全都是key-value数据,所以决定采用redis集群作为缓存。

方案很符合常理!于是我们开始向测试的redis集群疯狂输出,很快写了3000万条数据进去,以为一切都会很顺利。但天有不测风云!监控显示内存不足!测试集群三台(4核8G)机器,每台机器上一主一从,这才存了3000万数据而已,真存百亿数据的话内存成本就太高了。

怎么办呢?显然key太多,内存膨胀明显!改用Hash类型存储这些数据,使用一致性哈希取余的方法,将海量用户分配到2^n个Hash对象上,把用户标签存储在Hash对象的field中。于是key的数量有了数量级的下降,且由于Redis对Hash数据的压缩编码,实际节省内存将近80%。

以上是Redis内存优化的方法之一,也是业界很多人都会用的方案。Redis本身提供了很多内存优化方法,继续往下看,我结合官方文章来做一个全面介绍!

1.针对聚合数据类型进行的特殊编码

Redis从2.2版本开始,对许多数据类型都进行了优化,小于一定大小的情况下可以使用更少的存储空间,包括Hash、List、仅由整数组成的Set以及Sorted Set。当不超过最大值时,会以内存高效的方式对数据进行编码,最高可以减少90%的内存占用(平均节省80%),这对于用户和API来说是完全透明的。

马克思主义哲学告诉我们一个真理:任何事物总是存在矛盾的。所以我们经常面临着权衡的问题,不能两全其美的时候,就要寻求平衡。Redis的这种优化就是在内存和CPU之间的权衡,用户可以使用redis.conf中的配置去调整可支持特殊编码的元素最大数量和最大大小,下面是几个相关的配置项:

hash-max-ziplist-entries 512 //hash中最大的field数量
hash-max-ziplist-value 64    //hash中的每个field-name和field-value最大不超过64 bytes
list-max-ziplist-size -2     // -2 8kb,-1 4kb
zset-max-ziplist-entries 128 //zset类型支持压缩编码的最大元素数量
zset-max-ziplist-value 64    //zset中每个元素最大不超过64 bytes
set-max-intset-entries 512   //由64位有符号int组成的set 支持压缩编码的最大元素数量

以上配置在redis官方的redis.conf文件模板中有详细的说明,有兴趣可以去看看。

如果超过了配置的上限,Redis会自动将其转换为普通编码。对于较小的值,这种转换是非常快的。但要是想通过修改配置,对更大的值进行特殊编码,建议做好基准测试,确认转换的耗时,以免影响服务稳定性。

2.使用32位Redis实例

使用32位目标编译的Redis,每个键使用的内存非常少,因为指针比较小。但是,32位Redis实例的内存使用量上限是4GB(指的是key使用的内存,寻址空间只有2的32次方,也就是4GB)。RDB和AOF文件在32位和64位Redis实例上是兼容的(而且也兼容高位字节序和低位字节序),你可以从32位切换为64位,或者相反,都没有问题。

3.位和字节级操作

从Redis2.2开始,引入了一些新的位、字节级操作:GETRANGE、SETRANGE、GETBIT和SETBIT。使用这些命令,你可以将Redis的string类型当成可以随机访问的数组。

假设你有一个应用,使用递增的唯一整数来标识用户,你可以使用bitmap(位图)来保存某个邮件列表的用户订阅情况,每一个bit都代表一个用户的订阅状态。设置指定位代表订阅,清除指定位代表取消订阅。在一个Redis实例中,1亿用户的订阅信息只需要12M内存空间。

4.官方建议:尽可能使用Hash

将数据抽象成内存高效的Hash结构存储在Redis中,这也是上面案例中使用的方法。

对于较小的Hash数据,在编码后会占用很少的空间。所以,尽可能把数据组织成Hash。例如:如果在web应用程序中有表示用户的对象,那么不要为名称、姓氏、电子邮件、密码使用不同的键,而是使用一个包含所有必需字段的Hash。

在Redis中,一定数量的key占用的内存要大于单个key包含一定数量的Hash字段。

如何做到的呢?为了保证查询操作是常数时间,Redis使用了常数时间复杂度的数据结构,比如Hash Table。大多时候Hash只包含少数的几个字段,比较小,此时使用O(N)复杂度的数据结构,就像以键值对组成的线性数组。因为只有N比较小的时候才会这样做,所以HGET和HSET操作所花费的时间平摊下来也是O(1),线性数组可以比哈希表更好地利用CPU缓存(如果不太明白,那你需要复习下计算机原理了)。当Hash所包含元素的数量增长太大,超过最大限制时(可以在redis.conf中修改这个限制),它会被转换成一个真正的哈希表。这里再次体现了两个字:权衡!

不过,Hash的字段并不是拥有完整特性的Redis对象,无法像一个真正的key一样设置过期时间,而且值只能是字符串。但这并没有什么问题,简单比特性丰富更重要,这是Redis官方的设计意图和哲学。

5.关于内存分配

为了保存用户的key,Redis最多分配maxmemory设置所允许的内存,但实际上可能会有少量的额外内存。关于Redis的内存管理,以下几点值得关注:

  • 当某些key被删除后,Redis并不总是把内存返还给操作系统,并不是因为Redis故意这样做,这是大部分内存分配函数的实现方式所导致的。例如一个被5GB数据填充的Redis实例,当我们删除2GB的数据后,RSS(Resident Set Size,驻留集大小,即进程消费的内存页大小,这涉及到操作系统的页式虚拟内存管理)可能依然是5GB左右,即使Redis显示用户使用的内存有3GB左右。这是因为底层操作系统的内存分配器无法轻易地释放内存,被删除的key有可能和其它未被删除的key位于同一个内存页。操作系统是以页为单位给进程分配内存的。
  • 基于上一点,我们需要根据内存使用的峰值来分配内存,假设大部分时间只用5GB左右数据,偶尔需要10GB内存,那也要按照10GB来提供。
  • 内存分配器是很机智的,可以有效利用空闲的内存块,因此当你释放5GB数据中的2GB后,再添加更多key时,会发现RSS是保持稳定的,并不会增长太多。分配器会尝试复用之前被逻辑上释放的2GB内存。

如果maxmemory没有设置,Redis将会在找到合适的内存时继续进行分配,这样会逐步消耗掉所有空闲内存,建议配置一下这个上限。当内存达到上限时再执行写命令,Redis会返回一个内存不足的错误。这可能会导致应用程序的错误,但不会因为内存不足导致整个机器宕机。

以上就是Redis内存优化的一些方法,抛砖引玉,希望对你有所启发。官方的文档里有很多干货,建议大家多看看。

相关推荐

Let’s Encrypt免费搭建HTTPS网站

HTTPS(全称:HyperTextTransferProtocoloverSecureSocketLayer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。即HTTP下加入...

使用Nginx配置TCP负载均衡(nginx tcp负载)

假设Kubernetes集群已经配置好,我们将基于CentOS为Nginx创建一个虚拟机。以下是实验种设置的详细信息:Nginx(CenOS8Minimal)-192.168.1.50Kube...

Nginx负载均衡及支持HTTPS与申请免费SSL证书

背景有两台minio文件服务器已做好集群配置,一台是192.168.56.41:9000;另一台是192.168.56.42:9000。应用程序通过Nginx负载均衡调用这两台minio服务,减轻单点...

HTTPS配置实战(https配置文件)

原因现在网站使用HTTPS是规范操作之一,前些日子买了腾讯云服务,同时申请了域名http://www.asap2me.top/,目前该域名只支持HTTP,想升级为HTTPS。关于HTTPS的链接过程大...

只有IP地址没有域名实现HTTPS访问方法

一般来说,要实现HTTPS,得有个注册好的域名才行。但有时候呢,咱只有服务器的IP地址,没注册域名,这种特殊情况下,也能照样实现HTTPS安全访问,按下面这些步骤来就行:第一步,先确认公网...

超详解:HTTPS及配置Django+HTTPS开发环境

众所周知HTTP协议是以TCP协议为基石诞生的一个用于传输Web内容的一个网络协议,在“网络分层模型”中属于“应用层协议”的一种。在这里我们并不研究该协议标准本身,而是从安全角度去探究使用该协议传输数...

Godaddy购买SSL之后Nginx配置流程以及各种错误的解决

完整流程:参考地址:https://sg.godaddy.com/zh/help/nginx-generate-csrs-certificate-signing-requests-3601生成NGI...

Nginx从安装到高可用,一篇搞定(nginx安装与配置详解)

一、Nginx安装1、去官网http://nginx.org/下载对应的nginx包,推荐使用稳定版本2、上传nginx到linux系统3、安装依赖环境(1)安装gcc环境yuminstallgc...

阿里云免费证书申请,配置安装,使用tomcat,支持http/https访问

参数说明商品类型默认已选择云盾证书服务(无需修改)。云盾证书服务类型SSL证书服务的类型。默认已选择云盾SSL证书(无需修改),表示付费版SSL证书。如果您需要免费领取或付费扩容DV单域名证书【免费试...

你试过两步实现Nginx的规范配置吗?极速生成Nginx配置小工具

NGINX是一款轻量级的Web服务器,最强大的功能之一是能够有效地提供HTML和媒体文件等静态内容。NGINX使用异步事件驱动模型,在负载下提供可预测的性能。是当下最受欢迎的高性能的Web...

从零开始搭建HTTPS服务(搭建https网站)

搭建HTTPS服务的最初目的是为了开发微信小程序,因为wx.request只允许发起HTTPS请求,并且还必须和指定的域名进行网络通信。要从零开始搭建一个HTTPS的服务需要下面4...

群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问

安全第一步,群晖NAS使用官网域名和自己的域名配置SSL实现HTTPS访问【新手导向】NAS本质还是一个可以随时随地访问的个人数据存储中心,我们在外网访问的时候,特别是在公网IP下,其实会面临着很多安...

让网站快速升级HTTPS协议提高安全性

为什么用HTTPS网络安全越来越受到重视,很多互联网服务网站,都已经升级改造为https协议。https协议下数据包是ssl/tcl加密的,而http包是明文传输。如果请求一旦被拦截,数据就会泄露产生...

用Https方式访问Harbor-1.9版本(https访问流程)

我上周在头条号写过一篇原创文章《Docker-Harbor&Docker-kitematic史上最详细双系统配置手册》,这篇算是它的姊妹篇吧。这篇文章也将用到我在头条写的另一篇原创文章的...

如何启用 HTTPS 并配置免费的 SSL 证书

在Linux服务器上启用HTTPS并配置免费的SSL证书(以Let'sEncrypt为例)可以通过以下步骤完成:---###**一、准备工作**1.**确保域名已解析**...

取消回复欢迎 发表评论: