redis使用仕様


各業務のredisの使用状況が異なるため、単独でデータ構造ごとに制限することは、開発の進捗と難易度に大きな影響を及ぼすに違いないし、memcachedではなくredisの豊富なデータ構造を使用する初心を失ったに違いない.
だからredisの使い方をいくつか提案します.皆さんが受け入れてくれることを願っています.

redisの使い方


slowlog


redisのslowlogはredisクラスタボトルネック最適化を参照する点である
ビジネスにパフォーマンスのボトルネックが発生した場合、slowlogに時間がかかるcommandを分析することができます.
私の経験の中でHGETALL、DELは多くのvalueのkeyを格納することに対して、hash、比較的に長い時間をブロックすることができて、この方面の業務は極力回避する必要があります.1つのコマンドが複数のクライアントのtimeoutをもたらす可能性があるため、あるいは接続プールのtimeout、接続プールを使用する場合、read timeoutあるいはconnect timeoutはすべて災難的で、業務システムのTPSを極めて引き延ばすことができます

BGREWRITEAOF


このメカニズムは主にAOFが業務に与える影響を減らすためであり,このコマンドを実行するとredisサーバはaof書き換えバッファを作成し,書き換え中にすべての書き込みコマンドがこのバッファに書き込まれる
データセットが非常に大きい場合は、メモリを巡回してAOFを書き換えるのに多くの時間がかかります.この時間に高い同時書き込みがあると、多くのメモリが消費されます.そのため、大きなデータセットに十分なメモリがあるかどうか、またはBGREWRITEAOFコマンドが実行されているときに高い書き込み同時実行があるかどうかに注意してください.

valueの最適化


インスタンスの共有:
最近、ある業務のTPSがどうしても上がらない場合があり、テスト負荷によってredisのネットワークに押しつぶされ、会社の資源制限で機械を付けられなくなったので、取りに使うデータ量を切り落とすしかありません
この業務の歌詞ファイルは大きなvalueに属しており、この部分を切り落としてから業務のTPSはすぐにアップした(後期に歌詞が必要な場合はこのvalueを圧縮して再記憶する)
分析:
redis内部のvalueはint,raw,embstrの3種類の符号化に従って格納される
格納されたvalueが整数の場合、intオブジェクトに従って格納されます.
格納されたvalueが整数でなく32バイト未満の場合、embstrに従って格納される
格納されたvalueが整数でなく32バイトより大きい場合はrawに従って格納する
int整数を格納し、0-1000の常用数字を共有すると、格納または読み書き変更内容が直接そのオブジェクトに接続されます
Embstrは,短文字列記憶最適化のために実現された符号化であり,読み取りのみが可能であり,修正後raw符号化に変換される.
rawはその名の通り、未加工の文字列なのでvalueが大きい場合、このようなデータを読み書きするとネットワークのボトルネックになります
結論:
1.文字列を変更する必要がある場合は、32バイト以上の領域を直接保存し、変換に要する時間を短縮
2.redisの文字列はバイナリで安全なので、どんなものが詰まっているのか誤解する可能性があります.
実は長いvalueは圧縮されないので、短いvalueの読み書き効率は長いvalueよりずっと高いです.
長いvalueの記憶に対して、純粋なテキスト、例えば歌詞であれば、完全に圧縮することができ、現在の速度の速い圧縮率の高いテキスト圧縮アルゴリズムは非常に成熟しており、ビジネスサーバのcpu負荷を増やしてIO負荷を減らすことは、ネットワークIO密集型アプリケーションにとって明らかに画期的である.

メモリ使用率の最適化


参考になりましたhttp://oldblog.antirez.com/post/redis-weekly-update-7.html
彼はtrick RedisHLという方法を提案し、redisのメモリ利用率を著しく向上させることができる.
この文章を少し翻訳してください.
キー「foo」を格納するには、次の3つのことをします.
1.計算"foo"の16進数SHA 1チェックサム:0 beec 7 b 5 ea 3 f 0 fdbc 95 d 0 dd 47 f 3 c 5 bc 275 da 8 a 33
2.格納された(真の)keyとして最初の4バイト0 beeを使用
3.「foo」を0 beeのfieldストレージとする
だから「SET foo bar」は「HSET 0 bee foo bar」に相当する
具体的なrubyコードは以下の通りです.require 'rubygems' require 'redis' require 'digest/sha1' class RedisHL
   def initialize(r)
       @redis = r
   end
   def get_hash_name(key)
       Digest::SHA1.hexdigest(key.to_s)[0..3]
   end
   def exists(key)
       @redis.hexists(get_hash_name(key))
   end
   def [](key)
       @redis.hget(get_hash_name(key),key)
   end
   def []=(key,value)
       @redis.hset(get_hash_name(key),key,value)
   end
   def incrby(key,incr)
       @redis.hincrby(get_hash_name(key),key,incr)
   end

end
r = Redis.new() rr = RedisHL.new(r) rr[:foo] = "bar" puts(rr[:foo])
1000 Wの短いKは従来方式で1.7 Gのメモリが必要な場合は300 Mのメモリしか必要ありません!
文末にはテストデータの画像も添付されています
http://antirez.com/blogdata/214/memgraph.png
分析:
このようなamazingの結果がどのような原理なのか分析してみましょう
redisはhashタイプに対してziplistとhashtableの2つの実装方式がある.
get/setを直接使用して全hashをデータ操作すると、データ利用率(used/size)が一定数に達すると、rehash、すなわち2倍拡張が開始される
hashtableの予約空間メカニズムのため,データ利用率はそれほど高くない.
ziplistは非常に効率的なデータストレージフォーマットであり、ポインタが少なく、予約スペースがありません.
hashタイプが作成されるとziplist形式で格納され、一定の規模に達したらhashtableに移行します.
規模の制限はredis.confの次のフィールドの変更
hash-max-zipmap-entries 512
hash-max-zipmap-value 512
大量のデータがziplistで格納されると、メモリ使用率が非常に高くなります.
ただし,ziplistのデータ挿入削除などはCPUリソースを消費するため,大量の短いkeyや読み書きが大きい場合には,このtrick RedisHLの方式がよい.
結論:
1.大量のショートキーや読み書きが大きい場合には、このtrick RedisHLの使い方がいいです
2.大量の短いkeyや読み書きが大きい場合は、get/setで直接操作するよりも、いくつかのkeyを等化してhashタイプにパッケージして操作したほうがいい(hashタイプのfieldが多すぎないように注意してください.そうしないと、前述のHGETALLの穴に落ちます).これらのhashタイプがziplist形式で格納されている場合、メモリ使用率は驚くべきものです.

twemproxyでのredis使用の注意点


twemproxyはtwitterによって開発されたRedisとMemcachedエージェントです.
現在redis clusterがunstableバージョンであることを考慮すると、メカニズムの実現はまだ議論されている.(gossipアルゴリズムを用いたブロードキャストメカニズムを特に期待するのではなく,ネットワーク環境に対する要求が高いcassandraがこのメカニズムである)
大規模なredisクラスタの使用ではtwemproxyに代表されるproxy方式が主流となり、その中でtwemproxyが際立っており、redis著者のblogで点呼分析されているほど、proxyの性能損失は20%程度と言われている.
http://www.antirez.com/news/44
twemproxyのメカニズムとソースコード分析は次の文章で放出されます.この1編はtwemproxyの下でredisの使用の注意点を議論するだけです.

MGETの使用を避ける


これはredisの著者が前文で述べたblogで点呼されて批判されたもので、原話は:
So I expected to see almost the same numbers with an MGET as I see when I run the MGET against a single instance, but I get only 50% of the operations per second.
twemproxyでMGETを操作する性能はなんと操作単機の50%しかありません!
私はtwemproxyのソースコードを大まかに分析し、MGETに関連するkeyが複数のredisインスタンスに分布している場合、ネットワークの変動により、インスタンスごとに抽出する必要があるkeyの数が異なるなどの理由で、proxyは完全な結果を一度に処理してクライアントにフィードバックするわけではない.
一方、統合イベントがトリガーされるのを待つたびに、統合イベントがトリガーされ、最後に一度に統合され、クライアントに結果が送信されます.
消費時間=最も消費されたredisインスタンス+各時間ポーリング間隔*割り当てられたredisインスタンス数
これで遅いのも普通なので、
twemproxy環境でMGETを使わないように!!!

超大fieldを使用する複雑なタイプのオブジェクトを避ける


複雑なタイプのオブジェクトとはhash,setのような非stringオブジェクトを指す
このようなオブジェクトはkey field value形式です.
twemproxyはオブジェクトに対してhashを行うため、keyに対してのみ、fieldに対してhashを行うこともできない(fieldに対してhashを行うと、多くのredis原生操作がサポートされず、また、質問中に複数のredisインスタンスにアクセスして結果を返すことができるため、MGETピットも発生する)
したがって、オブジェクト全体が同じredisインスタンスに格納され、オブジェクトが大きすぎると、redisの分散パフォーマンスに深刻な影響を及ぼし、ストレージとパフォーマンスの深刻な分散の不均衡をもたらします.
OBJECTコマンドを使用して、オブジェクトの詳細を表示します.

field , 50m redis