前言
呵呵 最近再一次 環(huán)境部署的過程中碰到了這樣的一個問題
我基于 docker 啟動了一個 mysql 服務(wù), 然后 掛載出了 數(shù)據(jù)目錄 和 配置目錄, 沒有手動復(fù)制配置目錄出來, 所以配置目錄是空的
然后 我基于 docker 啟動了一個 nacos, 配置數(shù)據(jù)庫設(shè)置為上面的這個 mysql
然后 啟動 nacos, 啟動日志中老是會發(fā)現(xiàn) nacos 連接 mysql 出現(xiàn)問題, mysql server 沒有返回數(shù)據(jù)包 給客戶端 什么的, 呵呵 這個問題 還是挺有意思的, 繼續(xù)往下看
然后 我調(diào)整了 nacos 的 socketTimeout 的配置, 更新為 20s, 重新啟動 nacos 呵呵 效果還是一樣
然后 在普通的客戶端 比如 navicate, 或者 jdbcTemplate 中建立連接到查詢 也還是需要差不多是 10s 左右的時間, 這個很固定
?文章來源地址http://www.zghlxwxcb.cn/news/detail-664270.html
總結(jié)一下 這里面存在兩個問題
1. 為什么我 nacos 連接配置了 socoketTimeout, 為什么 客戶端 和 mysql 服務(wù)器交互還是失敗了?
2. 普通的客戶端 比如 navicate, 或者 jdbcTemplate 中建立連接到查詢 也還是需要差不多是 10s 左右的時間, 這個很固定, 這個 10s 到底是什么? mysql 服務(wù)器到底在干嘛?
?文章來源:http://www.zghlxwxcb.cn/news/detail-664270.html
?
為什么我 nacos 連接配置了 socoketTimeout, 為什么 客戶端 和 mysql 服務(wù)器交互還是失敗了?
這個涉及到幾個概念, connectionTimeout, socketTimeout, loginTimeout?
在這個場景里面主要涉及到的是 socketTimeout, loginTimeout?
ExternalDataSourceProperties 中設(shè)置了 connectionTimeout 為 3s, 進而設(shè)置了? DriverManager.loginTimeout 為 3s?
而這個配置是寫死的, 因此 除了修改 nacos 代碼之外的辦法, 就是處理?mysql 服務(wù)器出現(xiàn)連接超時的問題了?
?
客戶端 和 服務(wù)器 的交互流程大致如下?
1. 客戶端 和 服務(wù)器 建立 tcp 連接請求?
2. 服務(wù)器 發(fā)送 ServerGreeting 給客戶端?
3. 客戶端拿到 ServerGreeting 之后發(fā)送 認(rèn)證請求給服務(wù)器?
4. 服務(wù)端的認(rèn)證, 以及之后的流程?
我們這里客戶端是在 流程2 這里出現(xiàn)的問題, 設(shè)置的讀取超時時間為?socketTimeout 和 loginTimeout 二者的較小者, 然后服務(wù)器那邊 由于一些因素一直沒有發(fā)送 ServerGreeting 給客戶端, 因此 導(dǎo)致的超時?
build:89, ExternalDataSourceProperties (com.alibaba.nacos.config.server.service.datasource) 中寫死的配置 connectionTimeout 為 3s
connectTimeout 設(shè)置的是 客戶端 和 服務(wù)端 創(chuàng)建 tcp連接 的超時時間
socketTimeout 設(shè)置的是 客戶端 和 服務(wù)端 tcp 數(shù)據(jù)交互的超時時間
DriverManager.loginTimeout 設(shè)置的是登錄認(rèn)證期間 客戶端 和 服務(wù)端 tcp 數(shù)據(jù)交互的超時時間
登錄認(rèn)證期間 客戶端 和 服務(wù)端 tcp 數(shù)據(jù)交互的超時時間 是 socketTimeout 和 (DriverManager.loginTimeout - connect本身會損失一部分時間) 的較小者
在 登錄 tcp請求 之后, 將 客戶端 和 服務(wù)端 tcp 數(shù)據(jù)交互的超時時間 設(shè)置為了 socketTimeout
?
創(chuàng)建 dataSource 的地方?
獲取連接的時候設(shè)置 loginTimeout 的地方
??
?
普通的客戶端 比如 navicate, 或者 jdbcTemplate 中建立連接到查詢 也還是需要差不多是 10s 左右的時間, 這個很固定, 這個 10s 到底是什么? mysql 服務(wù)器到底在干嘛?
本問題中服務(wù)器這邊的處理, 客戶端這邊連接了之后, 服務(wù)端處理連接請求, 完整的 stacktrace 是 thd_prepare_connection - login_connection - check_connection - ip_to_hostname?
是位于 客戶端 和 服務(wù)端 建立 tcp 連接之后, 服務(wù)端 向 客戶端 發(fā)送 ServerGreeting 之前?
最終調(diào)用的 glibc 庫函數(shù) gethostbyaddr, 這個庫函數(shù)根據(jù) 客戶端ip 查詢 客戶端主機名 的時候, 向 dns 查詢, 沒有查詢到 有 10s 的超時時間
#0 0x00007ff9a20fc819 in poll () from target:/lib/x86_64-linux-gnu/libc.so.6
#0 0x00007ff9a20fc819 in poll () from target:/lib/x86_64-linux-gnu/libc.so.6
#1 0x00007ff98001e207 in ?? () from target:/lib/x86_64-linux-gnu/libresolv.so.2
#2 0x00007ff98001bc43 in __res_context_query () from target:/lib/x86_64-linux-gnu/libresolv.so.2
#3 0x00007ff99800b536 in _nss_dns_gethostbyaddr2_r () from target:/lib/x86_64-linux-gnu/libnss_dns.so.2
#4 0x00007ff99800b823 in _nss_dns_gethostbyaddr_r () from target:/lib/x86_64-linux-gnu/libnss_dns.so.2
#5 0x00007ff9a2118ee2 in gethostbyaddr_r () from target:/lib/x86_64-linux-gnu/libc.so.6
#6 0x00007ff9a21217d5 in getnameinfo () from target:/lib/x86_64-linux-gnu/libc.so.6
#7 0x000056048ea2e800 in vio_getnameinfo ()
#8 0x000056048de9606f in ip_to_hostname(sockaddr_storage*, char const*, char**, unsigned int*) ()
#9 0x000056048e2c8569 in ?? ()
#10 0x000056048e2c95d3 in thd_prepare_connection(THD*) ()
#11 0x000056048e3c103e in handle_connection ()
#12 0x000056048e9cfcd7 in pfs_spawn_thread ()
#13 0x00007ff9a255ffa3 in start_thread () from target:/lib/x86_64-linux-gnu/libpthread.so.0
#14 0x00007ff9a21074cf in clone () from target:/lib/x86_64-linux-gnu/libc.so.6
?
新增測試用例, 在宿主機上面跑一下, 并且在 mysql 所在的容器跑一下?
新增測試用例 Test09GetHostByAddr.c
/**
* Test09GetHostByAddr.c
*/
#include "stdio.h"
#include "netdb.h"
#include "stdlib.h"
#include "arpa/inet.h"
#include "string.h"
int main(int argc, char **argv) {
struct hostent *host;
const char *add = "10.60.50.16";
char p[30];
inet_pton(AF_INET, add, p);
host = gethostbyaddr(p, strlen(p), AF_INET);
printf("hostname : %s", host->h_name);
return 0;
}
?
新增 build 腳本, 并執(zhí)行, 觀察 執(zhí)行情況?
新增 build 的測試腳本
gcc -g -o Test09GetHostByAddr Test09GetHostByAddr.c
date
./Test09GetHostByAddr
date
執(zhí)行 build 腳本
root@ubuntu:~/docker/mysql/GetHostByAddr# ./build.sh
Thu Feb 24 23:21:46 PST 2022
./build.sh: line 5: 39782 Segmentation fault ./Test09GetHostByAddr
Thu Feb 24 23:21:56 PST 2022
?
?
skip-name-resolve 的影響 - 添加于?2023.08.15
這里是服務(wù)器?在嘗試根據(jù) ip信息?解析客戶端的 主機名 信息
核心的調(diào)用鏈如下, 關(guān)鍵的調(diào)用是?glibc?的?gethostbyaddr_r
?
然后?本文中提到的 config?目錄中,?影響這個問題更關(guān)鍵的是?skip-name-resolve 的這個配置,?更新之后的配置有這個?skip-name-resolve, 然后?mysql?服務(wù)器解析?主機名信息的時候 就 hang?住了,?這里是?10s
root@ubuntu:~/docker/mysql# cat config/conf.d/docker.cnf
[mysqld]
skip-host-cache
skip-name-resolve
?
在?my.cnf 中增加了?skip_name_resolve=ON 之后情況如下?
更新之后,?就不會解析?主機信息,?進而防止了?gethostbyaddr_r 的?hang?住?
?
?
?
?
完?
?
?
?
到了這里,關(guān)于07 mysql5.6.x docker 啟動, 無 config 目錄導(dǎo)致客戶端連接認(rèn)證需要 10s的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!