ワードリストをredisに保存しようとしています。パフォーマンスは素晴らしいです。
私のアプローチは、「words」と呼ばれるセットを作成し、「sadd」を介して新しい単語を追加することです。
15.9 MBで約100万語を含むファイルを追加する場合、redis-serverプロセスは160MBのRAMを消費します。なぜ私は10倍のメモリを使用しているのですか?この問題に取り組むためのより良い方法はありますか?
ワードリストをredisに保存しようとしています。パフォーマンスは素晴らしいです。
私のアプローチは、「words」と呼ばれるセットを作成し、「sadd」を介して新しい単語を追加することです。
15.9 MBで約100万語を含むファイルを追加する場合、redis-serverプロセスは160MBのRAMを消費します。なぜ私は10倍のメモリを使用しているのですか?この問題に取り組むためのより良い方法はありますか?
これは、効率的なデータストレージに期待されています。ポインタでリンクされたセルの動的データ構造で、メモリ内の単語にインデックスを付ける必要があります。構造メタデータ、ポインタ、およびメモリアロケータの内部フラグメンテーションのサイズが、データが対応するフラットファイルよりもはるかに多くのメモリを使用する理由です。
Redisセットはハッシュテーブルとして実装されます。これも:
上記のすべてのサイズは、64ビットの実装用に指定されています。メモリアロケータのオーバーヘッドを考慮すると、jemallocアロケータを使用するRedisの最近のバージョン(> = 2.4)の場合、Redisは(データに加えて)セットアイテムごとに少なくとも64バイトを使用することになります。
Redisは、一部のデータ型のメモリ最適化を提供しますが、文字列のセットは対象外です。セットのメモリ消費を本当に最適化する必要がある場合は、使用できるトリックがあります。160 MBのRAMに対してはこれを行いませんが、より大きなデータがある場合は、次のように実行できます。
セットの和集合、共通部分、差分機能が必要ない場合は、単語をハッシュオブジェクトに格納できます。利点は、ハッシュオブジェクトが十分に小さい場合、zipmapを使用してRedisによって自動的に最適化できることです。zipmapメカニズムはRedis>=2.6でziplistに置き換えられましたが、考え方は同じです。CPUキャッシュに収まるシリアル化されたデータ構造を使用して、パフォーマンスとコンパクトなメモリフットプリントの両方を実現します。
ハッシュオブジェクトが十分に小さいことを保証するために、データは何らかのハッシュメカニズムに従って分散される可能性があります。100万個のアイテムを保存する必要があるとすると、単語の追加は次の方法で実装できます。
保存する代わりに:
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として格納されることが保証されます。
私の実験に関しては、データをハッシュテーブル/辞書内に保存することをお勧めします。多くのベンチマークの後で私が到達したこれまでで最高のケースは、500キーを超えないハッシュテーブルデータエントリ内に格納することです。
標準の文字列set/getを試しましたが、100万個のキー/値の場合、サイズは79MBでした。約8GBを使用する1億のような大きな数がある場合、それは非常に巨大です。
同じデータを保存するためにハッシュを試しました。同じ100万個のキー/値に対して、サイズはますます16MB小さくなりました。
誰かがベンチマークコードを必要とする場合に備えて試してみてください、私にメールを送ってください
たとえば、データベースを永続化してBGSAVE
、サーバーをシャットダウンしてから元に戻そうとしましたか?断片化の動作により、バックアップして保存されたRDBファイルからデータを取り込むときに、必要なメモリが少なくなる可能性があります。
また、どのバージョンのRedisを使用していますか?このブログ投稿を見てください-バージョン2.4の時点で断片化が部分的に解決されたと書かれています。