基盤となるデータ構造とアプリケーションの原則から始めて、Redisを使い始める

目次

1つは、Redisを知っている

2つ、Redis5のビッグデータタイプ

3つ目は、データ構造分析の基礎となるRedisSDSです。

4つのリンクリストデータ構造分析

5、リストデータ構造

1.圧縮リスト

2.クイックリスト

6、Redis辞書

セブン、Redis整数コレクション

8、Redisジャンプテーブル

9、Redisオブジェクト

10、Redisの使用シナリオ


1つは、Redisを知っている

最近、Redisデータベースを学び、最も単純なコンテンツから学び、忘れてしまった場合に備えて、ここに要約して記録し、みんなと共有するようになりました。

Windowsのインストールを図に示します。

ダウンロードリンク:

Windows:https//github.com/microsoftarchive/redis/releases/download/win-3.2.100/Redis-x64-3.2.100.zip

Linux:http//download.redis.io/releases/redis-6.0.6.tar.gz

サーバ側:

クライアント側:

高性能のオープンソースNoSQLデータベースとして、Redisは主にC言語で開発されたキーと値のペアの形式でデータを格納し、BSDプロトコルを採用しています。強力な機能を備え、複数のデータ型をサポートしています。 -リレーショナルデータベース。

これは、Mysql、SQLServer、Oracleなどのリレーショナルデータベースとは異なります。したがって、Redisの特性には多くの利点があります。

  1. Java、C、C ++、Python、PHP、Go、Luaなどの複数のプログラミング言語をサポートします。
  2. 文字列、リスト、セット、ハッシュ、ソートされたセットなどの豊富なデータ型を含みます。
  3. 高速な読み取りと書き込みの速度と高性能。公式データ:読み取り速度110000回/秒、書き込み速度81000回/秒。これは、データが読み取りと書き込みのためにメモリに保存されることを意味します。
  4. 永続性。Redisの重要な機能は、永続性を実現し、メモリ内のデータを定期的にディスクに保存し、サーバーの再起動時にデータをメモリに再度ロードすることです。永続性にはAOFとRDBがあります。
  5. シンプルでパワフル。ニュース購読の発行、Luaスクリプト、データベーストランザクションなどを実現できます。Redisはシングルスレッドの作業であり、すべての操作はアトミックで使いやすいです。
  6. 高可用性マスタースレーブレプリケーションを実現します。
  7. 分散クラスターと高可用性、それぞれRedisClusterとRedisSentinelを実現します。
  8. 複数のデータ構造をサポートします。そのようなハッシュ、セット、ビットマップなど。

以下では、Redisの5つのデータ型を簡単に紹介します。

2つ、Redis5のビッグデータタイプ

Redis 5ビッグデータタイプの特定の操作コマンドは、http//www.redis.cn/commands.htmlにあります。

1.ストリング

文字列はRedisの最も基本的なデータ型であり、バイナリセーフです。文字列型キーは、最大512Mのデータを格納できます。

サポートされるデータには、バイナリデータ、シリアル化されたデータ、JSON化されたオブジェクトなどが含まれます。

2.ハッシュ

ハッシュ型は、文字列型のフィールドと値のマッピングテーブルであり、オブジェクト情報を格納するために一般的に使用されます。各ハッシュテーブルには、2 ^ 32-1のキーと値のペアを格納できます。これは、40億個のデータに相当します。

3.リスト

Redisリストは、挿入順にソートされた単純な文字列リストと同等であり、要素をテーブルの先頭または末尾に挿入できます。同じことが2 ^ 32-1要素を格納できます。

4.セット

Setデータ型は、文字列型の順序付けられていないコレクションであり、各要素は一意です。コレクションは、追加、削除、およびO(1)の複雑さの効率が高いハッシュテーブルによって実現されます。コレクションの最大容量は、2 ^ 32-1要素を格納することです。

5.ソート済みソート

順序付きコレクションは、文字列型のコレクションであり、各要素はdouble型の値に対応します。Redisは、この値のサイズに従って要素を並べ替えます。この値は、ハッシュテーブルを介して実装され、追加、削除、およびO(1)の複雑さの効率が高くなっています。コレクションの最大容量は、2 ^ 32-1要素を格納することです。

3つ目は、データ構造分析の基礎となるRedisSDSです。

RedisはC言語で記述されており、基盤となる実装にはC言語の文法と特性があります。Cの文字列型は直接使用されませんが、SDS(単純な動的文字列)型はRedisのデフォルトの文字列として単独で作成されます。

ソースコードの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[];
};

基礎となるコードから、さまざまなニーズに適応するためにさまざまな構造が定義されていることがわかります。

C文字列とSDSの違い:

  1. Cの文字列APIはバイナリで安全ではありません。バッファオーバーフローが発生する可能性があります。保存できるのはテキストデータのみです。string.hのすべてのライブラリ関数を使用できます。長さを変更すると、メモリが1回割り当てられます。取得の時間の複雑さ文字列の長さはO(n)です。
  2. SDS APIはバイナリセーフであり、バッファオーバーフローはありません。テキスト/バイナリデータを保存し、string.hのいくつかのライブラリ関数を使用し、N回の長さを変更し、メモリ時間を<= Nに割り当て、長さをO(1 )。

4つのリンクリストデータ構造分析

/* Node, List, and Iterator are the only data structures used currently. */

typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

typedef struct listIter {
    listNode *next;
    int direction;
} listIter;

typedef struct list {
    listNode *head;
    listNode *tail;
    void *(*dup)(void *ptr);
    void (*free)(void *ptr);
    int (*match)(void *ptr, void *key);
    PORT_ULONG len;
} list;

 C言語には組み込みのリンクリスト構造はありません。Redisはそれ自体でリンクリストを作成します。二重リンクリストを使用します。これは、ポインターで接続された複数の個別に分散されたノードで構成されます。各ノードには、先行ノードと後続ノードがあります。 、ヘッドノード(先行ノードなし)とテールノード(後続ノードなし)を除く。

5、リストデータ構造

1.圧縮リスト


#ifndef _ZIPLIST_H
#define _ZIPLIST_H

#define ZIPLIST_HEAD 0
#define ZIPLIST_TAIL 1

unsigned char *ziplistNew(void);
unsigned char *ziplistMerge(unsigned char **first, unsigned char **second);
unsigned char *ziplistPush(unsigned char *zl, unsigned char *s, unsigned int slen, int where);
unsigned char *ziplistIndex(unsigned char *zl, int index);
unsigned char *ziplistNext(unsigned char *zl, unsigned char *p);
unsigned char *ziplistPrev(unsigned char *zl, unsigned char *p);
unsigned int ziplistGet(unsigned char *p, unsigned char **sval, unsigned int *slen, PORT_LONGLONG *lval);
unsigned char *ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen);
unsigned char *ziplistDelete(unsigned char *zl, unsigned char **p);
unsigned char *ziplistDeleteRange(unsigned char *zl, int index, unsigned int num);
unsigned int ziplistCompare(unsigned char *p, unsigned char *s, unsigned int slen);
unsigned char *ziplistFind(unsigned char *p, unsigned char *vstr, unsigned int vlen, unsigned int skip);
unsigned int ziplistLen(unsigned char *zl);
size_t ziplistBlobLen(unsigned char *zl);

#ifdef REDIS_TEST
int ziplistTest(int argc, char *argv[]);
#endif

#endif /* _ZIPLIST_H */

 Redis圧縮リストは、リストキーとハッシュキーの最下層によって実装されます。

リストに含まれる要素が少なく、値が小さい場合、Redisは圧縮リストを使用してそれを実装します。これはシーケンシャルデータ構造です。

2.クイックリスト

クイックリストは、圧縮リストで構成される二重リンクリストであり、リンクリストの各ノードはデータを圧縮リストに保存します。

リストは次のように定義されています。

typedef struct quicklist {
    quicklistNode *head;
    quicklistNode *tail;
    PORT_ULONG count;        /* total count of all entries in all ziplists */
    unsigned int len;           /* number of quicklistNodes */
    int fill : 16;              /* fill factor for individual nodes */
    unsigned int compress : 16; /* depth of end nodes not to compress;0=off */
} quicklist;

クイックリストノード:

typedef struct quicklistNode {
    struct quicklistNode *prev;
    struct quicklistNode *next;
    unsigned char *zl;
    unsigned int sz;             /* ziplist size in bytes */
    unsigned int count : 16;     /* count of items in ziplist */
    unsigned int encoding : 2;   /* RAW==1 or LZF==2 */
    unsigned int container : 2;  /* NONE==1 or ZIPLIST==2 */
    unsigned int recompress : 1; /* was this node previous compressed? */
    unsigned int attempted_compress : 1; /* node can't compress; too small */
    unsigned int extra : 10; /* more bits to steal for future usage */
} quicklistNode;

 

6、Redis辞書

Redisディクショナリは、Redisのキーと値のペアを格納するために使用されるデータ構造であり、Redis自体によって構築されます。Redisデータベースの最下層もディクショナリによって実装され、CURD操作はディクショナリ上に構築されます。


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

typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

/* This is our hash table structure. Every dictionary has two of this as we
 * implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
    dictEntry **table;
    PORT_ULONG size;
    PORT_ULONG sizemask;
    PORT_ULONG used;
} dictht;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    PORT_LONG rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int iterators; /* number of iterators currently running */
} dict;

 

セブン、Redis整数コレクション

コレクションに整数値の要素のみが含まれ、要素の数が少ない場合、Redisはこのデータ構造を使用してコレクションキーの最下層を実装します。


#ifndef __INTSET_H
#define __INTSET_H
#include <stdint.h>

typedef struct intset {
    uint32_t encoding;
    uint32_t length;
    int8_t contents[];
} intset;

intset *intsetNew(void);
intset *intsetAdd(intset *is, int64_t value, uint8_t *success);
intset *intsetRemove(intset *is, int64_t value, int *success);
uint8_t intsetFind(intset *is, int64_t value);
int64_t intsetRandom(intset *is);
uint8_t intsetGet(intset *is, uint32_t pos, int64_t *value);
uint32_t intsetLen(intset *is);
size_t intsetBlobLen(intset *is);

#ifdef REDIS_TEST
int intsetTest(int argc, char *argv[]);
#endif

#endif // __INTSET_H

8、Redisジャンプテーブル

ジャンプテーブルは、ノードの高速ノード検索とバッチ処理をサポートする順序付けられたデータ構造です。順序セットに多くの要素があり、要素値が長い文字列である場合、Redisは順序セットの基礎となる実装としてジャンプテーブルを使用します。

9、Redisオブジェクト

上記のRedisのデータ構造は実際には直接使用されませんが、文字列オブジェクト、リストオブジェクトなどを含むオブジェクトシステムが作成されます。Red is objectシステムは、参照カウント技術に基づくメモリリサイクルメカニズムを実装しています。オブジェクトが使用されていない場合、システムはオブジェクトが占有しているメモリスペースを自動的に再利用します。

robj *dupStringObject(robj *o) {
    robj *d;

    serverAssert(o->type == OBJ_STRING);

    switch(o->encoding) {
    case OBJ_ENCODING_RAW:
        return createRawStringObject(o->ptr,sdslen(o->ptr));
    case OBJ_ENCODING_EMBSTR:
        return createEmbeddedStringObject(o->ptr,sdslen(o->ptr));
    case OBJ_ENCODING_INT:
        d = createObject(OBJ_STRING, NULL);
        d->encoding = OBJ_ENCODING_INT;
        d->ptr = o->ptr;
        return d;
    default:
        serverPanic("Wrong encoding.");
        break;
    }
}

robj *createQuicklistObject(void) {
    quicklist *l = quicklistCreate();
    robj *o = createObject(OBJ_LIST,l);
    o->encoding = OBJ_ENCODING_QUICKLIST;
    return o;
}

robj *createZiplistObject(void) {
    unsigned char *zl = ziplistNew();
    robj *o = createObject(OBJ_LIST,zl);
    o->encoding = OBJ_ENCODING_ZIPLIST;
    return o;
}

robj *createSetObject(void) {
    dict *d = dictCreate(&setDictType,NULL);
    robj *o = createObject(OBJ_SET,d);
    o->encoding = OBJ_ENCODING_HT;
    return o;
}

robj *createIntsetObject(void) {
    intset *is = intsetNew();
    robj *o = createObject(OBJ_SET,is);
    o->encoding = OBJ_ENCODING_INTSET;
    return o;
}

robj *createHashObject(void) {
    unsigned char *zl = ziplistNew();
    robj *o = createObject(OBJ_HASH, zl);
    o->encoding = OBJ_ENCODING_ZIPLIST;
    return o;
}

robj *createZsetObject(void) {
    zset *zs = zmalloc(sizeof(*zs));
    robj *o;

    zs->dict = dictCreate(&zsetDictType,NULL);
    zs->zsl = zslCreate();
    o = createObject(OBJ_ZSET,zs);
    o->encoding = OBJ_ENCODING_SKIPLIST;
    return o;
}

robj *createZsetZiplistObject(void) {
    unsigned char *zl = ziplistNew();
    robj *o = createObject(OBJ_ZSET,zl);
    o->encoding = OBJ_ENCODING_ZIPLIST;
    return o;
}

10、Redisの使用シナリオ

非常に多くのRedisの理論的知識ポイントについて話し合った後、どのように利点を確認できますか?

実際のアプリケーションでは、すべての主要なWebサイトとシステムでRedisを導入でき、リレーショナルデータベースでは解決できない問題を解決するために広く使用されています。

Redisの使用シナリオ:

  1. キャッシュを実行します。Redisの最も一般的な使用シナリオ。毎回データを再生成する必要はなく、キャッシュ速度とクエリ速度は高速です。ニュースコンテンツ、製品情報、ショッピングカートなどをキャッシュします。
  2. カウンターをしなさい。Redis操作はアトミックです。再投稿とコメントの数を記録するために使用できます。
  3. メッセージキューシステムを実現します。ニュースの購読と発行を実現できるパターンマッチングをサポートします。キューコマンドをブロックすると、スパイクやパニック買いなどのアクティビティを実現できます。
  4. リアルタイムシステム、メッセージシステム。Redisセット機能を使用して、ユーザーの特定の操作を表示し、リアルタイムシステムを実現できます。
  5. 十億レベルのランキング。これはRedisの重要なアプリケーションでもあり、Redisの読み取りと書き込みの速度のおかげで、順序付けられたコレクションを使用して数億人のユーザーをリアルタイムでランク付けします。
  6. 大規模なソーシャルネットワーク。QQ、Weiboなど、ユーザーはブラウジングとチャットのためにRedisサポートを必要とします。

この記事は、XiaobaiがRedisデータベースを学習し、最も単純なコンテンツからレコードを学習し、それをすべての人と共有するための最近の紹介です。高性能のオープンソースNoSQLデータベースであるRedisは、Mysql、SQLServer、Oracleなどのリレーショナルデータベースとは異なります。したがって、Redisの特性には多くの利点があります。永続性AOF、RDB、Redisクラスターなどの特定の実装原則など、ここに記録されていない重要な場所がたくさんあります。後で学習した後、自由に記録できます。

良いと思う場合は、ブックマーク、フォロー、質問がある場合は直接コメント、交換して学ぶなど、「ワンクリック、3リンク」へようこそ。 


私のCSDNブログ:https://blog.csdn.net/Charzous/article/details/114546348

おすすめ

転載: blog.csdn.net/Charzous/article/details/114546348