perf: 优化 server.Server 连接管理机制,优化 GetOnlineCount、GetOnlineBotCount 性能
This commit is contained in:
parent
f8d8d37216
commit
5e5fe8acca
|
@ -18,6 +18,7 @@ const (
|
||||||
DefaultPacketWarnSize = 1024 * 1024 * 1 // 1MB
|
DefaultPacketWarnSize = 1024 * 1024 * 1 // 1MB
|
||||||
DefaultDispatcherBufferSize = 1024 * 16
|
DefaultDispatcherBufferSize = 1024 * 16
|
||||||
DefaultConnWriteBufferSize = 1024 * 1
|
DefaultConnWriteBufferSize = 1024 * 1
|
||||||
|
DefaultConnHubBufferSize = 1024 * 1
|
||||||
)
|
)
|
||||||
|
|
||||||
func DefaultWebsocketUpgrader() *websocket.Upgrader {
|
func DefaultWebsocketUpgrader() *websocket.Upgrader {
|
||||||
|
|
|
@ -211,7 +211,7 @@ func (slf *event) RegConnectionClosedEvent(handler ConnectionClosedEventHandler,
|
||||||
|
|
||||||
func (slf *event) OnConnectionClosedEvent(conn *Conn, err any) {
|
func (slf *event) OnConnectionClosedEvent(conn *Conn, err any) {
|
||||||
slf.PushShuntMessage(conn, func() {
|
slf.PushShuntMessage(conn, func() {
|
||||||
slf.Server.online.Del(conn.GetID())
|
slf.unregisterConn(conn.GetID())
|
||||||
slf.connectionClosedEventHandlers.RangeValue(func(index int, value ConnectionClosedEventHandler) bool {
|
slf.connectionClosedEventHandlers.RangeValue(func(index int, value ConnectionClosedEventHandler) bool {
|
||||||
value(slf.Server, conn, err)
|
value(slf.Server, conn, err)
|
||||||
return true
|
return true
|
||||||
|
@ -231,7 +231,7 @@ func (slf *event) RegConnectionOpenedEvent(handler ConnectionOpenedEventHandler,
|
||||||
|
|
||||||
func (slf *event) OnConnectionOpenedEvent(conn *Conn) {
|
func (slf *event) OnConnectionOpenedEvent(conn *Conn) {
|
||||||
slf.PushSystemMessage(func() {
|
slf.PushSystemMessage(func() {
|
||||||
slf.Server.online.Set(conn.GetID(), conn)
|
slf.registerConn(conn)
|
||||||
slf.connectionOpenedEventHandlers.RangeValue(func(index int, value ConnectionOpenedEventHandler) bool {
|
slf.connectionOpenedEventHandlers.RangeValue(func(index int, value ConnectionOpenedEventHandler) bool {
|
||||||
value(slf.Server, conn)
|
value(slf.Server, conn)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"github.com/kercylan98/minotaur/utils/hash"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type hub struct {
|
||||||
|
connections map[string]*Conn // 所有连接
|
||||||
|
|
||||||
|
register chan *Conn // 注册连接
|
||||||
|
unregister chan string // 注销连接
|
||||||
|
broadcast chan hubBroadcast // 广播消息
|
||||||
|
|
||||||
|
botCount int // 机器人数量
|
||||||
|
onlineCount int // 在线人数
|
||||||
|
|
||||||
|
chanMutex sync.RWMutex // 避免外界函数导致的并发问题
|
||||||
|
}
|
||||||
|
|
||||||
|
type hubBroadcast struct {
|
||||||
|
packet []byte // 广播的数据包
|
||||||
|
filter func(conn *Conn) bool // 过滤掉返回 false 的连接
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *hub) run(ctx context.Context) {
|
||||||
|
h.connections = make(map[string]*Conn)
|
||||||
|
h.register = make(chan *Conn, DefaultConnHubBufferSize)
|
||||||
|
h.unregister = make(chan string, DefaultConnHubBufferSize)
|
||||||
|
h.broadcast = make(chan hubBroadcast, DefaultConnHubBufferSize)
|
||||||
|
go func(ctx context.Context, h *hub) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case conn := <-h.register:
|
||||||
|
h.chanMutex.Lock()
|
||||||
|
h.connections[conn.GetID()] = conn
|
||||||
|
h.onlineCount++
|
||||||
|
if conn.IsBot() {
|
||||||
|
h.botCount++
|
||||||
|
}
|
||||||
|
h.chanMutex.Unlock()
|
||||||
|
case connId := <-h.unregister:
|
||||||
|
h.chanMutex.Lock()
|
||||||
|
if conn, ok := h.connections[connId]; ok {
|
||||||
|
h.onlineCount--
|
||||||
|
delete(h.connections, conn.GetID())
|
||||||
|
if conn.IsBot() {
|
||||||
|
h.botCount--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
h.chanMutex.Unlock()
|
||||||
|
case packet := <-h.broadcast:
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
for _, conn := range h.connections {
|
||||||
|
if packet.filter != nil && !packet.filter(conn) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn.Write(packet.packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
case <-ctx.Done():
|
||||||
|
h.chanMutex.Lock()
|
||||||
|
close(h.register)
|
||||||
|
close(h.unregister)
|
||||||
|
h.connections = nil
|
||||||
|
h.botCount = 0
|
||||||
|
h.onlineCount = 0
|
||||||
|
h.chanMutex.Unlock()
|
||||||
|
return
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(ctx, h)
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerConn 注册连接
|
||||||
|
func (h *hub) registerConn(conn *Conn) {
|
||||||
|
select {
|
||||||
|
case h.register <- conn:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unregisterConn 注销连接
|
||||||
|
func (h *hub) unregisterConn(id string) {
|
||||||
|
select {
|
||||||
|
case h.unregister <- id:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOnlineCount 获取在线人数
|
||||||
|
func (h *hub) GetOnlineCount() int {
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
defer h.chanMutex.RUnlock()
|
||||||
|
return h.onlineCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOnlineBotCount 获取在线机器人数量
|
||||||
|
func (h *hub) GetOnlineBotCount() int {
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
defer h.chanMutex.RUnlock()
|
||||||
|
return h.botCount
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsOnline 是否在线
|
||||||
|
func (h *hub) IsOnline(id string) bool {
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
_, exist := h.connections[id]
|
||||||
|
h.chanMutex.RUnlock()
|
||||||
|
return exist
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOnlineAll 获取所有在线连接
|
||||||
|
func (h *hub) GetOnlineAll() map[string]*Conn {
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
cop := hash.Copy(h.connections)
|
||||||
|
h.chanMutex.RUnlock()
|
||||||
|
return cop
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetOnline 获取在线连接
|
||||||
|
func (h *hub) GetOnline(id string) *Conn {
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
conn := h.connections[id]
|
||||||
|
h.chanMutex.RUnlock()
|
||||||
|
return conn
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseConn 关闭连接
|
||||||
|
func (h *hub) CloseConn(id string) {
|
||||||
|
h.chanMutex.RLock()
|
||||||
|
conn := h.connections[id]
|
||||||
|
h.chanMutex.RUnlock()
|
||||||
|
if conn != nil {
|
||||||
|
conn.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Broadcast 广播消息
|
||||||
|
func (h *hub) Broadcast(packet []byte, filter ...func(conn *Conn) bool) {
|
||||||
|
m := hubBroadcast{
|
||||||
|
packet: packet,
|
||||||
|
}
|
||||||
|
if len(filter) > 0 {
|
||||||
|
m.filter = filter[0]
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case h.broadcast <- m:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/alphadose/haxmap"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/kercylan98/minotaur/server/internal/logger"
|
"github.com/kercylan98/minotaur/server/internal/logger"
|
||||||
"github.com/kercylan98/minotaur/utils/concurrent"
|
"github.com/kercylan98/minotaur/utils/concurrent"
|
||||||
|
@ -36,9 +35,9 @@ func New(network Network, options ...Option) *Server {
|
||||||
dispatcherBufferSize: DefaultDispatcherBufferSize,
|
dispatcherBufferSize: DefaultDispatcherBufferSize,
|
||||||
connWriteBufferSize: DefaultConnWriteBufferSize,
|
connWriteBufferSize: DefaultConnWriteBufferSize,
|
||||||
},
|
},
|
||||||
|
hub: &hub{},
|
||||||
option: &option{},
|
option: &option{},
|
||||||
network: network,
|
network: network,
|
||||||
online: haxmap.New[string, *Conn](),
|
|
||||||
closeChannel: make(chan struct{}, 1),
|
closeChannel: make(chan struct{}, 1),
|
||||||
systemSignal: make(chan os.Signal, 1),
|
systemSignal: make(chan os.Signal, 1),
|
||||||
dispatchers: make(map[string]*dispatcher),
|
dispatchers: make(map[string]*dispatcher),
|
||||||
|
@ -71,6 +70,7 @@ type Server struct {
|
||||||
*event // 事件
|
*event // 事件
|
||||||
*runtime // 运行时
|
*runtime // 运行时
|
||||||
*option // 可选项
|
*option // 可选项
|
||||||
|
*hub // 连接集合
|
||||||
ginServer *gin.Engine // HTTP模式下的路由器
|
ginServer *gin.Engine // HTTP模式下的路由器
|
||||||
httpServer *http.Server // HTTP模式下的服务器
|
httpServer *http.Server // HTTP模式下的服务器
|
||||||
grpcServer *grpc.Server // GRPC模式下的服务器
|
grpcServer *grpc.Server // GRPC模式下的服务器
|
||||||
|
@ -80,7 +80,6 @@ type Server struct {
|
||||||
messagePool *concurrent.Pool[*Message] // 消息池
|
messagePool *concurrent.Pool[*Message] // 消息池
|
||||||
ctx context.Context // 上下文
|
ctx context.Context // 上下文
|
||||||
cancel context.CancelFunc // 停止上下文
|
cancel context.CancelFunc // 停止上下文
|
||||||
online *haxmap.Map[string, *Conn] // 在线连接
|
|
||||||
systemDispatcher *dispatcher // 系统消息分发器
|
systemDispatcher *dispatcher // 系统消息分发器
|
||||||
systemSignal chan os.Signal // 系统信号
|
systemSignal chan os.Signal // 系统信号
|
||||||
closeChannel chan struct{} // 关闭信号
|
closeChannel chan struct{} // 关闭信号
|
||||||
|
@ -106,6 +105,7 @@ func (srv *Server) preCheckAndAdaptation(addr string) (startState <-chan error,
|
||||||
kcp.SystemTimedSched.Close()
|
kcp.SystemTimedSched.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
srv.hub.run(srv.ctx)
|
||||||
return srv.network.adaptation(srv), nil
|
return srv.network.adaptation(srv), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,52 +174,6 @@ func (srv *Server) TimeoutContext(timeout time.Duration) (context.Context, conte
|
||||||
return context.WithTimeout(srv.ctx, timeout)
|
return context.WithTimeout(srv.ctx, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOnlineCount 获取在线人数
|
|
||||||
func (srv *Server) GetOnlineCount() int {
|
|
||||||
return int(srv.online.Len())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOnlineBotCount 获取在线机器人数量
|
|
||||||
func (srv *Server) GetOnlineBotCount() int {
|
|
||||||
var count int
|
|
||||||
srv.online.ForEach(func(id string, conn *Conn) bool {
|
|
||||||
if conn.IsBot() {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOnline 获取在线连接
|
|
||||||
func (srv *Server) GetOnline(id string) *Conn {
|
|
||||||
c, _ := srv.online.Get(id)
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetOnlineAll 获取所有在线连接
|
|
||||||
func (srv *Server) GetOnlineAll() map[string]*Conn {
|
|
||||||
var m = map[string]*Conn{}
|
|
||||||
srv.online.ForEach(func(id string, conn *Conn) bool {
|
|
||||||
m[id] = conn
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOnline 是否在线
|
|
||||||
func (srv *Server) IsOnline(id string) bool {
|
|
||||||
_, exist := srv.online.Get(id)
|
|
||||||
return exist
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloseConn 关闭连接
|
|
||||||
func (srv *Server) CloseConn(id string) {
|
|
||||||
if conn, exist := srv.online.Get(id); exist {
|
|
||||||
conn.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ticker 获取服务器定时器
|
// Ticker 获取服务器定时器
|
||||||
func (srv *Server) Ticker() *timer.Ticker {
|
func (srv *Server) Ticker() *timer.Ticker {
|
||||||
if srv.ticker == nil {
|
if srv.ticker == nil {
|
||||||
|
|
Loading…
Reference in New Issue