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

81
wind/air/discovery.go Normal file
View File

@@ -0,0 +1,81 @@
package air
import (
airClient "flswld.com/air-api/client"
"flswld.com/common/config"
"flswld.com/logger"
"strings"
"time"
"wind/entity"
)
type Air struct {
serviceAddressMap *entity.AddressMap
}
func NewAir(addressMap *entity.AddressMap) (r *Air) {
r = new(Air)
r.serviceAddressMap = addressMap
airClient.SetAirAddr(config.CONF.Air.Addr, config.CONF.Air.Port)
go r.fetchHttpService()
go r.pollHttpService()
return r
}
func (a *Air) syncServiceMap(responseData *airClient.ResponseData) {
a.serviceAddressMap.Lock.Lock()
for _, v := range config.CONF.Routes {
instanceSlice := responseData.Service[v.ServiceName]
serviceAddress := make([]string, 0)
for _, vv := range instanceSlice {
if strings.Contains(vv.InstanceAddr, "http://") {
serviceAddress = append(serviceAddress, vv.InstanceAddr)
}
}
a.serviceAddressMap.Map[v.ServiceName] = serviceAddress
}
a.serviceAddressMap.Lock.Unlock()
}
// 从注册中心获取所有服务
func (a *Air) fetchHttpService() {
ticker := time.NewTicker(time.Second * 600)
for {
var responseData *airClient.ResponseData
var err error
responseData, err = airClient.FetchAllHttpService()
if err != nil {
logger.LOG.Error("fetch all http service error: %v", err)
return
}
a.syncServiceMap(responseData)
a.serviceAddressMap.Lock.RLock()
logger.LOG.Debug("fetch tick finished, serviceAddressMap: %v", a.serviceAddressMap.Map)
a.serviceAddressMap.Lock.RUnlock()
<-ticker.C
}
}
// 从注册中心长轮询监听所有服务变化
func (a *Air) pollHttpService() {
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.PollAllHttpService()
if err != nil {
logger.LOG.Error("poll all http service error: %v", err)
continue
}
a.syncServiceMap(responseData)
a.serviceAddressMap.Lock.RLock()
logger.LOG.Debug("poll finished, serviceAddressMap: %v", a.serviceAddressMap.Map)
a.serviceAddressMap.Lock.RUnlock()
}
}

31
wind/cmd/application.toml Normal file
View File

@@ -0,0 +1,31 @@
http_port = 80
[logger]
level = "DEBUG"
method = "CONSOLE"
track_line = true
[air]
addr = "air"
port = 8086
service_name = "wind-gateway"
[[routes]]
service_name = "water-auth"
service_predicates = "/api/v1/auth"
strip_prefix = 2
[[routes]]
service_name = "annie-user-app"
service_predicates = "/api/v1/user"
strip_prefix = 2
[[routes]]
service_name = "annie-wxmp-app"
service_predicates = "/api/v1/wxmp"
strip_prefix = 2
[[routes]]
service_name = "gm-hk4e-app"
service_predicates = "/api/v1/gm"
strip_prefix = 2

44
wind/cmd/main.go Normal file
View File

@@ -0,0 +1,44 @@
package main
import (
"flswld.com/common/config"
"flswld.com/logger"
"os"
"os/signal"
"syscall"
"time"
"wind/air"
"wind/entity"
"wind/proxy"
)
func main() {
filePath := "./application.toml"
config.InitConfig(filePath)
logger.InitLogger()
logger.LOG.Info("wind start")
svcAddrMap := new(entity.AddressMap)
svcAddrMap.Map = make(map[string][]string)
_ = air.NewAir(svcAddrMap)
_ = proxy.NewProxy(svcAddrMap)
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
logger.LOG.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
logger.LOG.Info("wind exit")
time.Sleep(time.Second)
return
case syscall.SIGHUP:
default:
return
}
}
}

9
wind/entity/service.go Normal file
View File

@@ -0,0 +1,9 @@
package entity
import "sync"
// 服务列表
type AddressMap struct {
Map map[string][]string
Lock sync.RWMutex
}

17
wind/go.mod Normal file
View File

@@ -0,0 +1,17 @@
module wind
go 1.19
require flswld.com/common v0.0.0-incompatible
replace flswld.com/common => ../common
require flswld.com/logger v0.0.0-incompatible
require github.com/BurntSushi/toml v0.3.1 // indirect
replace flswld.com/logger => ../logger
require flswld.com/air-api v0.0.0-incompatible
replace flswld.com/air-api => ../air-api

2
wind/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=

119
wind/proxy/proxy.go Normal file
View File

@@ -0,0 +1,119 @@
package proxy
import (
"flswld.com/common/config"
"flswld.com/logger"
"fmt"
"net/http"
"net/http/httputil"
"net/url"
"strconv"
"strings"
"sync"
"wind/entity"
)
type Proxy struct {
service Service
}
// 服务
type Service struct {
// 服务地址列表map
serviceAddrMap *entity.AddressMap
// 服务负载均衡索引map
serviceLoadBalanceIndexMap map[string]int
serviceLoadBalanceIndexMapLock sync.Mutex
}
func NewProxy(addressMap *entity.AddressMap) (r *Proxy) {
r = new(Proxy)
r.service.serviceAddrMap = addressMap
go r.startServer()
return r
}
// 路由转发处理
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
logger.LOG.Debug("[proxy:ServeHTTP] Request: %v", *r)
urlParamDiv := strings.Index(r.RequestURI, "?")
var reqUrl string
if urlParamDiv != -1 {
reqUrl = (r.RequestURI)[:urlParamDiv]
} else {
reqUrl = r.RequestURI
}
var svcNameStr = ""
var stripPrefix = 0
// 匹配服务
for _, v := range config.CONF.Routes {
if strings.Contains(reqUrl, v.ServicePredicates) {
svcNameStr = v.ServiceName
stripPrefix = v.StripPrefix
break
}
}
// 匹配服务失败
if len(svcNameStr) == 0 {
logger.LOG.Info("[proxy:ServeHTTP] 404 Not Found")
_, _ = fmt.Fprintf(w, "404 Not Found")
return
}
path := reqUrl
// 去除路径前缀
for i := 0; i < stripPrefix; i++ {
path = path[strings.Index(path, "/")+1:]
path = path[strings.Index(path, "/"):]
}
r.URL.Path = path
var remote *url.URL
p.service.serviceAddrMap.Lock.RLock()
serviceAddr := p.service.serviceAddrMap.Map[svcNameStr]
p.service.serviceAddrMap.Lock.RUnlock()
// 服务不可用
if len(serviceAddr) == 0 {
logger.LOG.Info("[proxy:ServeHTTP] 503 Service Unavailable")
_, _ = fmt.Fprintf(w, "503 Service Unavailable")
return
}
p.service.serviceLoadBalanceIndexMapLock.Lock()
serviceLoadBalanceIndex := p.service.serviceLoadBalanceIndexMap[svcNameStr]
p.service.serviceLoadBalanceIndexMapLock.Unlock()
// 下一个待轮询的服务已下线
if int(serviceLoadBalanceIndex) >= len(serviceAddr) {
logger.LOG.Info("[proxy:ServeHTTP] serviceLoadBalanceIndex out of range, len is: %d, but value is: %d", len(serviceAddr), serviceLoadBalanceIndex)
serviceLoadBalanceIndex = 0
}
logger.LOG.Debug("[proxy:ServeHTTP] serviceLoadBalanceIndex: %d", serviceLoadBalanceIndex)
remote, _ = url.Parse(string(serviceAddr[serviceLoadBalanceIndex]))
logger.LOG.Debug("[proxy:ServeHTTP] remote: %v", remote)
// 轮询
p.service.serviceLoadBalanceIndexMapLock.Lock()
if int(p.service.serviceLoadBalanceIndexMap[svcNameStr]) < len(serviceAddr)-1 {
p.service.serviceLoadBalanceIndexMap[svcNameStr] += 1
} else {
p.service.serviceLoadBalanceIndexMap[svcNameStr] = 0
}
p.service.serviceLoadBalanceIndexMapLock.Unlock()
proxy := httputil.NewSingleHostReverseProxy(remote)
//p.log.Debug("Response: %v", w)
proxy.ServeHTTP(w, r)
}
// 启动http路由转发
func (p *Proxy) startServer() {
// 初始化服务负载均衡索引map
p.service.serviceLoadBalanceIndexMap = make(map[string]int)
for _, v := range config.CONF.Routes {
p.service.serviceLoadBalanceIndexMap[v.ServiceName] = 0
}
port := strconv.FormatInt(int64(config.CONF.HttpPort), 10)
logger.LOG.Info("[proxy:startServer] start listen port: %s", port)
portStr := ":" + port
// 启动
err := http.ListenAndServe(portStr, p)
if err != nil {
logger.LOG.Error("[proxy:startServer] ListenAndServe fail ! err: %v", err)
panic(err)
}
}