从文档中我们知道redis会对范围内的数据进行压缩(默认为512)。如果散列范围超过512,那么内存差异将是10倍。
我做了一个小的实验,哈希范围从1到512,并找到了一些有趣的模式。
此图表示1000个哈希值的内存量(以KB为单位),每个哈希值包含1到512之间的条目。
正如您在此图中所见。在一定的时间间隔内存陡峭。我理解redis中的哈希实现也遵循一些逻辑,用于在达到某个范围时扩展大小,而不是为每个新条目增加它。从数字来看,它并没有始终遵循加倍模式,但从215到216它确实加倍,4 MB到8 MB。从420到421,它几乎增加了一半8 MB到12 MB。在215以内的陡峭地区,我无法看到它在1 / 4,1 / 5和1/6之间变化的任何模式。
以下观察我的问题是:
提前致谢
答案 0 :(得分:3)
由于你在redis中一直有1000个密钥,每个哈希密钥只有字段编号改变,而你的字段编号低于512,所以这种现象只是由jemalloc引起的。
这是我使用libc作为我的mem_allocator的行为:
您可以通过以下方式重新制作redis:
make MALLOC=libc
再次运行测试,看看你会得到什么。
回答你的问题:
有人可以根据内存和调整大小向我解释一下hashmap的内部事件吗?调整大小时遵循的逻辑是什么?
如前所述,您遇到的与redis本身无关。 Jemalloc这样做是为了提高效率
如果我不得不松开双倍的内存只是为了存储215到216的另一个条目,为什么我不能限制我的应用程序总是有一个小于215的哈希值,除非并且直到系统需要它最多。
当然,只要您可以限制字段数字,就可以这样做
假设我想存储100万个哈希值,每个哈希值由250个值组成,我需要800MB。如果我将它们分成两个125个值的哈希值,即200个哈希值为125个值,我需要500MB。通过这种方式,我节省了300 MB,这是巨大的!这个计算是对的吗?我在这种情况下遗漏了什么吗?
我认为这不是一种正确的方法。也许你可以通过这样做来节省一些内存。但是,缺点是:当你将100万个哈希值拆分为200万个时,redis会进行重新散列(这将占用你一些空间)并且它会花费你更多的时间来找到一个键,因为它会导致更多的哈希冲突机会强>
答案 1 :(得分:3)
@ sel-fish说得对。它完全是关于内存分配器的。为了其他人的利益,我想为此添加更多信息。
我还做了一个实验,比较了在jemalloc和libc中进行相同操作所花费的时间。为了更清晰,我在完全相同的情况下完成了这两个实验。我无法找到性能上的任何重大差异,libc大多数时候都会获胜。
我附上了截图。
因此,正如您在图表中看到的那样,jemalloc调整大小有点加倍,而libc正在逐渐增加。
使用libc没有重大的性能下降(花费时间)。实际上,在大多数领域,libc花费的时间较少。
我还研究了一些关于libc和jemalloc的文章,在我看来,对于这种情况,libc获胜。
我也希望听取其他人对他们观点的看法。
答案 2 :(得分:1)
Yoy可能会在文章Redis under the hood: Hash(part1)和Redis under the hood: Hash(part2)中找到哈希内部的完整描述。简而言之,每次内存都会变得很大:
ziplist
移至dict
内部编码。请记住 - Redis使用dict
来处理密钥空间。因此,每次创建新密钥(任何类型)时,都将其放在密钥的内部哈希表中。所以这里有相同的逻辑 - 当你向Redis添加新密钥时它会增长为dict
。