当前位置: 编码机 >> 编码机发展 >> Redis经典面试实战之深入理解内存模型
Redis是目前最流行的内存NoSql数据库之一,通过在内存中读写数据,大大提高了读写速度,因为CPU不是Redis的瓶颈。Redis的瓶颈最有可能是机器内存或者网络带宽,既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。关于redis的性能,官方网站也有,普通笔记本轻松处理每秒几十万的请求。可以说Redis是实现网站高并发不可或缺的一部分。
下面我们就进一步了解Redis的内存模型,本文将主要从以上三个方向介绍Redis的内存模型,包括Redis占用内存的情况及如何查询、不同的对象类型在内存中的编码方式、内存划分、Redis使用过程中如何节省内存、Redis内存耗尽处理机制等。
1、估算Redis内存使用量。目前为止,内存的使用成本仍然相对较高,使用内存不能无所顾忌;根据需求合理的评估Redis的内存使用量,选择合适的机器配置,可以在满足需求的情况下节约成本。
2、Redis内存优化占用。了解Redis内存模型可以选择更合适的数据类型和编码,更好地利用Redis内存。
3、Redis内存耗尽处理机制。当Redis出现内存不足、耗尽时等问题时,它的底层处理机制是怎么样的。
一、Redis内存统计
工欲善其事必先利其器,在说明Redis内存之前首先说明如何统计Redis使用内存的情况。在客户端通过redis-cli连接服务器后(后面如无特殊说明,客户端一律使用redis-cli),通过info命令可以查看内存使用情况。
其中,info命令可以显示redis服务器的许多信息,包括服务器基本信息、CPU、内存、持久化、客户端连接信息等等;memory是参数,表示只显示内存相关的信息。返回结果中比较重要的几个说明如下:
1、used_memory:Redis分配器分配的内存总量(单位是字节),包括使用的虚拟内存(即swap);Redis分配器后面会介绍。used_memory_human只是显示更友好。
2、used_memory_rss:Redis进程占据操作系统的内存(单位是字节),与top及ps命令看到的值是一致的;除了分配器分配的内存之外,used_memory_rss还包括进程运行本身需要的内存、内存碎片等,但是不包括虚拟内存。
3、mem_fragmentation_ratio:内存碎片比率,该值是used_memory_rss/used_memory的比值。
4、mem_allocator:Redis使用的内存分配器,在编译时指定;可以是libc、jemalloc或者tcmalloc,默认是jemalloc;截图中使用的便是默认的jemalloc。
更多详细可以自行查阅资料。
二、Redis内存划分
Redis作为内存数据库,在内存中存储的内容主要是数据(键值对);通过前面的叙述可以知道,除了数据以外,Redis的其他部分也会占用内存。
Redis的内存占用主要可以划分为以下几个部分:
1、数据
作为数据库,数据是最主要的部分;这部分占用的内存会统计在used_memory中。
Redis使用键值对存储数据,其中的值(对象)包括5种类型,即字符串、哈希、列表、集合、有序集合。这5种类型是Redis对外提供的,实际上,在Redis内部,每种类型可能有2种或更多的内部编码实现;此外,Redis在存储对象时,并不是直接将数据扔进内存,而是会对对象进行各种包装:如redisObject、SDS等;这篇文章后面将重点介绍Redis中数据存储的细节。
2、进程本身运行需要的内存
Redis主进程本身运行肯定需要占用内存,如代码、常量池等等;这部分内存大约几兆,在大多数生产环境中与Redis数据占用的内存相比可以忽略。这部分内存不是由jemalloc分配,因此不会统计在used_memory中。
补充说明:除了主进程外,Redis创建的子进程运行也会占用内存,如Redis执行AOF、RDB重写时创建的子进程。当然,这部分内存不属于Redis进程,也不会统计在used_memory和used_memory_rss中。
3、缓冲内存
缓冲内存包括客户端缓冲区、复制积压缓冲区、AOF缓冲区等;其中,客户端缓冲存储客户端连接的输入输出缓冲;复制积压缓冲用于部分复制功能;AOF缓冲区用于在进行AOF重写时,保存最近的写入命令。在了解相应功能之前,不需要知道这些缓冲的细节;这部分内存由jemalloc分配,因此会统计在used_memory中。
4、内存碎片
内存碎片是Redis在分配、回收物理内存过程中产生的。例如,如果对数据的更改频繁,而且数据之间的大小相差很大,可能导致redis释放的空间在物理内存中并没有释放,但redis又无法有效利用,这就形成了内存碎片。内存碎片不会统计在used_memory中。
内存碎片的产生与对数据进行的操作、数据的特点等都有关;此外,与使用的内存分配器也有关系:如果内存分配器设计合理,可以尽可能的减少内存碎片的产生。后面将要说到的jemalloc便在控制内存碎片方面做的很好。
如果Redis服务器中的内存碎片已经很大,可以通过安全重启的方式减小内存碎片:因为重启之后,Redis重新从备份文件中读取数据,在内存中进行重排,为每个数据重新选择合适的内存单元,减小内存碎片。
三、Redis内存优化占用
众所周知,Redis的性能之所以如此之高,原因就在于它的数据都存储在「内存」中,所以访问Redis中的数据速度极快。
但从资源利用率层面来说,机器的内存资源相比于磁盘,还是比较昂贵的。
当你的业务应用在Redis中存储数据很少时,你可能并不太关心内存资源的使用情况。但随着业务的发展,你的业务存储在Redis中的数据就会越来越多。
如果没有提前制定好内存优化策略,那么等业务开始增长时,Redis占用的内存也会开始膨胀。
所以,提前制定合理的内存优化策略,对于资源利用率的提升是很有必要的。
那在使用Redis时,怎样做才能更节省内存呢?这里我给你总结了6点建议,我们依次来看:
1)控制key的长度
最简单直接的内存优化,就是控制key的长度。
在开发业务时,你需要提前预估整个Redis中写入key的数量,如果key数量达到了百万级别,那么,过长的key名也会占用过多的内存空间。
所以,你需要保证key在简单、清晰的前提下,尽可能把key定义得短一些。
例如,原有的key为user:book:,则可以优化为u:bk:。
这样一来,你的Redis就可以节省大量的内存,这个方案对内存的优化非常直接和高效。
2)避免存储bigkey
除了控制key的长度之外,你同样需要
转载请注明:http://www.aideyishus.com/lktp/2874.html