これは、効率的なデータストレージに期待されます。単語は、ポインタでリンクされたセルの動的データ構造のメモリでインデックス付けする必要があります。構造メタデータ、ポインタ、およびメモリアロケータの内部断片化のサイズが、データが対応するフラットファイルよりもはるかに多くのメモリを使用する理由です。
Redisセットはハッシュテーブルとして実装されます。これには以下が含まれます:
- 幾何学的に成長するポインタの配列(2の累乗)
- インクリメンタルリハッシュがアクティブな場合は、2番目のアレイが必要になる場合があります
- ハッシュテーブルのエントリを表す単一リンクリストセル(3ポインター、エントリあたり24バイト)
- Redisオブジェクトラッパー(値ごとに1つ)(エントリごとに16バイト)
- 実際のデータ自体(サイズと容量のためにそれぞれに8バイトのプレフィックスが付いています)
上記のすべてのサイズは、64ビットの実装用に指定されています。メモリアロケータのオーバーヘッドを考慮すると、jemallocアロケータ(> =2.4)を使用するRedisの最近のバージョンでは、Redisは(データに加えて)セットアイテムごとに少なくとも64バイトを使用することになります
Redisは、一部のデータ型のメモリ最適化を提供しますが、文字列のセットは対象外です。セットのメモリ消費を本当に最適化する必要がある場合でも、使用できるトリックがあります。 160 MBのRAMに対してはこれを行いませんが、より大きなデータがある場合は、次のことができます。
セットの和集合、共通部分、差分機能が必要ない場合は、単語をハッシュオブジェクトに格納できます。利点は、ハッシュオブジェクトが十分に小さい場合、zipmapを使用してRedisによって自動的に最適化できることです。 zipmapメカニズムはRedis>=2.6でziplistに置き換えられましたが、考え方は同じです。CPUキャッシュに収まるシリアル化されたデータ構造を使用して、パフォーマンスとコンパクトなメモリフットプリントの両方を実現します。
ハッシュオブジェクトが十分に小さいことを保証するために、データは何らかのハッシュメカニズムに従って分散される可能性があります。 100万個のアイテムを保存する必要があるとすると、単語の追加は次の方法で実装できます。
- 10000を法としてハッシュします(クライアント側で実行)
- HMSETワード:[hashnum][ワード]1
保存する代わりに:
words => set{ hi, hello, greetings, howdy, bonjour, salut, ... }
保存できます:
words:H1 => map{ hi:1, greetings:1, bonjour:1, ... }
words:H2 => map{ hello:1, howdy:1, salut:1, ... }
...
単語の存在を取得または確認する場合も同じです(ハッシュしてHGETまたはHEXISTSを使用します)。
この戦略では、zipmap構成(またはRedis> =2.6の場合はziplist)に従って選択されたハッシュのモジュロを使用して、大幅なメモリ節約を実行できます。
# Hashes are encoded in a special way (much more memory efficient) when they
# have at max a given number of elements, and the biggest element does not
# exceed a given threshold. You can configure this limits with the following
# configuration directives.
hash-max-zipmap-entries 512
hash-max-zipmap-value 64
注意:これらのパラメーターの名前は、Redis>=2.6で変更されています。
ここで、1Mアイテムのモジュロ10000は、ハッシュオブジェクトごとに100アイテムを意味します。これにより、すべてのアイテムがzipmap/ziplistとして格納されることが保証されます。