Redis被称为key/value应用中的瑞士军刀,除了其丰富的数据结构支持,更重要的是高效的内存使用,分析源码可以发现作者使用每一个byte都精打细算。在hashtable实现中,Redis引入了zipmap数据结构,保证在hashtable刚创建以及元素较少时,用更少的内存来存储,同时对查询的效率也不会受太大的影响。下面就以源码和例子结合的方式来分析一下zipmap的内存布局。
先来看一下zipmap提供的和存储相关的3个API:
zipmapNew:创建一个zipmap字符串。zipmap创建时只有2个字节,后面会随着set和delete操作动态扩展和收缩。
zipmapSet: 加入新的key/value或者修改zipmap中已有key对应的value。
zipmapDel:从zipmap中删除key/value。
下面给出一段伪代码并分析其内存布局的变化,如下图:
zipmapNew();
zipmapSet(key1,value1);
zipmapSet(key2,value2);
zipmapSet(key1,value3);
zipmapDel(key2);
zipmapSet(key1,value4);
1. zipmapNew();
创建一个zipmap结构体,包含两个字节,第一个字节(zmlen)是长度为1个字节的无符号整数,用来保存zipmap当前元素个数(而非字符串长度)。当zipmap的元素个数大于等于254时,zmlen将不再起作用,zipmap需要遍历整个字符串来获取当前元素个数。最后一个字节为255,表示zipmap的结束。
2. zipmapSet(key1, value1)
一个元素(key/value)在zipmap中有5部分组成:<len><key><len><free><value>。
<len>表示紧跟其后的string(key或者value)的长度。如果string的长度小于254(这里代码和注释不统一,注释是253,但代码是254,以代码为准),<len>用一个字节就可以表示(254和255有特殊含义),如果string的长度大于等于254,<len>需要5个字节来表示,第一个字节设置为254,紧跟其后的4个字节通过编码(按主机字节序)来表示<len>的值。zipmapEncodeLength和zipmapDecodeLength就是用来对<len>进行编解码的。<key>和<value>是char型string,<free>在第6步进行说明。
3. zipmapSet(key2, value2)
调用zipmapSet加入新的key/value时,zipmap将根据key2/value2的长度调用zipmapResize扩展空间,并将key2/value2插入到新分配的空间。同时将zipmap元素的个数加1(如果<zmlen>小于254)。
4. zipmapSet(key1,value3)
调用zipmapSet对已有的key修改其value,且新的value值大于现有value占用的空间时(加free的空间),zipmap将再次调用zipmapResize扩展空间,并调用memmove将key1/vaule1之后的字符串向后顺移。这里只调用一次memmove,不会对性能有太大影响。
5. zipmapDel(key2)
调用zipmapDel删除key2/value2时,zipmap将把key2/value2之后的字符串前移,并调用zipmapResize收缩占用的内存空间。同时将zipmap元素个数减1。
6. zipmapSet(key1, value4)
调用zipmapSet对已有的key1修改其value,且新的value值小于现有value占用的空间时,zipmap不会马上去调用zipmapResize做内存空间收缩,而是将空闲字节数存入free中,用于后面对这个key再次修改value时,避免调用zipmapResize(要根据新value的长度而定)。当然free的空间也不能太多,否则会造出空间的浪费。zipmap在free字节数大于等于ZIPMAP_VALUE_MAX_FREE(代码中定义为4)时,就对free的空间进行收缩。
以上就是zipmap内存布局和扩展收缩的过程,你可能会问zipmapGet岂不是O(n)的吗?没错,但因为key和value都是确定长度的字符串,所以这个n是zipmap中元素的个数,而不是zipmap整个串的长度。只要在使用zipmap时保证元素个数不是很多,就可以在时间复杂度和空间复杂度两方面找到很好的平衡点。redis.conf中默认配置hash-max-zipmap-entries为512。
分享到:
相关推荐
此外,还可以考虑在分析过程中使用内存分析工具,如Redis的`MEMORY USAGE`命令,以更精确地获取单个键的内存占用。 总结来说,通过Key前缀分析Redis内存占用并导出结果到CSV文件,是一个涉及Redis内存管理、PHP编程...
标题 "Go 实现的 Redis 内存分析工具" 指出这是一款使用 Go 语言编写的工具,其主要功能是针对 Redis 数据库进行内存分析。Redis 是一个高性能的键值存储系统,常用于缓存和数据持久化,而这款工具能够帮助用户更...
### Redis内存存储结构分析 #### 一、Redis内存存储总体结构概述 Redis是一种高性能的键值存储系统,它将所有数据存储在内存中,从而实现了非常快的数据读写速度。然而,这种设计也有其局限性,例如对于拥有大量...
但是由于数据量的不断增大,单机的Redis物理内存远远无法满足大数据的需要,因此需要搭建分布式的Redis,可以动态扩展内存,弥补单机Redis物理内存不够的缺点。本次测试旨在对Redis各方面性能有深入的了解,为今后的...
在Redis内存分布分析中,涉及到的核心知识点包括Redis的数据结构存储、数据类型操作、内存管理机制以及命令执行过程解析。 首先,我们来了解Redis的数据结构存储。Redis作为一个高性能的键值存储系统,其内部通过...
Redis 内存溢出 Bug 根因分析 在 Redis 中,内存溢出是一种常见的错误,会导致 Redis 服务崩溃,影响业务的稳定性。下面我们会对 Redis 内存溢出 Bug 的根因进行分析,并总结出相应的解决方案。 1. Redis 持久化 ...
了解Redis的数据结构和命令是进行内存分析的基础。 3. **Key前缀筛选**: 在Redis中,可以通过Key前缀来筛选特定类型的数据。例如,如果所有的用户ID都以"user:"开头,那么可以使用前缀"user:"来查询所有用户相关...
1、基于springboot+echarts+redis实现的数据分析及可视化系统源码+项目说明.zip 2、该资源包括项目的全部源码,下载可以直接使用! 3、本项目适合作为计算机、数学、电子信息等专业的课程设计、期末大作业和毕设项目...
### Redis内存模型介绍 #### 一、Redis简介与数据类型 **Redis** 是一款高性能的键值对存储系统,它采用内存作为主要存储介质,并提供了丰富的数据结构支持,包括字符串(Strings)、哈希(Hashes)、列表(Lists)、...
总结,Redis流量分析涉及到多个层面,包括数据结构的选择、操作频率的监控、内存管理、持久化策略、网络优化以及使用适当的监控工具。通过对这些方面的深入了解和细致调整,可以有效控制和优化Redis的流量,确保系统...
基于springboot+echarts+redis开发的数据分析及可视化系统源码-毕业设计作品.zip基于springboot+echarts+redis开发的数据分析及可视化系统源码-毕业设计作品.zip基于springboot+echarts+redis开发的数据分析及可视化...
Redis作为一个高效的键值存储系统,其内存管理是监控和优化的关键环节。了解如何查看Redis的内存信息对于确保系统的稳定...同时,结合其他监控工具和日志分析,可以更全面地了解Redis的运行状态,及时发现和解决问题。
分析key内存大小
Redis Analyzer - 用Rust编写的Redis内存分析器
作为一款开源的内存数据库,Redis以其高效、灵活的特性在IT行业中广泛应用,尤其是在缓存、消息队列、实时数据统计等方面。本文将深入探讨Redis 2.4.1版本的主要特性和功能。 首先,Redis的核心特性之一是其基于...
redis源码阅读中文分析注释
墨墨导读:本文节选自《Redis 5设计与源码分析》,主要为读者分析Redis高性能内幕,重点从源码层次讲解了Redis事件模型,网络IO事件重在使用IO复用模型,时间事件重在限制最大执行CPU时间。最后简单介绍了Redis的...