Jaeger插件开发及背后的思考
簡介:?本文主要介紹Jaeger最新的插件化后端的接口以及開發方法,讓大家能夠一步步的根據文章完成一個Jaeger插件的開發。此外SLS也推出了對于Jaeger的支持,歡迎大家試用。
隨著云原生 + 微服務的推廣和落地,服務監控也變得越來越重要了。中等規模的微服務場景下,運維同學已經無法通過日志還原請求的調用軌跡和請求所經過服務的執行耗時,更不用說去定位和分析服務異常根因,研發運維同學需要一個服務監控工具,它可以還原每次請求的服務調用軌跡以及服務執行時間,并以圖的形式展現出來。分布式鏈路追蹤系統孕育而生。
近些年市面上有大量優秀的商業產品,這些商業產品通常也叫APM(應用性能監控);比如國內商業公司有阿里云ARMS,聽云,博瑞,云智慧等等,國外優秀的商業公司有AppDynamic,DynaTrace等等,它們在產品方面做非常完善,能夠適配各種場景。同樣地,開源也有非常優秀的解決方案。比如說 CNCF Jaeger,Apache SkyWalking,Cat, Pinpoint等。Jaeger作為CNCF畢業的頂級項目, 在云原生場景下,通常會成為運維同學首選監控解決方案。
Jaeger項目是Uber 在 2015 年開發的。2017 年,Jaeger 納入云原生計算基金會(CNCF)的孵化項目,2019 年,Jaeger 正式畢業。下圖是Jaeger架構圖。圖中包含兩中架構模式,兩種架構上大體一樣,區別在于添加了Kafka作為緩沖,以解決峰值流量過載的問題。Jaeger Jaeger組件包括 :Client,Agent,Collector,DB,UI等組件,另外Jaeger支持還多種后端存儲,其中包括:內存,Badger,Cassandra,ElasticSearch,gRPC插件。
今天我們就來說一說gRPC插件,這個強大且容易被人遺忘的功能。簡單點來說,gRPC插件提供了一種能夠將Trace數據從Jaeger系統中導出的能力。通過這個能力,開發同學可以很輕松的將Trace對接到一個具備Trace存儲和分析的后端服務,這些服務可以對Trace進行二次分析加工,比如說異常根因分析,異常檢測和告警等,幫助運維和開發同學更好的發現和定位系統潛在的問題
jaeger插件開發流程
為了更好的了解jaeger插件開發,需要先補充gRPC插件的底層實現原理,Jaeger gRPC插件是使用HashiCorp/go-plugin框架實現的。接下我們將介紹Go Plugin以及插件的開發流程。
Go Plugin由HashiCorp公司開源,它遵循設計模式中的開閉原則,通過接口固定上層業務邏輯,通過改變調用不同的RPC服務接口來改實現對業務的擴展。 目前Go Plugin包含兩類插件:RPC Plugin和 GRPCPlugin,兩類插件Client的底層調用不一樣。一個通過net/rpc調用,一個是grpc服務調用,兩個插件都提供了兩個方法,Server和Client方法。Service方法的完成的功能是充當服務端的stub,服務端接受到請求后,調用接口服務端接口的實現。Client方法充當了一個工廠方法,為客戶端生成接口的實現對象。
Go Plugin在啟動過程中會啟動一個子進程,讓子進程開啟RPC/gRPC服務,主進程直接通過RPC/gRPC接口達到插件的方式,它支持多版本服務(后面會講到)并存,它本身并不提供服務的高可用相關的解決方案,這塊需要用戶自己去提供。講了這么多,接下來簡單的介紹Go Plugin的開發的過程
插件開發
下面介紹Go Plugin中的Example下的KV例子,KV例子定義了兩個方法,Put和 Get方法,KV例子包含多個協議版本,本文以gRPC為例。
定義服務接口
type KV interface {// KV接口是KV插件定義的接口Put(key string, value []byte) errorGet(key string) ([]byte, error) }實現接口客戶端
// KV接口客戶端實現, type GRPCClient struct{ // 接口的客戶端封裝了gRPC服務client proto.KVClient }func (m *GRPCClient) Put(key string, value []byte) error {// 調用gRPC服務接口_, err := m.client.Put(context.Background(), &proto.PutRequest{...})return err }func (m *GRPCClient) Get(key string) ([]byte, error) {// 本身調用KV的gRPC服務resp, err := m.client.Get(context.Background(), &proto.GetRequest{...})....return resp.Value, nil實現接口服務端
type GRPCServer struct {Impl KV }// 實現KV gRPC服務 func (m *GRPCServer) Put(ctx context.Context,req *proto.PutRequest) (*proto.Empty, error) {// 接受到請求后,便會調用接口的服務端實現return &proto.Empty{}, m.Impl.Put(req.Key, req.Value) }func (m *GRPCServer) Get(ctx context.Context, req *proto.GetRequest) (*proto.GetResponse, error) {// 接受到請求后,便會調用接口的服務端實現v, err := m.Impl.Get(req.Key)return &proto.GetResponse{Value: v}, err }type KV struct{}func (KV) Put(key string, value []byte) error {// 具體業務實現 }func (KV) Get(key string) ([]byte, error) {// 具體業務實現 }實現go plugin插件接口
// 實現GrpcPlugin接口 type KVGRPCPlugin struct {plugin.Plugin Impl KV //KV接口的實現, }func (p KVGRPCPlugin) GRPCClient(ctx context.Context, broker plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {// 注意返回為接口客戶端實現return &GRPCClient{client: proto.NewKVClient(c)}, nil }func (p KVGRPCPlugin) GRPCServer(broker plugin.GRPCBroker, s *grpc.Server) error {// 注冊gRpc服務proto.RegisterKVServer(s, &GRPCServer{Impl: p.Impl})return nil }插件使用
上面介紹了插件的開發,這部分將介紹插件是如何使用的,插件使用分為兩個部分,插件服務端和插件的客戶端部分
插件服務端
上面部分提到,go plugin啟動時會啟動在本地一個子進程,這里的子進程指的就是插件的服務端,插件服務端需要是一個包含main方法的可執行文件。下面介紹開始簡單介紹插件服務端使用
插件客戶端
插件客戶端流程主要包括,創建插件的Client,啟動插件服務端,獲取插件的接口實現,調用服務接口
client := plugin.NewClient(&plugin.ClientConfig{// shakeConfig包含查件版本和認證信息HandshakeConfig: shared.Handshake,//插件名字和插件的實例的映射關系Plugins: shared.PluginMap,// 這里填寫插件可執行文件的路徑Cmd: exec.Command("sh", "-c", os.Getenv("KV_PLUGIN")),// 插件支持的協議。AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC, plugin.ProtocolNetRPC}, }), // 獲取插件的client端,在這步,go plugin通過Cmd穿過來的參數啟動子進程,同時做插件版本和認證信息的校驗 rpcClient, err := client.Client() // 獲取接口客戶端的對象 raw, err := rpcClient.Dispense("kv_grpc") kv := raw.(shared.KV) // 執行命令 result, err := kv.Get(os.Args[1])jaeger插件接口規范
通過上面的介紹,我們已經可以了解到,Jaeger已經幫我們實現了插件的客戶端&服務端和接口的客戶端,我們只需完成接口的服務端開發,一個gRPC插件的開發完成了。Jaeger在gRPC插件預留了2個插件接口,StorePlugin和ArchiveStorePlugin,兩者區別在于StorePlugin比ArchiveStorePlugin多了DependencyReader接口的定義,DependencyReader接口用來查詢服務間依賴關系。同時這兩個插件接口都暴露了SpanReader和SpanWriter接口,用于Trace/Span的讀寫操作。
SpanReader
// 讀取所有的operation Name func GetOperations(ctx context.Context, query spanstore.OperationQueryParameters) ([]spanstore.Operation, error) // 讀取所有的應用名稱 func GetServices(ctx context.Context) ([]string, error) // 通過符合條件的Trace func FindTraces(ctx context.Context, query *spanstore.TraceQueryParameters) ([]*model.Trace, error) // 通過符合條件的Trace ID func FindTraceIDs(ctx context.Context, query *spanstore.TraceQueryParameters) ([]model.TraceID, error) // 通過Trace ID獲取具體Trace詳情 func GetTrace(ctx context.Context, traceID model.TraceID) (*model.Trace, error)SpanWriter
// 寫入Trace func WriteSpan(ctx context.Context, span *model.Span) errorDependencyReader
// 讀取應用之間的依賴關系,用于繪應用拓撲圖和DAG圖 func GetDependencies(ctx context.Context, endTs time.Time, lookback time.Duration) ([]model.DependencyLink, error)開發SLS Jaeger插件
SLS現已推出分布式鏈路追蹤(Trace)的統一存儲和分析方案,目前支持接入Jaeger,Apache SkyWalking,OpenTelemetry,Zipkin等多種追蹤數據接入。感興趣的可以點擊查看Demo。
SLS的Jaeger插件里的代碼邏輯這里就不贅述。目前插件代碼現在已經開源,GitHub地址:https://github.com/aliyun/aliyun-log-jaeger 歡迎大家加??拍磚,倉庫也提供了一個一鍵Run的Demo示例,歡迎使用,使用方面的文檔已經在Github上提供,下面給大家演示一下效果以及開發Jaeger插件開發背后的意義。
插件背后的思考
整個插件至此開發完成,同時,我們也需要思考一下插件的背后給我們帶來了什么。用戶利用trace所帶來的信息價值,Trace數據采集上來僅僅只是系統監控的開始,挖掘Trace隱藏的信息是構建監控系統最重要的能力。同樣的,再利用Trace所帶來的的信息價值同時,如何持續地保障這種能力也是我們思考的重心
“海恩法則”指出:每一起嚴重事故的背后,必然有29次輕微事故和300起未遂先兆以及1000起事故隱患。 “海恩法則”告訴我們這樣一個道理:每一起安全事故的背后看似偶然,其實都是各種因素積累到一定程度的必然結果, 業務系統每天都再生產大量的Trace數據,這些Trace數據用人的肉眼是無法了解系統運行的狀態的信息,更別去發現系統一些隱藏起來的問題。這時就需要系統提供大數據場景下的分析的能力。SLS做日志起家,每天處理數PB級別的日志量,另外也提供一堆的日志分析的算子,加工處理的工具,為用戶分析系統背后的故事。Trace我們可以理解為是一種特定的日志,只是這個日志帶了關聯的上下文(TraceID,parentSpanID,SpanID),相信SLS在處理Trace日志的也會游刃有余,
作為Jaeger作為一個可觀察性/監控系統的組成部分,是定位和發現業務系統問題的重要數據來源,我們需要保證監控系統比業務系統活的更久。一旦監控系統先于業務系統down掉,此時的監控可以說是完全沒有意義。而Jaeger作為一個開源項目,它本身只提供解決方案,并不會提供部署規模的評估方案和服務如何保證高可用的方案,這種情況下怎么去提供高可用和高性能的后端服務?誰去為監控系統提供最后一層保障? SLS作為一個云服務,其最大的一個特點就是高性能、彈性和免運維,讓用戶輕松應對激增流量或者規模評估不準確的問題,SLS服務本身提供99.9%的可用性以及11個9的數據可靠性。
總結
構建完備的監控體系體系,不僅要保證監控系統的可用性,還需要強大的分析能力。分析能力幫助運維同學快速的定位和發現故障,提高系統的可用性。而Jaeger插件為我們提供接入多種分析系統的擴展能力,這樣的擴展能力能夠讓專業的分析團隊提供專業的分析能力,讓運維和開發團隊的更加專注業務運維。
原文鏈接
本文為阿里云原創內容,未經允許不得轉載。
總結
以上是生活随笔為你收集整理的Jaeger插件开发及背后的思考的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Dubbo-go 服务代理模型
- 下一篇: 【ClickHouse 技术系列】- C