Redis High Availability and High Performance Cache のアプリケーション シリーズ 1 - データ型と基礎となる構造と原則

概要

redisキャッシュの原理と設計実行プロセスを紹介し、シングルスレッド処理方法が高効率の理由であり、redisのデータ型、基礎となる構造と原理を説明します。これはRedisを使用するのに非常に役立ちます.

低レベルの実行中の実装モデル

redis_01.png

クライアントのリクエストは、最初に Linux でカーネルを実行することによって実行され、リクエストを処理するために redis とカーネルの間で epoll ノンブロッキング I/O 多重化メソッドが使用されます. リクエストの I/O 操作は保留中に保存されます.順番に epoll のキュー. その中で, Redis はメモリ操作であり, メモリ操作の速度は I/O 操作の速度よりもはるかに高速です. Redis は効率的なシングルスレッド処理方法です. Redis は順次処理します.リクエストの epoll の保留キューに 1 つずつ。

いわゆる Redis シングル スレッドは、コンピューティングに使用されるワーカー スレッドであり、redis には、永続性や非同期削除などの他のスレッドもあります。

Redisの基本構造

Redis コア構造が redisServer と redisObject で構成されている限り、Redis を初期化するときは、最初に RedisServer 構造を初期化し、dict を介して dictEntry をマップし、特定の型と値を redisObject に格納して一元管理する必要があります。わかりません、redisの設計を見て、本を実現することができます。

redis_02.png

returnServer

1. 以下は、ファイル server.h 内の redisServer の構造の初期化です。

struct redisServer {
    /* General */
    pid_t pid;                  /* Main process pid. */
    pthread_t main_thread_id;         /* Main thread id */
    char *configfile;    /* Absolute config file path, or NULL */
    
    //...
    redisDb *db;
    dict *commands;             /* Command table */
    dict *orig_commands;        /* Command table before command renaming. */
    aeEventLoop *el;
    // ...
}

redisDb *db : データベース情報を保存し、デフォルトの 16 データベースを初期化し、パラメーター `` を介して変更できます。dict は redisDb のコア構造であり、すべてのキーと値のペアはキーと呼ばれる dict に格納されます空。

dict の理解は非常に重要です. Redis オブジェクトは大きな dict 構造オブジェクトに相当します. すべての型構造は dict に基づいて実装されています.

typedef struct redisDb {
    dict *dict;                
    dict *expires;              
    dict *blocking_keys;       
    dict *blocking_keys_unblock_on_nokey;  
    dict *ready_keys;           
    dict *watched_keys; 
    // ...
} redisDb;

次に、dict 構造を見てみましょう.これはプログレッシブ ハッシュ用に 2 つの辞書を作成し、データ グループには特定の dictEntry が格納されます。

struct dict {
    dictType *type;
    dictEntry **ht_table[2];
    unsigned long ht_used[2];
    long rehashidx; 
    int16_t pauserehash; 
    signed char ht_size_exp[2];
    void *metadata[];           
};

struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;    
    void *metadata[];
};

dictEntry *次に、ハッシュ値が同じ場合、リンクされたリストが形成され、次の dictEntry を指します。dictEntry 構造では、key は実際のキー値を格納し、val は redisObject 構造を指します。

redisObject

以下は、redisObject 型と構造体の主な機能の詳細な紹介です。

  • type: 外部データ型、文字列、ハッシュ、リスト、セット、zset、type コマンドで表示される型。
  • エンコーディング: 内部に実際に保存されているデータの種類。特定の選択は、構成ファイルの対応するパラメーターによって実現されます。たとえば、リストは保存された値に応じて ziplist と quicklist に分割されます。
  • lru: キャッシュ削除メカニズムの管理
  • refcount: 主にメモリのリサイクルに使用される参照カウント
  • ptr: 実データを格納する物理ポインタアドレス
struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; 
    int refcount;
    void *ptr;
};

Redis データ構造

Redis の基本的な実装は C 言語の文字列を実装していませんが、動的文字列 Sds のレイヤーをカプセル化するだけであり、Sds は内部で int、embstr、および raw に変換できます。

127.0.0.1:6379> set number 100
OK
127.0.0.1:6379> object encoding number
"int"

127.0.0.1:6379> set name stark张宇
OK
127.0.0.1:6379> object encoding name
"embstr"

127.0.0.1:6379> set logstr “stark张宇关于Redisraw类型编码的演示,他需要超过44字节”
OK
127.0.0.1:6379> object encoding logstr
"raw"

Sds の内部変換は、格納する値のバイトサイズに依存し、値が int の場合は int としてそのまま格納され、44 バイト以下の場合は embstr 型として格納され、44 バイト以下の場合は embstr 型として格納されます。 44 バイトを超える場合は、raw タイプとして格納されます。

embstr と raw ストレージの違い: embstr は 1 回の読み取りが可能な連続メモリに格納されますが、raw は 2 回の読み取りが必要な不連続メモリを格納します。

Redis が文字列を格納するために Sds 構造を設計するのはなぜですか?

1. 効率性: 文字列長 len は変数でよく使われます. C 言語の文字長を使用すると, 文字列全体をトラバースする必要があります. その時間複雑度は O(n). Sds の len は時間複雑度です. O(1)、同時実行性の高いシナリオでは、文字列を頻繁に走査するとパフォーマンスのボトルネックが発生します。

2. データのオーバーフローを防ぐ: C 言語の文字列はそれ自体の長さを記録しないため、バイナリを Sds に保存すると安全です。これは、値が変更されたときにストレージ スペースを変更するのに便利です。

3. メモリ空間の事前割り当て: 文字列メモリ空間を変更する場合、文字列ストレージ空間が変更されるだけでなく、追加の領域も予約され、次の変更が行われるときに未使用のメモリ領域が最初にチェックされます。

4. レイジー スペース リリース: 変更された文字列メモリ スペースが小さくなると、それ以上の変更を防ぐためにメモリ スペースがすぐに再利用されることはありません。

メモリ空間の割り当て規則: 値が 1M 未満の場合は同じ領域が割り当てられ、1M を超える場合は 1M の領域が割り当てられます。

ハッシュ

Redis の Hash の最下層は dict で、データ量が比較的少ない場合やデータ値が比較的小さい場合は ziplist を使用し、データが大きい場合は hashtable の構造を使用してデータを格納します。

127.0.0.1:6379> hgetall user1
1) "name"
2) "stark"
3) "age"
4) "33"
5) "sex"
6) "1"
127.0.0.1:6379> object encoding user1
"ziplist"

127.0.0.1:6379> hset user1 mark "stark张宇关于HashTable类型编码的演示,值很大他就变成了HashTable"
(integer) 1
127.0.0.1:6379> object encoding user1
"hashtable"

ジップリスト

ziplist 構造のコンポーネントの詳細な説明:

  • zlbytes: 32 ビットの符号なし整数。zlbytes が占める 4 バイトを含む、ziplist 全体が占めるスペースを示します。このフィールドは、サイズ、時間のスペースを決定するためにリスト全体をトラバースすることなく、ziplist 全体のサイズをリセットできます。
  • zltail: 32 ビットの符号なし整数。リスト全体の最後の項目のオフセットを示します。これは、最後の pop 操作に便利です。
  • zllen: ziplist に格納されているエントリの数を示す 16 ビット。
  • エントリ: 可変長。複数ある場合があります。
  • zlend: ziplist の最後に示される 8 ビットで、固定値は 255 です。

エントリは、前のエントリのサイズ、現在のエンコーディング タイプと長さ、実際の文字列と数値の 3 つの部分で構成されます。

ziplistのメリットとデメリット メリット:
連続メモリ空間なので利用率が高く、アクセス効率が高い。
短所:更新効率が低い 要素の挿入や削除を行うと、頻繁にメモリの増減が発生し、データの移動効率が悪い。

リスト

Redis のリストの順序付きデータ構造は、下部で ziplist と quicklist に分かれています。

Ziplist は Hash 型で既に言及されているので、ここでは冗長な説明はしません。

クイックリスト構造の長所と短所:

利点: 二重連結リストであるため、更新効率が比較的高く、操作の挿入と削除に非常に便利です. 複雑さはO(n)で、前後の要素の複雑さはO(1)です. .
短所: メモリ オーバーヘッドが増加します。

設定

The Set in Redis is an unordered, automatically deduplicated data type. その下にあるレイヤーは dict です. データが整数を使用し、データ要素が構成ファイルのデータより小さい場合、それ以外の場合は dict が使用されますset-max-intest-entries.

127.0.0.1:6379> sadd gather 100 200 300
(integer) 3
127.0.0.1:6379> object encoding gather
"intset"
127.0.0.1:6379> sadd gather stark
(integer) 1
127.0.0.1:6379> object encoding gather
"hashtable"

設定

Redis の Zset は、順序付けられ、自動的に重複排除されるデータ型です. 最下層は辞書 Dict とスキップ テーブル Skiplist によって実装されます. データが少ない場合は、Ziplist 構造を使用してデータを格納します.

Ziplist は、構成ファイルでzset-max-ziplist-entries構成できますzset-max-ziplist-value

よくある質問: Redis の Zset が赤黒木と二分木を使用せず、ジャンプ テーブルを選択するのはなぜですか?

1) 赤黒木や二分木の範囲探索は苦手 順序集合が大きいシーンは範囲探索 連結リスト、赤黒木なのでジャンプテーブルでの範囲探索は非常に便利二分木. 範囲検索は比較的複雑です. 2) ジャンプ テーブルの実装は、赤黒ツリーの実装よりもはるかに簡単です。

おすすめ

転載: blog.csdn.net/xuezhiwu001/article/details/130090223