[11]高度なアプリケーションのRedisのRedisのシリーズ-scan

オリジナル: 高度なアプリケーションの11 []のRedis Redisのシリーズ-scan

通常のオンラインRedisの保守作業では、時々手動でデータを処理するために、キーリスト内のキーの数千人のRedisのインスタンスから特定のプレフィックスを見つける必要があり、その値は、キーを削除することがあり、修正することができます。問題は、どのようにキーリスト内の鍵満たす特定のプレフィックスの塊から見つけるために、ここにあるのでしょうか?

Redisのは、暴力が簡単な指示を提供keys満たす特定のキーを支配することを、すべての文字列をリストするために使用します。

127.0.0.1:6379> set codehole1 a
OK
127.0.0.1:6379> set codehole2 b
OK
127.0.0.1:6379> set codehole3 c
OK
127.0.0.1:6379> set code1hole a
OK
127.0.0.1:6379> set code2hole b
OK
127.0.0.1:6379> set code3hole b
OK
127.0.0.1:6379> keys *
1) "codehole1"
2) "code3hole"
3) "codehole3"
4) "code2hole"
5) "codehole2"
6) "code1hole"
127.0.0.1:6379> keys codehole*
1) "codehole1"
2) "codehole3"
3) "codehole2"
127.0.0.1:6379> keys code*hole
1) "code3hole"
2) "code2hole"
3) "code1hole"

このコマンドは、使用することは非常に簡単です、簡単な通常の文字列缶を提供していますが、二つの重要な存在な欠点が

  1. ノーWキー条件の数百の例がある場合は、すべての時間スピットキーの条件を満たすように、制限パラメータをオフセットあなたは終わることがない文字列フルスクリーンのブラシを見ると、あなたが不快知って、満足しています。
  2. このアルゴリズムは、トラバーサルアルゴリズムの複雑さはO(n)は、キーの例以上の千万がある場合は、このディレクティブは、RedisのサービスケイトンにつながるRedisの読み取りおよびすべての他の命令を記述であるキーは、時​​間を遅らせたりしますRedisのシングルスレッドのプログラムであるため、エラーは、彼らが継続する前に現在の命令までのキーの上に実行されるすべての命令、他の命令を実行します。

フェイス2つの重大な欠点は、どのようにそれを行うには?

この問題を解決するためのRedis、それはバージョン2.8に干し草の山でコマンド針に参加しました- scanscan比較するとkeys、次の特性を持ちます:

  1. 複雑さはO(N)であり、それは、カーソルを介してステップバイステップであって、スレッドをブロックしないであろうが。
  2. 制限パラメータを提供する結果の最大数は、唯一のヒント制限をするたびに返され、返された結果は、多かれ少なかれであってもよい制御します。
  3. キーのように、それはまた、パターンマッチングを提供します。
  4. サーバーカーソルは状態、クライアントカーソル整数にカーソルバックをスキャンのみ状態を保存する必要はありません。
  5. リピートへのクライアントのニーズを重複することが返された結果が、これは非常に重要です。
  6. 横断データ変更時に、データが変更に行き来することができない場合は不明です。
  7. 返された単一の結果が返された値がゼロのトラバースの終わりを意味するものではありません空ですが、カーソルに依存します。

スキャンの基礎

使用する前に、テスト用10000のRedisのデータINSERT内部手放します

import redis

client = redis.StrictRedis()
for i in range(10000):
    client.set("key%d" % i, i)

まあ、Redisのは今万件のデータを持っているし、我々はkey99キーリストを始めることを見つけます。

スキャンパラメータは三つのパラメータ、最初のものを提供するcursor 整数值第二は、key 的正则模式第三です遍历的 limit hint次いで、第0のカーソル値、スルー時間、及び次トラバーサルカーソルの最初の整数値として結果を返します。カーソルが夜12時を終了さ返すように横断されています。

127.0.0.1:6379> scan 0 match key99* count 1000
1) "13976"
2)  1) "key9911"
    2) "key9974"
    3) "key9994"
    4) "key9910"
    5) "key9907"
    6) "key9989"
    7) "key9971"
    8) "key99"
    9) "key9966"
   10) "key992"
   11) "key9903"
   12) "key9905"
127.0.0.1:6379> scan 13976 match key99* count 1000
1) "1996"
2)  1) "key9982"
    2) "key9997"
    3) "key9963"
    4) "key996"
    5) "key9912"
    6) "key9999"
    7) "key9921"
    8) "key994"
    9) "key9956"
   10) "key9919"
127.0.0.1:6379> scan 1996 match key99* count 1000
1) "12594"
2) 1) "key9939"
   2) "key9941"
   3) "key9967"
   4) "key9938"
   5) "key9906"
   6) "key999"
   7) "key9909"
   8) "key9933"
   9) "key9992"
......
127.0.0.1:6379> scan 11687 match key99* count 1000
1) "0"
2)  1) "key9969"
    2) "key998"
    3) "key9986"
    4) "key9968"
    5) "key9965"
    6) "key9990"
    7) "key9915"
    8) "key9928"
    9) "key9908"
   10) "key9929"
   11) "key9944"

これは、制限を設けること1000ながら、上記のプロセスから見ることができるが、結果は、10の周りに戻されます。返された結果の制限数が定義されていない理由が、辞書定義の数スロットサーバ(ほぼ等しい)を通る単一パス。上限が10に設定されている場合は、結果が空であることがわかりますが、カーソルがゼロではない、それが横行はまだ終わっていないことを意味します。

127.0.0.1:6379> scan 0 match key99* count 10
1) "3072"
2) (empty list or set)

辞書構造

Redisのキーの全てにおいて、大辞書に格納されている同じ構造の辞書とJavaのHashMapに、一次元アレイ+次元鎖構造であり、配列の最初の次元のサイズは常に2 ^ n個(nは> = 0)は、最初の拡張は、N ++で配列のサイズを倍増。

image.png

カーソル位置は、この位置はスロットインデックス(スロット)と呼ばれる、リターンへスキャン指示の次元配列の最初のインデックスです。減容辞書の拡充、配列内の一つ一つを考慮せずに、添え字がリストにトラバーサル。スロットの数は、それが横断する手段のパラメータを必要としないすべてのスロットは、いくつかのスロットが空である可能性があり、リストを添付するだけでなく、いくつかのスロットに連接されるため、結果は、リターンが少なくてもよいためのより多くの理由であってもよい制限リストの要素は、複数のかもしれません。すべてのリストの要素の各横断後にクライアントにワンタイムバック、パターンマッチングフィルタスロットの数の限界に取り付けられています。

スキャントラバーサル順序

スキャントラバーサル順序は特別です。それは、常に代わりに横断する高キャリー加算器を使用する、端にビット0から配列の最初の次元を横断していません。アカウントに辞書コンテンツの伸縮を撮るときのスロットを通過するの重複や漏れを避けるために、トラバースに、このような特別な方法を使用する理由。

まず、我々は通常、高キャリー加算器の追加の違いについてのアニメーションを使用しています。

画像

映画からの反対の共通の加算器と、右運ぶために、移動を適用左上バイナリ法から分かります。しかし、最終的に、彼らはすべてのスロットを通過し、何の重複はありません。

辞書拡張

JavaのHashMapののloadFactorがしきい値に達すると、拡張、配列の新しい2倍の大きさを再割り当てする必要があり、その後、すべての下に新しい配列の焼き直しにリンクされているすべての要素の概念。要素の焼き直しハッシュ値は長さとなるので、各要素のフックスロットも変更することができる、配列モジュロ演算の長さです。配列の長さが2 ^ n個のパワーであるためと、モジュロ演算は、操作位置に相当します。

a mod 8 = a & (8-1) = a & 7
a mod 16 = a & (16-1) = a & 15
a mod 32 = a & (32-1) = a & 31

ここでは7、15、辞書と呼ばれるマスク値の31は、マスクの役割は、0が高に設定されている低保持ハッシュ値は、です。

次に、我々は、スロット素子の焼き直し前後の変化を見てください。

これは、8〜16の現在の辞書配列の長さの膨張は、スロット011は、焼き直しのスロット3及びスロット11、リスト要素の半分程度であるスロットに3になることを想定しました米国特許第3スロットは、他の要素は第11スロットに配置され、11の数字1011バイナリ、バイナリ0113高い1だけ増加されます。

image.png

2進数XXX開始スロットであると仮定すると、次に、要素が内(XXX + 8)焼き直し0XXXと1XXXにスロット内のことながら、抽象ポイント。16から32への膨張による辞書の長さがあれば、バイナリXXXXスロット内の要素のため0XXXXと1xxxx(XXXX + 16)に焼き直しです。

トラバーサル順膨張体積縮小前と後の比較

image.png

図この観察は、我々は、トラバーサル順序焼き直し後のスロットに、2進加算の高次トラバーサルを使用して、隣接していることを見出しました。

假设当前要即将遍历 110 这个位置 (橙色),那么扩容后,当前槽位上所有的元素对应的新槽位是 0110 和 1110(深绿色),也就是在槽位的二进制数增加一个高位 0 或 1。这时我们可以直接从 0110 这个槽位开始往后继续遍历,0110 槽位之前的所有槽位都是已经遍历过的,这样就可以避免扩容后对已经遍历过的槽位进行重复遍历。

再考虑缩容,假设当前即将遍历 110 这个位置 (橙色),那么缩容后,当前槽位所有的元素对应的新槽位是 10(深绿色),也就是去掉槽位二进制最高位。这时我们可以直接从 10 这个槽位继续往后遍历,10 槽位之前的所有槽位都是已经遍历过的,这样就可以避免缩容的重复遍历。不过缩容还是不太一样,它会对图中 010 这个槽位上的元素进行重复遍历,因为缩融后 10 槽位的元素是 010 和 110 上挂接的元素的融合。

渐进式 rehash

Java 的 HashMap 在扩容时会一次性将旧数组下挂接的元素全部转移到新数组下面。如果 HashMap 中元素特别多,线程就会出现卡顿现象。Redis 为了解决这个问题,它采用渐进式 rehash

它会同时保留旧数组和新数组,然后在定时任务中以及后续对 hash 的指令操作中渐渐地将旧数组中挂接的元素迁移到新数组上。这意味着要操作处于 rehash 中的字典,需要同时访问新旧两个数组结构。如果在旧数组下面找不到元素,还需要去新数组下面去寻找。

scan 也需要考虑这个问题,对与 rehash 中的字典,它需要同时扫描新旧槽位,然后将结果融合后返回给客户端。

更多的 scan 指令

scan 指令是一系列指令,除了可以遍历所有的 key 之外,还可以对指定的容器集合进行遍历。比如 zscan 遍历 zset 集合元素,hscan 遍历 hash 字典的元素、sscan 遍历 set 集合的元素。

その原理は基本的なハッシュが辞書であるため、同一のスキャンは、類似するであろう、セットには、特別なハッシュ(同じ要素へのすべてのポイントの値)、コンテンツのすべての要素を格納するための辞書をも使用する内部ZSETですので、ここではそれらを繰り返すことはしません。

ビッグキースキャン

時にはので、ラージオブジェクトの形成におけるビジネスマン、Redisのインスタンスの不適切な使用が、このようなハッシュたくさんのように、これは偉大なZSETが頻繁に表示されています。キーが大きすぎる場合は、クラスタ化された環境で、それはデータカトンの移行の原因となりますので、データ移行のようなオブジェクトRedisのクラスタは、大きな問題です。また、それはカトンにつながる可能性が膨張、メモリの大きなチャンクのためのワンタイムアプリケーションを必要とするとき、キーが大きすぎると、メモリの割り当てです。大きなキーが削除された場合、メモリは1回の回復となり、カトン現象が再び生成されます。

通常の事業開発では、我々は大きなキーを回避しようとしてください

あなたはRedisのメモリ浮き沈みを見れば、これは最も可能性の高い原因は大きなキー理由で、あなたが特定のキーを見つける必要があり、この時間は、さらなる事業の特定のソースを見つけ、その後、関連するビジネスコードの設計を改善するために、ということです。

どのように大きなそれを見つけるの鍵?

Redisのは、各キーのスキャン命令スキャンを使用オンラインカトンを、もたらした避けるために、鍵を得、その大きさに対応するLEN方法を使用して、命令の種類とサイズの種類またはデータ構造を使用して得られますタイプごとに、上位N個の保持の大きさは、走査の結果として現れます。

上記のスクリプトを書くためにこのような処理の必要性は、より複雑な、しかし、Redisの公式は、このようなスキャン機能のRedis-cliの指示を提供してきた、我々は直接使用する準備ができて使用することができます。

redis-cli -h 127.0.0.1 -p 7001 –-bigkeys

あなたはRedisのオプスにかなりの隆起にオンラインアラームをリードするこのディレクティブを心配している場合、あなたはまた、睡眠パラメータを追加することができます。

redis-cli -h 127.0.0.1 -p 7001 –-bigkeys -i 0.1

上記のコマンド命令は、すべて100のスリープ0.1秒をスキャンします、OPSを激しく上昇しませんが、スキャン時間が長くなります。

おすすめ

転載: www.cnblogs.com/lonelyxmas/p/12515053.html