AWS: JavaのDNSキャッシュ ( TTL )について
AWSのサービスではDNSを用いて可用性を向上する仕組みを用いている。
- 各種APIのエンドポイント
- RDSのエンドポイント
- ELBのエンドポイント
- ElastiCacheのエンドポイント
- CloudSearchのエンドポイント
- Redshiftのエンドポイント
などなど。AWSが提供するエンドポイントのFQDNを、自分のアプリケーションから参照するように設定したり、一旦DNSでCNAME設定することも多い。
ただし、これらのエンドポイントFQDNで設定されているIPアドレスは、運用中に変更される可能性がある(ノード障害、フェイルオーバー等によるIPアドレス変更、スケーリングによるIPアドレス増減、等)。そのため、アプリケーション側はエンドポイントのIPアドレス変更に追随する必要がある。(追随しないと、古いIPアドレスにアクセス試行しつづけて、結果としてシステム障害になってしまう)
ここで問題になるのがJava (というかJVM)の1.5以前。デフォルトで、一度名前解決したIPアドレスは、JVMが終了するまでキャッシュし、再度名前解決することがないようになっている(キャッシュのttlが-1 となっている)。AWSにアクセスするJavaアプリケーションではこちらが問題になる。
ということで、以下のいずれかを設定しておくことになる。(例としてTTL=60秒)
java.security ファイルに追記。
networkaddress.cache.ttl=60 networkaddress.cache.negative.ttl=1
コードの中に以下を書く
// Set DNS results to be cached for only 1 minute java.security.Security.setProperty("networkaddress.cache.ttl" , "60"); // Do not cache un-successful name lookups from the DNS java.security.Security.setProperty("networkaddress.cache.negative.ttl", "1");
JVM起動オプションに追加する
java -Dsun.net.inetaddr.ttl=0 -Dsun.net.inetaddr.negative.ttl=1 -Dxxx=yyy .... com.example.Main
Tomcatの場合
<env> <variable name="JAVA_OPTS" value="-Dsun.net.inetaddr.ttl=60 -Dsun.net.inetaddr.negative.ttl=1 -server -Xms512m -Xmx2048m"></variable> </env>
ちなみに、Java1.6のあるバージョン以降は若干挙動が異なる。以下で確認可能。
sun.net.InetAddressCachePolicy.get()
参考
Setting the JVM TTL for DNS Name Lookups - AWS SDK for Java
Honoring DNS TTLs : Articles & Tutorials : Amazon Web Services