NoSQLじゃないRedisをもっと知ってほしい
みんな大好きなRedisいいですよね。私もお世話になっています。
RedisといえばNoSQLのキーバリューストアとして使ったり、キャッシュ置き場として使うのが一般的かと思います。とはいってもそんなパフォーマンスを求められる使い方が必要になるには相当数のアクセスがあるサイトを開発しているエンジニアだけが必要なもの?
いや、Redisはもっとできる子なんです。今回の記事では小規模な開発でも、キーバリューストアやキャッシュ用途以外の使い道があるよということをまとめてみました。
1. メッセージキューとして使う
複数のプロセス間でメッセージキューを使って値の受け渡しをするようなことがあるかと思います。
RDBを用いた場合は
- 値の挿入
- 値の取得
- 読み取った値の削除
という処理になるかと思いますが、Redisの型の一つリスト型
を用いることで簡単にメッセージキューとを実装することができます。
まずメッセージの投入側ではリストの先頭からメッセージを追加していきます。
LPUSH MyQueue "MessageA" => MyQueueは["MessageA"]
LPUSH MyQueue "MessageB" => MyQueueは["MessageB","MessageA"]
SpringDataRedisを使用すると上記Redisコマンドはこのようになります。
@Autowired
private RedisTemplate redisTemplate;
public void lpush() {
redisTemplate.opsForList().leftPush("MyQueue", "MessageA");
redisTemplate.opsForList().leftPush("MyQueue", "MessageB");
}
SpringBootでRedisを使用するための設定については Java: Spring Boot で Redis を使う! - akihyrox が参考になります。
メッセージの取り出し側ではリストの末尾からメッセージを追加していきます。
RPOP MyQueue ==> MessageAが返される
RPOP MyQueue ==> MessageBが返される
SpringDataRedisを使用すると上記Redisコマンドはこのようになります。
@Autowired
private RedisTemplate redisTemplate;
public void lpush() {
String v;
v = redisTemplate.opsForList().rightPop("MyQueue");
v = redisTemplate.opsForList().rightPop("MyQueue");
}
このメッセージのやり取りはRedisを介することで、異なるプロセスの間で可能なので実行したいメソッドやその時のパラメーターなどをメッセージとしてやり取りすることでメッセージキューとして使用することができます。
実際の運用ではRPOPLPUSHを用いて、実行中のメッセージを別のリスト(実行中リスト)に移してから実行終了時に実行中リストから削除するという実装が良いと思います。
2. ロックとして使う
Webのリクエストによってデータを登録するような処理の場合、重複登録しないように何らかのロックをかける必要があります。RDB上にロックテーブルを作成してロックフラグをチェックさせるようなこともありますが、ロックの解除に失敗した場合ロックテーブル上のフラグが残ったままになってしまう危険性があります。
RedisではSETNX
というコマンドを使用することで簡単にロック機構を実装することが可能です。
Redisで文字列を格納するときに使用するコマンドにSET
というコマンドを用いますが、SETNX
は
- キーが存在していない場合には値をセットしてその返り値として 1 を返します。
- キーが既にあった場合は、値をセットしないでその返り値として 0 を返します。
SETNX MyLockKey "Locked" ==> 返り値は 1
SETNX MyLockKey "Locked2" ==> 返り値は 0 MyLockKeyの値は "Locked"のまま
この返り値を見ることでロックされているかどうかを取得することができます。
また、Redisでは登録したキーに対して有効期限(Expire)を指定することができます。
有効期限を過ぎたキーはRedisがキーを削除してくれますので万が一キーの削除に失敗した場合でもオペレーションなしでロックを外すことができます。
上記のSETNX
を用いた例では、下記のようにEXPIRE
指定します。この例ではキーMyLockKey
に対して60秒の有効期限を設けています。
SETNX MyLockKey "Locked"
EXPIRE MyLockKey 60
SpringDataRedisを使用するとロック処理はこのようになります。
@Autowired
private RedisTemplate redisTemplate;
public void process() {
while (true) {
// ロックがかかっていないで、値が登録できた場合はisLock = true
// すでに値が登録されていた場合はisLock = false
Boolean isLock = redisTemplate.opsForValue().setIfAbsent("MyLockKey", "Locked");
// 60秒のExpireを設定
redisTemplate.expire("MyLockKey", 60, TimeUnit.Seconds);
if (isLock) {
// ロック取得した後の処理
// ここで上のメッセージキューを読みだして処理を行うとかできます。
.....
// 正常終了した後のロック解除
redisTemplate.delete("MyLockKey");
} else {
// ロック中
}
}
}
参考
redisドキュメント日本語訳 データ型-文字列型
Redisのsetnxを使ってマルチサーバ環境での Web API ロック機構を実現する - Developers.IO
3. メッセージングのPub/Subに使う
HTTPのリクエスト以外のトリガーによって何らかの処理を実行したいようなケースではPublish/Subscribeを用いたメッセージングの仕組みを用いると任意のタイミングで処理の実行が可能になります。
Redisにはこのための仕組みが組み込まれていますので簡単にメッセージングの実装が可能です。
メッセージの送信には PUBLISH
を用いて 購読にはSUBSCRIBE
を用います。
SUBSCRIBEコマンドを実行すると引数となるチャンネルに対してPUBLISHが行われるまで待ち受けをします。
SUBSCRIBE MyMessage
この状態で別のプロセスからこのチャンネルに対してPULISHを行います。
PUBLISH MyMessage "Send Message"
すると、SUBSCRIBE側でメッセージを受信し次のメッセージが来るまで再び待ち続けます。
SpringDataRedisを用いたPub/Sub実装は少し長くなるので、こちらのサイトを参照してみてください。
PubSub Messaging with Spring Data Redis -baeldung
参考
redisドキュメント日本語訳 パブリッシュ/サブスクライブ
余談ですが
http://www.baeldung.com には、SpringBootを用いた実装例が簡潔に多く掲載されており非常に参考になります。
spring関連のインデクス
http://www.baeldung.com/category/spring/
Author And Source
この問題について(NoSQLじゃないRedisをもっと知ってほしい), 我々は、より多くの情報をここで見つけました https://qiita.com/euledge/items/38bf182b0e27ccc77616著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .