golang 使用 consul 做服務發現


當我們服務越來越多,如果服務配置了彈性伸縮,或者當服務不可用時,我們需要隨時動態掌握可以使用的服務數量,並向可提供響應的服務發送請求。這時我們需要服務發現功能,當新增服務時,服務可以自動向consul注冊,客戶端直接向consul發送請求,獲取可用服務的地址和端口;當服務不可用時,動態的更新consul,刪除該服務在consul中的列表

 

docker安裝consul

  • docker run --name consul1 -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600 consul:latest agent -server -bootstrap-expect 2 -ui -bind=0.0.0.0 -client=0.0.0.0
  • 8500 http 端口,用於 http 接口和 web ui
  • 8300 server rpc 端口,同一數據中心 consul server 之間通過該端口通信
  • 8301 serf lan 端口,同一數據中心 consul client 通過該端口通信
  • 8302 serf wan 端口,不同數據中心 consul server 通過該端口通信
  • 8600 dns 端口,用於服務發現
  • -bbostrap-expect 2: 集群至少兩台服務器,才能選舉集群leader
  • -ui:運行 web 控制台
  • -bind: 監聽網口,0.0.0.0 表示所有網口,如果不指定默認未127.0.0.1,則無法和容器通信
  • -client : 限制某些網口可以訪問
  • docker run --name consul2 -d -p 8501:8500 consul agent -server -ui -bind=0.0.0.0 -client=0.0.0.0 -join 172.17.0.2
  • docker run --name consul2 -d -p 8502:8500 consul agent -server -ui -bind=0.0.0.0 -client=0.0.0.0 -join 172.17.0.2

 

consul_server.go

package main

import (
    "fmt"
    "log"
    "net"
    "net/http"
    _ "net/http/pprof"

    consulapi "github.com/hashicorp/consul/api"
)

var count int64

// consul 服務端會自己發送請求,來進行健康檢查
func consulCheck(w http.ResponseWriter, r *http.Request) {

    s := "consulCheck" + fmt.Sprint(count) + "remote:" + r.RemoteAddr + " " + r.URL.String()
    fmt.Println(s)
    fmt.Fprintln(w, s)
    count++
}

func registerServer() {

    config := consulapi.DefaultConfig()
    config.Address = "10.0.0.10:8500"
    client, err := consulapi.NewClient(config)
    if err != nil {
        log.Fatal("consul client error : ", err)
    }

    registration := new(consulapi.AgentServiceRegistration)
    registration.ID = "serverNode_1"      // 服務節點的名稱
    registration.Name = "serverNode"      // 服務名稱
    registration.Port = 9527              // 服務端口
    registration.Tags = []string{"v1000"} // tag,可以為空
    registration.Address = localIP()      // 服務 IP

    checkPort := 8080
    registration.Check = &consulapi.AgentServiceCheck{ // 健康檢查
        HTTP:                           fmt.Sprintf("http://%s:%d%s", registration.Address, checkPort, "/check"),
        Timeout:                        "3s",
        Interval:                       "5s",  // 健康檢查間隔
        DeregisterCriticalServiceAfter: "30s", //check失敗后30秒刪除本服務,注銷時間,相當於過期時間
        // GRPC:     fmt.Sprintf("%v:%v/%v", IP, r.Port, r.Service),// grpc 支持,執行健康檢查的地址,service 會傳到 Health.Check 函數中
    }

    err = client.Agent().ServiceRegister(registration)
    if err != nil {
        log.Fatal("register server error : ", err)
    }

    http.HandleFunc("/check", consulCheck)
    http.ListenAndServe(fmt.Sprintf(":%d", checkPort), nil)

}

func localIP() string {
    addrs, err := net.InterfaceAddrs()
    if err != nil {
        return ""
    }
    for _, address := range addrs {
        if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
            if ipnet.IP.To4() != nil {
                return ipnet.IP.String()
            }
        }
    }
    return ""
}

func main() {
    registerServer()
}

 

consul_client.go

package main

import (
    "fmt"
    "net"
    "strconv"

    "github.com/Sirupsen/logrus"
    "github.com/hashicorp/consul/api"
)

func main() {
    var lastIndex uint64
    config := api.DefaultConfig()
    config.Address = "10.0.0.10:8500" //consul server

    client, err := api.NewClient(config)
    if err != nil {
        fmt.Println("api new client is failed, err:", err)
        return
    }
    services, metainfo, err := client.Health().Service("serverNode", "v1000", true, &api.QueryOptions{
        WaitIndex: lastIndex, // 同步點,這個調用將一直阻塞,直到有新的更新
    })
    if err != nil {
        logrus.Warn("error retrieving instances from Consul: %v", err)
    }
    lastIndex = metainfo.LastIndex

    addrs := map[string]struct{}{}
    for _, service := range services {
        fmt.Println("service.Service.Address:", service.Service.Address, "service.Service.Port:", service.Service.Port)
        addrs[net.JoinHostPort(service.Service.Address, strconv.Itoa(service.Service.Port))] = struct{}{}
    }
}

go run ./consul_server.go 

在瀏覽器中輸入http://localhost:8500/ui/dc1/services 即可看到注冊

 

 執行 go run consul_client.go 即可獲取到 server 注冊的 IP和地址

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM