Jaeger源碼分析——服務發現與註冊

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

原文:Jaeger源碼分析——服務發現與註冊

聲明

 Jaeger官方並沒有明確說明其服務註冊和服務發現的具體使用和介紹,這部分功能是在分析源碼的時候,發現其原理與服務註冊和服務發現類似,所以結合自己對服務註冊和服務發現的認識,做一次總結,有錯還請指點。

TChannel服務註冊和服務發現

 Jaeger不藉助第三方工具也能實現服務註冊和服務發現,這部分功能由其依賴的RPC架構提供。

第三方註冊——手動註冊

go run cmd/agent/main.go --collector.host-port=192.168.0.10:14267,192.168.0.11:14267

 在啟動agent的時候,可配置多個collector靜態地址,這部分地址會形成一張註冊表。

註冊表

  • 註冊表結構
github.com/uber/tchannel-go/peer.go #59type PeerList struct {    sync.RWMutex    parent          *RootPeerList    //以hostPort為下標組成註冊表    peersByHostPort map[string]*peerScore    //負載平衡實現    peerHeap        *peerHeap    scoreCalculator ScoreCalculator    lastSelected    uint64}
  • 健全狀態檢查
github.com/jaegertracing/jaeger/pkg/discovery/peerlistmgr/peer_list_mgr.go  #150func (m *PeerListManager) ensureConnections() {    peers := m.peers.Copy()    minPeers := m.getMinPeers(peers)    numConnected, notConnected := m.findConnected(peers)    //只要有3個有效服務,就不會進行健全狀態檢查    if numConnected >= minPeers {      return    }    ......    for i := range notConnected {      // swap current peer with random from the remaining positions      r := i + m.rnd.Intn(len(notConnected)-i)      notConnected[i], notConnected[r] = notConnected[r], notConnected[i]      // try to connect to current peer (swapped)      peer := notConnected[i]      m.logger.Info("Trying to connect to peer", zap.String("host:port", peer.HostPort()))      //用於控制逾時      ctx, cancel := context.WithTimeout(context.Background(), m.connCheckTimeout)      conn, err := peer.GetConnection(ctx)      cancel()      if err != nil {        m.logger.Error("Unable to connect", zap.String("host:port", peer.HostPort()), zap.Duration("connCheckTimeout", m.connCheckTimeout), zap.Error(err))        continue      }      ......    }}

 在註冊表上的地址,TChannel都會進行健全狀態檢查,每秒進行一次,如果0.25秒沒有串連上,視為服務不可用。如果串連成功則保留當前服務執行個體,供agent提交資料使用。

github.com/uber/tchannel-go/connection.go #228func (ch *Channel) newOutboundConnection(timeout time.Duration, hostPort string, events connectionEvents) (*Connection, error) {    conn, err := net.DialTimeout("tcp", hostPort, timeout)    if err != nil {      if ne, ok := err.(net.Error); ok && ne.Timeout() {        ch.log.WithFields(LogField{"hostPort", hostPort}, LogField{"timeout", timeout}).Infof("Outbound net.Dial timed out")        err = ErrTimeout      }      return nil, err    }    return ch.newConnection(conn, hostPort, connectionWaitingToSendInitReq, events), nil}

用戶端服務發現

  • 軟負載平衡
github.com/uber/tchannel-go/peer.go #149func (l *PeerList) choosePeer(prevSelected map[string]struct{}, avoidHost bool) *Peer {    var psPopList []*peerScore    var ps *peerScore    ......    size := l.peerHeap.Len()    for i := 0; i < size; i++ {      //把peer從Heap頭部彈出來      popped := l.peerHeap.popPeer()      if canChoosePeer(popped.HostPort()) {          ps = popped          break      }      psPopList = append(psPopList, popped)    }    //不符合的放入Heap尾部    for _, p := range psPopList {        heap.Push(l.peerHeap, p)    }    if ps == nil {        return nil    }    //合格打分,再放入Heap尾部    l.peerHeap.pushPeer(ps)    ps.chosenCount.Inc()    return ps.Peer}

 當Agent需要提交資料的時候,會從TChannel的負載平衡擷取peer(服務資訊),當有多個的時候,TChannel通過輪詢方式,查詢peer。實現方式:註冊表把所有peer放入peerHeap,先把peer從頭部彈出,再把peer放回尾部,從而實現輪詢策略的負載平衡。

  • 重試
github.com/uber/tchannel-go/retry.go #212func (ch *Channel) RunWithRetry(runCtx context.Context, f RetriableFunc) error {    var err error    opts := getRetryOptions(runCtx)    rs := ch.getRequestState(opts)    defer requestStatePool.Put(rs)    //預設重試5次    for i := 0; i < opts.MaxAttempts; i++ {        rs.Attempt++        if opts.TimeoutPerAttempt == 0 {            err = f(runCtx, rs)        } else {            attemptCtx, cancel := context.WithTimeout(runCtx, opts.TimeoutPerAttempt)            err = f(attemptCtx, rs)            cancel()        }        if err == nil {            return nil        }        if !opts.RetryOn.CanRetry(err) {            if ch.log.Enabled(LogLevelInfo) {                ch.log.WithFields(ErrField(err)).Info("Failed after non-retriable error.")            }          return err        }        ......    }    // Too many retries, return the last error    return err}

 網路之間的通訊避免不了網路異常,所以為了提高可用性,重試是其中一種方式。當從負載平衡擷取peer提交資料到Collector,如果提交失敗,會再從負載平衡擷取peer,最多5次,如果5次都不成功就會放棄這次提交。

Consul+docker 服務註冊和服務發現

 使用consul實現服務註冊和服務發現是一件很簡單的事情。很多功能都是開箱即用。

準備工作

  • 啟動Consul——ip:172.18.0.2
docker run -itd --network=backend \-p 8400:8400 -p 8500:8500 -p 8600:53/udp \-h node1 progrium/consul -server -bootstrap -ui-dir /ui
  • 啟動Agent
docker run \-itd --network=backend \--name=jaeger-agent \-p5775:5775/udp \-p6831:6831/udp \-p6832:6832/udp \-p5778:5778/tcp \--dns-search="service.consul" --dns=172.18.0.2 \jaegertracing/jaeger-agent \/go/bin/agent-linux --collector.host-port=jaeger-collector:14267
  • 啟動Collector
#node1docker run -itd --network=backend \--name=jaeger-collector-node1 \-p :14267 \--dns-search="service.consul" --dns=172.18.0.2 \jaegertracing/jaeger-collector \/go/bin/collector-linux \--span-storage.type=cassandra \--cassandra.keyspace=jaeger_v1_dc \--cassandra.servers=cassandra:9042#node2docker run -itd --network=backend \--name=jaeger-collector-node2 \-p :14267 \--dns-search="service.consul" --dns=172.18.0.2 \jaegertracing/jaeger-collector \/go/bin/collector-linux \--span-storage.type=cassandra \--cassandra.keyspace=jaeger_v1_dc \--cassandra.servers=cassandra:9042

服務註冊——自動註冊

docker run -itd --net=backend --name=registrator \--volume=/var/run/docker.sock:/tmp/docker.sock \gliderlabs/registrator:latest \consul://172.18.0.2:8500

 使用consul+docker的形式,只要部署好服務,就會被自動註冊到consul,十分簡單。

註冊表

  • 查看註冊表資訊

查看註冊表資訊http://localhost:8500/ui/#/dc1/nodes/node1

 可以看到啟動的2個Collector服務ip分別為:172.18.0.5和172.18.0.8

  • 健全狀態檢查

 consul提供了很多種健全狀態檢查方式:HTTP、TCP、Docker、Shell和TTL。詳情可以查看官網。

服務端服務發現

 Consul相對於Agent和Collector是遠程服務,所以提供了2種服務發現方式:HTTP和DNS,在這裡主要使用是DNS,因為簡單,輕量。

  • DNS和軟負載平衡

 當Agent通過DNS解析出多個IP的時候,Consul會隨機選擇一個IP給Agent實現負載平衡。

 由於DNS存在緩衝,所以有可能出現,服務不健康,一樣會被正常解析,所以在預設情況下Consul是沒有設定緩衝時間,TTL為0,但是也考慮到了不緩衝對Consul的壓力,所以開放配置,讓我們去決定緩衝時間點DNS Caching。

總結

TChannel與Consul+docker實現的服務發現和服務註冊中都有他們的優缺點:

服務註冊

  • TChannel

 TChannel的服務註冊適用於一些基礎服務,例如Jaeger就屬於一種基礎服務,這種服務一旦部署很少會變動。

  • Consul + docker

 在現在docker流行的大環境下使用Consul實現的服務註冊會簡單很多,docker有一個特點就是ip地址是動態,所以它很適合業務情境,因為業務經常變動,服務也隨著變化。

健全狀態檢查

 TChannel和Consul都提供了健全狀態檢查,但是都只是檢測服務是否正在運行,無法瞭解是否能夠正常處理請求。

服務發現

  • TChannel

 TChannel使用的是用戶端服務發現,這種方式相對於Consul的服務端服務發現的優點就是沒有了遠程網路開銷,單點問題。同時缺點就是各個語言都需要自己實現註冊表,負載平衡等功能。

  • Consul

 Consul使用服務端服務發現,它可以很好的和其他服務結合使用,不需要關係註冊表,負載平衡等。而且關於網路開銷和單點問題都提供了方案。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.