基於網絡抓包實現K8S中微服務的應用級監控

微服務監控的挑戰
監控的目的是爲了讓集羣中所有的服務組件,不管是HTTP服務,數據庫服務,還是中間件服務。都能夠健康穩定的運行,能發現問題,遇到問題能找到原因。在過去,監控工具側重於基礎設施或單一軟件組件以及衡量運營健康。這些工具在實現這一目標方面只取得了一定的成功,但是對於單一的,傳統的應用程序和基礎設施來說效果不錯。微服務的出現暴露了工具中的弱點。現在,組件託管在位於私有云,公共雲或兩者的混合體之間的虛擬化機器或容器內。獲悉我並不需要關心服務cpu用了多少,內存用了多少?確保這些服務相互通信以提供所需的結果需要從監控的角度重要看幾件事情:

微服務集羣中是否所有的服務的吞吐率,響應時間都正常?

服務調用線中哪些線負載過大,哪些線負載過小?

服務的錯誤率,例如HTTP 500錯誤。

我們想要監控分析應用,從它的服務狀態出發是否更直接呢?

已有監控方案
目前有些廠商提出了微服務的監控解決方案。

從APM角度監控服務端到端狀態。

爲每種類型服務開發agent收集應用狀態信息。

通過產生統一的應用日誌分析監控方案

其他方案

每一種商業或開源方案都有它的優勢所在。可以根據你的需求來進行選擇。例如你的所有服務都是自己研發,日誌標準一致or能夠統一處理。所有訪問信息都能打出日誌,那麼我認爲日誌分析可能是你最適合的方案。但是對於公有云平臺,那就不同了。

好雨雲幫採用的方案
好雨雲幫提供了公有云和私有化的部署方式,平臺內部署的服務各式各樣。各種通信協議,各種日誌標準。我們怎麼實現對所有服務的應用狀態監控?好雨雲幫完善的租戶網絡,環境隔離,因此我們提供用戶在自己環境下安裝自己的監控組件,我們的基礎數據收集是通過網絡分析。下文詳細講解:

kubernetes POD共享機制
kubernetes中pod內容器共享網絡空間,掛在卷等爲我們監控pod內主服務容器提供方便。其實按照官方對pod的定義的使用面來說:

* content management systems, file and data loaders, local cache managers, etc.
* log and checkpoint backup, compression, rotation, snapshotting, etc.
* data change watchers, log tailers, logging and monitoring adapters, event publishers, etc.
* proxies, bridges, and adapters
* controllers, managers, configurators, and updaters

pod內除了主服務外我們可以部署一些附屬服務。之前的文章我談過使用pod的插件服務收集處理日誌。今天我再談使用pod的網絡便利監控主服務應用級指標。

通過共享的網卡抓包分析網絡流量反應應用狀況
我們拿一個http服務爲例,我們監控網絡流量能拿到幾乎所有訪問和服務返回信息。例如1分鐘內多少request,分別請求哪些path,多長時間服務返回了。返回狀態碼等等信息。

要獲得以上的數據,我們需要獲取到網絡包,解碼網絡包然後獲得http協議數據。

我們WatchData服務容器與應用容器在同pod中,經過應用容器eth0網卡的流量我們再WatchData容器中eth0網卡獲取。通過解碼網絡包獲取http報文頭關鍵信息,每一個Response形成一個消息發送到server端完成分析,存儲然後形成連續的實時的監控數據。下圖展現個簡要的整體架構圖:

當然,上文已經說了,我們採取此方案主要就是爲了能夠監控各種應用,只是http怎麼行。不通的通信應用使用不同的通信協議,比如mysql的協議,mongodb的協議。TCP/IP網絡協議棧分爲應用層(Application)、傳輸層(Transport)、網絡層(Network)和鏈路層(Link)四層。。我們抓取到的網絡包信息也是四層模型。

網絡抓包Golang實現
使用golang實現網絡抓包非常容易。得益於谷歌的包:

github.com/google/gopacket
github.com/google/gopacket/layers
github.com/google/gopacket/pcap

這裏我舉一個監聽網卡的Demo主要代碼

//device 網卡名
if handle, err := pcap.OpenLive(device, int32(n.Option.Snaplen), true, n.Option.TimeOut); err != nil {
            log.With("error", err.Error()).Errorln("PCAP OpenLive Error.")
            return 1
        } else if err := handle.SetBPFFilter(n.Option.Expr); err != nil { // optional
            log.With("error", err.Error()).Errorln("PCAP SetBPFFilter Error.", n.Option.Expr)
            return 1
        } else {
            log.Infoln("Start listen the device ", device)
            packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
            go func(close chan struct{}, h *pcap.Handle) {
                for {
                    select {
                    case packet := <-packetSource.Packets():
                        n.handlePacket(packet) // Do something with a packet here.
                    case <-close:
                        log.Infoln("stop listen the device.")
                        h.Close()
                        return
                    }
                }
            }(n.Option.Close, handle)
        }

這段代碼就是監聽某個網卡,通過n.Option.Expr規則過濾點無用網絡包,規則語法與linux tcpdump一樣。參考:PCAP-FILTER

接收到網絡包一般有多種類型:2層模型的包,和4層模型的包。如果你不關注tcp握手這種類型的包你只需要關注具有四層模型的網絡包。n.handlePacket(packet)處理網絡包。

app := packet.ApplicationLayer()
    if app != nil {
        //log.With("type", app.LayerType().String()).Infoln("Receive a application layer packet")
        //log.Infoln(packet.String())
        go func() {
            sd := &SourceData{
                Source:      app.Payload(),
                ReceiveDate: packet.Metadata().Timestamp,
            }
            tran := packet.TransportLayer()
            if tran != nil {
                src, dst := tran.TransportFlow().Endpoints()
                sd.SourcePoint = &src
                sd.TargetPoint = &dst
                if tran.LayerType().Contains(layers.LayerTypeTCP) {
                    tcp := &layers.TCP{}
                    err := tcp.DecodeFromBytes(tran.LayerContents(), gopacket.NilDecodeFeedback)
                    if err != nil {
                        log.With("error", err.Error()).Errorln("Decode bytes to TCP error")
                    } else {
                        sd.TCP = tcp
                    }
                }
            }
            netL := packet.NetworkLayer()
            if netL != nil {
                src, dst := packet.NetworkLayer().NetworkFlow().Endpoints()
                sd.SourceHost = &src
                sd.TargetHost = &dst
            }
            decode := FindDecode(n.Option.Protocol)
            if decode != nil {
                decode.Decode(sd)
            } else {
                log.Debugf("%s protol can not be supported \n", n.Option.Protocol)
            }

如上代碼簡單處理四層模型網絡包。一般你可以從網絡層獲取雙方ip地址,從傳輸層獲取雙方端口以及tcp包的相關信息。從應用層獲取應用數據。具體的怎麼優化和實踐就留給大家自己嘗試吧。

網絡抓包監控的優缺點
優點:
應用無關性,監控工具通用性強。

數據全面性,你可以獲取很多直接和間接反應應用狀態的數據。

不侵入代碼,一般不影響網絡。

高併發下不影響應用。

缺點:
資源消耗,抓包分析包是一個物理資源消耗的過程。

需要自己開發。

總之,就像上文說得一樣。如果你的需求只是想監控一個應用。你就別考慮這個方案了。如果你想監控集羣中所有應用,你可以嘗試。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章