2012-04-04 24 views
17

私は小さな質問があります。Redisはデータよりもメモリ使用量が10倍多い

私は単語リストを赤字で保存しようとしています。パフォーマンスは素晴らしいです。

私のアプローチは、「単語」と呼ばれるセットを作成し、新しい単語を「sadd」で追加することです。

15.9MBのファイルを追加するときに問題が発生し、約100万語が含まれるため、redis-serverプロセスでは160MBのRAMが消費されます。どのように私は10倍のメモリを使用していますが、この問題に近づく方法はありますか?アドバンス

答えて

75

これは効率的なデータ格納が期待されています。ポインタは、リンクされたセルの動的データ構造内でメモリ内で索引付けする必要があります。構造メタデータ、ポインタ、メモリアロケータの内部断片化のサイズは、データが対応するフラットファイルよりもはるかに多くのメモリを必要とする理由です。

Redisセットはハッシュテーブルとして実装されています。これには、

  • 増分再ハッシュは、ハッシュテーブルのエントリを表す
  • 単一リンクリストセル(アクティブのとき二番目の配列が必要とされ得る
  • (2のべき乗)幾何学的に成長しているポインタの配列3つのポインタを、エントリあたり24バイト)
  • Redisのオブジェクトラッパー(値1つ)(エントリ当たり16バイト)
  • 実データそのもの(それらのそれぞれのサイズ及び容量を8つのバイトで始まる)

すべての上記のサイズは、64ビットの実装に与えられています。メモリアロケータのオーバーヘッドを考慮すると、Redisは、jemallocアロケータ(> = 2.4)を使用して、最新バージョンのRedisの設定項目ごとに少なくとも64バイトを取得します。

Redisはmemory optimizationsをいくつかデータ型は含まれていますが、文字列の集合は含まれません。あなたが実際にセットのメモリ消費を最適化する必要があるなら、あなたが使うことができるトリックがあります。私は160 MBのRAMでこれをやってはいけませんが、より大きなデータがあれば、ここでできることです。

集合の交叉、差異の機能が必要ない場合は、単語をハッシュオブジェクトに格納することができます。メリットは、ハッシュオブジェクトがRedisによってzipmapを使用して自動的に最適化できることです。 zipmapメカニズムはRedis> = 2.6のziplistに置き換えられましたが、考え方は同じです:CPUキャッシュに収まるシリアル化されたデータ構造を使用して、パフォーマンスとコンパクトなメモリフットプリントを得ることができます。

ハッシュオブジェクトが十分に小さいことを保証するために、データはいくつかのハッシュメカニズムに従って配信される可能性があります。仮定すると、あなたは単語以下の方法で実施することができる追加し、1Mのアイテムを保存する必要があります。

  • ハッシュそれはモジュロを10000
  • HMSETワード(クライアント側で行う):1
  • [hashnum] [単語]代わりに、保存の

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を使用します)。

# 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 

は注意:の名前をこの方法で

、有意なメモリ節約は、ハッシュのモジュロをzipmap構成(またはRedisの> = 2.6 ziplist)に従って 選択される設け行うことができこれらのパラメータはRedis> = 2.6で変更されています。

ここで、1Mアイテムのモジュロ10000は、ハッシュオブジェクトごとに100アイテムを意味します。これらのアイテムは、すべてがzipmaps/ziplistsとして格納されることを保証します。

+0

魅惑的で詳細な答え。私はそれを知らなかった。ありがとう@Didier! –

+0

申し訳ありませんが、私はかなり私の問題を解決することは非常に肯定的です。そして、罰金160メガバイトのためにええ、しかし、私は平文のデータの最大1ギガバイトで動作すると期待していると10ギガビットにスパイクしたくありませんでした。もう一度おねがいします、詳細な答えを感謝します。 – cwoebker

+2

@Didier - すばらしい答え!しかし、訂正のカップルa)Hashtableエントリは、ダブルではなく、24バイトのオーバーヘッドは正しいが、単一のリンクされたリストb)Redisオブジェクトラッパーは各セット/ハッシュエントリには適用されない。これは、トップレベルのキーと値のペアにのみ適用されるので、オーバーヘッドは一定です。c)zipmapが2.6 /不安定で廃止され、ziplistが同等のことを行うことを示すことができます。 –

2

おかげで、サーバーをシャットダウンし、アップ戻ってそれを取得し、データベース(例えばBGSAVE)を永続化しようとしましたか?フラグメンテーション動作のため、バックアップされて保存されたRDBファイルからデータが移入されると、メモリが少なくなる可能性があります。

Redisのどのバージョンを使用しますか? this blog postを見てください - 断片化がバージョン2.4のように部分的に解決されたと言います。

4

私の実験では、データをハッシュテーブル/辞書の中に保存する方が良いです。多くのベンチマークの後に私が到達した最高のケースは、500個のキーを超えないハッシュテーブルのデータエントリを格納することです。

私は標準的な文字列セットを試しました/取得、100万のキー/値のために、サイズは79 MBでした。約8GBを使用する100万のような大きな数字がある場合は非常に巨大です。

同じデータを保存するためにハッシュを試しましたが、同じキー/値の場合、サイズはますます小さくなりました(16 MB)。

誰かがベンチマークコードを必要とする場合は、私にメールをドロップしてみてください。

関連する問題