背景
因爲業務需求導致服務遷移,遷移過程中發現新機房同樣接口的系統響應時間變的異常緩慢(普通有100-200ms的時延)。整個遷移過程中代碼發佈包完全拷貝,所以當時就定位爲系統原因進行排查。
整個排查過程通過在代碼中關鍵路徑切入耗時監控,從而定位具體耗時部分的代碼,縮小排查範圍。
排查過程
定位的代碼邏輯因爲保密原因省略了很多跟問題無關的代碼,僅列出核心的代碼。
- try/catch過程中的核心代碼沒有任何耗時的邏輯。
- finally的處理過程中增加了getLocalIP()方法獲取本地ip地址。
- 經過添加日誌監控耗時懷疑getLocalIP()方法比較耗時。
public RecomResult recommend(RequestId reqId, RecomParam condition) {
lock.readLock().lock();
long timeStart = System.currentTimeMillis();
try {
// 省略核心代碼
return result;
} catch (Throwable t) {
// 省略核心代碼
} finally {
mapTag.put("ip", engineContext.getLocalIP());
lock.readLock().unlock();
}
}
getLocalIP()方法的實現邏輯就是調用java api獲取本機ip地址
- 網上查詢類似文章InetAddress.getLocalHost() 執行很慢開始懷疑DNS解析問題。
- 通過for循環執行dig命令確認dns解析時好時壞耗時在100-200ms不等。
- 驗證猜測確認是DNS解析問題,並開始通過本地hosts或緩存本地ip地址減少解析。。
public String getLocalIP() {
try {
if (null == localIp) {
localIp = InetAddress.getLocalHost().getHostAddress();
}
} catch (UnknownHostException e1) {
LOG.error("get ip failed, e is {}", e1);
}
return localIp;
}
解決方案
解決方案本身分爲代碼本身優化和DNS解析優化。
- DNS層優化主要是服務器DNS解析增加本地緩存,犧牲DNS解析的時效性。
- 代碼層面優化主要獲取本地ip地址後緩存只需要進行一次host解析即可。