sql >> データベース >  >> NoSQL >> Redis

リアルタイムのストックアプリケーション用のRedisキーデザイン

    私の提案は、関心のあるすべての間隔の最小/最大/合計を保存し、到着するすべてのデータポイントで現在の間隔に更新することです。比較のために以前のデータを読み取るときにネットワーク遅延を回避するために、Luaスクリプトを使用してRedisサーバー内で完全に読み取ることができます。

    データポイントごとに(またはさらに悪いことに、データポイントフィールドごとに)1つのキーは、大量のメモリを消費します。最良の結果を得るには、それを小さなリスト/ハッシュにグループ化する必要があります(http://redis.io/topics/memory-optimizationを参照)。 Redisでは、データ構造に1レベルのネストしか許可されていません。データに複数のフィールドがあり、キーごとに複数のアイテムを保存する場合は、何らかの方法で自分でエンコードする必要があります。幸い、標準のRedis Lua環境には、非常に効率的なバイナリJSONのような形式であるmsgpackサポートが含まれています。 msgpackで「そのまま」エンコードされた例のJSONエントリは、52〜53バイトの長さになります。キーごとに100〜1000エントリになるように、時間でグループ化することをお勧めします。 1分間隔がこの要件に適合すると仮定します。その場合、キーイングスキームは次のようになります。

    YYmmddHHMMSStidからのハッシュ 指定された分のmsgpackでエンコードされたデータポイントへ。5m:YYmmddHHMM1h:YYmmddHH1d:YYmmddminを含むウィンドウデータハッシュ 、maxsum フィールド。

    1つのデータポイントを受け入れ、必要に応じてすべてのキーを更新するサンプルのLuaスクリプトを見てみましょう。 Redisスクリプトの動作方法により、スクリプトによってアクセスされるすべてのキーの名前、つまりライブデータと3つのウィンドウキーすべてを明示的に渡す必要があります。 Redis LuaにはJSON解析ライブラリも用意されているため、簡単にするために、JSONディクショナリを渡すだけであると仮定します。つまり、アプリケーション側とRedis側の2回データを解析する必要がありますが、パフォーマンスへの影響は明確ではありません。

    local function update_window(winkey, price, amount)
        local windata = redis.call('HGETALL', winkey)
        if price > tonumber(windata.max or 0) then
            redis.call('HSET', winkey, 'max', price)
        end
        if price < tonumber(windata.min or 1e12) then
            redis.call('HSET', winkey, 'min', price)
        end
        redis.call('HSET', winkey, 'sum', (windata.sum or 0) + amount)
    end
    
    local currkey, fiveminkey, hourkey, daykey = unpack(KEYS)
    local data = cjson.decode(ARGV[1])
    local packed = cmsgpack.pack(data)
    local tid = data.tid
    redis.call('HSET', currkey, tid, packed)
    local price = tonumber(data.price)
    local amount = tonumber(data.amount)
    update_window(fiveminkey, price, amount)
    update_window(hourkey, price, amount)
    update_window(daykey, price, amount)
    

    この設定では、1秒あたり数千の更新を実行でき、メモリをあまり消費せず、ウィンドウデータを即座に取得できます。

    更新:メモリの部分では、数百万を超えて保存したい場合は、ポイントあたり50〜60バイトがまだたくさんあります。この種のデータでは、カスタムバイナリ形式、デルタエンコーディング、およびその後のスナッピーなどを使用したチャンクの圧縮を使用して、ポイントあたり2〜3バイトまで低くすることができると思います。これを行う価値があるかどうかは、要件によって異なります。




    1. MongoDB$type集約パイプライン演算子

    2. redisサーバーでのSpringセッションの設定

    3. Windowsでmongodbサーバーを停止する方法は?

    4. KubernetesクラスターのNodeJSでECONNREFUSEDを再接続します