1.普通接口注册服务
执行后就会出现下面那个服务,他这里会检查这个服务是否可用,不可用就会自动剔除
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() {
// 创建连接consul服务配置
config := consulapi.DefaultConfig()
config.Address = consulAddress
client, err := consulapi.NewClient(config)
if err != nil {
fmt.Println("consul client error : ", err)
}
// 创建注册到consul的服务到
registration := new(consulapi.AgentServiceRegistration)
registration.ID = "shitingbao"
registration.Name = "service_shitingbao"//根据这个名称来找这个服务
registration.Port = localPort
registration.Tags = []string{"shitingbao_test_service"}//这个就是一个标签,可以根据这个来找这个服务,相当于V1.1这种
registration.Address = localIP
// 增加consul健康检查回调函数
check := new(consulapi.AgentServiceCheck)
check.HTTP = fmt.Sprintf("http://%s:%d", registration.Address, registration.Port)
check.Timeout = "5s" //超时
check.Interval = "5s" //健康检查频率
check.DeregisterCriticalServiceAfter = "30s" // 故障检查失败30s后 consul自动将注册服务删除
registration.Check = check
// 注册服务到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 启动
func ServerLoad() {
consulRegister()
//定义一个http接口
http.HandleFunc("/", Handler)
err := http.ListenAndServe(":3001", nil)
if err != nil {
fmt.Println("error: ", err.Error())
}
}
2.grpc注册入consul
grpc需要多做一步,因为consul需要一个健康检查,在api中验证是否可用是可以直接检查就行了,但是对于rpc的这种协议不一样处理,这里需要写一个自定义的检查函数,给consul检查。这个函数需要实现consul包中的RegisterHealthServer接口,grpc服务的代码就不展示了,这里展示了注册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 健康检查实现
type HealthImpl struct{}
// Check 实现健康检查接口,这里直接返回健康状态,这里也可以有更复杂的健康检查策略,比如根据服务器负载来返回
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 这个没用,只是为了让HealthImpl实现RegisterHealthServer内部的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("外置服务开启失败:", 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注册进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), // 服务节点的名称
Name: fmt.Sprintf("grpc.health.v1.%v", "StbServe"), // 服务名称
Tags: []string{"StbServe"}, // tag,可以为空
Port: localPort, // 服务端口
Address: localIP, // 服务 IP
Check: &api.AgentServiceCheck{ // 健康检查
Interval: "5s", // 健康检查间隔
// grpc 支持,执行健康检查的地址,service 会传到 Health.Check 函数中
GRPC: fmt.Sprintf("%v:%v/%v", localIP, localPort, "StbServe"),
DeregisterCriticalServiceAfter: "5s", // 注销时间,相当于过期时间
},
}
if err := agent.ServiceRegister(reg); err != nil {
panic(err)
}
}
func grpcLoad() {
grpcRegister()
externalServer()
}
3.服务查看
你可以在你的consul的UI中看见这个服务
4.发现服务
发现服务中的代码都是一样的,如下
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, // 同步点,这个调用将一直阻塞,直到有新的更新
})
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标签为shitingbao_test_service的服务,这个service_shitingbao就是上面红框里面的那个服务名称,对应的tag标签要对应上,没有就是空,不然获取不到