SpringBootで作ったアプリを起動すると、以下のエラーが起こり起動に失敗する現象に遭遇しました。
Caused by: com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
この現象の原因と解決策についてメモします。
環境
言語: Java8
FW: SpringBoot
DB: MySQL5.7
ビルドツール: Maven
現象
application.propertiesにdb接続の設定を以下のように記述し、
spring.datasource.url=jdbc:mysql://localhost:3306/sample_app
spring.datasource.username=testuser
spring.datasource.password=testuser
spring.jpa.database=MYSQL
mvn spring-boot:run とターミナルで叩きアプリを起動します。
すると以下のようにエラーが発生しました。
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.5.RELEASE)
2021-07-05 18:57:34.756 INFO 10112 --- [ restartedMain] com.example.demo.DemoApplication : Starting DemoApplication on N0128.local with PID 10112 (/Users/akiyoshi.tokiya/develop/iTICKET/app_in_app/springbootsample/target/classes started by akiyoshi.tokiya in /Users/akiyoshi.tokiya/develop/iTICKET/app_in_app/springbootsample)
2021-07-05 18:57:34.758 INFO 10112 --- [ restartedMain] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2021-07-05 18:57:34.788 INFO 10112 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2021-07-05 18:57:34.789 INFO 10112 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : For additional web related logging consider setting the 'logging.level.web' property to 'DEBUG'
2021-07-05 18:57:35.631 INFO 10112 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-07-05 18:57:35.651 INFO 10112 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-07-05 18:57:35.651 INFO 10112 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.19]
2021-07-05 18:57:35.718 INFO 10112 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-07-05 18:57:35.718 INFO 10112 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 929 ms
2021-07-05 18:57:35.806 INFO 10112 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-07-05 18:57:37.040 ERROR 10112 --- [ restartedMain] com.zaxxer.hikari.pool.HikariPool : HikariPool-1 - Exception during pool initialization.
com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at com.mysql.cj.jdbc.exceptions.SQLError.createCommunicationsException(SQLError.java:174) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:64) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:835) ~[mysql-connector-java-8.0.16.jar:8.0.16]
...
at com.mysql.cj.NativeSession.connect(NativeSession.java:165) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:955) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825) ~[mysql-connector-java-8.0.16.jar:8.0.16]
... 104 common frames omitted
Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
at java.base/sun.security.ssl.HandshakeContext.(HandshakeContext.java:172) ~[na:na]
at java.base/sun.security.ssl.ClientHandshakeContext.(ClientHandshakeContext.java:98) ~[na:na]
at java.base/sun.security.ssl.TransportContext.kickstart(TransportContext.java:238) ~[na:na]
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:434) ~[na:na]
at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:412) ~[na:na]
at com.mysql.cj.protocol.ExportControlled.performTlsHandshake(ExportControlled.java:316) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.protocol.StandardSocketFactory.performTlsHandshake(StandardSocketFactory.java:188) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.protocol.a.NativeSocketConnection.performTlsHandshake(NativeSocketConnection.java:99) ~[mysql-connector-java-8.0.16.jar:8.0.16]
at com.mysql.cj.protocol.a.NativeProtocol.negotiateSSLConnection(NativeProtocol.java:352) ~[mysql-connector-java-8.0.16.jar:8.0.16]
... 111 common frames omitted
結論
application.propertiesのspring.datasource.url=jdbc:mysql://localhost:3306/sample_appの末尾に?enabledTLSProtocols=TLSv1.2をつけることで解決しました。
spring.datasource.url=jdbc:mysql://localhost:3306/sample_app?enabledTLSProtocols=TLSv1.2
原因
ログを詳しく見ると、Caused by: javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) というエラーに起因しています。これはRHEL 7 から RHEL 8 でサポートされる最新の TLS プロトコルバージョンが異なるために発生するようで、これにより、TLSハンドシェイクのネゴシエーション中にアプリケーションとT LSプロトコルの不一致が発生し接続が失敗してしまいます。
これの回避策として、データベース接続URLにTLSプロトコルバージョンを手動で指定すると接続できるようになるようです。
また、Communications link failureというエラーに関してですが、これはアプリケーションがdbにアクセスできていないために起こるエラーで、原因としては以下が考えられるようです。
- JDBC URLで指定しているIPアドレスやホストアドレスが間違っている
- JDBC URLで指定しているホスト名がローカルDNSに認識されていない
- JDBC URLで指定しているポート番号が間違っている
- DBサーバが起動していない
- DBサーバがTCP/IPコネクションを受け付けない
- DBサーバのコネクションが足りていない
- ファイアウォールやプロキシなどによってアプリケーションとDBの接続がブロックされている
上記の対策、調査方法としては以下があります。
- pingを試す
- DNSをリフレッシュ、またはJDBC URLに指定しているIPアドレスを指定する
- MySQLの場合、my.cnfのポート番号と一致するか確認
- DBを起動する
- mysqldが--skip-networking optionの指定なしで動いているか確認
- DBを再起動し、DB接続後にコネクションをしっかり閉じているか確認
- ファイアウォールやプロキシの設定を確認
今回の場合は5が当てはまりますね。
参考
・https://access.redhat.com/documentation/ja-jp/red_hat_build_of_thorntail/2.7/html/release_notes_for_thorntail_2.7/connection-between-a-rhel-8-based-application-and-a-rhel-7-based-mysql-5-7-database-fails-due-to-tls-protocol-version-mismatch
・https://stackoverflow.com/questions/2983248/com-mysql-jdbc-exceptions-jdbc4-communicationsexception-communications-link-fai