1、httpserver使用中间件来携带sync.pool创建和回收对象。2、废弃channel的方式,而是通过nginx识别通道号进行转发。

This commit is contained in:
redhat 2025-06-04 10:54:05 +08:00
parent 5a24eff7f1
commit 813076f168
12 changed files with 115 additions and 61 deletions

View File

@ -27,10 +27,10 @@ unis:
type: "json" type: "json"
network: "tcp" network: "tcp"
host: "" host: ""
base_port: 5500 port: 5500
httpc: httpc:
clients: 5 clients: 5
instances: 2 instances: 1
# 使用令牌桶限流 # 使用令牌桶限流
rate: rate:

View File

@ -4,7 +4,6 @@ import (
"dashboard/models" "dashboard/models"
"dashboard/utils" "dashboard/utils"
"net/http" "net/http"
"sync"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -12,30 +11,25 @@ import (
type httpHandle struct { type httpHandle struct {
httpC []chan *models.UnisHttpRequest httpC []chan *models.UnisHttpRequest
pool sync.Pool
} }
func newhttpHandle(httpc []chan *models.UnisHttpRequest) *httpHandle { func newhttpHandle(httpc []chan *models.UnisHttpRequest) *httpHandle {
res := new(httpHandle) res := new(httpHandle)
res.httpC = httpc res.httpC = httpc
res.pool.New = func() any { return new(models.UnisHttpRequest) }
return res return res
} }
func httpSendWithExpire(httpc chan *models.UnisHttpRequest, data *models.UnisHttpRequest) (*models.UnisHttpResponse, error) { func (u *httpHandle)httpSendWithExpire(req *models.UnisHttpRequest) (*models.UnisHttpResponse, error) {
resc := make(chan *models.UnisHttpResponse)
data.ResC = resc
select { select {
case httpc <- data: case u.httpC[0] <- req:
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
return nil, models.ErrorSendTimeOut return nil, models.ErrorSendTimeOut
} }
select { select {
case resp := <-resc: case resp := <-req.ResC:
return resp, nil return resp, nil
case <-time.After(2 * time.Second): case <-time.After(2 * time.Second):
return nil, models.ErrorReciveTimeOut return nil, models.ErrorReciveTimeOut
@ -51,11 +45,12 @@ func (u *httpHandle) stationConfig(c *gin.Context) error {
return err return err
} }
channel := c.GetInt(models.GinContextChannel) // 不再使用channel的方式而是使用配置文件启动不同进程的方式
if channel > len(u.httpC)-1 { // channel := c.GetInt(models.GinContextChannel)
log.Sugar().Errorf("stationConfig channel err: %d", channel) // if channel > len(u.httpC)-1 {
return models.ErrorParamsErr // log.Sugar().Errorf("stationConfig channel err: %d", channel)
} // return models.ErrorParamsErr
// }
// if !config.StationConfig.ConfigType { // if !config.StationConfig.ConfigType {
// res, ok := unisd.UnisDataGet(unisd.DadisKey_UnisStationInfo.KeyWithChannel(channel)) // res, ok := unisd.UnisDataGet(unisd.DadisKey_UnisStationInfo.KeyWithChannel(channel))
@ -72,16 +67,20 @@ func (u *httpHandle) stationConfig(c *gin.Context) error {
// } // }
// } // }
req := u.pool.Get().(*models.UnisHttpRequest) req, err := getUnisHttpReqFromContext(c)
req.Id = models.UnisHttpUrl(c.Request.URL.String()).GetMsgId() if err != nil {
req.Msg = config log.Sugar().Errorf("stationConfig get http req from context err: %v", err)
return models.ErrorParamsErr
}
req.SetReqParam(models.UnisHttpUrl(c.Request.URL.String()).GetMsgId(), config)
// req := &models.UnisHttpRequest{ // req := &models.UnisHttpRequest{
// Id: models.UnisHttpUrl(c.Request.URL.String()).GetMsgId(), // Id: models.UnisHttpUrl(c.Request.URL.String()).GetMsgId(),
// Msg: config, // Msg: config,
// } // }
resp, err := httpSendWithExpire(u.httpC[channel], req) resp, err := u.httpSendWithExpire(req)
if err != nil { if err != nil {
log.Sugar().Errorf("stationConfig send or recive err: %v", err) log.Sugar().Errorf("stationConfig send or recive err: %v", err)
return err return err

View File

@ -10,6 +10,7 @@ import (
"io" "io"
"net/http" "net/http"
"strconv" "strconv"
"sync"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -40,17 +41,31 @@ func NewHttpRoute(httpc ...UnisHttpChanneler) *HttpRoute {
func (u *HttpRoute) AddRoute(r *gin.Engine) { func (u *HttpRoute) AddRoute(r *gin.Engine) {
unisr := r.Group(models.UnisHttpUrlPrefix) unisr := r.Group(models.UnisHttpUrlPrefix)
unisr.Use(routes.ErrWapper(u.middleWare.ginCheckServerId), routes.ErrWapper(u.middleWare.ginStoreRequest)) unisr.Use(routes.ErrWapper(u.middleWare.ginCheckServerId), routes.ErrWapper(u.middleWare.ginStoreRequest), u.middleWare.ginSetUnisHttpReq)
{ {
unisr.POST(models.UNIS_HTTP_URL_CONFIG_ADD.Url(), routes.ErrWapper(u.httpHandle.stationConfig)) unisr.POST(models.UNIS_HTTP_URL_CONFIG_ADD.Url(), routes.ErrWapper(u.httpHandle.stationConfig))
} }
} }
type middleWare struct { type middleWare struct {
pool sync.Pool
} }
func newmiddleWare() *middleWare { func newmiddleWare() *middleWare {
return new(middleWare) res := new(middleWare)
res.pool.New = func() any { return createUnisHttpRequest() }
return res
}
func createUnisHttpRequest() *models.UnisHttpRequest {
res := new(models.UnisHttpRequest)
res.ResC = make(chan *models.UnisHttpResponse)
res.ResP = new(models.UnisHttpResponse)
return res
} }
func (m *middleWare) ginCheckServerId(c *gin.Context) error { func (m *middleWare) ginCheckServerId(c *gin.Context) error {
@ -160,7 +175,7 @@ func (m *middleWare) ginWithUnisObject(unis *uniss.UnisStation) gin.HandlerFunc
} }
} }
func (m *middleWare) getUnisObjectFromContext(c *gin.Context) (*uniss.UnisStation, error) { func getUnisObjectFromContext(c *gin.Context) (*uniss.UnisStation, error) {
res, ok := c.Get(models.GinContextUnis) res, ok := c.Get(models.GinContextUnis)
if !ok { if !ok {
return nil, models.ErrorInvalidData return nil, models.ErrorInvalidData
@ -180,3 +195,24 @@ func (m *middleWare) ginWithExpireTime(expire time.Duration) gin.HandlerFunc {
c.Next() c.Next()
} }
} }
func (m *middleWare) ginSetUnisHttpReq(c *gin.Context) {
req := m.pool.Get()
c.Set(models.GinContextUnisHttpReq, req)
c.Next()
m.pool.Put(req)
}
func getUnisHttpReqFromContext(c *gin.Context)(*models.UnisHttpRequest,error){
res, ok := c.Get(models.GinContextUnisHttpReq)
if !ok {
return nil, models.ErrorInvalidData
}
unis, ok := res.(*models.UnisHttpRequest)
if !ok {
return nil, models.ErrorInvalidData
}
return unis, nil
}

View File

@ -6,11 +6,12 @@ import (
) )
const ( const (
GinContextLog = "log" GinContextLog = "log"
GinContextChannel = "channel" GinContextChannel = "channel"
GinContextServerId = "serverid" GinContextServerId = "serverid"
GinContextUnis = "unis" GinContextUnis = "unis"
GinContextExpire = "expire" GinContextExpire = "expire"
GinContextUnisHttpReq = "unis_http_req"
) )
const ( const (

View File

@ -3,10 +3,15 @@ package models
import "strings" import "strings"
type UnisHttpRequest struct { type UnisHttpRequest struct {
ResC chan *UnisHttpResponse ResC chan *UnisHttpResponse
Channel int ResP *UnisHttpResponse
Id string Id string
Msg interface{} Msg interface{}
}
func (u *UnisHttpRequest) SetReqParam(id string, msg interface{}) {
u.Id = id
u.Msg = msg
} }
type UnisHttpResponse struct { type UnisHttpResponse struct {
@ -15,6 +20,12 @@ type UnisHttpResponse struct {
Data interface{} Data interface{}
} }
func (u *UnisHttpResponse) SetResParam(code int, msg, data interface{}) {
u.Code = code
u.Msg = msg
u.Data = data
}
type UnisHttpClientRequest struct { type UnisHttpClientRequest struct {
Url string Url string
Methord string Methord string

View File

@ -43,10 +43,9 @@ func (c *commonService) stationConfig(reqest *models.UnisHttpRequest, respons *m
// Code: int(models.CodeSuccess), // Code: int(models.CodeSuccess),
// Msg: "config ok", // Msg: "config ok",
// } // }
respons.Code = int(models.CodeSuccess) respons.SetResParam(int(models.CodeSuccess), "config ok", nil)
respons.Msg = "config ok"
unisd.UnisDataSet(unisd.DadisKey_UnisStationInfo.KeyWithChannel(reqest.Channel), req, 0) unisd.UnisDataSet(unisd.DadisKey_UnisStationInfo.KeyWithChannel(0), req, 0)
c.comm.httpClientHandler.curl(&models.UnisHttpClientRequest{ c.comm.httpClientHandler.curl(&models.UnisHttpClientRequest{
Url: "http://192.168.177.7:8080/api/unis/source-list/v1/update", Url: "http://192.168.177.7:8080/api/unis/source-list/v1/update",

View File

@ -21,7 +21,7 @@ func newcommunicateService(conf *settings.UnisConfig) (res *communicateService,
var rpcConf = &rpcsup.RpcConfig{ var rpcConf = &rpcsup.RpcConfig{
Typec: conf.RpcConfig.Type, Typec: conf.RpcConfig.Type,
Network: conf.RpcConfig.Network, Network: conf.RpcConfig.Network,
Address: fmt.Sprintf("%s:%d", conf.RpcConfig.Host, conf.RpcConfig.BasePort+conf.Instances)} Address: fmt.Sprintf("%s:%d", conf.RpcConfig.Host, conf.RpcConfig.Port+conf.Instances)}
res.rpcService, err = rpcsup.NewRpcService(rpcConf) res.rpcService, err = rpcsup.NewRpcService(rpcConf)
if err != nil { if err != nil {

View File

@ -9,27 +9,37 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"time"
"go.uber.org/zap" "go.uber.org/zap"
) )
type httpClientHandler struct { type httpClientHandler struct {
swarm *swarm.Swarm[*models.UnisHttpClientRequest] swarm *swarm.Swarm[*models.UnisHttpClientRequest]
httpC chan *models.UnisHttpClientResponse httpC chan *models.UnisHttpClientResponse
client *http.Client
} }
func newhttpClientHandle(clients int) *httpClientHandler { func newhttpClientHandle(clients int) *httpClientHandler {
res := new(httpClientHandler) res := new(httpClientHandler)
res.swarm = swarm.NewSwarm(clients, res.doRequest, swarm.WithLog(zap.NewStdLog(log.Logger))) res.swarm = swarm.NewSwarm(clients, res.doRequest, swarm.WithLog(zap.NewStdLog(log.Logger)))
res.httpC = make(chan *models.UnisHttpClientResponse) res.httpC = make(chan *models.UnisHttpClientResponse)
res.client = http.DefaultClient
return res return res
} }
// cald by mainthred
func (c *httpClientHandler) curl(msg *models.UnisHttpClientRequest) { func (c *httpClientHandler) curl(msg *models.UnisHttpClientRequest) {
c.swarm.Submit(msg) c.swarm.Submit(msg)
} }
// cald by mainthred
func (c *httpClientHandler) httpClientHandle(msg *models.UnisHttpClientResponse) {
fmt.Println(string(msg.Msg.([]byte)))
}
// Note cald by swarm goroutines
func (c *httpClientHandler) doRequest(req *models.UnisHttpClientRequest) error { func (c *httpClientHandler) doRequest(req *models.UnisHttpClientRequest) error {
body, err := json.Marshal(req.Msg) body, err := json.Marshal(req.Msg)
fmt.Println(string(body), err) fmt.Println(string(body), err)
@ -40,10 +50,12 @@ func (c *httpClientHandler) doRequest(req *models.UnisHttpClientRequest) error {
return err return err
} }
reqs.Header.Add("Content-type", "application/json;charset=utf-8") c.client.Timeout = time.Second
client := http.Client{} reqs.Header.Add("Content-type", "application/json;charset=utf-8")
resp, err := client.Do(reqs) reqs.Header.Add("User-Agent", "avcnetRuntime/0.0.1")
resp, err := c.client.Do(reqs)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return err return err

View File

@ -2,14 +2,12 @@ package uniss
import ( import (
"dashboard/models" "dashboard/models"
"sync"
) )
type httpServerHandler struct { type httpServerHandler struct {
httpC chan *models.UnisHttpRequest httpC chan *models.UnisHttpRequest
mu sync.RWMutex // mu sync.RWMutex // 没有必要使用锁应为完全可以保证在一个协程内访问map
mapFn map[string]HttpServerHandlerFunc mapFn map[string]HttpServerHandlerFunc
pool sync.Pool
} }
type HttpServerHandlerFunc func(*models.UnisHttpRequest, *models.UnisHttpResponse) error type HttpServerHandlerFunc func(*models.UnisHttpRequest, *models.UnisHttpResponse) error
@ -19,45 +17,44 @@ func newhttpServerHandler() *httpServerHandler {
res.httpC = make(chan *models.UnisHttpRequest) res.httpC = make(chan *models.UnisHttpRequest)
res.mapFn = make(map[string]HttpServerHandlerFunc) res.mapFn = make(map[string]HttpServerHandlerFunc)
res.pool.New = func() any { return new(models.UnisHttpResponse) }
return res return res
} }
func (u *httpServerHandler) httpHandle(msg *models.UnisHttpRequest) { func (u *httpServerHandler) httpHandle(msg *models.UnisHttpRequest) {
res := u.pool.Get().(*models.UnisHttpResponse) resP := msg.ResP
resC := msg.ResC resC := msg.ResC
defer func() { defer func() {
if resC != nil { if resC != nil {
resC <- res resC <- resP
} }
}() }()
fn, ok := u.getHandle(msg.Id) fn, ok := u.getHandle(msg.Id)
if ok { if ok {
if err := fn(msg, res); err == nil { if err := fn(msg, resP); err == nil {
} }
} }
} }
func (u *httpServerHandler) pushHandle(key string, handle HttpServerHandlerFunc) { func (u *httpServerHandler) pushHandle(key string, handle HttpServerHandlerFunc) {
u.mu.Lock() // u.mu.Lock()
defer u.mu.Unlock() // defer u.mu.Unlock()
u.mapFn[key] = handle u.mapFn[key] = handle
} }
func (u *httpServerHandler) delHandle(key string) { func (u *httpServerHandler) delHandle(key string) {
u.mu.Lock() // u.mu.Lock()
defer u.mu.Unlock() // defer u.mu.Unlock()
delete(u.mapFn, key) delete(u.mapFn, key)
} }
func (u *httpServerHandler) getHandle(key string) (HttpServerHandlerFunc, bool) { func (u *httpServerHandler) getHandle(key string) (HttpServerHandlerFunc, bool) {
u.mu.RLock() // u.mu.RLock()
defer u.mu.RUnlock() // defer u.mu.RUnlock()
res, ok := u.mapFn[key] res, ok := u.mapFn[key]
if !ok { if !ok {

View File

@ -9,7 +9,6 @@ import (
"dashboard/models" "dashboard/models"
"dashboard/pkg/errgroups" "dashboard/pkg/errgroups"
"dashboard/settings" "dashboard/settings"
"fmt"
) )
var log *logger.Logger var log *logger.Logger
@ -48,7 +47,7 @@ func (u *UnisStation) mainthread(ctx context.Context) error {
case httpMsg := <-u.communicateService.httpServerHandler.httpC: case httpMsg := <-u.communicateService.httpServerHandler.httpC:
u.communicateService.httpServerHandler.httpHandle(httpMsg) u.communicateService.httpServerHandler.httpHandle(httpMsg)
case httpc := <-u.communicateService.httpClientHandler.httpC: case httpc := <-u.communicateService.httpClientHandler.httpC:
fmt.Println(string(httpc.Msg.([]byte))) u.communicateService.httpClientHandler.httpClientHandle(httpc)
// default: // default:
} }

View File

@ -43,7 +43,7 @@ func (r *rpcClientStub) flushRpcClients(ids []*rpcIdAddres) {
} }
for _, idAddr := range ids { for _, idAddr := range ids {
address := fmt.Sprintf("%s:%d", idAddr.host, idAddr.index+r.conf.BasePort) address := fmt.Sprintf("%s:%d", idAddr.host, idAddr.index+r.conf.Port)
cli, err := rpcsup.RpcClient(&rpcsup.RpcConfig{ cli, err := rpcsup.RpcClient(&rpcsup.RpcConfig{
Typec: r.conf.Type, Typec: r.conf.Type,

View File

@ -42,10 +42,10 @@ type UnisConfig struct {
} }
type RpcConfig struct { type RpcConfig struct {
BasePort int `mapstructure:"base_port"` Port int `mapstructure:"port"`
Network string `mapstructure:"network"` Network string `mapstructure:"network"`
Host string `mapstructure:"host"` Host string `mapstructure:"host"`
Type string `mapstructure:"type"` Type string `mapstructure:"type"`
} }
type HttpClientConfig struct { type HttpClientConfig struct {