Redisハッシュは、(直感的には十分です!)文字列名を文字列値にマップするハッシュです。それらは基本的に、一意のフィールドとその値のコンテナと呼ばれます。これらは、オブジェクトをRedisデータ構造として表現するのに最適な方法です。予想どおり、get、set、existsなどの一定時間の基本操作を提供します。一連の高度な操作も提供されます。ハッシュコマンドの完全なリストはここにあります。
redis-cliから試してみましょう 。
# hmset key field value [field value ...] : Insert elements in a hash. O(N), N is # of field being set 127.0.0.1:6379> hmset std:101 name "John Smith" dob "01-01-2000" gender M active 0 cgpa 2.9 OK # hgetall key : key all keys and values in the hash. O(N), N is size of hash 127.0.0.1:6379> hgetall std:101 1) "name" 2) "John Smith" 3) "dob" 4) "01-01-2000" 5) "gender" 6) "M" 7) "active" 8) "0" 9) "cgpa" 10) "2.9" 127.0.0.1:6379> hmset std:102 name "Jane" name "Ann" OK # If duplicates are found, only the last set is valid 127.0.0.1:6379> hgetall std:102 1) "name" 2) "Ann" # hexists key field: does field exist in the hash with key. O(1) 127.0.0.1:6379> hexists std:102 cgpa (integer) 0 # hincrby key field increment: Increment the integer field by increment. O(1) 127.0.0.1:6379> hincrby std:101 active 1 (integer) 1 # hget key field : the value for field in the hash stored at key. O(1) 127.0.0.1:6379> hget std:101 active 1) "1" # If field doesn't exist, hincrby sets it to 0 and then applies increment 127.0.0.1:6379> hincrby std:102 active 2 (integer) 2 # hmget key field [field ...]: the values of the fields requested for the hash with key. O(N), N is # of keys requested 127.0.0.1:6379> hmget std:102 active 1) "2" # hincrbyfloat key field increment: Increment the float value in field by increment. O(1) 127.0.0.1:6379> HINCRBYFLOAT std:101 cgpa 1.0 "3.9" # HSETNX key field value: set field to value if not alread set. O(1) 127.0.0.1:6379> hsetnx std:102 cgpa 4.0 (integer) 1 127.0.0.1:6379> hget std:102 cgpa "4.0" # hlen key: number of fields in the hash. O(1) 127.0.0.1:6379> hlen std:101 (integer) 5 # hkeys key : all fields in the hash. O(N), N is size of hash 127.0.0.1:6379> hkeys std:101 1) "name" 2) "dob" 3) "gender" 4) "active" 5) "cgpa"
データ構造サーバーとしてのRedis™*のホスティングに期待するようになったため、Redisはハッシュに対してかなり便利で高度な操作を提供していることがわかります。
内部
Redisセットと同様に、Redisハッシュも辞書として実装されます。 Redisのディクショナリは、ハッシュ関数MurmurHash2を使用するハッシュテーブルとして実装され、増分サイズ変更によって拡張されます。ハッシュの衝突は連鎖によって処理されます。詳細については、dict.cの辞書のRedis実装を参照してください。
セットと同様に、より小さなハッシュ用にストレージの最適化が行われます。このデータ構造は、Redisの実装ではziplistと呼ばれます(ハッシュは、Redis 2.6より前のzipmapと呼ばれる別のデータ構造を使用して最適化されていました)。これは基本的に、メモリ節約のために最適化された、特別にエンコードされた二重リンクリストです。データとポインタはインラインで保存されます。 Ziplistは、ソートされた小さなセットとリストのストレージを最適化するためにも使用されます。このようなリストにフラット化されたときのハッシュは、[key1、value1、key2、value2、...]のようになります。これはプレーンキーよりもどのように効率的ですか?キーが少ないハッシュは、getとsetの償却O(1)パフォーマンスを保証しながら、この線形配列のような構造(つまり、ziplist)に巧みにパックできます。明らかに、これはハッシュフィールドが増えるにつれて追いつくことができません。ハッシュが大きくなると、O(1)のパフォーマンスを維持するために標準の辞書構造に変換され、スペースの節約が失われます。この変換を制御するRedis構成パラメーターは次のとおりです。
- list-max-ziplist-entries デフォルト(512):ハッシュがこの制限より大きくなる場合は、標準表現に変更します。
- list-max-ziplist-value デフォルト(64):ハッシュの最大要素がこの制限より大きくなる場合は、標準表現に変更します。
詳細は、ここにある実装のコードとコメントから理解できます。この特別な最適化を使用することによるメモリの節約は重要です。詳細については、次のセクションで説明します。
メモリの最適化
Redisを使用する際のメモリ節約に関するよく知られた推奨事項の1つは、プレーンな文字列の代わりにハッシュを使用することです。これは、実際のアプリケーションでRedisハッシュのパワーを利用するための重要なユースケースです。メモリ最適化に関するRedisの公式ドキュメントから:
可能な場合はハッシュを使用する
小さなハッシュは非常に小さなスペースにエンコードされるため、可能な限りハッシュを使用してデータを表現するようにしてください。たとえば、Webアプリケーションでユーザーを表すオブジェクトがある場合、名前、名前、電子メール、パスワードに異なるキーを使用する代わりに、すべての必須フィールドで単一のハッシュを使用します。
この投稿では、メモリの節約を活用するために、オブジェクトの範囲をハッシュのセットにマップする1つの方法を提案しています。 Instagramは、非常に人気のあるブログ投稿で、同様の手法を使用して、潜在的な節約の桁数を達成するのに役立ったと説明しています。最適化のメリットを測定しようとする別のブログはこれです。
アプリケーション
- Redisハッシュは、セッション、ユーザー、訪問者などのオブジェクトを格納するのに自然に適しています。これにより、Redisが提供する重要なデータ構造の1つになります。
- メモリに最適化された形式であるため、大量のデータをキャッシュするのに最適です。
オブジェクトアドレスストア
メモリの最適化はハッシュの重要なユースケースであるため、Instagramの展開に似た例を説明して、Redisハッシュのメモリ節約機能を利用する方法を示しましょう。たとえば、何億ものオブジェクトが保存されている巨大なコンテンツアドレス可能ストレージ(CAS)の展開があるとします。各オブジェクトの場所はハッシュ文字列です。 IDを指定してオブジェクトの場所を見つけるためのルックアップシステムを開発する予定です。 Redisでこれを行う一般的な方法は、文字列を使用することです。
set object:14590860 "007f80f0a62408..."
set object:11678 "009f80abcd0a60..."
...
このアプローチは問題なく機能します。ただし、オブジェクトの数が非常に多いため、Redisには大量のメモリが必要になります。もっと上手くやりたいです。この問題に対して、メモリ最適化ハッシュアプローチを採用しましょう。 list-max-ziplist-entriesに適切な値を選択する必要があります およびlist-max-ziplist-value 。 list-max-ziplist-valueの正しい値 ストレージアドレスハッシュ文字列の最大長は何でもかまいません。 list-max-ziplist-entriesの値 十分に低く保つ必要があり、作成するハッシュバケットの総数によって異なります。それは経験的に最もよく理解されるでしょう。たとえば1億個のオブジェクトの場合、10万個のハッシュを使用することを選択できます。その場合の最大エントリは100m/100k =1000になります。オブジェクトのストレージアドレスがどのハッシュに入るかを決定するアプリケーションのロジックは、オブジェクトIDを100kで除算し、残りを破棄することです。したがって、オブジェクトID 14590860はハッシュ(14590860 / 100k)=145になります。つまり、
hset object:145 14590860 "007f80f0a62408..."
hget object:145 14590860
> "007f80f0a62408..."
この実装は、メモリを大幅に削減するだけでなく、優れたキャッシュの局所性も提供するはずです。
これがRedisデータ構造シリーズの他の投稿です。
- Redisセット
- Redisビットマップ
- 並べ替えられたセットをRedisします