仕事では結構前から使っていたのですが、最近プライベートな小規模開発でも Redis を使う機会が増えてきました。
イマイチな点もありますが、正しく使えば便利なデータストアなので、一度各言語別の接続方法をまとめておきます。
前準備
まずは、接続先のRedisサーバを用意する必要があるので、ローカル環境用のRedisサーバを用意します。
(AWSのElastiCacheなど、接続先が既に存在する場合はこの手順は不要です)
【Mac】
homebrewでインストールするのが管理的にも楽ですね。
1 |
brew install redis |
インストールしたらコンソールからredisサーバを起動。
1 |
redis-server |
起動したRedisサーバに接続し、テストデータを入れてみて接続確認します。
1 2 3 4 5 6 7 |
redis-cli -h localhost localhost:6379> set test-key test-value OK localhost:6379> get test-key "test-value" localhost:6379> del test-key (integer) 1 |
-h の後が接続先のホスト名になるので、ElastiCacheに繋ぐ場合などはEndPointのURLに置き換えてください。
(デフォルトがlocalhostなのでローカル環境では -h オプションは不要です)
【Windows】
Redis自体がWindows環境をサポートしていないようなのでMSOpenTeckを利用して使うそうです。
試していませんが、こちらとか参照して進めれば使えるようになるはず!
環境が用意できたところで、各言語別の接続方法をざっと書いていきます。
(とりあえず5つほど書きますが、要望があればその他の言語も追記します)
Ruby
Java
Python
Node.js
PHP
Ruby
接続用ライブラリに redis を使用するので事前に用意しておきます。
1 |
gem install redis |
* permission error で拒否される場合は、sudo をつけて実行で対処します
後は、以下のように自由に操作するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
require 'redis' # ここはそれぞれの環境に合わせて書き換える REDIS_HOST_NAME = "localhost" REDIS_PORT_NO = 6379 redis = Redis.new(:host => REDIS_HOST_NAME, :port => REDIS_PORT_NO) # 操作は基本的にRedisのコマンド名をそのまま使用 # String redis.set("string-key", "string-value") # List redis.rpush("list-key", "list-value1") redis.rpush("list-key", "list-value2") # Set redis.sadd("set-key", "set-value1") redis.sadd("set-key", "set-value2") # Sortedset redis.zadd("sortedset-key", [[10, "value1"], [20, "value2"]]) # Hash redis.hset("hash-key", "member-name", "hash-value") redis.hset("hash-key", "member-name2", "hash-value2") |
Sortedsetに追加するzaddの書き方に少し癖があるぐらいで、後は環境の用意含めて非常に楽です。
Java
接続用ライブラリに Jedis を使用するのでmavenのpom.xmlに以下のように書いて用意しておきます。
以下の例では2016年10月時点での最新バージョンの2.9.0を落としていますが、バージョンは最新のものに書き換えてください。
1 2 3 4 5 6 |
<!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency> |
後は、以下のように自由に操作するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
package java.redis.sample; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; public class JavaRedisSample { // ここはそれぞれの環境に合わせて書き換える private static final String REDIS_HOST_NAME = "localhost"; private static final int REDIS_PORT_NO = 6379; public static void main(String... args) { JedisPool pool = new JedisPool(REDIS_HOST_NAME, REDIS_PORT_NO); Jedis jedis = null; try { jedis = pool.getResource(); // 操作は基本的にRedisのコマンドをそのまま使用 // String jedis.set("string-key", "string-value"); // List jedis.rpush("list-key", "list-value1"); jedis.rpush("list-key", "list-value2"); // Set jedis.sadd("set-key", "set-value1"); jedis.sadd("set-key", "set-value2"); // Sortedset jedis.zadd("sortedset-key", 10, "value1"); jedis.zadd("sortedset-key", 20, "value2"); // Hash jedis.hset("hash-key", "member-name", "hash-value"); jedis.hset("hash-key", "member-name2", "hash-value2"); // 最後に必ずpoolにインスタンスを返す pool.returnResource(jedis); } catch (Exception e) { // 接続障害などで落ちた場合もインスタンスを閉じる if (jedis != null) { jedis.close(); } } } } |
Redisのコマンドをそのまま書くだけなので非常にシンプルです。
poolを使ってインスタンスを管理する場合は、必ずインスタンスを閉じるのを徹底しないとpoolの枯渇が起こるので注意ですね。
Python
接続用ライブラリに redis を使用するので事前に用意しておきます。
1 |
pip install redis |
* pip が未インストールの場合は、公式からDL or 使用するpythonを brew install python で落としてきた方に変更のどちらかで対処します
後は、以下のように自由に操作するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# -*- coding: utf-8 -*- import redis # ここはそれぞれの環境に合わせて書き換える REDIS_HOST_NAME = "localhost" REDIS_PORT_NO = 6379 r = redis.Redis(host = REDIS_HOST_NAME, port = REDIS_PORT_NO) # 操作は基本的にRedisのコマンド名をそのまま使用 # String r.set("string-key", "string-value") # List r.rpush("list-key", "list-value1") r.rpush("list-key", "list-value2") # Set r.sadd("set-key", "set-value1") r.sadd("set-key", "set-value2") # Sortedset r.zadd("sortedset-key", value1 = 10, value2 = 20) # Hash r.hset("hash-key", "member-name", "hash-value") r.hset("hash-key", "member-name2", "hash-value2") |
PythonもSortedsetの入れ方に特徴がありますね。
Node.js
接続用ライブラリに redis を使用するので事前に用意しておきます。
1 |
npm install redis |
* npm が未インストールの場合は、homebrew の brew install node で対処します
後は、以下のように自由に操作するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// ここはそれぞれの環境に合わせて書き換える const REDIS_HOST_NAME = 'localhost'; const REDIS_PORT_NO = 6379; var redis = require('redis'), client = redis.createClient(REDIS_PORT_NO, REDIS_HOST_NAME); client.on("error", function (err) { // Redis接続時エラーの処理を記載する場合はここに書く }); // 操作は基本的にRedisのコマンド名をそのまま使用 // String client.set("string-key", "string-value") // List client.rpush("list-key", "list-value1") client.rpush("list-key", "list-value2") // Set client.sadd("set-key", "set-value1") client.sadd("set-key", "set-value2") // Sortedset client.zadd("sortedset-key", 10, "value1") client.zadd("sortedset-key", 20, "value2") // Hash client.hset("hash-key", "member-name", "hash-value") client.hset("hash-key", "member-name2", "hash-value2") |
書き方はNode.jsが一番オーソドックスかもしれません。
constがIE10以下ではサポートされていません問題については、今回は一旦抜きで…
PHP
接続用ライブラリに phpredis を使用するので事前に用意しておきます。
用意の仕方は色々ありますが、使用しているPHPバージョンに応じたFormulaをhomebrewでインストールするのが早いです。
以下の例ではMacにデフォルトで入っているPHP5.5用のphp-redisを落としていますが、各自の環境に合わせて数字部分を変えてください。
1 |
brew install php55-redis |
* .bash_profile(.zshrc) にhomebrewで落としたPHPのパスを通さないと使えるようにならないので忘れずに行うようにしましょう
1 |
echo export PATH=$(brew --prefix)/bin:$PATH >> ~/.bash_profile(.zshrc) |
後は、以下のように自由に操作するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php // ここはそれぞれの環境に合わせて書き換える define('REDIS_HOST_NAME', 'localhost'); define('REDIS_PORT_NO', 6379); $redis = new Redis(); $redis->connect(REDIS_HOST_NAME, REDIS_PORT_NO); // 操作は基本的にRedisのコマンド名をそのままキャメルケースにして使用 // String $redis->set("string-key", "string-value"); // List $redis->rPush("list-key", "list-value1"); $redis->rPush("list-key", "list-value2"); // Set $redis->sAdd("set-key", "set-value1"); $redis->sAdd("set-key", "set-value2"); // Sortedset $redis->zAdd("sortedset-key", 10, "value1"); $redis->zAdd("sortedset-key", 20, "value2"); // Hash $redis->hset("hash-key", "member-name", "hash-value"); $redis->hset("hash-key", "member-name2", "hash-value2"); ?> |
redisコマンドをキャメルケースで書くのは個人的に少し違和感が…
後、phpredisの用意は、composerで用意した方が楽かもしれません。
必要とするライブラリや細かい文法が若干違うだけで、基本的にはどの言語も一緒ですね。
今回載せたのは基本コマンドだけですが、もちろんRedisのその他コマンドも使用可能なので公式リファレンスを見て色々試してみてください。
また、全言語共通して接続の詳細設定を設定する事も可能なので、指定したい場合は別途confファイルを用意して設定して下さい。
Redisの適切な使用用途について
RedisはオンメモリのKVSという特性上、その他のデータストアと比較して非常に高速であったりと便利な部分もある反面、保存可能容量が少ないことや、キーに入ったデータの管理が難しいこと、そもそも揮発性なのでいつ消えてもおかしくない(データの永続化は可能)などの難しい側面もあります。
メインのデータストアとして使うのではなく、あくまでもキャッシュDBとして考えるのが良さそうです。
最後に、色々使ってみて感じた個人的に適切だと思う使い方についていくつか書いて終わりにします。
1. メインDBから取得すると時間がかかる重い取得処理のキャッシュDBとして使用
メインDBから取得することも可能なものの、取得に時間がかかり毎回取りにいくのはパフォーマンス的に厳しいデータのキャッシュ保存先として使う方法です。
履歴系テーブルに保存されたデータのユーザ毎のカウント数や最終更新日時などを入れておく使い方で、おそらくこの用途が一番多くRedisで使われていそうです。
user-id-1: {
login-count: 3,
last-login-time: ‘2016-10-31 01:12:126’,
footprint-count: 123,
last-footprint-time: ‘2016-10-31 02:04:257’
}
上記のようなデータの持たせ方をしておき、user-id-の後の1の部分を各ユーザのIDで置き換える感じです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
require 'redis' # ここはそれぞれの環境に合わせて書き換える REDIS_HOST_NAME = "localhost" REDIS_PORT_NO = 6379 redis = Redis.new(:host => REDIS_HOST_NAME, :port => REDIS_PORT_NO) begin login_count = redis.hget("user-id-1", "login-count") rescue Redis::CannotConnectError => e # Redisコネクションエラー時処理をここに書く(ログ出力など) end if login_count.nil? # Redisからデータ取得ができない場合は、メインDBへのデータ取得処理を行う end |
取得処理はこんな感じでしょうか。
大事なのは、Redisからデータが取得できなかった場合(接続エラーなども含む)には必ずメインDBから取得処理を追加で行うようにしておき、取得速度の観点以外でRedisに依存しないようにしておく事ですね。
2. 各ジャンル別ランキング管理用DBとして使用
Redisには Sortedset というランキング管理に非常に向いたデータ型が存在するので、ジャンル別の売上数ランキングや評価レートランキングなどに使う方法です。
ganle-book-sales: {
book-name-a: 2,
book-name-b: 0,
book-name-c: 3,
book-name-d: 1
}
ganle-book-rate: {
book-name-a: 3.5,
book-name-b: 0,
book-name-c: 4.0,
book-name-d: 2.5
}
キーをもっと細かくすれば小分類毎のランキングなども作れますし、普通にやろうとすると非常に重そうなランキング表示もRedisなら楽々です。
1 |
zrevrange ganle-book-sales 0 100 |
スコアの降順に最大100件取得したいなら、こんな感じです。
一点注意なのは、挿入処理のバグやRedis障害発生などでデータが壊れても大丈夫なようにレプリケーション設定は必ずやっておきたいです。
AWSのElasticacheを採用するユーザが多いのは、バックアップや自動フェールオーバーも楽に設定できたりな耐障害性の面が大きい気がします。
3. サーバ監視など、サービス本体とは分離させた形で使用
サービス本体がRedisに依存してしまうのはできるだけ避けたいところですが、仮にRedisが止まってもサービス本体に影響が出ない形で使用するならば選択肢の一つとして有ではないでしょうか。
サーバ監視が止まってしまうのはそれはそれで怖いですが、Redis自身への監視を別に用意しておけばRedisが止まってしまう発生頻度を考えても良い選択肢だと個人的には思います。
代表的なサーバ監視のSensu&UchiwaがRedisを使っているのも大きいです。
長くなってしまいましたが、冒頭で書いた通り適切な使い方をすれば重宝するデータストアなので今後も使っていきたいです。