DCOS 場景 訪問 l4lb vip 偶現(xiàn)超時(shí)
環(huán)境信息
centos7,linux 3.10,lvs 使用 nat 模式。client 容器化部署,使用veth連接到linux網(wǎng)橋
業(yè)務(wù)背景
redisclient 使用長連接訪問 vip,由lvs轉(zhuǎn)發(fā)到后端redis,偶現(xiàn)出現(xiàn)redisclient請(qǐng)求報(bào)文報(bào)文超時(shí),連接斷開
分析進(jìn)展:
- 問題出現(xiàn)時(shí),veth,bridge上抓包有報(bào)文,lvs轉(zhuǎn)發(fā)后接口沒抓到,filter表input鏈里添加規(guī)則,也能匹配到包。
- 出現(xiàn)問題時(shí),客戶端因?yàn)闆]收到回復(fù)重傳了多次都沒轉(zhuǎn)發(fā)出去,最后因?yàn)榉?wù)器沒收到報(bào)文發(fā)送tcp keepalive,客戶端能收到,但是keepalive 回復(fù)報(bào)文也沒轉(zhuǎn)出去。
- 跟同事交流說可能是gro的問題,我們?cè)O(shè)備開啟了gro,但是抓到的報(bào)文都是不超過200的小包(奇怪為啥gro沒生效),所以gro導(dǎo)致報(bào)文過大影響lvs轉(zhuǎn)發(fā)也說不過去。
環(huán)境信息
centos7,linux 3.10,lvs 使用 nat 模式。client 容器化部署,使用veth連接到linux網(wǎng)橋
業(yè)務(wù)背景
redisclient 使用長連接訪問 vip,由lvs轉(zhuǎn)發(fā)到后端redis,偶現(xiàn)出現(xiàn)redisclient請(qǐng)求報(bào)文報(bào)文超時(shí),連接斷開
分析進(jìn)展:
- 問題出現(xiàn)時(shí),veth,bridge上抓包有報(bào)文,lvs轉(zhuǎn)發(fā)后接口沒抓到,filter表input鏈里添加規(guī)則,也能匹配到包。
- 出現(xiàn)問題時(shí),客戶端因?yàn)闆]收到回復(fù)重傳了多次都沒轉(zhuǎn)發(fā)出去,最后因?yàn)榉?wù)器沒收到報(bào)文發(fā)送tcp keepalive,客戶端能收到,但是keepalive 回復(fù)報(bào)文也沒轉(zhuǎn)出去。
- 跟同事交流說可能是gro的問題,我們?cè)O(shè)備開啟了gro,但是抓到的報(bào)文都是不超過200的小包(奇怪為啥gro沒生效),所以gro導(dǎo)致報(bào)文過大影響lvs轉(zhuǎn)發(fā)也說不過去。
原因是由于刪除和創(chuàng)建service的判斷邏輯有問題。
分析如下:
之前分析過lvs和overlay的配置沒有發(fā)現(xiàn)問題。后面發(fā)現(xiàn)系統(tǒng)日志中頻繁出現(xiàn)如下日志,即lvs刪除service,而且是指刪除。
Jul 12 21:14:57 test-agent-3 kernel: IPVS: __ip_vs_del_service: enter
Jul 12 21:14:57 test-agent-3 kernel: IPVS: __ip_vs_del_service: enter
Jul 12 21:14:57 test-agent-3 kernel: IPVS: __ip_vs_del_service: enter
Jul 12 21:14:57 test-agent-3 kernel: IPVS: __ip_vs_del_service: enter
這些刪除lvs service是由dcos-navstar發(fā)起的,調(diào)高日志級(jí)別發(fā)現(xiàn),navstar刪除service后,又重新批量添加回來services,如下代碼所示,非常奇怪。
apply_diff({ServicesToAdd, ServicesToRemove, ServicesToModify}, Namespace, State) ->
lists:foreach(fun({VIP, _BEs}) -> remove_service(VIP, Namespace, State) end, ServicesToRemove),
lists:foreach(fun({VIP, BEs}) -> add_service(VIP, BEs, Namespace, State) end, ServicesToAdd),
再往前追溯修改的原因,發(fā)現(xiàn)是由于 vip 變動(dòng)導(dǎo)致的,即有使用內(nèi)部負(fù)載均衡的服務(wù)被刪除或者創(chuàng)建,或者配額有改變。
push_vips(VIPs0) ->
VIPs1 = ordsets:from_list(VIPs0),
gen_statem:cast(?SERVER, {vips, VIPs1}).
之后引發(fā)狀態(tài)機(jī)的變化,apply_diff 根據(jù)下面Diff變量得到刪除或者添加service,Diff 根據(jù)最新獲取的service列表及之前的緩存做對(duì)比得到的。
LastConfigured 是之前的 service 緩存, VIPs1是最新得到 service 列表,兩個(gè)列表都做過排序。
maintain(VIPs0, State = #state{ns = Namespaces, routes = Routes, last_configured_vips = LastConfigured}) ->
VIPs1 = process_reachability(VIPs0, State),
Diff = generate_diff(LastConfigured, VIPs1),
NewRoutes = ordsets:from_list([VIP || {{_Proto, VIP, _Port}, _Backends} <- VIPs1]),
lager:debug("Last Configured: ~p, VIPs: ~p, NewRoutes ~p, Diff ~p", [LastConfigured, VIPs1, NewRoutes, Diff]),
lists:foreach(fun(Namespace) ->
do_update_routes(NewRoutes, Routes, Namespace, State),
apply_diff(Diff, Namespace, State)
end, Namespaces),
State#state{last_configured_vips = VIPs1, last_received_vips = VIPs0, routes = NewRoutes}.
假設(shè)有這樣的service列表,原有的service為[1,2,4,5], 最新的service列表為[1,2,3,4,5],有如下執(zhí)行的結(jié)果

修復(fù)方案: 修改上面兩個(gè)函數(shù)判斷條件如下,即可。
generate_diff(Lhs = [VIPLhs|_RestLhs], [VIPRhs|RestRhs], VIPsToAdd0, VIPsToRemove, Mutations) when VIPLhs > VIPRhs ->
generate_diff(Lhs, RestRhs, [VIPRhs|VIPsToAdd0], VIPsToRemove, Mutations);
%% To delete VIP
generate_diff([VIPLhs|RestLhs], Rhs = [VIPRhs|_RestRhs], VIPsToAdd, VIPsToRemove0, Mutations) when VIPLhs < VIPRhs ->
generate_diff(RestLhs, Rhs, VIPsToAdd, [VIPLhs|VIPsToRemove0], Mutations);
修改 PR 鏈接 :
https://github.com/dcos/navstar/pull/100
https://github.com/dcos/dcos-net/pull/59
jira問題跟蹤鏈接 :
https://jira.mesosphere.com/browse/DCOS_OSS-3602
posted on 2018-07-26 10:59 mainred 閱讀(710) 評(píng)論(0) 收藏 舉報(bào)
浙公網(wǎng)安備 33010602011771號(hào)