etcd v3 服務註冊與發現 Go代碼

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

本文整理一下思路,編寫樣本(golang),以便加深etcd的理解

大致如下,監聽程式為master,服務為service

1 service 啟動時向etcd註冊自己的資訊,即註冊到services/  這個目錄 

2 service 可能異常推出,需要維護一個TTL(V3 使用 lease實現),類似於心跳,掛掉了,master可以監聽到

3 master監聽 services/ 目錄下的所有服務,根據不同action(V3有put/delete),進行處理

service註冊 

提供 key(service name), value(serviceInfo)進行registered

start 啟動後,執行keeplive(), 維護心跳,掛掉時revoke()

同時監聽 stop chan, 相當於unregistered

package discoveryimport (    "github.com/coreos/etcd/clientv3"    "context"    "time"    "log"    "encoding/json"    "errors")//the detail of service type ServiceInfo struct{    IP   string}type Service struct {    Name        string    Info        ServiceInfo    stop        chan error    leaseid     clientv3.LeaseID    client      *clientv3.Client}func NewService(name string, info ServiceInfo,endpoints []string) (*Service, error) {    cli, err := clientv3.New(clientv3.Config{        Endpoints:    endpoints,        DialTimeout: 2*time.Second,    })    if err != nil {        log.Fatal(err)        return nil, err    }    return &Service {        Name:        name,        Info:        info,        stop:        make (chan error),        client:     cli,    },err}func (s *Service)  Start() error {        ch, err := s.keepAlive()    if err != nil {        log.Fatal(err)        return err    }    for {        select {        case err := <- s.stop:            s.revoke()            return err        case <- s.client.Ctx().Done():            return errors.New("server closed")        case ka, ok := <-ch:            if !ok {                log.Println("keep alive channel closed")                s.revoke()                return nil            } else {                log.Printf("Recv reply from service: %s, ttl:%d", s.Name, ka.TTL)            }        }    }}func (s *Service) Stop()  {    s.stop <- nil }func (s *Service) keepAlive() (<-chan *clientv3.LeaseKeepAliveResponse, error){    info := &s.Info    key := "services/" + s.Name    value, _ := json.Marshal(info)    // minimum lease TTL is 5-second    resp, err := s.client.Grant(context.TODO(), 5)    if err != nil {        log.Fatal(err)        return nil, err    }    _, err = s.client.Put(context.TODO(), key, string(value), clientv3.WithLease(resp.ID))    if err != nil {        log.Fatal(err)        return nil, err    }    s.leaseid = resp.ID    return  s.client.KeepAlive(context.TODO(), resp.ID)}func (s *Service) revoke() error {    _, err := s.client.Revoke(context.TODO(), s.leaseid)    if err != nil {        log.Fatal(err)    }    log.Printf("servide:%s stop\n", s.Name)    return err}

監聽程式Master

提供監聽路徑path,啟動master,當put時加入 map,  delete時 從map去掉

package discoveryimport (    "github.com/coreos/etcd/clientv3"    "context"    "log"    "time"    "encoding/json"    "fmt")type Master struct {    Path         string    Nodes         map[string] *Node    Client         *clientv3.Client}//node is a client type Node struct {    State    bool    Key        string    Info    ServiceInfo}func NewMaster(endpoints []string, watchPath string) (*Master,error) {    cli, err := clientv3.New(clientv3.Config{        Endpoints:    endpoints,        DialTimeout: time.Second,    })    if err != nil {        log.Fatal(err)        return nil,err    }    master := &Master {        Path:    watchPath,        Nodes:    make(map[string]*Node),        Client: cli,    }    go master.WatchNodes()    return master,err}func (m *Master) AddNode(key string,info *ServiceInfo) {    node := &Node{        State:    true,        Key:    key,        Info:    *info,    }    m.Nodes[node.Key] = node}func GetServiceInfo(ev *clientv3.Event) *ServiceInfo {    info := &ServiceInfo{}    err := json.Unmarshal([]byte(ev.Kv.Value), info)    if err != nil {        log.Println(err)    }    return info}func (m *Master) WatchNodes()  {    rch := m.Client.Watch(context.Background(), m.Path, clientv3.WithPrefix())    for wresp := range rch {        for _, ev := range wresp.Events {            switch ev.Type {                case clientv3.EventTypePut:                    fmt.Printf("[%s] %q : %q\n", ev.Type, ev.Kv.Key, ev.Kv.Value)                    info := GetServiceInfo(ev)                        m.AddNode(string(ev.Kv.Key),info)                case clientv3.EventTypeDelete:                    fmt.Printf("[%s] %q : %q\n", ev.Type, ev.Kv.Key, ev.Kv.Value)                    delete(m.Nodes, string(ev.Kv.Key))            }        }    }}

service使用樣本,20s後斷開

package mainimport ("fmt"dis "discovery""log""time")func main() {serviceName := "s-test"serviceInfo := dis.ServiceInfo{IP:"192.168.1.26"}s, err := dis.NewService(serviceName, serviceInfo,[]string {"http://192.168.1.17:2379", "http://192.168.1.17:2479", "http://192.168.1.17:2579",})if err != nil {log.Fatal(err)}fmt.Printf("name:%s, ip:%s\n", s.Name, s.Info.IP)go func() {time.Sleep(time.Second*20)s.Stop()}()s.Start()}

 master使用樣本

package mainimport ("log""time""fmt"dis "discovery")func main() {m, err := dis.NewMaster([]string{"http://192.168.1.17:2379","http://192.168.1.17:2479","http://192.168.1.17:2579",}, "services/")if err != nil {log.Fatal(err)}for {for k, v := range  m.Nodes {fmt.Printf("node:%s, ip=%s\n", k, v.Info.IP)}fmt.Printf("nodes num = %d\n",len(m.Nodes))time.Sleep(time.Second * 5)}}

 

執行結果(需要提前搭建 etcd伺服器,可以到github下載,文末提供簡單啟動指令碼)

go run master

go run service

 

etcd伺服器啟動指令碼(執行環境 CentOS6.5)

#!/bin/shwork_path=$(dirname $0)cd ./${work_path}#echo $(pwd)#echo `date`case $1 in1)echo -e "[1]start first server\n"./etcd --name cd0 --initial-advertise-peer-urls http://127.0.0.1:2380 \  --listen-peer-urls http://127.0.0.1:2380 \  --listen-client-urls http://192.168.1.17:2379,http://127.0.0.1:2379 \  --advertise-client-urls http://192.168.1.17:2379,http://127.0.0.1:2379 \  --initial-cluster-token etcd-cluster-1 \  --initial-cluster cd0=http://127.0.0.1:2380,cd1=http://127.0.0.1:2480,cd2=http://127.0.0.1:2580 \  --initial-cluster-state new  ;;2)echo -e "[2]start second  server\n"./etcd --name cd1 --initial-advertise-peer-urls http://127.0.0.1:2480 \  --listen-peer-urls http://127.0.0.1:2480 \  --listen-client-urls http://192.168.1.17:2479,http://127.0.0.1:2479 \  --advertise-client-urls http://192.168.1.17:2479,http://127.0.0.1:2479 \  --initial-cluster-token etcd-cluster-1 \  --initial-cluster cd0=http://127.0.0.1:2380,cd1=http://127.0.0.1:2480,cd2=http://127.0.0.1:2580 \  --initial-cluster-state new  ;;3)echo -e "[3]start third server\n"./etcd --name cd2 --initial-advertise-peer-urls http://127.0.0.1:2580 \  --listen-peer-urls http://127.0.0.1:2580 \  --listen-client-urls http://192.168.1.17:2579,http://127.0.0.1:2579 \  --advertise-client-urls http://192.168.1.17:2579,http://127.0.0.1:2579 \  --initial-cluster-token etcd-cluster-1 \  --initial-cluster cd0=http://127.0.0.1:2380,cd1=http://127.0.0.1:2480,cd2=http://127.0.0.1:2580 \  --initial-cluster-state new  ;;*)echo "error paramater";;esac
View Code

 

完整代碼,請移步 git@github.com:moonlong/etcd-discovery.git 

歡迎斧正

 

完!

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.