これは、なにをしたくて書いたもの?
Redisのクライアントライブラリを使っていると、たまにデータベースのインデックスらしいきものを指定させられることが
あります。
redis-cli
のドキュメントでURI指定して接続している例だと、0
の部分ですね。
$ redis-cli -u redis://p%40ssw0rd@redis-16379.hosted.com:16379/0 ping PONG
redis-cli, the Redis command line interface – Redis
これがなんなのかはなんとなく予想できないことはないですが、気にはなっていたのでちゃんと見てみようと思います。
databases
Redisは、複数のデータベースを持ちます。設定ファイルのドキュメントに記載のある、databases
が該当します。
# Set the number of databases. The default database is DB 0, you can select # a different one on a per-connection basis using SELECT <dbid> where # dbid is a number between 0 and 'databases'-1 databases 16
https://raw.githubusercontent.com/redis/redis/6.0/redis.conf
0から始まり、databases
- 1までの数のデータベースを持ちます。dbid
というみたいですね。
設定は、config get
コマンドで確認できます。
databases
の説明は、select
コマンドにもうちょっと書いてあります。select
コマンドを使うと、使用するデータベースを
切り替えることができます。
データベースは複数ありますが、(永続化した場合)同じRDB、AOFファイルに保存されます、と。
Selectable Redis databases are a form of namespacing: all databases are still persisted in the same RDB / AOF file.
関連の無い複数のアプリケーションで、ひとつのRedisを使わない方が良いとしています。
not to use a single Redis instance for multiple unrelated applications.
また、Redis Clusterでは0
のデータベースしかサポートしていないようです。
When using Redis Cluster, the SELECT command cannot be used, since Redis Cluster only supports database zero.
この時点で、もういいかなぁとか思ったりします…。
ちなみに、現在の接続がどのデータベースを使っているかはわからないそうですが、Redisに接続しているクライアントが
どのデータベースを使っているかはclient list
コマンドで確認できるようです。
ドキュメントはこれくらいにして、実際に試してみましょう。
環境
今回の環境は、こちら。Redis 6.2.5を使います。
$ redis-server --version Redis server v=6.2.5 sha=00000000:0 malloc=jemalloc-5.1.0 bits=64 build=e19c0ce090e3ecc7
起動コマンドは、こちらで。
$ redis-server --bind '0.0.0.0' --requirepass [パスワード]
Redisで複数データベースを使ってみる
とりあえず、redis-cli
でRedisに接続してみます。
$ redis-cli -a [パスワード]
config get
でdatabases
を見てみます。
127.0.0.1:6379> config get databases 1) "databases" 2) "16"
16ですね。1度Redisを停止して、databases
を32にして起動してみましょう。
$ redis-server --bind '0.0.0.0' --requirepass [パスワード] --databases 32
今度は、32になりました。
127.0.0.1:6379> config get databases 1) "databases" 2) "32"
これで、32個のデータベースを持っていることになります。
16に戻しましょう。
$ redis-server --bind '0.0.0.0' --requirepass [パスワード]
デフォルトでは0のデータベースに接続するようですが、redis-cli
の-n
オプションで使用するデータベースを指定することが
できます。たとえば、3を指定。
$ redis-cli -a redispass -n 3
すると、redis-cli
での表示でポートの隣に数字が表れます。
127.0.0.1:6379[3]>
select
で、データベースを変更してみましょう。15に変更します。
127.0.0.1:6379[3]> select 15 OK 127.0.0.1:6379[15]>
現在のdatabases
は16なので、16 - 1で15までデータベースが使用可能です。16を指定すると、エラーになります。
127.0.0.1:6379[15]> select 16 (error) ERR DB index is out of range
0に戻すと、ポートの表示がなくなります。
127.0.0.1:6379[15]> select 0 OK 127.0.0.1:6379>
見慣れた表示になりましたね。
-n
を指定せずに接続した時と同じですね。
$ redis-cli -a [パスワード] Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe. 127.0.0.1:6379>
次に、データベースを変更すると、データが分離されていることも確認してみましょう。
データベースの0で、set
します。
127.0.0.1:6379> set key1 value1 OK 127.0.0.1:6379> get key1 "value1"
データベースの1に切り替え。
127.0.0.1:6379> select 1 OK
get
してみます。
127.0.0.1:6379[1]> get key1 (nil)
取得できませんね。逆もやってみましょう。
127.0.0.1:6379[1]> set key2 value2 OK 127.0.0.1:6379[1]> get key2 "value2" 127.0.0.1:6379[1]> select 0 OK 127.0.0.1:6379> get key2 (nil)
確認できましたね。
まあ、実際のアプリケーションでこんな感じで接続途中に切り替えるとよくわからないことになる気がするので、
基本的には接続とデータベースを紐づけて管理するんでしょうね。
クライアントライブラリを使って確認してみる
最後に、クライアントライブラリを使って確認してみましょう。今回はPythonを使います。
$ python3 -V Python 3.8.10
redis-pyと、pytestを使って確認してみます。
$ pip3 install redis==3.5.3 pytest==6.2.5
Redisは、172.17.0.2で動作しているものとします。
確認したテストコードは、こちらです。
test_redis.py
import redis from redis import Redis def test_redis_database_indexes(): redis_default: Redis = redis.Redis(host='172.17.0.2', port=6379, password='[パスワード]', decode_responses=True) redis0: Redis = redis.Redis(host='172.17.0.2', port=6379, password='[パスワード]', db=0, decode_responses=True) redis1: Redis = redis.Redis(host='172.17.0.2', port=6379, password='[パスワード]', db=1, decode_responses=True) redis_default.set('key1', 'value1') assert redis_default.get('key1') == 'value1' assert redis0.get('key1') == 'value1' assert redis1.get('key1') is None redis1.set('key2', 'value2') assert redis1.get('key2') == 'value2' assert redis_default.get('key2') is None assert redis0.get('key2') is None redis_default.close() redis0.close() redis1.close()
こちらでも確認できました、と。