這個註冊的 IP 網路都不通了,Eureka 註冊中心竟然無法踢掉它!

来源:https://www.cnblogs.com/ldws/archive/2019/09/27/11600555.html
-Advertisement-
Play Games

本文導讀: 微服務技術架構選型介紹 k8s 容器化部署架構方案 Eureka 註冊中心問題場景 問題解決手段及原理剖析 閱讀本文建議先瞭解: 1. 註冊中心基本原理 2. K8s(Kuberneters)基本概念 我們的微服務目前都是在伺服器上部署的,也是基於 Docker 來部署的。 運維部門基於 ...


本文導讀:

  • 微服務技術架構選型介紹
  • k8s 容器化部署架構方案
  • Eureka 註冊中心問題場景
  • 問題解決手段及原理剖析

閱讀本文建議先瞭解:

  1. 註冊中心基本原理
  2. K8s(Kuberneters)基本概念

我們的微服務目前都是在伺服器上部署的,也是基於 Docker 來部署的。

運維部門基於 K8s 自研了一套容器雲管理平臺,平臺名稱叫做 Ares,我們也開始準備將微服務遷移到這平臺上,降低虛擬機或實體機伺服器運維成本,提高伺服器資源利用效率。

Ares:阿瑞斯(戰神)

希臘神話中為戰爭而生的神,奧林匹斯十二神之一,被視為尚武精神的化身。看起來很牛逼的樣子!

file

1、微服務技術架構選型介紹

微服務框架使用了流行的 Spring Cloud 框架。

框架技術組件如下:

  • 註冊中心選擇的是 Eureka
  • 網關使用的 Zuul
  • 配置中心使用的 Apollo
  • 熔斷限流使用了 Sentienl + Hystrix

網關 Zuul 層使用了 Ribbon 做負載均衡、Hystrix 做限流熔斷。
後端微服務使用了阿裡巴巴開源的 Sentinel 做限流熔斷。

由於當時伺服器的配置不同,比如有低配置的虛擬機,還有高配置的物理機伺服器。

所以呢,我們基於當時的伺服器配置現狀,基於 Ribbon 自行擴展了按照權重的負載均衡策略,對 Eureka 註冊中心管理界面做了一點改造,能夠支持動態對每台伺服器變更權重。

因為本文的問題跟 Eureka 註冊中心有關,對 Eureka 架構做個介紹下。

Eureka 註冊中心簡易架構圖:
file

上圖簡要描述了 Eureka 的基本架構,由3個角色組成:

1)Eureka Server

提供服務註冊、發現、健康檢查。

2)Service Provider

服務提供方,
將自身服務註冊到 Eureka,從而使服務消費方能夠找到,
我們將容器可以作為服務提供者,會註冊到 Eureka。

3)Service Consumer

服務消費方,
從Eureka獲取註冊服務列表,從而能夠消費服務
我們可以將 Zuul 網關作為服務消費者。

2、K8s 容器化部署架構方案

考慮到使用的 Spring Cloud 框架,結合運維提供的容器平臺。

制定容器化部署架構如下:
file

從容器創建到可訪問流程:

1)創建容器

選擇鏡像及版本、CPU、記憶體配置、配置健康檢查、日誌收集、Pod 副本數量。提交創建容器。

2)服務註冊

容器啟動時,申請 SLB VIP,作為服務註冊 IP,向 Eureka 上發起註冊。

3)網關發起請求

功能變數名稱請求,DNS 解析經過 GSLB(全局軟負載均衡)負載到 Zuul 網關,Zuul 網關從 Eureka 註冊中心拉取服務註冊表,通過 Ribbon 負載均衡,從本地服務註冊列表中,選擇其中一臺 Server,發起 Http 調用。

4)容器提供服務

容器內註冊的是 SLB VIP(軟負載均衡),這個 SLB 通過內部的 Nginx 負載均衡機制,輪詢到後端的容器的多個 Pod IP 上,Pod IP 正是我們部署的微服務業務。

為什麼要使用SLB VIP呢?

當時我們對介面壓測時,發現使用 K8s 內部的 Service IP 存在性能瓶頸,該問題還在研究中。後來運維內部商榷,使用 SLB 來達到負載均衡的效果。

另外說明一點:
運維基於 K8s 自研的這套容器平臺,網路層面做了重新架設和優化,打通了各個機房的網路。

這樣做給我們的架構部署帶來了好處:
前期目標僅為了遷移微服務業務,考慮到穩定性等因素,正式上線的Zuul網關和Eureka 註冊中心部署在 K8s 集群外,微服務業務部署在容器內,因網路可通,容器啟動後申請的 VIP,可以直接註冊到 Eureka 上。

模擬環境(預上線環境)是直接將Eureka註冊中心,也部署在了容器平臺中,接下來會說下,因此導致的一些問題,以及解決該問題的方式。

** 3、Eureka 註冊中心問題場景**

容器測試階段結束,由於運維調整為了 SLB VIP,將以前的應用(一個應用下包含多個 Pod 容器)都刪除掉,我們重新搭建一套模擬環境用於,上線前的性能測試環境。

但是當我們部署完 Eureka 後,發現以前刪除掉的應用VIP 也註冊上來了,而且這個 VIP 網路是不通的,無法訪問的。

Eureka 管理控制台示意圖:
file

telnet 命令測試:

telnet 10.11.195.197 80 
Trying 10.11.195.197...
telnet: connect to address 10.11.195.197: Network is unreachable
telnet: Unable to connect to remote host

結果提示 10.11.195.197 這個 VIP,網路是不可達的。

那為什麼這個服務能註冊上來呢?

起初,跟運維老哥請教,經過容器內排查後,也暫時沒有太多眉目,確定是這個 VIP,已經下線了,網路也不通。

按照這個推測,是不太可能註冊到 Eureka 上來的。

開始考慮到以為是 Eureka 機制是不是有問題,但仔細用「屁股」猜想論思考一下,結合 Eureka 框架底層原理來看,是不應該出現這個情況。

根據 Eureka 續約機制,一定是有哪個「哥們」在默默給這個服務 IP 發續約(向註冊中心發送心跳)。

我們在 Eureka Server 服務端,也有監聽各個動作的機制,如註冊服務、續約服務、下線服務,根據日誌看,也的確是有這個服務 IP 一直在發送續約動作。

續約監聽代碼:

@EventListener
public void listen(EurekaInstanceRenewedEvent event) {
    InstanceInfo instanceInfo = event.getInstanceInfo();
    if (instanceInfo != null) {
        logger.info("renew ...." + instanceInfo.getInstanceId());
    } else {
        logger.info("renew ....instanceInfo is null");
    }
}
4、問題解決手段及原理剖析

既然引出了上述問題,當然不能放任不管,一定要一探究竟。
這種問題你若不理他,早晚會搞出點別的事情來的。

Eureka 服務端已經收到了註冊和一直續約的請求,說明一定是有哪個服務一直在偷偷發送心跳。

到底是誰乾的啊?
file

到底如何找到這個上報的服務呢?

運維老哥暫時比較忙,看來只能先查找網路鏈路,抓取網路數據包看看到底是怎麼回事了。

網路工具一般常用的就是 tcpdump、Wireshark。

Wireshark 小故事:
大概發生在 10 幾年前,主導 Ethereal(應該聽說過吧)的大佬跳槽了,然後這個商標就不能繼續使用了,但是這個工具在當時來說人氣很旺,後來大佬就將項目更名為 Wireshark 了。
伺服器上命令行的抓包程式 tethereal 更名為了 tshark。

容器鏡像中預設是不會自帶這些工具的。鏡像中 Linux 操作系統使用的是 CentOS,通過自帶的 yum 源安裝網路工具包,比較方便。

安裝 wireshark:

yum install -y wireshark

安裝 tcpdump:

yum install -y tcpdump

這裡我們使用的是 Wireshark 工具,簡單介紹下這個工具:

如果你要看到全部網路數據包,直接執行tshark命令即可。

1)獲得 tshark 命令幫助

tshark --help

2)tshark 抓包模式參數一覽

file

3)tshark 命令實戰使用

列印源目標 Host 及 Http 協議信息:

tshark -s 512 -i eth0 -n -f 'tcp dst port 80' -t ad -R 'http.host and http.request.uri' -T fields -e "frame.time" -e "ip.src" -e "http.host" -e "http.request.method" -e "http.request.uri" | tr -d ' '

參數解釋:

-i 捕獲 eth0 網卡;

-n 禁止所有地址名字解析(預設為允許所有)

-t 設置解碼結果的時間格式。
"ad"表示帶日期的絕對時間,"a"表示不帶日期的絕對時間,"r"表示從第一個包到現在的相對時間,“d”表示兩個相鄰包之間的增量時間(delta)

-R 設置讀取(顯示)過濾表達式(read filter expression)

-T -e 輸出指定的欄位

執行結果:
file

來段文本:

[root@mas-manager-eureka-es1-66cb79bfb7-snmxm manager]# tshark -n -t a -R http.request -T fields -e "frame.time" -e "ip.src" -e "http.host" -e "http.request.method" -e "http.request.uri" | grep 10.11
Running as user "root" and group "root". This could be dangerous.
Capturing on eth0
Sep 27, 2019 00:22:05.174770971 10.124.12.169   10.124.14.4     PUT     /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569490783397
Sep 27, 2019 00:22:13.814821143 10.124.11.125   10.124.14.4     PUT     /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569407741389
Sep 27, 2019 00:22:15.180243816 10.124.11.123   10.124.14.4     PUT     /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569490783397

通過抓包,根據問題 IP 過濾得到的結果,我們看到了
/eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569490783397
說明是有 IP 在上報,上報來源 IP 就是第二列的 IP。

將這個信息提供給運維同學,根據來源 IP 去繼續查找線索。

但是,發現第二列 IP 並不是實際的伺服器節點 IP,查不到。因為這些 IP 都是主機上的虛擬 IP,每次上報來源 IP 不同,所以還要反向查找實際歸屬的主機節點。

為什麼要有虛擬 IP?

實際是 SLB 節點上虛擬 IP,因為會負載到它所屬主機節點,這台主機上預設只能支撐最大 65535 個 TCP 連接,所以為了單機能支撐更高的 TCP 連接數,會虛擬出來很多個 IP。假設有 10 個虛擬 IP,每個虛擬 IP 支撐 65535 個 TCP 連接,這台主機總共可以支撐 10 * 65535 = 60萬以上的連接數了。

K8s 有多套集群,每個集群中有很多台主機節點,茫茫主機池中怎麼去查找這些虛擬 IP 呢,

其實我們的目的是為了找到,誰往註冊中心發送請求了,還是可以繼續通過抓取網路數據包來定位這個問題。

這些網路數據包一定會經過 K8s 集群里的某一臺節點,一臺一臺去找,很麻煩,編寫簡單腳本抓包查找

#!/bin/bash
tcpdump -i any host 10.124.14.4 -n -s 0 -X -l | grep 10.11.195>/tmp/1.txt &
sleep 20s
kill -2 %1
cat /tmp/1.txt

網路抓包結果:
file

截取了關鍵的抓包信息:

11:41:56.598204 IP 10.110.157.81.54078 > 10.124.14.4.http: Flags [P.], seq 273:622, ack 218, win 245, options [nop,nop,TS val 3348483954 ecr 1420800289], length 349: HTTP: PUT /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569394834392 HTTP/1.1

這裡的 10.110.157.81.54078 就是主機節點 IP,目標地址 10.124.14.4 就是容器內的 Eureka 註冊中心地址。

發送的請求是 /eureka/apps/LETV-MAS-CALLER-TVPROXY-USER/10.11.195.197:80?status=UP&lastDirtyTimestamp=1569394834392
這個請求地址上就帶了 10.11.195.197 這個網路不可達的 IP 地址。

到這裡,其實我們已經基本定位到了,一定是從 K8s 集群容器內發出來了。
根據這個有價值的節點信息,連接到 K8s 集群內,查找該節點上部署的容器。

查找 K8s 集群內 Pod 命令行:
kubectl get pod --all-namespaces -o wide |grep 10.110.157.81

部署在改節點上的容器:
file

運維根據 Eureka 上名稱大概猜測一下,終於找到這個「罪魁禍首」的容器了。
進入容器內,查看配置 SVIP (Eureka上的註冊IP)就是 10.11.195.197 這個IP。

將這個問題容器徹底關閉後,沒有再繼續發送續約請求,Eureka 註冊中心上過了一段時間摘掉了 IP。

大家可能有疑問,這麼繁瑣,為啥不直接到 K8s 集群內去找,因為 K8s 集群內目前已有業務在運行著,集群內有幾百個容器在跑著。當時運維一起測試時,容器名稱都是自定義的,所以不是很好查找。

咱們經過這個過程的排查,確認了這個 Eureka 註冊中心上的地址雖然不通,但是一直是有容器在上報,而上報的「ServerId」指向的 10.11.195.197:80 地址。

我們也可以結合底層源碼瞭解下。

Eureka 續約時序圖:
file

介面實現方式跟註冊服務類似,更新自身狀態後,會同步到其他集群節點。

PeerAwareInstanceRegistryImpl 類的 renew 方法會調用到 AbstractInstaceRegistry 抽象實例註冊類的 renew 方法。

AbstractInstaceRegistry#renew 方法源碼:
file

會根據服務 id 從註冊表中獲取 Lease 對象,如果不為空,則完成續約,更新 lastUpdateTimestamp 欄位。

file

Eureka 註冊表的數據結構:

private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry
= new ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>();

是一個 ConcurrentHashMap 結構,Key 就是應用名稱,Value 也是一個 Map 結構。
Map 結構中的 Key 是註冊ID(IP + 埠),Value 是 Lease 服務續約對象,裡面包含了動作類型,最後上報(心跳)更新時間戳等等信息。

容器服務作為 Eureka Client,每隔一定時間間隔(預設60秒)向註冊中心發起一次續約。

Eureka Server 會定時檢測服務實例心跳是否正常,如果間隔一定時間(90秒),還沒有來續約,就會將這個服務從註冊中心摘除掉。

最後總結:

總結上述分析過程,一圖勝千言:
file

重要的不是結果,而是這個過程,希望你也能享受這個過程。

參考資料:

Wireshark 使用文檔:
https://www.wireshark.org/docs/man-pages/tshark.html

Netflix Eureka 源代碼:
https://github.com/netflix/eureka

歡迎關註我的公眾號,更多精彩文章,與你一同成長,掃碼二維碼關註~
Java愛好者社區


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄 "Java中的構造方法" "構造方法簡介" "構造方法實例" "例 1" "例 2" "Java中的幾種構造方法詳解" "普通構造方法" "預設構造方法" "重載構造方法" "java子類構造方法調用父類構造方法" "Java中的代碼塊簡介" "Java代碼塊使用" "局部代碼塊" "構造代碼 ...
  • 目錄 "抽象類介紹" "為什麼要用抽象類" "一個抽象類小故事" "一個抽象類小游戲" "介面介紹" "介面與類相似點:" "介面與類的區別:" "介面特性" "抽象類和介面的區別" "介面的使用:" "介面最佳實踐:設計模式中的工廠模式" "介面與抽象類的本質區別是什麼?" "基本語法區別" "設 ...
  • [TOC] OS模塊 能與操作系統交互,控制文件 / 文件夾 | 方法 | 詳解 | | : : | : : | | os.getcwd() | 獲取當前工作目錄,即當前python腳本工作的目錄路徑 | | os.chdir("dirname") | 改變當前腳本工作目錄;相當於shell下cd ...
  • 現在的Spring相關開發都是基於SpringBoot的。最後在打包時可以把所有依賴的jar包都打進去,構成一個獨立的可執行的jar包。如下圖13: 使用java -jar命令就可以運行這個獨立的jar包。如下圖14: 這個jar包的執行入口就是一個main函數,典型的格式如下: 從代碼中可以得知, ...
  • 本文索引 語言變化 數字字面量 越界索引報錯的完善 工具鏈改進 GOPROXY GOSUMDB GOPRIVATE 標準庫的新功能 判斷變數是否為0值 錯誤處理的革新 Unwrap Is As golang1.13發佈已經有一個月了,本文將會列舉其中幾個較為重要的特性。我們將會從語言變化、庫變化以及 ...
  • 來一點咖啡,準備好進入註解的世界。 註解一直是 Java 的一個非常重要的部分,它從 J2SE 5.0 開始就已經存在了。在我們的應用程式代碼中,經常看到 和 這樣的註解。在本文中,我將討論註解到底是什麼,為什麼引入註解,它們是如何工作的,如何編寫自定義註解(有示例代碼),註解的有效場景是什麼,最後 ...
  • 群里看到有人詢問:誰會用python將微信音頻文件尾碼m4a格式轉成mp3格式,毫不猶豫回了句:我會。然後就私下聊起來了 解決方法介紹如下: 工具:windows系統,python2.7,轉換庫ffmpeg 安裝ffmpeg庫:下載對應電腦系統版本 https://ffmpeg.zeranoe.co ...
  • 1. 概覽 在編寫 Spring Boot 應用程式時, "將配置屬性映射到 Java bean 上" 是非常有用的。但是,記錄這些屬性的最好方法是什麼呢? 在本教程中,我們將探討 "Spring Boot Configuration Processor" 和 "關聯的 JSON 元數據文件" ,該 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...