これは、なにをしたくて書いたもの?
Infinispan 14.0で「RESP endpoint」というものが実装され、Redis互換のエンドポイントをサポートするようになったというのでちょっと
試してみました。
なお、このブログには書かれていませんが、現時点でRESPエンドポイントは「実験的モジュール」扱いです。
RESPエンドポイント
RESPエンドポイントに関するドキュメントは、こちら。
Using the RESP protocol endpoint with Infinispan
以下のようなドキュメントの一覧ページには載っていないのですが、
Infinispan 14.0 documentation index
各ドキュメント内の「Document Index」の中から「RESP protocol endpoint」を選択すると見ることができます。
ドキュメントによると、RESPエンドポイントはRESP3を実装した実験的モジュールのようです。RESPエンドポイントを使うと、
Infinispan ServerをバックエンドとするRESPサーバーに対してRedisクライアントから接続し、Cache操作を行うことができます。
Infinispan Server includes an experimental module that implements the RESP3 protocol. The RESP endpoint allows Redis clients to connect to one or more one or several Infinispan-backed RESP servers and perform cache operations.
RESPエンドポイントのモジュールは、こちら。
https://github.com/infinispan/infinispan/tree/14.0.0.Final/server/resp
RESP3自体については、RedisのGitHubリポジトリに記載があります。
https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md
RESPというのは、「Redis Serialization Protocol」の略のようです。
Redis Serialization Protocol (RESP)
https://github.com/redis/redis-specifications/blob/master/protocol/README.md
RESPとは、クライアントとサーバーの間のリクエスト、レスポンスをどのように扱うかを設計したプロトコルです。クライアントがなんらかの
リクエストを実行し、サーバーがなんらかのデータを返すようなものです。
The protocol is designed to handle request-response chats between clients and servers, where the client performs some kind of request, and the server replies with some data.
RESP3では、以下のデータ型を扱えます。
- 配列
- Blob
- 文字列
- エラー
- Number
- Null
- Double
- Boolean
- Blobエラー
- Verbatim string
- Map
- Set
- Attribute
- Push
- Hello
Infinispan ServerのRESP3エンドポイントでサポートされているコマンドは、以下になります。
- AUTH
- DECR
- DEL
- ECHO
- GET
- HELLO
- INCR
- MGET
- MSET
- PING
- PUBLISH
- QUIT
- RESET
- SET
- SUBSCRIBE
- UNSUBSCRIBE
Using the RESP protocol endpoint with Infinispan / Redis commands
Redis本家と比べると、まだまだ少ないですね。
InfinispanとRedis
RESPエンドポイントに対するチケットはこちらです。
[ISPN-12439] Add server endpoint that implements RESP protocol from Redis - Red Hat Issue Tracker
このチケットにはInfinispan ServerにRESPを使ってRedisクライアントから接続できれば便利だ、と書かれているのですが。
It could be beneficial to have a server endpoint that we can enable to allow a Redis client to connect to Infinispan Server using the RESP protocol to perform cache operations.
Redisとして使えた方が、Infinispan Serverのユースケースが増えるんですかね…?
Redisの代替として使いたいというリクエストが多かったのでしょうか?
個人的には「今、この機能を追加するんだ…?」と思ったので、もう少し背景が知りたかったですね。
それはさておき、ちょっと試してみるとしましょう。
環境
今回の環境は、こちら。
$ java --version openjdk 17.0.4.1 2022-08-12 OpenJDK Runtime Environment Temurin-17.0.4.1+1 (build 17.0.4.1+1) OpenJDK 64-Bit Server VM Temurin-17.0.4.1+1 (build 17.0.4.1+1, mixed mode, sharing) $ bin/server.sh --version Infinispan Server 14.0.0.Final (Flying Saucer) Copyright (C) Red Hat Inc. and/or its affiliates and other contributors License Apache License, v. 2.0. http://www.apache.org/licenses/LICENSE-2.0
Infinispan Serverは、172.17.0.2で動作しているものとします。
起動は、以下のコマンドで行っておきます。
$ bin/server.sh \ -b 0.0.0.0 \ -Djgroups.tcp.address=`hostname -i`
RedisはCLIのみ使います。
$ bin/redis-cli --version redis-cli 7.0.5
RESPエンドポイントにRedis CLIから接続する
では、RESPエンドポイントにRedis CLIから接続してみましょう。
なお、Infinispan Serverを起動すると気づきますが、RESPエンドポイントはデフォルトで有効になっているようです。
2022-10-02 14:44:12,868 INFO (ForkJoinPool.commonPool-worker-1) [org.infinispan.SERVER] ISPN080018: Started connector Resp (internal)
デフォルトの状態では、認証情報なしで接続しようとするとエラーになります。
$ bin/redis-cli -h 172.17.0.2 -p 11222 172.17.0.2:11222> set key1 value1 (error) WRONGPASS invalid username-password pair or user is disabled.
そこで、まずはInfinispan Serverにユーザーを追加します。今回は、管理ユーザーとアプリケーションユーザーを追加しました。
$ bin/cli.sh user create -g admin -p password ispn-admin $ bin/cli.sh user create -g application -p password ispn-user
アプリケーションユーザーのユーザー名、パスワードを使って、もう1度Redis CLIから接続。
$ bin/redis-cli -h 172.17.0.2 -p 11222 --user ispn-user --pass password Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
今度は接続できたので、set
およびget
コマンドで確認。
172.17.0.2:11222> set key1 value1 OK 172.17.0.2:11222> get key1 "value1"
すごく、あっさり動きました…。
このデータが永続化されるかどうかなどは、RedisのふりをしているInfinispan ServerのCacheの設定次第ということになるわけですが。
RESPエンドポイントが使用するCacheについて
こうあっさり動いてしまうと、いろいろ気になります。まず、データはどのCacheに保存されているのでしょうか?
Infinispanの管理CLIでログイン。
$ bin/cli.sh -c- Username: ispn-admin Password:
Cacheを見ると、respCache
という見慣れないCacheがあります。
[c6b2176b23ba-18766@cluster//containers/default]> ls caches ___script_cache respCache
データを見てみます。
[c6b2176b23ba-18766@cluster//containers/default]> ls caches/respCache Key ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- key1 [c6b2176b23ba-18766@cluster//containers/default]> cache respCache [c6b2176b23ba-18766@cluster//containers/default]> get key1 value1
確かに、REPSエンドポイントで使われているCacheのようです。
Cacheの種類は、Replicated Cacheでした。
describe caches/respCache { "respCache" : { "replicated-cache" : { "mode" : "SYNC", "encoding" : { "key" : { "media-type" : "text/plain" }, "value" : { "media-type" : "application/octet-stream" } } } } }
このCache名は、RESPエンドポイントのドキュメントには記載がありませんでしたが、XML Schemaの方には記載がありました。
Names the cache that the RESP connector exposes. The default cache name is respCache.
respCache
というのは、RESPエンドポイントが使うデフォルトのCache名のようです。
このReplicated Cacheは、起動時に作成するようです。
そして、クラスタリングが有効になっている場合はReplicated Cacheに設定されます。
if (cacheManager.getCacheManagerConfiguration().isClustered()) { // We are running in clustered mode builder.clustering().cacheMode(CacheMode.REPL_SYNC); }
メディアタイプは、明示的に指定されていますね。キーはtext/plain
、値はapplication/octet-stream
ですね。
builder.encoding().key().mediaType(MediaType.TEXT_PLAIN_TYPE); builder.encoding().value().mediaType(MediaType.APPLICATION_OCTET_STREAM_TYPE);
RESPエンドポイントの設定を変えてみる
ドキュメントを見ていると、resp-connector
のcache
属性で使用するCacheを設定できそうです。
Using the RESP protocol endpoint with Infinispan / Enabling the RESP endpoint
といっても、起動時にCacheを作成してしまうのでした。
実際、デフォルトのinfinispan.xml
にはRESPエンドポイント用のCacheの定義はありません。
<cache-container name="default" statistics="true"> <transport cluster="${infinispan.cluster.name:cluster}" stack="${infinispan.cluster.stack:tcp}" node-name="${infinispan.node.name:}"/> <security> <authorization/> </security> </cache-container>
なんなら、エンドポイントの定義もなにもないわけですが。
<endpoints socket-binding="default" security-realm="default" />
ということは、Cacheを明示的に定義する場合はInfinispan Serverの起動前に行う必要がありますね。
まずは、ドキュメントに習ってRESPエンドポイントを設定してみます。myRespCache
というCacheを使うように設定してみました。
<endpoints socket-binding="default" security-realm="default"> <endpoint> <resp-connector cache="myRespCache"> <authentication/> </resp-connector> <hotrod-connector> <authentication> <sasl mechanisms="SCRAM-SHA-512 SCRAM-SHA-384 SCRAM-SHA-256 SCRAM-SHA-1 DIGEST-SHA-512 DIGEST-SHA-384 DIGEST-SHA-256 DIGEST-SHA DIGEST-MD5 PLAIN" server-name="infinispan" qop="auth"/> </authentication> </hotrod-connector> <rest-connector> <authentication mechanisms="DIGEST BASIC"/> </rest-connector> </endpoint> </endpoints>
Hot RodエンドポイントとRESTエンドポイントは明示的に設定が必要です。
認証が有効になっているInfinispan Serverでは、Hot RodエンドポイントまたはRESTエンドポイントの少なくともどちらかは認証の設定が
行われている必要があるようです。
単にRESPエンドポイントの設定だけすれば良いと思って、以下のような状態にしてしまうと
<endpoints socket-binding="default" security-realm="default"> <endpoint> <resp-connector cache="myRespCache"> <authentication/> </resp-connector> </endpoint> </endpoints>
Infinispan Serverが起動に失敗します。
2022-10-02 16:09:28,754 FATAL (main) [org.infinispan.SERVER] ISPN080028: Infinispan Server failed to start org.infinispan.commons.CacheConfigurationException: ISPN080070: The cache container requires authorization, but none of the connectors enable authentication
endpoint
を定義したら、Hot RodエンドポイントもRESTエンドポイントも明示的に設定しなければいけません。
気を取り直して、Infinispan Serverを再起動します。
すると、RESPエンドポイントに指定した名前でCacheが作成されていました。
Redis CLIでデータを保存したりするとこのCacheに格納されますが、確認は省略。
次に、infinispan.xml
に明示的にCacheを定義して、そちらを使うようにしてみましょう。
今回はDistributed Cacheを定義。
<cache-container name="default" statistics="true"> <transport cluster="${infinispan.cluster.name:cluster}" stack="${infinispan.cluster.stack:tcp}" node-name="${infinispan.node.name:}"/> <distributed-cache name="distributedRespCache"> <encoding> <key media-type="text/plain"/> <value media-type="application/octet-stream"/> </encoding> </distributed-cache> <security> <authorization/> </security> </cache-container>
RESPエンドポイントは、distributedRespCache
を参照するように設定。
<endpoints socket-binding="default" security-realm="default"> <endpoint> <resp-connector cache="distributedRespCache"> <authentication/> </resp-connector> <hotrod-connector> <authentication> <sasl mechanisms="SCRAM-SHA-512 SCRAM-SHA-384 SCRAM-SHA-256 SCRAM-SHA-1 DIGEST-SHA-512 DIGEST-SHA-384 DIGEST-SHA-256 DIGEST-SHA DIGEST-MD5 PLAIN" server-name="infinispan" qop="auth"/> </authentication> </hotrod-connector> <rest-connector> <authentication mechanisms="DIGEST BASIC"/> </rest-connector> </endpoint> </endpoints>
これで、Infinispan Serverを再起動。
定義したDistributed Cacheが現れます。
[3f666276f239-57422@cluster//containers/default]> ls caches distributedRespCache ___script_cache
定義の確認。
[3f666276f239-57422@cluster//containers/default]> describe caches/distributedRespCache { "distributedRespCache" : { "distributed-cache" : { "mode" : "SYNC", "remote-timeout" : "17500", "statistics" : true, "encoding" : { "key" : { "media-type" : "text/plain" }, "value" : { "media-type" : "application/octet-stream" } }, "locking" : { "concurrency-level" : "1000", "acquire-timeout" : "15000", "striping" : false }, "state-transfer" : { "timeout" : "60000" } } } }
Redis CLIから、再度データを保存してみましょう。
172.17.0.2:11222> set key1 value1 OK 172.17.0.2:11222> get key1 "value1"
Infinispan側からも確認してみます。
[3f666276f239-57422@cluster//containers/default]> ls caches/distributedRespCache Key ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- key1 [3f666276f239-57422@cluster//containers/default]> cache distributedRespCache [3f666276f239-57422@cluster//containers/default/caches/distributedRespCache]> get key1 value1
OKですね。
オマケ
RESPエンドポイントで実装されているコマンドを確認するは、このあたりを見るとよさそうです。
また、内部的にはLettuceも使われていたりして、ちょっと面白いです。
まとめ
Infinispan 14.0で追加された、RESPエンドポイントを試してみました。
割と簡単に使えるのですが、ちょっと動きを変えようとすると癖がある…というかドキュメントがあまり書かれていない感じがするので
ちょっと注意ですね。
個人的には、この機能の使いどころが気になるところですが…実験的モジュールのようなので、もう少し様子をみましょうか。