go_dreamfactory/lego/sys/registry/nacos.go
2022-06-07 20:18:22 +08:00

414 lines
11 KiB
Go

package registry
import (
"context"
"fmt"
"sync"
"time"
"go_dreamfactory/lego/core"
"go_dreamfactory/lego/sys/log"
hash "github.com/mitchellh/hashstructure"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/clients/naming_client"
"github.com/nacos-group/nacos-sdk-go/common/constant"
"github.com/nacos-group/nacos-sdk-go/model"
"github.com/nacos-group/nacos-sdk-go/vo"
)
func newNacos(options Options) (sys *Nacos_Registry, err error) {
ctx, cancel := context.WithCancel(context.TODO())
sys = &Nacos_Registry{
options: options,
ctx: ctx,
cancel: cancel,
shash: make(map[string]uint64),
services: make(map[string]*ServiceNode),
subscribe: make(map[string]*vo.SubscribeParam),
rpcsubs: make(map[core.Rpc_Key][]*ServiceNode),
}
// 创建clientConfig
clientConfig := constant.ClientConfig{
NamespaceId: options.Nacos_NamespaceId,
TimeoutMs: options.Nacos_TimeoutMs,
BeatInterval: options.Nacos_BeatInterval,
Username: options.Nacos_UserName,
Password: options.Nacos_Password,
NotLoadCacheAtStart: true,
UpdateCacheWhenEmpty: true,
LogDir: "nacos/log",
CacheDir: "nacos/cache",
RotateTime: "1h",
MaxAge: 3,
LogLevel: "error",
}
// 至少一个ServerConfig
serverConfigs := []constant.ServerConfig{
{
IpAddr: options.Nacos_NacosAddr,
ContextPath: "/nacos",
Port: options.Nacos_Port,
Scheme: "http",
},
}
// 创建服务发现客户端的另一种方式 (推荐)
sys.client, err = clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: &clientConfig,
ServerConfigs: serverConfigs,
},
)
return
}
type Nacos_Registry struct {
options Options
client naming_client.INamingClient
isstart bool
ctx context.Context
cancel context.CancelFunc
slock sync.RWMutex
shash map[string]uint64
subscribe map[string]*vo.SubscribeParam
services map[string]*ServiceNode
rlock sync.RWMutex
rpcsubs map[core.Rpc_Key][]*ServiceNode
}
func (this *Nacos_Registry) Start() (err error) {
if err = this.getServices(); err != nil && err.Error() != "instance list is empty!" {
return
}
if err = this.registerSNode(&ServiceNode{
Tag: this.options.Service.GetTag(),
Id: this.options.Service.GetId(),
IP: this.options.Service.GetIp(),
Port: this.options.Service.GetPort(),
Type: this.options.Service.GetType(),
Category: this.options.Service.GetCategory(),
Version: this.options.Service.GetVersion(),
RpcId: this.options.Service.GetRpcId(),
PreWeight: this.options.Service.GetPreWeight(),
}); err != nil {
return
}
ctx1, _ := context.WithCancel(this.ctx)
go this.run(ctx1)
ctx2, _ := context.WithCancel(this.ctx)
go this.listener(ctx2)
this.isstart = true
return
}
func (this *Nacos_Registry) Stop() (err error) {
this.cancel()
this.isstart = false
return
}
func (this *Nacos_Registry) PushServiceInfo() (err error) {
if this.isstart {
err = this.registerSNode(&ServiceNode{
Tag: this.options.Service.GetTag(),
Id: this.options.Service.GetId(),
IP: this.options.Service.GetIp(),
Port: this.options.Service.GetPort(),
Type: this.options.Service.GetType(),
Category: this.options.Service.GetCategory(),
Version: this.options.Service.GetVersion(),
RpcId: this.options.Service.GetRpcId(),
PreWeight: this.options.Service.GetPreWeight(),
})
}
return
}
func (this *Nacos_Registry) GetServiceById(sId string) (n *ServiceNode, err error) {
this.slock.RLock()
n, ok := this.services[sId]
this.slock.RUnlock()
if !ok {
return nil, fmt.Errorf("No Found %s", sId)
}
return
}
func (this *Nacos_Registry) GetServiceByType(sType string) (n []*ServiceNode) {
this.slock.RLock()
defer this.slock.RUnlock()
n = make([]*ServiceNode, 0)
for _, v := range this.services {
if v.Type == sType {
n = append(n, v)
}
}
return
}
func (this *Nacos_Registry) GetAllServices() (n []*ServiceNode) {
this.slock.RLock()
defer this.slock.RUnlock()
n = make([]*ServiceNode, 0)
for _, v := range this.services {
n = append(n, v)
}
return
}
func (this *Nacos_Registry) GetServiceByCategory(category core.S_Category) (n []*ServiceNode) {
this.slock.RLock()
defer this.slock.RUnlock()
n = make([]*ServiceNode, 0)
for _, v := range this.services {
if v.Category == category {
n = append(n, v)
}
}
return
}
func (this *Nacos_Registry) GetRpcSubById(rId core.Rpc_Key) (n []*ServiceNode) {
n = make([]*ServiceNode, 0)
this.rlock.RLock()
d, ok := this.rpcsubs[rId]
this.rlock.RUnlock()
if ok {
n = d
}
return
}
//内部函数-------------------------------------------------------------------------------------------------------------------------
func (this *Nacos_Registry) run(ctx context.Context) {
t := time.NewTicker(time.Duration(this.options.Consul_RegisterInterval) * time.Second)
defer t.Stop()
locp:
for {
select {
case <-t.C:
err := this.PushServiceInfo()
if err != nil {
log.Warnf("service run Server.Register error: %v", err)
}
case <-ctx.Done():
break locp
}
}
log.Infof("Sys Registry is succ exit run")
}
func (this *Nacos_Registry) listener(ctx context.Context) {
var (
slist model.ServiceList
instances []model.Instance
err error
)
t := time.NewTicker(time.Duration(this.options.Nacos_RegisterTTL) * time.Second)
defer t.Stop()
locp:
for {
select {
case <-t.C:
if slist, err = this.client.GetAllServicesInfo(vo.GetAllServiceInfoParam{
NameSpace: this.options.Nacos_NamespaceId,
GroupName: this.options.Service.GetTag(),
PageNo: 1,
PageSize: 100,
}); err == nil {
var service = make(map[string]struct{})
for _, v := range slist.Doms {
if instances, err = this.client.SelectInstances(vo.SelectInstancesParam{
ServiceName: v,
GroupName: this.options.Service.GetTag(),
HealthyOnly: true,
}); err == nil {
for _, v1 := range instances {
if v1.Enable && v1.Healthy {
service[v] = struct{}{}
this.addandupdataServiceNode(v1)
}
}
}
}
temp := make(map[string]*ServiceNode)
this.rlock.RLock()
for k, v := range this.services {
temp[k] = v
}
this.rlock.RUnlock()
for k, v := range temp {
if _, ok := service[k]; !ok { //不存在了 移除
this.removeServiceNode(v.Id)
}
}
}
case <-ctx.Done():
break locp
}
}
log.Infof("Sys Registry is succ exit listener")
}
func (this *Nacos_Registry) getServices() (err error) {
var (
slist model.ServiceList
instances []model.Instance
)
if slist, err = this.client.GetAllServicesInfo(vo.GetAllServiceInfoParam{
NameSpace: this.options.Nacos_NamespaceId,
GroupName: this.options.Service.GetTag(),
PageNo: 1,
PageSize: 20,
}); err == nil {
for _, v := range slist.Doms {
this.rlock.RLock()
_, ok := this.services[v]
this.rlock.RUnlock()
if !ok {
if instances, err = this.client.SelectInstances(vo.SelectInstancesParam{
ServiceName: v,
GroupName: this.options.Service.GetTag(),
HealthyOnly: true,
}); err == nil {
for _, v1 := range instances {
if v1.Enable && v1.Healthy {
this.addandupdataServiceNode(v1)
}
}
}
}
}
}
return err
}
func (this *Nacos_Registry) registerSNode(snode *ServiceNode) (err error) {
h, err := hash.Hash(snode, nil)
if err != nil {
return err
}
if v, ok := this.shash[snode.Id]; ok && v != 0 && v == h { //没变化不用注册
return
}
var (
// success bool
)
this.deregisterSNode()
_, err = this.client.RegisterInstance(vo.RegisterInstanceParam{
Ip: snode.IP,
Port: uint64(snode.Port),
Weight: snode.PreWeight,
GroupName: snode.Tag,
ServiceName: snode.Id,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{
"id": snode.Id,
"tag": snode.Tag,
"type": string(snode.Type),
"category": string(snode.Category),
"version": fmt.Sprintf("%v", snode.Version),
"rpcid": snode.RpcId,
},
})
return
}
func (this *Nacos_Registry) deregisterSNode() (err error) {
_, err = this.client.DeregisterInstance(vo.DeregisterInstanceParam{
Ip: this.options.Service.GetIp(),
Port: 8848,
ServiceName: this.options.Service.GetId(),
GroupName: this.options.Service.GetTag(),
})
return
}
func (this *Nacos_Registry) addandupdataServiceNode(as model.Instance) (sn *ServiceNode, err error) {
var (
version string
rpcid string
snode *ServiceNode
h uint64
)
version = as.Metadata["version"]
rpcid = as.Metadata["rpcid"]
snode = &ServiceNode{
Tag: as.Metadata["tag"],
Type: as.Metadata["type"],
Category: core.S_Category(as.Metadata["category"]),
Id: as.Metadata["id"],
IP: as.Ip,
Port: int(as.Port),
Version: version,
RpcId: rpcid,
PreWeight: as.Weight,
}
if h, err = hash.Hash(snode, nil); err == nil {
_, ok := this.services[snode.Id]
if !ok {
log.Infof("发现新的服务【%s:%s】", snode.Id, snode.Version)
sub := &vo.SubscribeParam{
ServiceName: snode.Id,
GroupName: snode.Tag,
SubscribeCallback: this.subscribecallback,
}
this.rlock.Lock()
this.services[snode.Id] = snode
this.shash[snode.Id] = h
this.subscribe[snode.Id] = sub
this.rlock.Unlock()
if this.options.Listener != nil { //异步通知
go this.options.Listener.FindServiceHandlefunc(*snode)
}
err = this.client.Subscribe(sub)
} else {
this.rlock.RLock()
v, ok := this.shash[snode.Id]
this.rlock.RUnlock()
if !ok || v != h { //校验不一致
// log.Debugf("更新服务【%s】", snode.Id)
this.rlock.Lock()
this.services[snode.Id] = snode
this.shash[snode.Id] = h
this.rlock.Unlock()
if this.options.Listener != nil { //异步通知
go this.options.Listener.UpDataServiceHandlefunc(*snode)
}
}
}
} else {
log.Errorf("registry 校验服务 hash 值异常:%s", err.Error())
}
return
}
func (this *Nacos_Registry) removeServiceNode(sId string) {
this.rlock.RLock()
_, ok := this.services[sId]
sub, _ := this.subscribe[sId]
this.rlock.RUnlock()
if !ok {
return
}
log.Infof("丢失服务【%s】", sId)
this.rlock.Lock()
delete(this.services, sId)
delete(this.subscribe, sId)
delete(this.shash, sId)
this.rlock.Unlock()
this.client.Unsubscribe(sub)
if this.options.Listener != nil { //异步通知
go this.options.Listener.LoseServiceHandlefunc(sId)
}
}
func (this *Nacos_Registry) subscribecallback(services []model.SubscribeService, err error) {
for _, v := range services {
// log.Debugf("subscribecallback:%+v", v)
this.addandupdataServiceNode(model.Instance{
Valid: v.Valid,
Enable: v.Enable,
ServiceName: v.ServiceName,
Ip: v.Ip,
Port: v.Port,
Metadata: v.Metadata,
Weight: v.Weight,
})
}
}