【问题标题】:Redis encoding of objects and the size impact对象的 Redis 编码和大小影响
【发布时间】:2018-08-30 17:20:04
【问题描述】:

当我将一些对象写入 redis 时,我可以获得不同的内存使用统计信息。我想了解这是怎么发生的。

简单示例:

127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> MEMORY usage a
(integer) 49
127.0.0.1:6379> set a "1"
OK
127.0.0.1:6379> MEMORY usage a
(integer) 49
127.0.0.1:6379> set a \x01 <<<< Message packed of number 1
OK
127.0.0.1:6379> MEMORY usage a
(integer) 55
127.0.0.1:6379> set a '\x01' <<<< Message pack of number 1 but added '' 
OK
127.0.0.1:6379> MEMORY usage a
(integer) 55
127.0.0.1:6379> set a "\x01" <<<<< Message pack of number 1 but added "" 
OK
127.0.0.1:6379> MEMORY usage a
(integer) 52

以及每次的编码(作为embstr):

127.0.0.1:6379> set a 1
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f9858217ba0 refcount:2147483647 encoding:int serializedlength:2 lru:11691925 lru_seconds_idle:222
127.0.0.1:6379> set a "1"
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f9858217ba0 refcount:2147483647 encoding:int serializedlength:2 lru:11692152 lru_seconds_idle:1
127.0.0.1:6379> set a \x01
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f98563a1398 refcount:1 encoding:embstr serializedlength:5 lru:11692162 lru_seconds_idle:0
127.0.0.1:6379> set a '\x01'
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f98563a13e0 refcount:1 encoding:embstr serializedlength:5 lru:11692168 lru_seconds_idle:1
127.0.0.1:6379> set a "\x01"
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f98563a1788 refcount:1 encoding:embstr serializedlength:2 lru:11692177 lru_seconds_idle:1

稍微复杂一点的值(带数字的字符串)

127.0.0.1:6379> set a "abc123"
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f985821b260 refcount:1 encoding:embstr serializedlength:7 lru:11692243 lru_seconds_idle:3
127.0.0.1:6379> MEMORY usage a
(integer) 57
127.0.0.1:6379> set a \xa6abc123
OK
127.0.0.1:6379> MEMORY usage a
(integer) 61
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f985821b320 refcount:1 encoding:embstr serializedlength:11 lru:11692273 lru_seconds_idle:9
127.0.0.1:6379> set a "\xa6abc123"
OK
127.0.0.1:6379> MEMORY usage a
(integer) 58
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f985821b260 refcount:1 encoding:embstr serializedlength:8 lru:11692291 lru_seconds_idle:11
127.0.0.1:6379>

还有一个大的 JSON 字符串(然后是消息打包),编码是“原始”

127.0.0.1:6379> set a '[{"id":1,"first_name":"Kyrstin","last_name":"Ifill","email":"kifill0@livejournal.com","count":93,"ip_address":"182.218.153.253"}]'
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f98582b96f0 refcount:1 encoding:raw serializedlength:128 lru:11692490 lru_seconds_idle:2
127.0.0.1:6379> MEMORY usage a
(integer) 182
127.0.0.1:6379> set a '\x91\x86\xa5count]\xaafirst_name\xa7Kyrstin\xa9last_name\xa5Ifill\xa5email\xb7kifill0@livejournal.com\xaaip_address\xaf182.218.153.253\xa2id\x01'
OK
127.0.0.1:6379> MEMORY usage a
(integer) 197
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f98582b9700 refcount:1 encoding:raw serializedlength:143 lru:11692517 lru_seconds_idle:6
127.0.0.1:6379> set a "\x91\x86\xa5count]\xaafirst_name\xa7Kyrstin\xa9last_name\xa5Ifill\xa5email\xb7kifill0@livejournal.com\xaaip_address\xaf182.218.153.253\xa2id\x01"
OK
127.0.0.1:6379> DEBUG OBJECT a
Value at:0x7f98582b96f0 refcount:1 encoding:raw serializedlength:107 lru:11692535 lru_seconds_idle:2
127.0.0.1:6379> MEMORY usage a
(integer) 158

【问题讨论】:

    标签: memory redis redis-cli redis-cache


    【解决方案1】:

    此答案基于 Redis 4.0,在 bit-64 机器上

    为了节省内存,Redis 以三种方式对值字符串进行编码:

    1. Int:如果值字符串可以转换为整数,例如-2^63~2^63,Redis 将值保存为整数。这是最有效的编码。
    2. 嵌入字符串:如果值字符串的大小小于或等于44 字节,Redis 将字符串保存在 Redis 对象本身的同一块中。这比Raw String 编码更节省内存。此外,它对缓存更友好。
    3. 原始字符串:否则,Redis 使用原始编码。

    在你的情况下:

    1. set a 1set a "1":该值是一个可以转换为1 的字符串。所以Redis使用Int编码,即encoding:int
    2. set a \x01set a '\x01':该值是一个带有4 字符的字符串(注意:由于该字符串用单引号括起来,因此不会被转义)。它不能转换为整数,并且它的大小小于44。所以Redis使用Embeded String编码,即encoding:embstr
    3. set a "\x01":由于字符串是用双引号括起来的,所以值被转义为二进制字符串,其长度,即1字节,小于44,不能转换为整数。所以Redis使用Embeded String编码,即encoding:embstr
    4. 设置大json字符串:值为大于44的字符串。所以 Redis 使用 Raw String 编码,即encoding:raw

    【讨论】:

    • 我认为在“3”中您的意思是它可以转换为整数,对吗?那么将字符串和二进制字符串混合在一起的情况呢?即“mylongkeykeyabc1234”的内存占用与“mylongkeykeyabc\xcd\x04\xd2”不同
    • 不,“\x01”不能转换为整数。它不同于“1”,它的 ASCII 码是“\x31”。所以set a "\x31"set a 1 是一样的。
    • 如果混合使用 ascii 字符串和二进制字符串,Redis 将使用 Embeded StringRaw String 编码,具体取决于字符串长度。在您的情况下,mylongkeykeyabc1234mylongkeykeyabc\xcd\x04\xd2 长一个字节,因为字符串转义。所以它们有不同的内存占用。
    猜你喜欢
    • 1970-01-01
    • 2012-05-20
    • 2013-02-08
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    • 2016-10-08
    • 2016-07-09
    • 2020-12-24
    相关资源
    最近更新 更多