【Azure 應用服務】App Service 無法連線到Azure MySQL服務,報錯:com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

路邊兩盞燈發表於2021-11-25

問題描述

App Service使用jdbc連線MySQL服務,出現大量的  Communications link failure:

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

 

問題分析

最開始出現連線不上的原因,懷疑是MySQL服務的IP地址白名單沒有配置正確的App Service 出站IP。但是根據錯誤提示,發現明顯不對,因為如果是IP地址不允許訪問,它的錯誤訊息應該是:

Client with IP address '183.2xx.xx.xx' is not allowed to connect to this MySQL server.

所以不應該是MySQL伺服器對IP白名單設定的問題。

 

為了深入找出問題,單獨用Java Spring Boot來寫一個簡單的資料庫連線程式碼,根據MySQL官方的程式碼:https://docs.azure.cn/zh-cn/mysql/connect-java

POM.XML內容為:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>

    <properties>
        <java.version>1.8</java.version>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
    </dependencies>
</project>

注:這裡使用的 mysql-connector-java 依賴版本為 8.0.20 

Java Main函式程式碼:

    public static void main(String[] args) {
        String url = "jdbc:mysql://xxxxxx.mysql.database.chinacloudapi.cn:3306/xxxxxx?useSSL=true&requireSSL=false&characterEncoding=utf8&serverTimezone=UTC";
        String username = "xxxxxx@xxxxxx";
        String password = "xxxxxxxxxxxx";
        try {
            Connection connection = DriverManager.getConnection(url, username, password);
            System.out.println(connection.getMetaData().getURL());
            connection.close();
            System.out.println("connected!");
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            System.out.println(e.getMessage());
            return; // return because nothing can be done w/out a connection
        }

    }

同樣的資料庫連線字串,執行結果正常。根據驗證結果對比,出現 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, 的JDBC版本為 8.0.15, 所以瞬間定位問題原因:客戶端jdbc的驅動問題。

 

根據這一判斷,再次檢查了MySQL的版本為8.0並且為單例項(Single Server)。而微軟的官方文件中提示了 use 8.0.17+ with MySQL 8.0 (https://docs.microsoft.com/en-us/azure/mysql/concepts-compatibility#mysql-drivers)

【Azure 應用服務】App Service 無法連線到Azure MySQL服務,報錯:com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

 

隨後,對mysql-connector jdbc的版本 8.0.17, 8.0.18, 8.0.19 這三個版本進行驗證,看是否不會出現 Communications link failure 異常:

8.0.17 Error

【Azure 應用服務】App Service 無法連線到Azure MySQL服務,報錯:com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

8.0.18 Error

【Azure 應用服務】App Service 無法連線到Azure MySQL服務,報錯:com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

8.0.19 Successful

【Azure 應用服務】App Service 無法連線到Azure MySQL服務,報錯:com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure

 

 

經過以上驗證,得出微軟官方文件中的 8.0.17+有問題,需要在8.0.19+的驅動版本後才能成功。(一個調查了三天的大坑)

 

參考資料

將 Java 和 JDBC 與 Azure Database for MySQL 配合使用 : https://docs.azure.cn/zh-cn/mysql/connect-java

 

相關文章