Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization 当字符串超过7个字节时,字符串的Redis int表示形式更大,反之则更小_Optimization_Redis_Int - Fatal编程技术网

Optimization 当字符串超过7个字节时,字符串的Redis int表示形式更大,反之则更小

Optimization 当字符串超过7个字节时,字符串的Redis int表示形式更大,反之则更小,optimization,redis,int,Optimization,Redis,Int,我正试图尽可能地减小Redis的对象大小,我花了整整一周的时间来进行实验 在测试不同的数据表示时,我发现字符串“hello”的int表示会产生更小的对象。它看起来可能不多,但如果您有大量数据,那么使用几GB内存与使用几十GB内存会有所不同 请看以下示例(如果您愿意,可以自己尝试): 特别要注意的是serializedlength,在本例中为6(字节) 现在,看看它的以下int表示: > SET test:2 "857715" > debug object test:2 > Va

我正试图尽可能地减小Redis的对象大小,我花了整整一周的时间来进行实验

在测试不同的数据表示时,我发现字符串“hello”的int表示会产生更小的对象。它看起来可能不多,但如果您有大量数据,那么使用几GB内存与使用几十GB内存会有所不同

请看以下示例(如果您愿意,可以自己尝试):

特别要注意的是serializedlength,在本例中为6(字节)

现在,看看它的以下int表示:

> SET test:2 "857715"
> debug object test:2
> Value at:0xb6c9f460 refcount:1 encoding:int serializedlength:5 lru:9535401 lru_seconds_idle:2
正如您所看到的,它会导致一个字节更短的对象(请注意编码:int,我认为这表明int的处理效率更高)

使用字符串“hello w”(过一会儿你就会明白为什么我没有使用“hello world”),当它表示为int时,我们得到了更大的节省:

> SET test:3 "hello w"
> SET test:4 "857715023" <- Int representation. Notice that I inserted a "0", if I don't, it results in a bigger object and the encoding is set to "raw" instead (after all a space is not an int).
>
> debug object test:3
> Value at:0xb6c9f3a0 refcount:1 encoding:raw serializedlength:8 lru:9535788 lru_seconds_idle:6
> debug object test:4
> Value at:0xb6c9f380 refcount:1 encoding:int serializedlength:5 lru:9535809 lru_seconds_idle:5
如您所见,int(12字节)比字符串表示(9字节)大

我的问题是,当你把一个字符串表示为int时,它会变小,直到你达到7个字节,在幕后发生了什么

是否有一种方法可以像“列出最大ziplist条目/列出最大ziplist值”那样增加此限制,或者有一种聪明的方法来优化此过程,使其始终(或几乎)产生比字符串更小的对象

更新

我还进一步尝试了其他技巧,实际上可以得到比string更小的int,不管它的大小如何,但这需要更多的数据结构建模工作

我发现,如果你把一个字符串的int表示形式分成8个数字的块,它最终会变小

以单词“Hello World Hi Universe”为例,创建字符串和int集:

> HMSET test:7 "Hello" "World" "Hi" "Universe"
> HMSET test:8 "74111114" "221417113" "78" "2013821417184"
结果如下:

> debug object test:7
> Value at:0x7d12d600 refcount:1 encoding:ziplist serializedlength:40 lru:9567096 lru_seconds_idle:296
>
> debug object test:8
> Value at:0x7c17d240 refcount:1 encoding:ziplist serializedlength:37 lru:9567531 lru_seconds_idle:2
如您所见,我们将int设置为小于3字节

这其中的问题是如何组织这样的事情,但它表明这是可能的

不过,我不知道这个限制是在哪里设定的。700K内存的持续使用(即使内存中没有数据)让我觉得有一个预定义的“池”专门用于优化int集

更新2

我想我已经找到了在Redis source中定义这个intset“pool”的地方

在文件redis.h的第81行,有defredis_SHARED_整数设置为10000

我怀疑是它定义了整数集字节长度的限制

我必须尝试用一个更高的值重新编译它,看看是否可以使用更长的int值(如果是我想到的,它很可能会分配更多内存)

更新3

我要感谢安特里兹的回复!没想到

他让我注意到了,len!=内存使用

我在实验中更进一步,看到对象已经被稍微压缩(序列化)。我可能遗漏了Redis文档中的某些内容

确认来自使用Redis memory for keykey命令分析Redis键,该命令实际返回内存使用情况,而不是序列化长度

例如,让我们以前面使用的“hello”字符串和int为例,看看结果是什么:

~ # redis-memory-for-key test:1
Key             "test:1"
Bytes               101
Type            string
~ #
~ # redis-memory-for-key test:2
Key             "test:2"
Bytes           87
Type            string
正如您所注意到的,无论如何,整数集比字符串(101字节)小(87字节)

更新4

令人惊讶的是,较长的intset似乎会影响其serializedlength,但不会影响内存使用

这使得实际构建2digit char映射成为可能,同时它仍然比字符串更具内存效率,甚至不需要对其进行分块

通过2digit char映射,我的意思是,我们没有将“hello”映射到“85121215”,而是将其映射到每个固定长度为2的数字,如果数字<10,则在其前面加上“0”,如“0805121215”

然后,自定义脚本将每两个数字分开,并将其转换为等效字符:

08 05 12 12 15
\  |  |   |  /
 h e  l   l o
这足以避免歧义消除(如“o”和“ae”,它们都会导致数字“15”)

我将通过创建另一个集合并因此像以前一样分析其内存使用情况来向您展示这一点:

> SET test:9 "0805070715"

Unix shell
----------
~ # redis-memory-for-key test:9
Key             "test:9"
Bytes           87
Type            string
你可以看到我们在这里赢得了记忆

使用Smaz压缩的相同“hello”字符串用于比较:

>>> smaz.compress('hello')
'\x10\x98\x06'

// test:10 would be unfair as it results in a byte longer object
SET post:1 "\x10\x98\x06"

~ # redis-memory-for-key post:1
Key            "post:1"
Bytes          99
Type           string
我的问题是,当你代表一个 字符串作为int,在达到7个字节之前它会变小吗

请注意,作为test#6提供的整数实际上不再编码 作为整数,但作为原始值:

设置测试:6“85771502315”

0xb6c9f470参考计数处的值:1编码:原始序列化长度:12 lru:9535913 lru_秒_空闲:

所以我们看到一个“原始”值占用一个字节加上它的字符串表示的长度。记忆中 你可以得到这个加上价值的开销

我怀疑整数编码将数字编码为32位整数;那么它将永远 需要五个字节,一个用来告诉它的类型,四个用来存储32位

一旦您在32位中溢出了最大可表示整数,即20亿或4,这取决于您是否使用符号,您需要恢复到原始编码

所以可能

2147483647 -> five bytes     (TYPE_INT 0x7F 0xFF 0xFF 0xFF)
2147483649 -> eleven bytes   (TYPE_RAW '2'  '1'  '4'  '7'  '4'  '8'  '3'  '6'  '4'  '9')
现在,如果只使用ASCII集,如何压缩字符串表示

您可以获取字符串(140个字符):

并将每个字符转换为六位表示;基本上它的索引在字符串中

"ABCDEFGHIJKLMNOPQRSTUVWXYZ01234 abcdefghijklmnopqrstuvwxyz56789."
这是您可以使用的所有字符的集合

您现在可以在三个“二进制字符”中编码四个这样的“纯文本字符”,这是一种“反向基64编码”;base64编码wil
2147483647 -> five bytes     (TYPE_INT 0x7F 0xFF 0xFF 0xFF)
2147483649 -> eleven bytes   (TYPE_RAW '2'  '1'  '4'  '7'  '4'  '8'  '3'  '6'  '4'  '9')
When in the Course of human events it becomes necessary for one people
to dissolve the political bands which have connected them with another
"ABCDEFGHIJKLMNOPQRSTUVWXYZ01234 abcdefghijklmnopqrstuvwxyz56789."