123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- --[[
- Author: neo
- Date: 2021-05-27 14:43:17
- LastEditTime: 2021-05-31 20:52:30
- LastEditors: Please set LastEditors
- Description: 游戏业务节点分配服务
- --]]
- local baseService = require("baseService")
- local nodeMgr = require("nodeMgr")
- local util_node = require("utils.util_node")
- local lib_game_redis = require("lib_game_redis")
- local root = {}
- -- match节点分配优化
- -- | 1. 玩家更集中
- -- | 2. 减少交互拥堵 - 如何判断拥堵
- -- TODO:心跳检查
- -- 开始心跳定时器
- function root.start_timer_heart_beat()
- root.timerHeatBeat =
- create_timeout(
- 500,
- function()
- root.timer_out_heart_beat()
- end
- )
- end
- function root.timer_out_heart_beat()
- root.timerHeatBeat.delete()
- root.timerHeatBeat = nil
- root.start_timer_heart_beat()
- if root.mapCluster == nil then
- return
- end
- local currTime = skynet_time()
- for k, v in pairs(root.mapCluster) do
- local isUpdate = false
- for _k, _v in pairs(v) do
- if _v.isAlive and currTime >= _v.updateTime + 20 then
- _v.isAlive = false
- log.warning("节点[%s]已失效", tostring(_v.nodeName))
- isUpdate = true
- end
- end
- if isUpdate then
- root.update_weight(k)
- end
- end
- end
- -- 节点心跳
- function root.node_heart_beat(nodeInfo)
- if is_empty(nodeInfo) or is_empty(nodeInfo.clusterName) or is_empty(nodeInfo.nodeName) then
- return false
- end
- local clusterName = nodeInfo.clusterName
- local nodeName = nodeInfo.nodeName
- if root.mapCluster == nil then
- root.mapCluster = {}
- end
- if root.mapCluster[clusterName] == nil then
- root.mapCluster[clusterName] = {}
- end
- nodeInfo.updateTime = skynet_time()
- nodeInfo.isAlive = true
- -- 是否更新权重
- local nInfo = root.get_cluster_node_info(clusterName, nodeName)
- -- 重新加入节点
- if nInfo == nil or not nInfo.isAlive then
- util_node:node_load_init_grains(nodeName)
- end
- local isUpdateWeight = false
- if nInfo == nil or not nInfo.isAlive or nInfo.weight ~= nodeInfo.weight then
- isUpdateWeight = true
- end
- root.mapCluster[clusterName][nodeName] = nodeInfo
- -- 更新权重
- if isUpdateWeight then
- root.update_weight(clusterName)
- end
- return true
- end
- -- 停止节点
- function root.node_stop(clusterName, nodeName)
- if is_empty(clusterName) or is_empty(nodeName) then
- return false
- end
- if root.mapCluster[clusterName] == nil then
- return false
- end
- if root.mapCluster[clusterName][nodeName] == nil then
- return false
- end
- root.mapCluster[clusterName][nodeName].isAlive = false
- -- 更新权重
- root.update_weight(clusterName)
- return true
- end
- -- 更新权重
- function root.update_weight(clusterName)
- if root.mapClusterWeight == nil then
- root.mapClusterWeight = {}
- end
- local weightInfo = {}
- weightInfo.total = 0
- weightInfo.list = {}
- for k, v in pairs(root.mapCluster[clusterName]) do
- if v.isAlive then
- local info = {}
- info.nodeName = v.nodeName
- info.min = weightInfo.total + 1
- weightInfo.total = weightInfo.total + (v.weight or 0)
- info.max = weightInfo.total
- table.insert(weightInfo.list, info)
- end
- end
- root.mapClusterWeight[clusterName] = weightInfo
- end
- -- 获取节点信息
- function root.get_cluster_node_info(clusterName, nodeName)
- if is_empty(clusterName) or is_empty(nodeName) then
- return
- end
- if root.mapCluster == nil or root.mapCluster[clusterName] == nil then
- return
- end
- return root.mapCluster[clusterName][nodeName]
- end
- -- 更新玩家分配节点
- function root.user_band_node(uid, clusterName, nodeName)
- if uid == nil then
- return false
- end
- if root.mapUid2NodeInfo == nil then
- root.mapUid2NodeInfo = {}
- end
- if root.mapUid2NodeInfo[uid] == nil then
- root.mapUid2NodeInfo[uid] = {}
- end
- root.mapUid2NodeInfo[uid][clusterName] = nodeName
- return true
- end
- -- 分配match节点
- function root.dispatch_match_node(uid, conf)
- -- TODO:根据match节点下匹配队列人数分配
- -- 本地管理匹配队列玩家列表?
- local clusterName = "match"
- -- 按照负载集中分配
- local nodeName = root.user_dispatch_node_by_grain(uid, clusterName)
- if is_empty(nodeName) then
- -- 按照权重分配
- nodeName = root.user_dispatch_node_by_weight(uid, clusterName)
- end
- if not is_empty(nodeName) then
- root.user_band_node(uid, clusterName, nodeName)
- return nodeName
- end
- end
- -- 分配战斗逻辑服节点
- function root.dispatch_battle_node(uid)
- -- 按照权重做负载均衡
- local clusterName = "battle"
- local nodeName = root.user_dispatch_node_by_weight(uid, clusterName)
- root.user_band_node(uid, clusterName, nodeName)
- if is_empty(nodeName) then
- return
- end
- -- 全服 - 战斗ID
- local battleId = lib_game_redis:hincrby("battle", "id", 1)
- if battleId >= 1000000000 then
- battleId = 1
- lib_game_redis:hset("battle", "id", battleId)
- end
- local ret = {}
- ret.battleNode = nodeName
- ret.battleId = battleId
- return ret
- end
- -- 获取当前战斗数
- function root.get_total_battle_count()
- if root.mapCluster == nil or root.mapCluster["match"] == nil then
- return 0
- end
- local count = 0
- for k, v in pairs(root.mapCluster["match"]) do
- local ok, battleCount = nodeMgr.call(v.nodeName, ".BattleMatch", "getBattleCount")
- if ok and battleCount then
- count = count + battleCount
- end
- end
- return count
- end
- -- 获取节点类型节点列表
- function root.get_cluster_node_list(clusterName)
- if is_empty(clusterName) then
- return
- end
- if root.mapCluster == nil or root.mapCluster[clusterName] == nil then
- return
- end
- local nodeList = {}
- for k, v in pairs(root.mapCluster[clusterName]) do
- if v.isAlive then
- table.insert(nodeList, v.nodeName)
- end
- end
- return nodeList
- end
- ----------------------------------------
- -- 分配玩家节点
- ----------------------------------------
- -- 按照节点权重
- function root.user_dispatch_node_by_weight(uid, clusterName)
- if is_empty(clusterName) then
- return
- end
- if root.mapCluster == nil then
- return
- end
- if root.mapCluster[clusterName] == nil then
- return
- end
- -- 已分配
- if uid and root.mapUid2NodeInfo and root.mapUid2NodeInfo[uid] and root.mapUid2NodeInfo[uid][clusterName] then
- local nodeName = root.mapUid2NodeInfo[uid][clusterName]
- local nodeInfo = root.get_cluster_node_info(clusterName, nodeName)
- if nodeInfo and nodeInfo.isAlive then
- return nodeName
- end
- end
- local rand = math.random(1, root.mapClusterWeight[clusterName].total)
- for k, v in ipairs(root.mapClusterWeight[clusterName].list) do
- if v.min <= rand and rand <= v.max then
- log.info("user_dispatch_node_by_weight uid[%s] nodeName[%s]", tostring(uid), tostring(v.nodeName))
- return v.nodeName
- end
- end
- end
- -- 根据负载
- function root.user_dispatch_node_by_grain(uid, clusterName)
- if is_empty(clusterName) or root.mapCluster == nil or root.mapCluster[clusterName] == nil then
- return
- end
- -- 已分配
- if uid and root.mapUid2NodeInfo and root.mapUid2NodeInfo[uid] and root.mapUid2NodeInfo[uid][clusterName] then
- local nodeName = root.mapUid2NodeInfo[uid][clusterName]
- local nodeInfo = root.get_cluster_node_info(clusterName, nodeName)
- if nodeInfo and nodeInfo.isAlive then
- return nodeName
- end
- end
- -- 按顺序分配
- local firstNode = nil
- for k, v in pairs(root.mapCluster[clusterName]) do
- -- 首个节点
- if firstNode == nil then
- firstNode = v.nodeName
- end
- -- 该节点当前负载
- local grains = util_node:node_load_get_grains(k)
- if grains < v.weight * 10 then
- log.info(
- "user_dispatch_node_by_grain clusterName[%s] uid[%s] nodeName[%s]",
- tostring(clusterName),
- tostring(uid),
- tostring(v.nodeName)
- )
- return v.nodeName
- end
- end
- -- 找不到节点,返回首个节点
- log.info(
- "user_dispatch_node_by_grain clusterName[%s] uid[%s] firstNode[%s]",
- tostring(clusterName),
- tostring(uid),
- tostring(firstNode)
- )
- return firstNode
- end
- function root.onStart()
- root.start_timer_heart_beat()
- end
- baseService.start(root, ".srvNodeMgr", true)
|