基于ectd实现go的服务注册
2021年11月27日 18:42
描述
基于etcd实现go程序的服务注册,所看的学习资料均比较简单, 实际中要经过反复测试,自己写了一个先用着,有坑再填.
需求
1. 注册一个服务: 程序启动时 2. 注销服务: a. 程序异常退出时, 自动注销, 有5秒TTL延迟; b. 调用Stop()接口主动注销 3. 健壮性: a.ectd单节点重启, ectd本身支持; b. etcd全部重启后, 能够恢复正常 4. key的格式: 前缀/ip/pid 5. value: 字符串.(可以先转为json, 再转string)
创建etcd客户端
//不是重点, 摘要如下代码
cli, err := clientv3.New(clientv3.Config{
Endpoints: ec.Endpoints,
DialTimeout: 5 * time.Second,
})
if err != nil {
log.Fatal(err)
}
创建Service对象, 包含服务注册
package main import ( "context" "errors" "fmt" clientv3 "go.etcd.io/etcd/client/v3" "go.etcd.io/etcd/client/v3/clientv3util" "go.uber.org/zap" "go.uber.org/zap/zapcore" "net" "os" "strings" "sync" "test/etcd" "time" ) var IP string var PID int func init(){ //日志 encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder encoder := zapcore.NewConsoleEncoder(encoderConfig) //创建 var clevel zapcore.Level clevel.Set("debug") log := zap.New(zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), clevel)) //设为全局 zap.ReplaceGlobals(log) // IP, _ = GetLocalIP() PID = os.Getpid() } func GetLocalIP() (string,error){ addrs, err := net.InterfaceAddrs() if err != nil { zap.S().Warn(err) return "", err } for _, addr := range addrs{ if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback(){ if ipnet.IP.To4() != nil { return ipnet.IP.String(), nil } } } return "", errors.New("unable to determine local ip") } func RegisterService(endpoints []string, key string, value string) *Service{ s := &Service{ Value: value, endpoints: endpoints, } s.TTL = 5 s.Key = strings.Join([]string{key, IP, fmt.Sprintf("%d", PID)}, "/") s.init() return s } type Service struct{ Key string //key 格式: /前缀/名称/ip/pid Value string //存放信息 endpoints []string //etcd地址 //心跳 IsAlive bool //是否存活 heartCancel context.CancelFunc //取消心跳 //租约 TTL int64 //租约(秒) grant *clientv3.LeaseGrantResponse //租约 } func (s *Service) init(){ //启用etcd连接 etcd.EnableEtcd(s.endpoints) //心跳 go s.start() } func (s *Service) start(){ defer func(){ s.IsAlive = false //注销服务 s.deleteService() //关闭续约(如果共用会误关?) etcd.Cli().Lease.Close() }() var aliveRsp <-chan *clientv3.LeaseKeepAliveResponse var err error var ctx context.Context for{ if !s.IsAlive{ // 注册服务 s.registerService() // 续期信号chan aliveRsp, err = etcd.Cli().KeepAlive(context.TODO(), s.grant.ID) if err != nil{ zap.S().Warn(err) } ctx, s.heartCancel = context.WithCancel(context.Background()) } // 监听心跳信号 select{ case rsp := <- aliveRsp: //异常时无信号 if rsp ==nil{ s.IsAlive = false zap.S().Info("service missing signal") time.Sleep(time.Second*5) continue } s.IsAlive = true zap.S().Debugf("service alive %v", rsp.ID) case <- ctx.Done(): zap.S().Info("service stopping") return } } } //停止 func (s *Service) Stop(){ s.heartCancel() }
[佛說大乘無量壽莊嚴清淨平等覺經pdf](http://www.sxjy360.top/page-download/)
[净土大经科注2014-doc](http://www.sxjy360.top/page-download/)
[此生必看的科学实验-水知道答案](http://www.sxjy360.top/page-download/)
[印光大师十念法(胡小林主讲第1集)](http://www.sxjy360.top/page-download/)