networkaddress.cache.ttlを試す
networkaddress.cache.ttl
とは
名前解決して得たアドレスをキャッシュする秒数を設定するためのセキュリティプロパティです。
デフォルト値は次の通りとなっています。
- セキュリティマネージャーがインストールされている場合は
-1
(永久) - セキュリティマネージャーがインストールされていない場合は実装依存(Liberica JDKは30秒)
これを設定する方法は2つあって、1つは$JAVA_HOME/conf/security/java.security
へ記載する方法、もう1つはJavaアプリケーションの中でjava.security.Security#setProperty
を呼び出す方法です。
なお、最初の名前解決時に設定が読み込まれて固定されるのでjava.security.Security#setProperty
を使用する場合は最初の名前解決前に設定する必要があります。
今回は後者を試します。
動作確認する構成
Javaアプリケーション、PostgreSQL(2台)、DNSサーバーを用意してJavaアプリケーションからPostgreSQLを名前解決してアクセスします。
その際、名前に対応するPostgreSQLを切り替えて規定の秒数後にJavaアプリケーションが切り替え後のアドレスを正しく認識するのか、つまりnetworkaddress.cache.ttl
が効いているのかを確認します。
環境全体はDockerを、DNSサーバーはConsulを、アプリケーションのフレームワークはSpring Bootを使用します。
アプリケーションの説明
動作確認用のアプリケーションは次のリポジトリに置いてあります。
メインクラスで環境変数NETWORKADDRESS_CACHE_TTL
を読み取ってnull
でなければそれをそのままセキュリティプロパティnetworkaddress.cache.ttl
へ設定しています。
また、DBアクセスする際はHikariCPを使用せずDriverManager
で都度DB接続しています。
動作確認の準備
まずJavaアプリケーションが1台目のPostgreSQLへ繋がる状態(構成図の1つめの状態)を作ります。
最初にネットワークを作成します。
docker network create --subnet 172.16.0.0/24 demo-nw
次にConsulを起動します。
docker run -d --name dns --network demo-nw --ip 172.16.0.10 \
-p 8500:8500 -p 8600:53/udp consul:1.13 \
agent -dev -client=0.0.0.0 -dns-port=53
1台目のPostgreSQLを起動します。
docker run -d --name db1 --network demo-nw --ip 172.16.0.20 \
-e POSTGRES_PASSWORD=password postgres:15
テーブルを作成してデータを投入します。
docker exec db1 psql -U postgres -c "create table demo ( \
id integer primary key, name varchar(10)); \
insert into demo (id, name) values (1, 'DB1')"
2台目のPostgreSQLも準備します。
docker run -d --name db2 --network demo-nw --ip 172.16.0.30 \
-e POSTGRES_PASSWORD=password postgres:15
テーブルを作成してデータを投入します。
1台目とはdemo
テーブルのname
カラムに設定する値が異なります。
これでどちらのPostgreSQLへ繋がっているのかを確認します。
docker exec db2 psql -U postgres -c "create table demo ( \
id integer primary key, name varchar(10)); \
insert into demo (id, name) values (1, 'DB2')"
1台目のPostgreSQLのアドレスをConsulへ登録します。
docker exec dns consul services register -address=172.16.0.20 -name=db
digで確認
登録されたアドレスをdig
で確認します。
dig @127.0.0.1 -p 8600 db.service.dc1.consul
次のような内容が返されるはずです。
; <<>> DiG 9.10.6 <<>> @127.0.0.1 -p 8600 db.service.dc1.consul
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 10550
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;db.service.dc1.consul. IN A
;; ANSWER SECTION:
db.service.dc1.consul. 0 IN A 172.16.0.20
;; Query time: 2 msec
;; SERVER: 127.0.0.1#8600(127.0.0.1)
;; WHEN: Sun Nov 06 07:35:51 JST 2022
;; MSG SIZE rcvd: 66
アプリケーションをビルドします。
./mvnw spring-boot:build-image
アプリケーションを実行します。
networkaddress.cache.ttl
は10秒に設定しました。
docker run -d --name app --network demo-nw --ip 172.16.0.40 \
--dns 172.16.0.10 -p 8080:8080 \
-e NETWORKADDRESS_CACHE_TTL=10 \
-e JAVA_OPTS='-Duser.timezone=Asia/Tokyo' \
networkaddress-cache-ttl-example:0.0.1-SNAPSHOT
curl
でアプリケーションへアクセスして確認してみましょう。
curl -s localhost:8080
次のような内容が返されるはずです。
{"name":"DB1","dateTime":"2022-11-06T16:16:25"}
以上で準備が整いました。
動作確認
次のようにして動作確認します。
- 1秒毎に
curl
を行う - 任意のタイミングでDNSサーバー(Consul)へ登録しているPostgreSQLのアドレスを変更する
- 10秒後にPostgreSQLから取得する値が変化する、つまり名前解決のキャッシュが切れて新しく名前解決していることを確認する
まず新しくコンソールを立ち上げて次のコマンドで1秒毎にcurl
を行います。
while true; do curl -s -w '\n' localhost:8080; sleep 1; done
次に任意のタイミングでDNSサーバー(Consul)へ登録されているPostgreSQLのアドレスを1台目から2台目へ変更します。
docker exec dns consul services deregister -id=db
docker exec dns consul services register -address=172.16.0.30 -name=db
curl
を行なっているコンソールを見て取得している値が"DB1"
から"DB2"
へ変化することを確認します。
{"name":"DB1","dateTime":"2022-11-06T16:18:00"}
{"name":"DB1","dateTime":"2022-11-06T16:18:02"}
{"name":"DB1","dateTime":"2022-11-06T16:18:03"}
{"name":"DB1","dateTime":"2022-11-06T16:18:04"}
{"name":"DB1","dateTime":"2022-11-06T16:18:05"}
{"name":"DB1","dateTime":"2022-11-06T16:18:06"}
{"name":"DB1","dateTime":"2022-11-06T16:18:07"}
{"name":"DB1","dateTime":"2022-11-06T16:18:08"}
{"name":"DB1","dateTime":"2022-11-06T16:18:09"}
{"name":"DB1","dateTime":"2022-11-06T16:18:10"}
{"name":"DB2","dateTime":"2022-11-06T16:18:11"}
{"name":"DB2","dateTime":"2022-11-06T16:18:12"}
{"name":"DB2","dateTime":"2022-11-06T16:18:13"}
また、任意のタイミングでDNSサーバー(Consul)へ登録されているPostgreSQLのアドレスを2台目から1台目へ戻して、curl
で取得している値が"DB2"
から"DB1"
へ変化することも確認します。
docker exec dns consul services deregister -id=db
docker exec dns consul services register -address=172.16.0.20 -name=db
{"name":"DB2","dateTime":"2022-11-06T16:18:11"}
{"name":"DB2","dateTime":"2022-11-06T16:18:12"}
{"name":"DB2","dateTime":"2022-11-06T16:18:13"}
{"name":"DB2","dateTime":"2022-11-06T16:18:14"}
{"name":"DB2","dateTime":"2022-11-06T16:18:15"}
{"name":"DB2","dateTime":"2022-11-06T16:18:16"}
{"name":"DB2","dateTime":"2022-11-06T16:18:17"}
{"name":"DB2","dateTime":"2022-11-06T16:18:18"}
{"name":"DB2","dateTime":"2022-11-06T16:18:19"}
{"name":"DB2","dateTime":"2022-11-06T16:18:20"}
{"name":"DB1","dateTime":"2022-11-06T16:18:21"}
{"name":"DB1","dateTime":"2022-11-06T16:18:22"}
{"name":"DB1","dateTime":"2022-11-06T16:18:23"}
以上で動作確認ができました。
コンテナの後始末
docker stop app db1 db2 dns
docker rm app db1 db2 dns
docker network rm demo-nw
docker rmi networkaddress-cache-ttl-example:0.0.1-SNAPSHOT
Discussion