1.普通接口注冊服務(wù)
執(zhí)行后就會出現(xiàn)下面那個(gè)服務(wù),他這里會檢查這個(gè)服務(wù)是否可用问裕,不可用就會自動(dòng)剔除
package main
import (
"fmt"
"net/http"
consulapi "github.com/hashicorp/consul/api"
)
const (
consulAddress = "124.70.156.31:8500"
localIP = "124.70.156.31"
localPort = 3001
)
func consulRegister() {
// 創(chuàng)建連接consul服務(wù)配置
config := consulapi.DefaultConfig()
config.Address = consulAddress
client, err := consulapi.NewClient(config)
if err != nil {
fmt.Println("consul client error : ", err)
}
// 創(chuàng)建注冊到consul的服務(wù)到
registration := new(consulapi.AgentServiceRegistration)
registration.ID = "shitingbao"
registration.Name = "service_shitingbao"http://根據(jù)這個(gè)名稱來找這個(gè)服務(wù)
registration.Port = localPort
registration.Tags = []string{"shitingbao_test_service"}//這個(gè)就是一個(gè)標(biāo)簽哥艇,可以根據(jù)這個(gè)來找這個(gè)服務(wù),相當(dāng)于V1.1這種
registration.Address = localIP
// 增加consul健康檢查回調(diào)函數(shù)
check := new(consulapi.AgentServiceCheck)
check.HTTP = fmt.Sprintf("http://%s:%d", registration.Address, registration.Port)
check.Timeout = "5s" //超時(shí)
check.Interval = "5s" //健康檢查頻率
check.DeregisterCriticalServiceAfter = "30s" // 故障檢查失敗30s后 consul自動(dòng)將注冊服務(wù)刪除
registration.Check = check
// 注冊服務(wù)到consul
err = client.Agent().ServiceRegister(registration)
}
//Handler 3001
func Handler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("you are visiting health check api:3001"))
}
//ServerLoad 啟動(dòng)
func ServerLoad() {
consulRegister()
//定義一個(gè)http接口
http.HandleFunc("/", Handler)
err := http.ListenAndServe(":3001", nil)
if err != nil {
fmt.Println("error: ", err.Error())
}
}
2.grpc注冊入consul
grpc需要多做一步僻澎,因?yàn)閏onsul需要一個(gè)健康檢查,在api中驗(yàn)證是否可用是可以直接檢查就行了十饥,但是對于rpc的這種協(xié)議不一樣處理窟勃,這里需要寫一個(gè)自定義的檢查函數(shù),給consul檢查逗堵。這個(gè)函數(shù)需要實(shí)現(xiàn)consul包中的RegisterHealthServer接口秉氧,grpc服務(wù)的代碼就不展示了,這里展示了注冊grpc的過程
package main
import (
"context"
"fmt"
"log"
"net"
stb_server "stb_consul/external_service/stb_server"
"stb_consul/external_service/stbserver"
"github.com/hashicorp/consul/api"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/health/grpc_health_v1"
)
// HealthImpl 健康檢查實(shí)現(xiàn)
type HealthImpl struct{}
// Check 實(shí)現(xiàn)健康檢查接口蜒秤,這里直接返回健康狀態(tài)汁咏,這里也可以有更復(fù)雜的健康檢查策略,比如根據(jù)服務(wù)器負(fù)載來返回
func (h *HealthImpl) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) {
return &grpc_health_v1.HealthCheckResponse{
Status: grpc_health_v1.HealthCheckResponse_SERVING,
}, nil
}
//Watch 這個(gè)沒用作媚,只是為了讓HealthImpl實(shí)現(xiàn)RegisterHealthServer內(nèi)部的interface接口
func (h *HealthImpl) Watch(req *grpc_health_v1.HealthCheckRequest, w grpc_health_v1.Health_WatchServer) error {
return nil
}
//grpc開啟
func externalServer() {
lis, err := net.Listen("tcp", ":3001")
if err != nil {
logrus.Info("外置服務(wù)開啟失敗:", err)
panic(err)
}
logrus.WithFields(logrus.Fields{
"tcp": ":3001",
}).Info("external server")
s := grpc.NewServer()
stbserver.RegisterStbServerServer(s, &stb_server.StbServe{})
grpc_health_v1.RegisterHealthServer(s, &HealthImpl{})//比普通的grpc開啟多了這一步
s.Serve(lis)
log.Println("grpc start")
}
//grpc注冊進(jìn)consul
func grpcRegister() {
config := api.DefaultConfig()
config.Address = consulAddress
client, err := api.NewClient(config)
if err != nil {
panic(err)
}
agent := client.Agent()
reg := &api.AgentServiceRegistration{
ID: fmt.Sprintf("%v-%v-%v", "StbServe", localIP, localPort), // 服務(wù)節(jié)點(diǎn)的名稱
Name: fmt.Sprintf("grpc.health.v1.%v", "StbServe"), // 服務(wù)名稱
Tags: []string{"StbServe"}, // tag攘滩,可以為空
Port: localPort, // 服務(wù)端口
Address: localIP, // 服務(wù) IP
Check: &api.AgentServiceCheck{ // 健康檢查
Interval: "5s", // 健康檢查間隔
// grpc 支持,執(zhí)行健康檢查的地址纸泡,service 會傳到 Health.Check 函數(shù)中
GRPC: fmt.Sprintf("%v:%v/%v", localIP, localPort, "StbServe"),
DeregisterCriticalServiceAfter: "5s", // 注銷時(shí)間漂问,相當(dāng)于過期時(shí)間
},
}
if err := agent.ServiceRegister(reg); err != nil {
panic(err)
}
}
func grpcLoad() {
grpcRegister()
externalServer()
}
3.服務(wù)查看
你可以在你的consul的UI中看見這個(gè)服務(wù)
image
image
4.發(fā)現(xiàn)服務(wù)
發(fā)現(xiàn)服務(wù)中的代碼都是一樣的,如下
package main
import (
"fmt"
"github.com/hashicorp/consul/api"
"github.com/sirupsen/logrus"
)
func client() {
var lastIndex uint64
config := api.DefaultConfig()
config.Address = "124.70.156.31: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("service_shitingbao", "shitingbao_test_service", true, &api.QueryOptions{
WaitIndex: lastIndex, // 同步點(diǎn)女揭,這個(gè)調(diào)用將一直阻塞蚤假,直到有新的更新
})
if err != nil {
logrus.Panic("error retrieving instances from Consul:", err)
}
lastIndex = metainfo.LastIndex
for _, service := range services {
fmt.Println("service.Service.Address:", service.Service.Address, "service.Service.Port:", service.Service.Port)
}
}
這里會輸出ServiceName為‘service_shitingbao’,tag標(biāo)簽為shitingbao_test_service的服務(wù)吧兔,這個(gè)service_shitingbao就是上面紅框里面的那個(gè)服務(wù)名稱磷仰,對應(yīng)的tag標(biāo)簽要對應(yīng)上,沒有就是空境蔼,不然獲取不到