init commit

This commit is contained in:
flswld
2022-11-20 15:38:00 +08:00
parent eda2b643b9
commit 3efed3defe
5834 changed files with 636508 additions and 0 deletions

221
light/consumer.go Normal file
View 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
View 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
View 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
View 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
View 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
}
}