理解哈希实现及其在Redis中的内存

时间:2016-06-03 10:31:15

标签: memory hash redis hashmap

从文档中我们知道redis会对范围内的数据进行压缩(默认为512)。如果散列范围超过512,那么内存差异将是10倍。

我做了一个小的实验,哈希范围从1到512,并找到了一些有趣的模式。

此图表示1000个哈希值的内存量(以KB为单位),每个哈希值包含1到512之间的条目。

enter image description here

正如您在此图中所见。在一定的时间间隔内存陡峭。我理解redis中的哈希实现也遵循一些逻辑,用于在达到某个范围时扩展大小,而不是为每个新条目增加它。从数字来看,它并没有始终遵循加倍模式,但从215到216它确实加倍,4 MB到8 MB。从420到421,它几乎增加了一半8 MB到12 MB。在215以内的陡峭地区,我无法看到它在1 / 4,1 / 5和1/6之间变化的任何模式。

以下观察我的问题是:

  1. 有人可以在内存和调整大小方面向我解释一下hashmap的内部事件吗?调整大小时遵循的逻辑是什么?
  2. 如果我不得不松开双倍的内存只是为了存储215到216的另一个条目,为什么我不能限制我的应用程序总是有一个小于215的哈希值,除非并且直到系统需要它最多。
  3. 假如我想存储100万个哈希值,每个哈希值由250个值组成,我需要800MB。如果我将它们分成两个125个值的哈希值,即200个哈希值为125个值,我需要500MB。通过这种方式,我节省了300 MB,这是巨大的!这个计算是对的吗?我在这种情况下遗漏了什么吗?
  4. 提前致谢

3 个答案:

答案 0 :(得分:3)

由于你在redis中一直有1000个密钥,每个哈希密钥只有字段编号改变,而你的字段编号低于512,所以这种现象只是由jemalloc引起的。

这是我使用libc作为我的mem_allocator的行为:

您可以通过以下方式重新制作redis:

make MALLOC=libc

再次运行测试,看看你会得到什么。

回答你的问题:

  1. 有人可以根据内存和调整大小向我解释一下hashmap的内部事件吗?调整大小时遵循的逻辑是什么?

    如前所述,您遇到的与redis本身无关。 Jemalloc这样做是为了提高效率

  2. 如果我不得不松开双倍的内存只是为了存储215到216的另一个条目,为什么我不能限制我的应用程序总是有一个小于215的哈希值,除非并且直到系统需要它最多。

    当然,只要您可以限制字段数字,就可以这样做

  3. 假设我想存储100万个哈希值,每个哈希值由250个值组成,我需要800MB。如果我将它们分成两个125个值的哈希值,即200个哈希值为125个值,我需要500MB。通过这种方式,我节省了300 MB,这是巨大的!这个计算是对的吗?我在这种情况下遗漏了什么吗?

    我认为这不是一种正确的方法。也许你可以通过这样做来节省一些内存。但是,缺点是:当你将100万个哈希值拆分为200万个时,redis会进行重新散列(这将占用你一些空间)并且它会花费你更多的时间来找到一个键,因为它会导致更多的哈希冲突机会

答案 1 :(得分:3)

@ sel-fish说得对。它完全是关于内存分配器的。为了其他人的利益,我想为此添加更多信息。

我还做了一个实验,比较了在jemalloc和libc中进行相同操作所花费的时间。为了更清晰,我在完全相同的情况下完成了这两个实验。我无法找到性能上的任何重大差异,libc大多数时候都会获胜。

我附上了截图。

enter image description here

enter image description here

因此,正如您在图表中看到的那样,jemalloc调整大小有点加倍,而libc正在逐渐增加。

使用libc没有重大的性能下降(花费时间)。实际上,在大多数领域,libc花费的时间较少。

我还研究了一些关于libc和jemalloc的文章,在我看来,对于这种情况,libc获胜。

我也希望听取其他人对他们观点的看法。

答案 2 :(得分:1)

Yoy可能会在文章Redis under the hood: Hash(part1)Redis under the hood: Hash(part2)中找到哈希内部的完整描述。简而言之,每次内存都会变得很大:

  1. 您将哈希从ziplist移至dict内部编码。
  2. 您使用填充因子强制Redis将哈希的大小加倍。
  3. 请记住 - Redis使用dict来处理密钥空间。因此,每次创建新密钥(任何类型)时,都将其放在密钥的内部哈希表中。所以这里有相同的逻辑 - 当你向Redis添加新密钥时它会增长为dict