Redis(1、文字列)の5つのデータ型の内部コーディングの分析

画像



概要概要


通常、Redisはユーザーレベルで使用しますが、データに簡単にアクセスするために、キーと値のペアを考えずに操作する場合があります。非常に便利です。しかし、これらのデータが舞台裏でどのように保存およびエンコードされているか知っていますか?この問題を明確に理解することは、Redisをより効率的に使用するための指針となる重要性を持っています。この記事の冒頭で、Redisのソースコードを組み合わせて、Redisの5つのデータ型の内部コーディングメカニズムについて1つずつ説明します。

  • 実験環境:Redis 4.0.10

注: この記事は、My public account CodeSheep最初に公開されました。以下の注意を長押しするスキャンしてサブスクライブできます↓↓↓        

画像




Redisデータ型の内部コーディングの概要


Redisの5つの一般的に使用される  データ型(String、Hash、List、Set、sorted set)の場合、各データ型は少なくとも2つの 内部エンコード形式を提供し、各データ型の 内部エンコードの選択 は完全にユーザー向けです。Transparent、Redisデータ量に応じて、より最適化された内部エンコーディング形式を適応的に選択します。

キーの内部エンコード形式を表示する場合は、次のようなコマンドを使用できます OBJECT ENCODING keyname

127.0.0.1:6379>  
127.0.0.1:6379> set foo bar 
OK 
127.0.0.1:6379>  
127.0.0.1:6379> object encoding foo // Redisキー値
"embstr"のエンコーディングを表示
127.0.0.1:6379>  
127.0.0.1:6379>

Redis の各キー値は、 このC言語構造と呼ばれる名前で内部的に redisObject保存され、コードは次のとおりです。

画像

説明は次のとおりです。

  • type:String、List、Set、ZSet、Hashなどのキー値のデータ型を表します

  • encoding:キー値の内部エンコード方法を表します。Redisソースコードから、現在の値は次のとおりです。

#define OBJ_ENCODING_RAW 0 / *生の表現* / 
#define OBJ_ENCODING_INT 1 / *整数としてエンコード* / 
#define OBJ_ENCODING_HT 2 / *ハッシュテーブルとしてエンコード* / 
#define OBJ_ENCODING_ZIPMAP 3 / * zipmapとしてエンコード* / 
#define OB使用されなくなった:古いリストエンコーディング。* /
の#define OBJ_ENCODING_ZIPLIST 5 / *エンコードziplist * /など
の#define OBJ_ENCODING_INTSET 6 / *エンコードINTSETなど* /
の#define OBJ_ENCODING_SKIPLIST 7 / *エンコードskiplistなど* / 
* /コードの#define OBJ_ENCODING_EMBSTR 8 / * SDS埋め込み文字列
の#define OBJ_ENCODING_QUICKLISTを9 / * ziplistのリンクリストとしてエンコードされます* /
  • refcount:キー値への参照数を示します。つまり、キー値は複数のキーで参照できます。

この記事では、Redisの最も基本的な文字列型の内部コーディングから始めます!




文字列型の内部エンコーディング


字符串是 Redis最基本的数据类型,Redis 中字符串对象的编码可以是 int, raw 或者 embstr 中的某一种,分别介绍如下:

  • int 编码:保存long 型的64位有符号整数

  • embstr 编码:保存长度小于44字节的字符串

  • raw 编码:保存长度大于44字节的字符串

我们不妨来做个实验实际看一下:

画像

实际情况就是 Redis 内部会根据用户给的不同键值而使用不同的编码格式,而这一切对用户完全透明!

Redis 是使用 SDS(“简单动态字符串”)这个结构体来存储字符串,代码里定义了 5种 SDS结构体:

struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* used */
    uint8_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* used */
    uint16_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* used */
    uint32_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* used */
    uint64_t alloc; /* excluding the header and null terminator */
    unsigned char flags; /* 3 lsb of type, 5 unused bits */
    char buf[];
};

可以看出,除了结构体字段数据类型的不同,其字段含义相差无几,其中:

  • len:字符串的长度(实际使用的长度)

  • alloc:分配内存的大小

  • flags:标志位,低三位表示类型,其余五位未使用

  • buf:字符数组

了解了这些基本的数据结构以后,我们就来看看上面例子中:

  • set foo 123

  • set foo abc

  • set foo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx

这三种情形下 Redis 内部到底是怎么存数据的!




INT 编码格式


命令示例: setfoo123

当字符串键值的内容可以用一个 64位有符号整形 来表示时,Redis会将键值转化为 long型来进行存储,此时即对应 OBJ_ENCODING_INT 编码类型。

OBJ_ENCODING_INT 编码类型内部的内存结构可以形象地表示如下:

画像

而且 Redis 启动时会预先建立 10000 个分别存储 0~9999 的 redisObject 变量作为共享对象,这就意味着如果 set字符串的键值在 0~10000 之间的话,则可以 直接指向共享对象 而不需要再建立新对象,此时键值不占空间!

因此,当执行如下指令时:

set key1 100set key2 100

其实 key1 和 key2 这两个键值都直接引用了一个 Redis 预先已建立好的共享 redisObject 对象,就像下面这样:

画像

源码之前,了无秘密,我们再对照下面的源码,来理解一下上述过程

image.png




EMBSTR 编码格式


命令示例: setfoo abc

Redis 在保存长度小于 44 字节的字符串时会采用 OBJ_ENCODING_EMBSTR编码方式,口说无凭,我们来瞅瞅源码:

image.png

从上述代码中很容易看出,对于长度小于 44的字符串,Redis 对键值采用 OBJ_ENCODING_EMBSTR 方式,EMBSTR 顾名思义即:embedded string,表示嵌入式的String。从内存结构上来讲 即字符串 sds结构体与其对应的 redisObject 对象分配在 同一块连续的内存空间,这就仿佛字符串 sds 嵌入在 redisObject 对象之中一样,这一切从下面的代码即可清楚地看到:

画像

因此,对于指令 setfoo abc 所设置的键值,其内存结构示意图如下:

画像




RAW 编码格式


指令示例: setfoo abcdefghijklmnopqrstuvwxyzabcdeffasdffsdaadsx

キー値ときだけ命令の例のように、文字列が ある非常に長い文字列より長大きく 44、Redisのは、鍵の内部エンコーディング変化する OBJ_ENCODING_RAW フォーマット。 相違点上記 OBJ_ENCODING_EMBSTR符号化は、動的な文字があるということですこの時点で、文字列sdsのメモリとそれが依存するredisObjectのメモリは連続してい ません 。上記のコマンドを例にとると、そのキー値のメモリ構造は次のとおりです。

画像

これで、最も基本的な文字列データ型の内部コーディングは終わりです。それでも、非常に簡単に理解できます。

後で、Redisのハッシュデータ型の内部エンコード形式の分析を続けます。




追記


能力が限られているため、間違いや不正があった場合は、批判して訂正し、一緒に学び、コミュニケーションしてください!

  • 私の個人ブログ:www.codesheep.cn


興味がある場合は、コンテナ化とマイクロサービスに関する著者の記事を読むこともできます。



公開番号CodeSheepを作成するための、より実用的で、読みやすく、再現可能な元の記事については、⬇️⬇️⬇️を購読してください。

画像


おすすめ

転載: blog.51cto.com/15127562/2663987