mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-02-12 09:22:28 +08:00
init commit
This commit is contained in:
221
light/consumer.go
Normal file
221
light/consumer.go
Normal file
@@ -0,0 +1,221 @@
|
||||
package light
|
||||
|
||||
import (
|
||||
airClient "flswld.com/air-api/client"
|
||||
"flswld.com/common/config"
|
||||
"flswld.com/logger"
|
||||
"net/rpc"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Consumer struct {
|
||||
serviceName string
|
||||
serviceList *ServiceList
|
||||
//httpInstanceName string
|
||||
//keepalive bool
|
||||
}
|
||||
|
||||
type ServiceInstance struct {
|
||||
// 服务地址
|
||||
serviceAddress string
|
||||
// 服务连接
|
||||
serviceClient *rpc.Client
|
||||
}
|
||||
|
||||
type ServiceList struct {
|
||||
// 服务实列列表
|
||||
serviceInstanceList []*ServiceInstance
|
||||
// 服务负载均衡索引
|
||||
serviceLoadBalanceIndex int
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func NewRpcConsumer(serviceName string) (r *Consumer) {
|
||||
r = new(Consumer)
|
||||
r.serviceName = serviceName
|
||||
r.serviceList = new(ServiceList)
|
||||
|
||||
// 服务注册
|
||||
//r.keepalive = true
|
||||
//r.httpInstanceName = RegisterHttpService(conf, log, &r.keepalive)
|
||||
|
||||
// 服务发现
|
||||
airClient.SetAirAddr(config.CONF.Air.Addr, config.CONF.Air.Port)
|
||||
go r.fetchAirService()
|
||||
go r.pollAirService()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (c *Consumer) CloseRpcConsumer() {
|
||||
//c.keepalive = false
|
||||
//CancelHttpService(c.conf, c.log, c.httpInstanceName)
|
||||
}
|
||||
|
||||
func (c *Consumer) CallFunction(svcName string, funcName string, req any, res any) bool {
|
||||
serviceInstance := c.getServiceInstanceLoadBalance()
|
||||
if serviceInstance == nil {
|
||||
logger.LOG.Error("no rpc provider find, service: %v", c.serviceName)
|
||||
return false
|
||||
}
|
||||
if serviceInstance.serviceClient == nil {
|
||||
serviceClient, err := rpc.DialHTTP("tcp", serviceInstance.serviceAddress)
|
||||
if err != nil {
|
||||
logger.LOG.Error("rpc connect error: %v", err)
|
||||
return false
|
||||
}
|
||||
serviceInstance.serviceClient = serviceClient
|
||||
}
|
||||
serviceMethod := svcName + "." + funcName
|
||||
err := serviceInstance.serviceClient.Call(serviceMethod, req, res)
|
||||
if err != nil {
|
||||
logger.LOG.Error("rpc call error: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Consumer) syncServiceList(responseData *airClient.ResponseData) {
|
||||
serviceAddressSlice := make([]string, 0)
|
||||
for _, v := range responseData.Instance {
|
||||
serviceAddressSlice = append(serviceAddressSlice, v.InstanceAddr)
|
||||
}
|
||||
|
||||
c.serviceList.lock.RLock()
|
||||
oldList := c.serviceList.serviceInstanceList
|
||||
c.serviceList.lock.RUnlock()
|
||||
// 相同服务列表
|
||||
sameList := make([]*ServiceInstance, 0)
|
||||
// 新增服务列表
|
||||
addList := make([]*ServiceInstance, 0)
|
||||
// 删除服务列表
|
||||
delList := make([]*ServiceInstance, 0)
|
||||
// 找出相同的服务
|
||||
for _, v := range serviceAddressSlice {
|
||||
for _, vv := range oldList {
|
||||
if v == vv.serviceAddress {
|
||||
sameList = append(sameList, vv)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 找出新增的服务
|
||||
for _, v := range serviceAddressSlice {
|
||||
hasItem := false
|
||||
for _, vv := range sameList {
|
||||
if v == vv.serviceAddress {
|
||||
hasItem = true
|
||||
}
|
||||
}
|
||||
if !hasItem {
|
||||
serviceInstance := new(ServiceInstance)
|
||||
serviceInstance.serviceAddress = v
|
||||
serviceInstance.serviceClient = nil
|
||||
addList = append(addList, serviceInstance)
|
||||
logger.LOG.Info("add service: %v, addr: %v", c.serviceName, serviceInstance.serviceAddress)
|
||||
}
|
||||
}
|
||||
// 找出删除的服务
|
||||
for _, v := range oldList {
|
||||
hasItem := false
|
||||
for _, vv := range sameList {
|
||||
if v.serviceAddress == vv.serviceAddress {
|
||||
hasItem = true
|
||||
}
|
||||
}
|
||||
if !hasItem {
|
||||
delList = append(delList, v)
|
||||
logger.LOG.Info("delete service: %v, addr: %v", c.serviceName, v.serviceAddress)
|
||||
}
|
||||
}
|
||||
c.serviceList.lock.Lock()
|
||||
c.serviceList.serviceInstanceList = make([]*ServiceInstance, len(sameList)+len(addList))
|
||||
copy(c.serviceList.serviceInstanceList, sameList)
|
||||
copy(c.serviceList.serviceInstanceList[len(sameList):], addList)
|
||||
c.serviceList.lock.Unlock()
|
||||
}
|
||||
|
||||
// 从注册中心获取服务实例
|
||||
func (c *Consumer) fetchAirService() {
|
||||
ticker := time.NewTicker(time.Second * 600)
|
||||
for {
|
||||
var responseData *airClient.ResponseData
|
||||
var err error
|
||||
responseData, err = airClient.FetchRpcService(c.serviceName)
|
||||
if err != nil {
|
||||
logger.LOG.Error("fetch all rpc service error: %v", err)
|
||||
return
|
||||
}
|
||||
if responseData.Code != 0 {
|
||||
logger.LOG.Error("response code error")
|
||||
return
|
||||
}
|
||||
if len(responseData.Instance) == 0 {
|
||||
logger.LOG.Error("no %v service instance find", c.serviceName)
|
||||
return
|
||||
}
|
||||
c.syncServiceList(responseData)
|
||||
<-ticker.C
|
||||
}
|
||||
}
|
||||
|
||||
// 从注册中心长轮询监听服务实例变化
|
||||
func (c *Consumer) pollAirService() {
|
||||
lastTime := int64(0)
|
||||
for {
|
||||
nowTime := time.Now().UnixNano()
|
||||
if time.Duration(nowTime-lastTime) < time.Second {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
continue
|
||||
}
|
||||
lastTime = time.Now().UnixNano()
|
||||
var responseData *airClient.ResponseData
|
||||
var err error
|
||||
responseData, err = airClient.PollRpcService(c.serviceName)
|
||||
if err != nil {
|
||||
logger.LOG.Error("poll all rpc service error: %v", err)
|
||||
continue
|
||||
}
|
||||
if responseData.Code != 0 {
|
||||
logger.LOG.Error("response code error")
|
||||
continue
|
||||
}
|
||||
if len(responseData.Instance) == 0 {
|
||||
logger.LOG.Error("no %v service instance find", c.serviceName)
|
||||
}
|
||||
c.syncServiceList(responseData)
|
||||
}
|
||||
}
|
||||
|
||||
// 负载均衡的方式获取服务实例
|
||||
func (c *Consumer) getServiceInstanceLoadBalance() (r *ServiceInstance) {
|
||||
c.serviceList.lock.RLock()
|
||||
index := c.serviceList.serviceLoadBalanceIndex
|
||||
length := len(c.serviceList.serviceInstanceList)
|
||||
c.serviceList.lock.RUnlock()
|
||||
|
||||
if length == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 下一个待轮询的服务已下线
|
||||
if index >= length {
|
||||
logger.LOG.Error("serviceLoadBalanceIndex out of range, len is: %d, but value is: %d", length, index)
|
||||
index = 0
|
||||
}
|
||||
|
||||
c.serviceList.lock.RLock()
|
||||
r = c.serviceList.serviceInstanceList[index]
|
||||
c.serviceList.lock.RUnlock()
|
||||
|
||||
c.serviceList.lock.Lock()
|
||||
// 轮询
|
||||
if c.serviceList.serviceLoadBalanceIndex < length-1 {
|
||||
c.serviceList.serviceLoadBalanceIndex += 1
|
||||
} else {
|
||||
c.serviceList.serviceLoadBalanceIndex = 0
|
||||
}
|
||||
c.serviceList.lock.Unlock()
|
||||
|
||||
return r
|
||||
}
|
||||
17
light/go.mod
Normal file
17
light/go.mod
Normal file
@@ -0,0 +1,17 @@
|
||||
module light
|
||||
|
||||
go 1.19
|
||||
|
||||
require flswld.com/common v0.0.0-incompatible
|
||||
|
||||
replace flswld.com/common => ../common
|
||||
|
||||
require flswld.com/logger v0.0.0-incompatible
|
||||
|
||||
replace flswld.com/logger => ../logger
|
||||
|
||||
require flswld.com/air-api v0.0.0-incompatible
|
||||
|
||||
require github.com/BurntSushi/toml v0.3.1 // indirect
|
||||
|
||||
replace flswld.com/air-api => ../air-api
|
||||
2
light/go.sum
Normal file
2
light/go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
63
light/provider.go
Normal file
63
light/provider.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package light
|
||||
|
||||
import (
|
||||
airClient "flswld.com/air-api/client"
|
||||
"flswld.com/common/config"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/rpc"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Provider struct {
|
||||
httpInstanceName string
|
||||
rpcInstanceName string
|
||||
listen net.Listener
|
||||
keepalive bool
|
||||
}
|
||||
|
||||
func NewRpcProvider(service any) (r *Provider) {
|
||||
r = new(Provider)
|
||||
|
||||
// 服务注册
|
||||
r.keepalive = true
|
||||
r.rpcInstanceName = RegisterRpcService(&r.keepalive)
|
||||
|
||||
// 开启本地RPC服务监听
|
||||
_ = rpc.Register(service)
|
||||
rpc.HandleHTTP()
|
||||
addr := ":" + strconv.FormatInt(int64(config.CONF.Light.Port), 10)
|
||||
listen, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
panic("Listen() fail")
|
||||
}
|
||||
r.listen = listen
|
||||
go r.startRpcListen()
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func NewHttpProvider() (r *Provider) {
|
||||
r = new(Provider)
|
||||
|
||||
// 服务注册
|
||||
airClient.SetAirAddr(config.CONF.Air.Addr, config.CONF.Air.Port)
|
||||
r.keepalive = true
|
||||
r.httpInstanceName = RegisterHttpService(&r.keepalive)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *Provider) startRpcListen() {
|
||||
_ = http.Serve(p.listen, nil)
|
||||
}
|
||||
|
||||
func (p *Provider) CloseRpcProvider() {
|
||||
p.keepalive = false
|
||||
CancelRpcService(p.rpcInstanceName)
|
||||
}
|
||||
|
||||
func (p *Provider) CloseHttpProvider() {
|
||||
p.keepalive = false
|
||||
CancelHttpService(p.httpInstanceName)
|
||||
}
|
||||
172
light/register.go
Normal file
172
light/register.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package light
|
||||
|
||||
import (
|
||||
airClient "flswld.com/air-api/client"
|
||||
"flswld.com/common/config"
|
||||
"flswld.com/logger"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 生成服务注册实例名
|
||||
func getInstanceName() (string, error) {
|
||||
host, err := os.Hostname()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
instName := host + "-" + strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
return instName, nil
|
||||
}
|
||||
|
||||
// 注册HTTP服务
|
||||
func RegisterHttpService(keepalive *bool) string {
|
||||
inst := new(airClient.Instance)
|
||||
inst.ServiceName = config.CONF.Air.ServiceName
|
||||
instName, err := getInstanceName()
|
||||
if err != nil {
|
||||
logger.LOG.Error("get instance name error: %v", err)
|
||||
panic(err)
|
||||
}
|
||||
inst.InstanceName = instName
|
||||
ipAddr := os.Getenv("IP_ADDR")
|
||||
if len(ipAddr) == 0 {
|
||||
panic("ip addr env is nil")
|
||||
}
|
||||
addr := "http://" + ipAddr + ":" + strconv.Itoa(config.CONF.HttpPort)
|
||||
inst.InstanceAddr = addr
|
||||
|
||||
var response *airClient.ResponseData
|
||||
response, err = airClient.RegisterHttpService(*inst)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if response.Code != 0 {
|
||||
panic("response code error")
|
||||
}
|
||||
go httpServiceKeepalive(*inst, keepalive)
|
||||
logger.LOG.Info("register http service success, instance: %v", *inst)
|
||||
return instName
|
||||
}
|
||||
|
||||
// HTTP服务心跳保持
|
||||
func httpServiceKeepalive(inst airClient.Instance, keepalive *bool) {
|
||||
ticker := time.NewTicker(time.Second * 15)
|
||||
for {
|
||||
<-ticker.C
|
||||
|
||||
if !*keepalive {
|
||||
return
|
||||
}
|
||||
|
||||
var response *airClient.ResponseData
|
||||
var err error
|
||||
response, err = airClient.KeepaliveHttpService(inst)
|
||||
if err != nil {
|
||||
logger.LOG.Error("http keepalive error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if response.Code != 0 {
|
||||
logger.LOG.Error("response code error")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 取消注册HTTP服务
|
||||
func CancelHttpService(instanceName string) {
|
||||
inst := new(airClient.Instance)
|
||||
inst.ServiceName = config.CONF.Air.ServiceName
|
||||
inst.InstanceName = instanceName
|
||||
|
||||
var response *airClient.ResponseData
|
||||
var err error
|
||||
response, err = airClient.CancelHttpService(*inst)
|
||||
if err != nil {
|
||||
logger.LOG.Error("cancel http service error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if response.Code != 0 {
|
||||
logger.LOG.Error("response code error")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 注册RPC服务
|
||||
func RegisterRpcService(keepalive *bool) string {
|
||||
inst := new(airClient.Instance)
|
||||
inst.ServiceName = config.CONF.Air.ServiceName
|
||||
instName, err := getInstanceName()
|
||||
if err != nil {
|
||||
logger.LOG.Error("get instance name error: %v", err)
|
||||
panic(err)
|
||||
}
|
||||
inst.InstanceName = instName
|
||||
ipAddr := os.Getenv("IP_ADDR")
|
||||
if len(ipAddr) == 0 {
|
||||
panic("ip addr env is nil")
|
||||
}
|
||||
addr := ipAddr + ":" + strconv.Itoa(config.CONF.Light.Port)
|
||||
inst.InstanceAddr = addr
|
||||
|
||||
var response *airClient.ResponseData
|
||||
response, err = airClient.RegisterRpcService(*inst)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if response.Code != 0 {
|
||||
panic("response code error")
|
||||
}
|
||||
go rpcServiceKeepalive(*inst, keepalive)
|
||||
logger.LOG.Info("register rpc service success, instance: %v", *inst)
|
||||
return instName
|
||||
}
|
||||
|
||||
// RPC服务心跳保持
|
||||
func rpcServiceKeepalive(inst airClient.Instance, keepalive *bool) {
|
||||
ticker := time.NewTicker(time.Second * 15)
|
||||
for {
|
||||
<-ticker.C
|
||||
|
||||
if !*keepalive {
|
||||
return
|
||||
}
|
||||
|
||||
var response *airClient.ResponseData
|
||||
var err error
|
||||
response, err = airClient.KeepaliveRpcService(inst)
|
||||
if err != nil {
|
||||
logger.LOG.Error("rpc keepalive error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if response.Code != 0 {
|
||||
logger.LOG.Error("response code error")
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 取消注册RPC服务
|
||||
func CancelRpcService(instanceName string) {
|
||||
inst := new(airClient.Instance)
|
||||
inst.ServiceName = config.CONF.Air.ServiceName
|
||||
inst.InstanceName = instanceName
|
||||
|
||||
var response *airClient.ResponseData
|
||||
var err error
|
||||
response, err = airClient.CancelRpcService(*inst)
|
||||
if err != nil {
|
||||
logger.LOG.Error("cancel rpc service error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if response.Code != 0 {
|
||||
logger.LOG.Error("response code error")
|
||||
return
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user