Redisには8つの一般的なオブジェクトがあります。
- 文字列オブジェクト-文字列
- リストオブジェクトリスト
- ハッシュオブジェクト-ハッシュ
- コレクションオブジェクトセット
- 順序付けられたコレクションオブジェクト-zset
- ビットマップ
- ジオ
- ハイパーログログ
0、Redisオブジェクトの紹介
Redisのキー値はオブジェクトで表されます。新しいキー値を作成すると、キーオブジェクトと値オブジェクトの少なくとも2つのオブジェクトが毎回作成されます。
RedisのオブジェクトredisObjectは、次のように定義されています。
typedef struct redisObject {
unsigned type:4; // 对象类型, string、list、hash、set、zset
unsigned encoding:4; // 编码方式
unsigned lru:LRU_BITS;
int refcount; //引用次数
void *ptr; // 数据指针
} robj;
- タイプタイプ:使用
TYPE key
、それぞれ出力します:文字列、リスト、ハッシュ、セット、zset、5つのタイプのオブジェクトに対応します。 - エンコーディング:文字列(int、embstr、raw)、辞書(ハッシュテーブル)、両端リンクリスト(linkedlist)、圧縮リスト(ziplist)、整数セット(intset)、スキップリストおよび辞書(skiplist)。
1つ、文字列オブジェクト(攪拌)
文字列オブジェクトのエンコーディングは、int、raw、embstrの3種類です。
1. int:文字列オブジェクトが整数値を保存する場合、intエンコード方式が使用され、値はptr属性に保存されます(ptrポインターが占めるスペースが保存されます)。
2. Raw:文字列オブジェクトが文字列値を保存し、文字列が39バイトを超える場合、SDS単純動的文字列を使用して保存し、エンコード方法はrawです。
3. embstr:短い文字列(<= 39バイト)を保存するために使用されます。
rawエンコーディングとの違い:rawエンコーディングはメモリ割り当て関数を2回呼び出して、redisObjectとsdsを作成します。Embstrは、メモリ割り当て関数を1回呼び出すだけで、連続したスペースを割り当てることができます(メモリの断片化を減らす)。
一般的な操作コマンド:
set key value
get key
mset key1 value1 keys2 value2
mget key1 key2...
incrby key integer :将key的值 + integer值
dncrby key integer :将key的值 - integer值
次に、リストオブジェクト(リスト)
リストオブジェクトのエンコーディングは、ziplistまたはlinkedlistです。
リストオブジェクトが文字列要素を格納する場合、および:
- 文字列の長さ<64バイト
- 文字列の数<512
ziplistを使用する前に両方を満たす必要があります。そうでない場合は、linkedlistが使用されます。
1、ziplist(圧縮リスト)
RPUSH numbers 1 "three" 5
2.リンクリスト(両端リンクリスト)
リストオブジェクトの一般的なコマンド:
l - left r - right
lpush key value1 [value2]
rpush key value1 [value2]
第三に、ハッシュオブジェクト(ハッシュ)
ハッシュオブジェクトのエンコーディングは、ziplistまたはhashtableにすることができます。
ハッシュオブジェクトに格納されているキーと値のペアの長さが64バイト未満の場合、キーと値のペアの数が512未満の場合は、ziplistを使用します。それ以外の場合は、ハッシュテーブルが使用されます。
1IPジップリスト
圧縮リストを使用してハッシュオブジェクトを保存する場合は、最初にキーオブジェクトを保存してから、値オブジェクトを保存します。新しく追加された要素は、テーブルの最後に配置されます。
設定されたキーがプレーヤーの場合、設定された値のキーと値は、バスケットボール-ジェームズ、バスターボール-ジョーダン、フットボール-ベリーになります。
即:hsetplayer baskterball James
hsetプレーヤーバスターボールジョーダン
hset player football belly
=> hsetキーkv
2、ハッシュテーブル
キー値はすべて文字列オブジェクトで保存されます:
一般的に使用されるコマンド:
存储:hset book name "Java"
hset book price "100"
获取:hget book name ==> Java
hget book price ==> 100
第四に、コレクションオブジェクト(セット)
コレクションオブジェクトのエンコーディングでは、intsetとhashtableを使用します。
コレクションオブジェクトによって保存される要素がすべて整数値である場合&&要素の数が512を超えない場合は、intsetが使用され、それ以外の場合はハッシュテーブルが使用されます。
1. intset:整数を格納するときは、このエンコード方式を使用します。
2.ハッシュテーブル:保存には辞書キーのみを使用し、各キーは文字列オブジェクトであり、値はnullに設定されます。
一般的に使用されるコマンド:
sadd numbers 1 2 3
获取集合所有元素:smembers numbers
删除元素:srem numbers 2
获取集合个数:scard numbers
5つの順序付けられたオブジェクトのセット(zset)
順序集合エンコーディングは、ziplistとskiplistを使用します。
要素数<128 &&長さが64バイト未満の場合、スキップリストエンコーディングが使用されます。
1IPジップリスト
圧縮されたリストは、要素の値とスコアを一緒に保存します。圧縮リスト内の要素はスコアが小さいものから大きいものへと並べ替えられ、スコアが低い要素はテーブルの先頭近くに配置されます。
例:、zadd price 8.5 apple 7.2 banana 2 cherry
キーは価格で、値は[8.5-apple]、[7.2-banana]、[2-chery]です。
2、出荷リスト
zsetはまた、辞書+ジャンプテーブルを使用して、順序付きセットzsl + dictを実装します。
(1)zsl:ジャンプテーブルノードのobject属性が要素を保存し、scoreがスコアを保存します。範囲クエリは、ジャンプテーブルを介して順序セットに対して実行できます。これは、範囲検索に便利です。
(2)dict:オブジェクトとスコアの間のマッピングを保存します。目的:見つけやすい、O(1)を見つけます。
注:順序集合がスキップリストと辞書の両方を使用するのはなぜですか?
=> zslのみを使用する場合、メンバーを検索すると、時間計算量がO(1)からO(logn)に変わります。dictのみを使用する場合は、範囲検索を実行するときに、最初にすべての要素スコアの並べ替えをトラバースする必要があります。最適な時間計算量はO(nlogn)であり、ストレージには追加のスペース計算量O(k)が必要です。
特殊オブジェクトタイプ
- ビットマップ
- ジオ
- HyperLogLog
1.ビットマップ-スペースを節約し、2値のステータス統計、つまり、サインイン、サインインまたはサインインなしなどの0または1の統計に適しています。
ビットマップは実際のデータ型ではなく、文字列型で定義されたビット指向の操作のコレクションです。文字列型はバイナリセーフバイナリラージオブジェクトであり、最大長は512MBであるため、2 ^ 32の異なるビットを設定するのに適しています。
ビットマップ操作はビットを操作するために使用され、その利点はメモリスペースを節約することです。なぜメモリスペースを節約できるのですか?100万人のユーザーのログインステータスを保存する必要がある場合、ビットマップを使用し、文字列の形式である場合は、少なくとも100万ビット(ビット1はログインを意味し、ビット0はログインしていないことを意味します)を保存できます。たとえば、userIdがキーであり、ログインするかどうか(文字列「1」はログインを意味し、文字列「0」はログインしていないことを意味します)が値として格納されている場合、100万文字列を格納する必要があります。 、ビットマップストレージを使用すると、占有するスペースがはるかに小さくなります。これは、ビットマップストレージの利点です。
ビットマップの最下層は、文字列を操作することによって実装されます。文字列型は、バイナリとして保存されるバイト配列です。したがって、Redisは、バイト配列の各ビットを使用して、要素のバイナリ状態を表します。ビットマップはビットの配列と考えることができます。
文法:SETBIT key offset value
たとえば、ユーザーが1年間にチェックする日数を数えます。キーはユーザーID、値は365ビットのビットマップです。各ビットは当日のユーザーのチェックインステータスに対応し、1-はチェックインを表し、11000011はユーザー番号を表し、0 12…360を表します。最初と最初を表す世代オフセット。2、3、360日。
たとえば、初日:setbit user:sign:11000011:2020 0 1
2日目:setbit user:sign:11000011:2020 1 1
、
3日目:setbit、
最後に、1年間のユーザーのチェックイン数を数えます。
BITCOUNT uid:sign:11000011:2020
別の例として、10月の1億人のユーザーのサインインステータスを数えます。キーは31個のキーを持つ毎日の日付であり、値は1億ビットのビットマップであり、1はサインインを表します。
10.01:
// 3个用户在10月1号的签到状态
setbit user:sign:20201001 user01 1
setbit user:sign:20201001 user02 0
setbit user:sign:20201001 user03 1
10.02:
// 3个用户在10月2号的签到状态
setbit user:sign:20201002 user01 1
setbit user:sign:20201002 user02 0
setbit user:sign:20201003 user03 1
31ビットマップのAND演算をカウントして、最終的なビットマップを取得し、ビットカウントを通じて結果を取得します。
BITCOUNT uid:sign:20201001
+
BITCOUNT uid:sign:20201002
+
BITCOUNT uid:sign:20201003
1億ビットマップが占めるメモリは次のとおりです。10^ 8ビット= 10 ^ 8/8 = 1.25 * 10 ^ 7バイト= 1.2207 * 10 ^ 4 KB = 12 MB
https://mp.weixin.qq.com/s?spm=a2c6h.12873639.0.0.5c245c15Ac1CVJ&__biz=MzAxNjM2MTk0Ng==&mid=2247484427&idx=1&sn=cb810acc286b9f85796ef4dc35587309&chksm=9bf4b4beac833da86eff09b2f68195930e5fd1c374448c7b22b16725a4ec717dacac63ba1da7&scene=21#wechat_redirect - ビットマップRedisの動作正常の使い方
2、HyperLogLog
HyperLogLogは、カーディナリティの計算に使用されるデータ収集タイプです。最大の利点は、収集要素の数が非常に多い場合、カーディナリティを計算するために必要なスペースが常に固定され、非常に小さいことです。
Redisでは、各HyperLogLogは、2 ^ 64に近い要素のベースを計算するために12KBのメモリのみを必要とします。ご覧のとおり、HyperLogLogは、より多くの要素でより多くのメモリを消費するSetおよびHashタイプと比較して、非常にスペースを節約します。
たとえば、Webページへの訪問者の数を数える場合、Setタイプを使用して、重複する統計を削除できます。ただし、要素が多いほど、占有されるメモリが大きくなるため、統計にHyperLogLogを使用できます。
PFADD page1:uv user1 user2 user3 user4 user5
、お問い合わせ:PFCOUNT page1:uv
実装の原則:HyperLogLogアルゴリズム、https ://blog.csdn.net/u011489043/article/details/78727128
一般的な考え方は次のとおりです。データセット内の繰り返されない要素の数を数えます。セット内の各要素は、ハッシュ関数を通過した後、0と1で構成される2進数の文字列として表すことができます。バイナリ文字列での0と1の出現回数は、コイントスに少し似ており、全体はローカルで異なる配列を介して推定されます。0.8前後のエラーが発生します。
3、ジオ
Geoの最下層は、並べ替えられたセットに基づいて実装されます。GEOタイプは、並べ替えられたセットの要素の重みスコアとして緯度と経度の間隔コードを使用します。
コーディング方法は?
「2つのパーティション間の間隔コーディング」の方法であるGeoHashを使用して、経度と緯度がそれぞれ緯度と経度のセットに対してコーディングされ、最後に最終的なコードが合成されます。
緯度と経度の間隔は連続して2つに分割され、左側の間隔は0に設定され、右側の間隔は1に設定されます。
最終的なコーディング規則は、最終的なコーディング値の偶数桁の後に経度コーディング値が続き、奇数桁の後に緯度コーディング値が続くというものです。このうち、偶数桁は0から始まり、奇数桁は1から始まります。 。
1110011101。
要約、いくつかのオブジェクトで使用されるデータ構造
いくつかのオブジェクトアプリケーションシナリオ
-
文字列:最も一般的なデータ型、一般的なKVストレージ。
たとえば、ユーザー情報を保存する場合、キーはユーザーIDであり、値はjson形式で保存できます。setuserid{"name": "aaa"、 "age": "123"}
一意のID生成:最初に初期化:
set uniqueid 1
実行されるたびに、incr uniqueid
増分されたID値が返され、シングルスレッド処理では同時実行性を考慮する必要はありません。 -
リスト:
キューを再試行し、リストからタスクを追加します。タスクの実行中に実行するタスクがないかリストを常に確認します。
-
セットする:
主に重複を削除します。重複排除が必要な一部のシーンでは、統計やフィルタリング機能などのセットを使用できます。少量のデータ量の統計にはsetを使用できます。
-
zset:
リーダーボード。映画のランキングなど:
zadd movie_rank_board 1 功夫 2 逃学威龙 3 大话西游
-
ハッシュ:
スパイクシナリオでは、さまざまなマーチャントからのさまざまな製品の購入はxx個に制限されています。マーチャントIDをキーとして使用できます。スナップアップ購入に参加している製品のIDがフィールドであり、対応するスナップアップ数量が値として保存されます。例:、
hmset 781287 product-001 100 product-002 50
急いで購入する場合は、控除操作を実行します。
メモリの再利用
Redisは、オブジェクトに参照カウンターを追加して、メモリ回復メカニズムを実装します。
- オブジェクトを作成するとき、参照カウンターrefCount = 1;
- オブジェクトが参照されるとき、refCount ++;
- 使用後、refCount–;
- refCount = 0のときに解放されます。
値オブジェクトの共有-整数値を持つオブジェクト文字列のみが共有されます
キーAが値オブジェクトとして100の整数値を持つ文字列オブジェクトを作成する場合、A <===> 100;キーBも値オブジェクトとして値が100の文字列オブジェクトを作成する必要がある場合、RedisはキーをポイントしますAとBから同じ文字列オブジェクトは100であり、同時にこの文字列オブジェクトのrefCount ++は100(= 3、最初は1、サーバーによって参照されます)です。
注:文字列配列のオブジェクトを共有しないのはなぜですか?
==> Redisが共有オブジェクトを特定のキーの値オブジェクトとして設定する場合、共有オブジェクトが必要なものであるかどうかを確認する必要があります。
したがって、この共有オブジェクトによって保存される値は複雑になりすぎることはありません。そうしないと、検証中の時間計算量が高くなりすぎます。現在、Redisは整数値を含む文字列オブジェクトのみを共有しており、検証時間の複雑さはO(1)です。
参照:
「Redisの設計と実装」
「Redisコアテクノロジーと実際の戦闘」