zenet_logo

-株式会社ゼネット技術ブログ-

Redisをクラスタ有効モードでマルチキー操作したらエラーになった時の対処法

こんにちは、システム事業部の田丸です。昨今、利活用が目立ってきているNoSQLデータベースですが、携わるプロジェクトでRedis使用時に発生した事象と留意点について、ごくざっくりと紹介したいと思います。少しでも皆さんのお役に立てれば。

 

【発生した例外エラー】

「redis.clients.jedis.exceptions.JedisDataException:CROSSSLOT Keys in request don't hash to the same slot」

Redisを利用したシステムにおいてアプリケーションでデータ更新をしようとしたところ、アプリケーションログに上記のエラーが出力されました。訳すと「リクエストされたCROSSSLOT キーが同じスロットにハッシュされません」とのこと。。。


【前提と発生事象】

まずは、前提となる構成やデータセットについて簡単に整理します。

 

<構成>
・Amazon MemoryDB for Redis を利用。
・クラスタ構成は組まず1ノード1シャードで構成。
・データは以下のようにkeyValue型で登録。

 

<やろうとしたこと>
・トランザクション処理(Multi Exec)オペレーションで複数のキーに対して同時にValue を更新(マルチキー操作)。

 

<発生した事象>
・アプリケーションログに冒頭で記載した例外エラー出力し、終了。当然ながらデータも更新はされないままでした。。。

 

【Redisの仕様について】

当該エラーの発生起因を調べるとRedisの仕様や制限に関わるものであることが分かりました。 

<HashSlotに関して>

そもそもRedisクラスタのキー空間は16384個のスロットに分割されていて、key登録時にハッシュ値計算し、計算によってはじき出されたスロットにマップする仕様のようです。ちなみに、以下のアルゴリズムで値をはじき出しているとのことです。

「HASH_SLOT = CRC16(key) mod 16384」

結果として、keyのマッピングされるスロットは以下のようにランダム割り当てになります。

 

 

<マルチキー操作に対する制限>

Redisはクラスタモードで構成している場合且つマルチキー操作する場合、対象のkeyは同一のハッシュスロットに存在する必要があるとのことです。ちなみにAmazon MemoryDB for Redisではノードやシャード構成に関わらずクラスタモードは有効。そのうえで、エラーを読み取ると、「取り扱い対象の複数のキーは同じハッシュスロットにないからダメ」ってことになりますね。概要図にすると以下の感じです。

 

つまり解決策としては、マルチキー操作対象となるkeyを、明示的に同一のハッシュスロットに登録できればよいということですよね。

 

【どうしたか】
対象のkeyにタグ付けをすることで、同一のハッシュスロットにkey登録が可能です。その名も「ハッシュタグ」。データ登録時にkey値の前に"{}"で同一名でタグ付けすれば同一のハッシュスロットに強制的に登録されます。


タグ付無しの場合

key1:11111
key2:22222


ハッシュタグ付けありの場合

{hoge}:key1:11111
{hoge}:key2:22222

 

上記の通り、同一ハッシュスロットに登録することで、マルチキー操作も問題なく実行することが出来ました!

 

【まとめ】
Redisをクラスタモード有効状態で利用するときは、マルチキー操作時対象のkeyはハッシュスロットを用い同一のハッシュスロットに格納する必要が分かりました。Amazon MemoryDB for Redisはノードやシャード構成に関わらずクラスタモードとなるため、特に注意ですね。

 

【しかし懸念もある】
マルチキー操作をする可能性もあるから、という理由だけで何でもかんでも同一ハッシュスロットに収めるのはおすすめはできません。複数ノード化や、シャーディングによる分散処理を前提とした構成である場合は、「特定のハッシュスロットにデータ集中させる」=「特定ノードのみに負荷と処理集中が発生する」ことになり、分散処理のうまみが発揮されないことになります。

 

【最後に】 

しっかりとデータの取り扱い方を見極め、格納方式を決定するプロセスを設計時に組み込む必要性を強く感じました。本記事ではざっくりと紹介しましたが、そもそもNoSQLとはとか種類とか、Redisのノードとかシャードって?については書き出すとキリがないので別途紹介記事でも書こうと思います。