service_con.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. package model
  2. import (
  3. "math/rand"
  4. "rocommon"
  5. "rocommon/service"
  6. "rocommon/util"
  7. "sync"
  8. )
  9. //远端服务器节点处理
  10. var (
  11. serviceNode sync.RWMutex
  12. //服务器节点之间的连接
  13. serviceConnBySID = map[string]rocommon.Session{}
  14. //跨服router节点使用
  15. serviceConnByZone = map[int][]string{} //[zone][sid...]
  16. //auth节点另外再存一份一份,提高效率
  17. authConnBySID = map[string]rocommon.Session{}
  18. dbSelectIndex = 0
  19. authSelectIndex = 0
  20. socialSelectIndex = 0
  21. gameSelectIndex = 0
  22. mapSelectIndex = 0
  23. bossSelectIndex = 0
  24. )
  25. //服务器节点类型枚举
  26. //服务器类型节点Type:[1 gate] [2 game] [3 db] [4 auth] [5 social chat mail] [10 map] [11 map router] [12 pev] [13 boss]
  27. //20 crossrouter跨服路由 21crossserver跨服玩家节点
  28. const (
  29. SERVICE_NODE_TYPE_GATE = 1
  30. SERVICE_NODE_TYPE_GATE_STR = "gate"
  31. SERVICE_NODE_TYPE_GAME = 2
  32. SERVICE_NODE_TYPE_GAME_STR = "game"
  33. SERVICE_NODE_TYPE_DB = 3
  34. SERVICE_NODE_TYPE_DB_STR = "db"
  35. SERVICE_NODE_TYPE_AUTH = 4
  36. SERVICE_NODE_TYPE_AUTH_STR = "auth"
  37. SERVICE_NODE_TYPE_SOCIAL = 5
  38. SERVICE_NODE_TYPE_SOCIAL_STR = "social"
  39. SERVICE_NODE_TYPE_RANK = 6
  40. SERVICE_NODE_TYPE_RANK_STR = "rank"
  41. SERVICE_NODE_TYPE_GUILD = 7
  42. SERVICE_NODE_TYPE_GUILD_STR = "guild"
  43. SERVICE_NODE_TYPE_AOI = 10
  44. SERVICE_NODE_TYPE_AOI_STR = "aoi"
  45. SERVICE_NODE_TYPE_MAP_ROUTER = 11
  46. SERVICE_NODE_TYPE_MAP_ROUTER_STR = "maprouter"
  47. SERVICE_NODE_TYPE_PVE = 12
  48. SERVICE_NODE_TYPE_PVE_STR = "pve"
  49. SERVICE_NODE_TYPE_BOSS = 13
  50. SERVICE_NODE_TYPE_BOSS_STR = "battleboss"
  51. SERVICE_NODE_TYPE_WEBGM = 14
  52. SERVICE_NODE_TYPE_WEBGM_STR = "gmweb"
  53. SERVICE_NODE_TYPE_BATTLERECORD = 15
  54. SERVICE_NODE_TYPE_BATTLERECORD_STR = "battlerecord"
  55. //跨服使用
  56. //局部跨服(部分服务器跨服)
  57. SERVICE_NODE_TYPE_CROSSROUTER = 20
  58. SERVICE_NODE_TYPE_CROSSROUTER_STR = "crossrouter"
  59. SERVICE_NODE_TYPE_CROSSSERVER = 21
  60. SERVICE_NODE_TYPE_CROSSSERVER_STR = "crossserver" //跨服玩法(远航试炼)
  61. SERVICE_NODE_TYPE_CROSSRANK = 22
  62. SERVICE_NODE_TYPE_CROSSRANK_STR = "crossrank" //跨服排行榜
  63. //全局跨服使用(所有服务器跨服)
  64. SERVICE_NODE_TYPE_GLOBALCROSSROUTER = 30
  65. SERVICE_NODE_TYPE_GLOBALCROSSROUTER_STR = "gcrossrouter"
  66. SERVICE_NODE_TYPE_GLOBALCROSSMAP = 31
  67. SERVICE_NODE_TYPE_GLOBALCROSSMAP_STR = "gcrossmap"
  68. )
  69. //需要加锁处理(后续放到主线程队列中做处理)
  70. func AddServiceNode(session rocommon.Session, sid, name string, from string) {
  71. serviceNode.Lock()
  72. defer serviceNode.Unlock()
  73. serverType, zone, index, err := service.ParseServiceID(sid)
  74. if err == nil {
  75. session.(rocommon.ContextSet).SetContextData("ctx",
  76. &service.ETCDServiceDesc{
  77. ID: sid,
  78. Name: name,
  79. Type: serverType,
  80. Zone: zone,
  81. Index: index,
  82. }, "AddServiceNode")
  83. serviceConnBySID[sid] = session
  84. if serverType == SERVICE_NODE_TYPE_SOCIAL {
  85. serviceConnByZone[zone] = append(serviceConnByZone[zone], sid)
  86. } else if serverType == SERVICE_NODE_TYPE_AUTH {
  87. authConnBySID[sid] = session
  88. }
  89. util.InfoF("[AddServiceNode_%v] %v", from, sid)
  90. } else {
  91. util.WarnF("[AddServiceNode_%v] %v err:%v", from, sid, err)
  92. }
  93. }
  94. func RemoveServiceNode(session rocommon.Session) string {
  95. retSID := ""
  96. if session == nil {
  97. return retSID
  98. }
  99. ctx := Session2Context(session)
  100. if ctx != nil {
  101. serviceNode.Lock()
  102. delete(serviceConnBySID, ctx.ID)
  103. delete(authConnBySID, ctx.ID)
  104. zoneNodeList, ok := serviceConnByZone[ctx.Zone]
  105. if ok {
  106. for idx := 0; idx < len(zoneNodeList); idx++ {
  107. if zoneNodeList[idx] == ctx.ID {
  108. serviceConnByZone[ctx.Zone] =
  109. append(serviceConnByZone[ctx.Zone][:idx], serviceConnByZone[ctx.Zone][idx+1:]...)
  110. break
  111. }
  112. }
  113. }
  114. serviceNode.Unlock()
  115. if ctx.Type == SERVICE_NODE_TYPE_GATE {
  116. retSID = ctx.ID
  117. }
  118. retSID = ctx.ID
  119. util.InfoF("[RemoveServiceNode]service nod conn removed sessionId:%v sid:%v", session.ID(), ctx.ID)
  120. } else {
  121. util.InfoF("[RemoveServiceNode]service nod conn removed sessionId:%v", session.ID())
  122. }
  123. return retSID
  124. }
  125. func Session2Context(serviceSess rocommon.Session) *service.ETCDServiceDesc {
  126. if raw, ok := serviceSess.(rocommon.ContextSet).GetContextData("ctx"); ok {
  127. return raw.(*service.ETCDServiceDesc)
  128. }
  129. return nil
  130. }
  131. func RemoveServiceNodeByName(sid string) {
  132. if sid == "" {
  133. return
  134. }
  135. serviceNode.Lock()
  136. delete(serviceConnBySID, sid)
  137. _, zone, _, _ := service.ParseServiceID(sid)
  138. zoneNodeList, ok := serviceConnByZone[zone]
  139. if ok {
  140. for idx := 0; idx < len(zoneNodeList); idx++ {
  141. if zoneNodeList[idx] == sid {
  142. serviceConnByZone[zone] =
  143. append(serviceConnByZone[zone][:idx], serviceConnByZone[zone][idx+1:]...)
  144. break
  145. }
  146. }
  147. }
  148. delete(authConnBySID, sid)
  149. serviceNode.Unlock()
  150. }
  151. //给定sid获得和服务器节点连接的session
  152. func GetServiceNode(sid string) rocommon.Session {
  153. serviceNode.RLock()
  154. defer serviceNode.RUnlock()
  155. if sess, ok := serviceConnBySID[sid]; ok {
  156. return sess
  157. }
  158. return nil
  159. }
  160. //获取指定服务器的节点名称列表
  161. func GetAllServiceNodeByName(serviceName string) []string {
  162. serviceNode.RLock()
  163. defer serviceNode.RUnlock()
  164. var serviceNodeList []string
  165. for _, node := range serviceConnBySID {
  166. if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
  167. sid := raw.(*service.ETCDServiceDesc)
  168. if sid.Name == serviceName {
  169. serviceNodeList = append(serviceNodeList, sid.ID)
  170. }
  171. }
  172. }
  173. return serviceNodeList
  174. }
  175. //获取指定服务器的index列表
  176. func GetAllServiceNodeIdByName(serviceName string) []int32 {
  177. serviceNode.RLock()
  178. defer serviceNode.RUnlock()
  179. var serviceIdList []int32
  180. for _, node := range serviceConnBySID {
  181. if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
  182. sid := raw.(*service.ETCDServiceDesc)
  183. if sid.Name == serviceName {
  184. serviceIdList = append(serviceIdList, int32(sid.Index))
  185. }
  186. }
  187. }
  188. return serviceIdList
  189. }
  190. func GetAllSocialServiceNodeByZone(zone int, serviceName string) []string {
  191. serviceNode.RLock()
  192. defer serviceNode.RUnlock()
  193. if zoneNodeList, ok := serviceConnByZone[zone]; ok {
  194. return zoneNodeList
  195. }
  196. return nil
  197. }
  198. func GetAllZoneSocialServiceNode(serviceName string) []string {
  199. serviceNode.RLock()
  200. defer serviceNode.RUnlock()
  201. var retNodeList []string
  202. for _, node := range serviceConnByZone {
  203. if len(node) > 0 {
  204. retNodeList = append(retNodeList, node[0])
  205. }
  206. }
  207. return retNodeList
  208. }
  209. //根据区组中的ID来获取对应服务器类型节点
  210. func GetServiceNodeById(serviceName string, id int) string {
  211. serviceNode.RLock()
  212. defer serviceNode.RUnlock()
  213. for _, node := range serviceConnBySID {
  214. if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
  215. sid := raw.(*service.ETCDServiceDesc)
  216. if sid.Name == serviceName && sid.Index == id {
  217. return sid.ID
  218. }
  219. }
  220. }
  221. return ""
  222. }
  223. func GetServiceNodeAndSession(serviceName string, serviceTypeName string, id uint64) (string, rocommon.Session) {
  224. if serviceName != "" {
  225. tmpSess := GetServiceNode(serviceName)
  226. if tmpSess == nil {
  227. RemoveServiceNodeByName(serviceName)
  228. } else {
  229. return serviceName, tmpSess
  230. }
  231. }
  232. tmpServiceName, tmpSess := SelectServiceNodeAndSession(serviceTypeName, id)
  233. if tmpServiceName != "" {
  234. return tmpServiceName, tmpSess
  235. } else {
  236. return "", nil
  237. }
  238. }
  239. func SelectServiceNodeAndSession(serviceName string, id uint64) (string, rocommon.Session) {
  240. serviceNode := SelectServiceNode(serviceName, id)
  241. if serviceNode == "" {
  242. return serviceNode, nil
  243. }
  244. serviceSess := GetServiceNode(serviceNode)
  245. if serviceSess == nil {
  246. RemoveServiceNodeByName(serviceNode)
  247. for {
  248. serviceNode = SelectServiceNode(serviceName, 0)
  249. if serviceNode == "" {
  250. break
  251. }
  252. serviceSess = GetServiceNode(serviceNode)
  253. if serviceSess == nil {
  254. RemoveServiceNodeByName(serviceNode)
  255. } else {
  256. break
  257. }
  258. }
  259. }
  260. return serviceNode, serviceSess
  261. }
  262. func SelectServiceNode(serviceName string, id uint64) string {
  263. if id == 0 {
  264. id = uint64(rand.Int31n(100))
  265. }
  266. switch serviceName {
  267. case SERVICE_NODE_TYPE_DB_STR:
  268. return selectServiceNode(serviceName, id)
  269. case SERVICE_NODE_TYPE_AUTH_STR:
  270. return SelectAuthServiceNode(serviceName, id)
  271. case SERVICE_NODE_TYPE_SOCIAL_STR:
  272. return selectServiceNode(serviceName, id)
  273. case SERVICE_NODE_TYPE_GAME_STR:
  274. return selectServiceNode(serviceName, id)
  275. case SERVICE_NODE_TYPE_AOI_STR:
  276. return selectServiceNode(serviceName, id)
  277. //return selectAoiServiceNode(serviceName)
  278. case SERVICE_NODE_TYPE_MAP_ROUTER_STR:
  279. return selectServiceNode(serviceName, id)
  280. case SERVICE_NODE_TYPE_BOSS_STR:
  281. return selectServiceNode(serviceName, id)
  282. case SERVICE_NODE_TYPE_RANK_STR:
  283. return selectAoiServiceNode(serviceName)
  284. case SERVICE_NODE_TYPE_GUILD_STR:
  285. return selectServiceNode(serviceName, id)
  286. case SERVICE_NODE_TYPE_BATTLERECORD_STR:
  287. return selectServiceNode(serviceName, id)
  288. case SERVICE_NODE_TYPE_WEBGM_STR:
  289. return selectServiceNode(serviceName, id)
  290. case SERVICE_NODE_TYPE_CROSSROUTER_STR:
  291. return selectServiceNode(serviceName, id)
  292. }
  293. return ""
  294. }
  295. //id确定的某一个服务器节点
  296. func selectServiceNode(serviceName string, id uint64) string {
  297. serviceNode.RLock()
  298. defer serviceNode.RUnlock()
  299. var retIDList []string
  300. for _, node := range serviceConnBySID {
  301. if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
  302. sid := raw.(*service.ETCDServiceDesc)
  303. if sid.Name == serviceName {
  304. retIDList = append(retIDList, sid.ID)
  305. }
  306. }
  307. }
  308. if len(retIDList) <= 0 {
  309. return ""
  310. }
  311. modNum := int(id % uint64(len(retIDList)))
  312. return retIDList[modNum]
  313. }
  314. func SelectAuthServiceNode(serviceName string, sessionId uint64) string {
  315. serviceNode.RLock()
  316. defer serviceNode.RUnlock()
  317. nodeLen := len(authConnBySID)
  318. if nodeLen <= 0 {
  319. return ""
  320. }
  321. selectIdx := int(sessionId % uint64(nodeLen))
  322. idx := 0
  323. for _, node := range authConnBySID {
  324. if idx == selectIdx {
  325. if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
  326. sid := raw.(*service.ETCDServiceDesc)
  327. if sid.Name == serviceName {
  328. //需要通知服务器状态
  329. return sid.ID
  330. }
  331. }
  332. }
  333. idx++
  334. }
  335. return ""
  336. }
  337. //todo..
  338. // 选择负载较低的节点进入
  339. func selectAoiServiceNode(serviceName string) string {
  340. serviceNode.RLock()
  341. defer serviceNode.RUnlock()
  342. for _, node := range serviceConnBySID {
  343. if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
  344. sid := raw.(*service.ETCDServiceDesc)
  345. if sid.Name == serviceName {
  346. //需要通知服务器状态
  347. return sid.ID
  348. }
  349. }
  350. }
  351. return ""
  352. }