package model import ( "math/rand" "rocommon" "rocommon/service" "rocommon/util" "sync" ) //远端服务器节点处理 var ( serviceNode sync.RWMutex //服务器节点之间的连接 serviceConnBySID = map[string]rocommon.Session{} //跨服router节点使用 serviceConnByZone = map[int][]string{} //[zone][sid...] //auth节点另外再存一份一份,提高效率 authConnBySID = map[string]rocommon.Session{} dbSelectIndex = 0 authSelectIndex = 0 socialSelectIndex = 0 gameSelectIndex = 0 mapSelectIndex = 0 bossSelectIndex = 0 ) // 服务器节点类型枚举 // 服务器类型节点Type:[1 gate] [2 game] [3 db] [4 auth] [5 social chat mail] [10 map] [11 map router] [12 pev] [13 boss] // 20 crossrouter跨服路由 21crossserver跨服玩家节点 const ( SERVICE_NODE_TYPE_GATE = 1 SERVICE_NODE_TYPE_GATE_STR = "gate" SERVICE_NODE_TYPE_GAME = 2 SERVICE_NODE_TYPE_GAME_STR = "game" SERVICE_NODE_TYPE_DB = 3 SERVICE_NODE_TYPE_DB_STR = "db" SERVICE_NODE_TYPE_AUTH = 4 SERVICE_NODE_TYPE_AUTH_STR = "auth" SERVICE_NODE_TYPE_SOCIAL = 5 SERVICE_NODE_TYPE_SOCIAL_STR = "social" SERVICE_NODE_TYPE_RANK = 6 SERVICE_NODE_TYPE_RANK_STR = "rank" SERVICE_NODE_TYPE_GUILD = 7 SERVICE_NODE_TYPE_GUILD_STR = "guild" SERVICE_NODE_TYPE_AOI = 10 SERVICE_NODE_TYPE_AOI_STR = "aoi" SERVICE_NODE_TYPE_MAP_ROUTER = 11 SERVICE_NODE_TYPE_MAP_ROUTER_STR = "maprouter" SERVICE_NODE_TYPE_PVE = 12 SERVICE_NODE_TYPE_PVE_STR = "pve" SERVICE_NODE_TYPE_BOSS = 13 SERVICE_NODE_TYPE_BOSS_STR = "battleboss" SERVICE_NODE_TYPE_WEBGM = 14 SERVICE_NODE_TYPE_WEBGM_STR = "gmweb" SERVICE_NODE_TYPE_BATTLERECORD = 15 SERVICE_NODE_TYPE_BATTLERECORD_STR = "battlerecord" SERVICE_NODE_TYPE_FRUIT = 16 SERVICE_NODE_TYPE_FRUIT_STR = "fruit" //跨服使用 //局部跨服(部分服务器跨服) SERVICE_NODE_TYPE_CROSSROUTER = 20 SERVICE_NODE_TYPE_CROSSROUTER_STR = "crossrouter" SERVICE_NODE_TYPE_CROSSSERVER = 21 SERVICE_NODE_TYPE_CROSSSERVER_STR = "crossserver" //跨服玩法(远航试炼) SERVICE_NODE_TYPE_CROSSRANK = 22 SERVICE_NODE_TYPE_CROSSRANK_STR = "crossrank" //跨服排行榜 //全局跨服使用(所有服务器跨服) SERVICE_NODE_TYPE_GLOBALCROSSROUTER = 30 SERVICE_NODE_TYPE_GLOBALCROSSROUTER_STR = "gcrossrouter" SERVICE_NODE_TYPE_GLOBALCROSSMAP = 31 SERVICE_NODE_TYPE_GLOBALCROSSMAP_STR = "gcrossmap" ) // 需要加锁处理(后续放到主线程队列中做处理) func AddServiceNode(session rocommon.Session, sid, name string, from string) { serviceNode.Lock() defer serviceNode.Unlock() serverType, zone, index, err := service.ParseServiceID(sid) if err == nil { session.(rocommon.ContextSet).SetContextData("ctx", &service.ETCDServiceDesc{ ID: sid, Name: name, Type: serverType, Zone: zone, Index: index, }, "AddServiceNode") serviceConnBySID[sid] = session if serverType == SERVICE_NODE_TYPE_SOCIAL { serviceConnByZone[zone] = append(serviceConnByZone[zone], sid) } else if serverType == SERVICE_NODE_TYPE_AUTH { authConnBySID[sid] = session } util.InfoF("[AddServiceNode_%v] %v", from, sid) } else { util.WarnF("[AddServiceNode_%v] %v err:%v", from, sid, err) } } func RemoveServiceNode(session rocommon.Session) string { retSID := "" if session == nil { return retSID } ctx := Session2Context(session) if ctx != nil { serviceNode.Lock() delete(serviceConnBySID, ctx.ID) delete(authConnBySID, ctx.ID) zoneNodeList, ok := serviceConnByZone[ctx.Zone] if ok { for idx := 0; idx < len(zoneNodeList); idx++ { if zoneNodeList[idx] == ctx.ID { serviceConnByZone[ctx.Zone] = append(serviceConnByZone[ctx.Zone][:idx], serviceConnByZone[ctx.Zone][idx+1:]...) break } } } serviceNode.Unlock() if ctx.Type == SERVICE_NODE_TYPE_GATE { retSID = ctx.ID } retSID = ctx.ID util.InfoF("[RemoveServiceNode]service nod conn removed sessionId:%v sid:%v", session.ID(), ctx.ID) } else { util.InfoF("[RemoveServiceNode]service nod conn removed sessionId:%v", session.ID()) } return retSID } func Session2Context(serviceSess rocommon.Session) *service.ETCDServiceDesc { if raw, ok := serviceSess.(rocommon.ContextSet).GetContextData("ctx"); ok { return raw.(*service.ETCDServiceDesc) } return nil } func RemoveServiceNodeByName(sid string) { if sid == "" { return } serviceNode.Lock() delete(serviceConnBySID, sid) _, zone, _, _ := service.ParseServiceID(sid) zoneNodeList, ok := serviceConnByZone[zone] if ok { for idx := 0; idx < len(zoneNodeList); idx++ { if zoneNodeList[idx] == sid { serviceConnByZone[zone] = append(serviceConnByZone[zone][:idx], serviceConnByZone[zone][idx+1:]...) break } } } delete(authConnBySID, sid) serviceNode.Unlock() } // 给定sid获得和服务器节点连接的session func GetServiceNode(sid string) rocommon.Session { serviceNode.RLock() defer serviceNode.RUnlock() if sess, ok := serviceConnBySID[sid]; ok { return sess } return nil } // 获取指定服务器的节点名称列表 func GetAllServiceNodeByName(serviceName string) []string { serviceNode.RLock() defer serviceNode.RUnlock() var serviceNodeList []string for _, node := range serviceConnBySID { if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok { sid := raw.(*service.ETCDServiceDesc) if sid.Name == serviceName { serviceNodeList = append(serviceNodeList, sid.ID) } } } return serviceNodeList } // 获取指定服务器的index列表 func GetAllServiceNodeIdByName(serviceName string) []int32 { serviceNode.RLock() defer serviceNode.RUnlock() var serviceIdList []int32 for _, node := range serviceConnBySID { if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok { sid := raw.(*service.ETCDServiceDesc) if sid.Name == serviceName { serviceIdList = append(serviceIdList, int32(sid.Index)) } } } return serviceIdList } func GetAllSocialServiceNodeByZone(zone int, serviceName string) []string { serviceNode.RLock() defer serviceNode.RUnlock() if zoneNodeList, ok := serviceConnByZone[zone]; ok { return zoneNodeList } return nil } func GetAllZoneSocialServiceNode(serviceName string) []string { serviceNode.RLock() defer serviceNode.RUnlock() var retNodeList []string for _, node := range serviceConnByZone { if len(node) > 0 { retNodeList = append(retNodeList, node[0]) } } return retNodeList } // 根据区组中的ID来获取对应服务器类型节点 func GetServiceNodeById(serviceName string, id int) string { serviceNode.RLock() defer serviceNode.RUnlock() for _, node := range serviceConnBySID { if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok { sid := raw.(*service.ETCDServiceDesc) if sid.Name == serviceName && sid.Index == id { return sid.ID } } } return "" } func GetServiceNodeAndSession(serviceName string, serviceTypeName string, id uint64) (string, rocommon.Session) { if serviceName != "" { tmpSess := GetServiceNode(serviceName) if tmpSess == nil { RemoveServiceNodeByName(serviceName) } else { return serviceName, tmpSess } } tmpServiceName, tmpSess := SelectServiceNodeAndSession(serviceTypeName, id) if tmpServiceName != "" { return tmpServiceName, tmpSess } else { return "", nil } } func SelectServiceNodeAndSession(serviceName string, id uint64) (string, rocommon.Session) { serviceNode := SelectServiceNode(serviceName, id) if serviceNode == "" { return serviceNode, nil } serviceSess := GetServiceNode(serviceNode) if serviceSess == nil { RemoveServiceNodeByName(serviceNode) for { serviceNode = SelectServiceNode(serviceName, 0) if serviceNode == "" { break } serviceSess = GetServiceNode(serviceNode) if serviceSess == nil { RemoveServiceNodeByName(serviceNode) } else { break } } } return serviceNode, serviceSess } func SelectServiceNode(serviceName string, id uint64) string { if id == 0 { id = uint64(rand.Int31n(100)) } switch serviceName { case SERVICE_NODE_TYPE_DB_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_AUTH_STR: return SelectAuthServiceNode(serviceName, id) case SERVICE_NODE_TYPE_SOCIAL_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_GAME_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_AOI_STR: return selectServiceNode(serviceName, id) //return selectAoiServiceNode(serviceName) case SERVICE_NODE_TYPE_MAP_ROUTER_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_BOSS_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_RANK_STR: return selectAoiServiceNode(serviceName) case SERVICE_NODE_TYPE_GUILD_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_BATTLERECORD_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_WEBGM_STR: return selectServiceNode(serviceName, id) case SERVICE_NODE_TYPE_CROSSROUTER_STR: return selectServiceNode(serviceName, id) } return "" } // id确定的某一个服务器节点 func selectServiceNode(serviceName string, id uint64) string { serviceNode.RLock() defer serviceNode.RUnlock() var retIDList []string for _, node := range serviceConnBySID { if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok { sid := raw.(*service.ETCDServiceDesc) if sid.Name == serviceName { retIDList = append(retIDList, sid.ID) } } } if len(retIDList) <= 0 { return "" } modNum := int(id % uint64(len(retIDList))) return retIDList[modNum] } func SelectAuthServiceNode(serviceName string, sessionId uint64) string { serviceNode.RLock() defer serviceNode.RUnlock() nodeLen := len(authConnBySID) if nodeLen <= 0 { return "" } selectIdx := int(sessionId % uint64(nodeLen)) idx := 0 for _, node := range authConnBySID { if idx == selectIdx { if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok { sid := raw.(*service.ETCDServiceDesc) if sid.Name == serviceName { //需要通知服务器状态 return sid.ID } } } idx++ } return "" } // todo.. // 选择负载较低的节点进入 func selectAoiServiceNode(serviceName string) string { serviceNode.RLock() defer serviceNode.RUnlock() for _, node := range serviceConnBySID { if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok { sid := raw.(*service.ETCDServiceDesc) if sid.Name == serviceName { //需要通知服务器状态 return sid.ID } } } return "" }