游戏服务端配置“热更”及“秒启动”终极方案(golang/ygluu/卢益贵)

游戏服务端配置“热更”及“秒启动”终极方案

ygluu  卢益贵

关键词:游戏微服务架构、游戏服务端热更、模块化解耦、golang

目录

一、前言

二、异步线程加载/重载方案

三、配置表碎片化方案

四、指针间接引用

五、重载通知

六、示例代码

七、相关连接


一、前言

众所周知,游戏服务端配置信息热更有几大问题(非lua架构):

1、因配置对象的指针被场景对象引用而导致热更复杂度提高

2、信息量大的配置表热更导致游戏卡顿、玩家闪断

3、一般重载后的配置信息仅影响重载后新创建的对应场景对象,不能影响已存在的场景对象

4、在高度解耦的模块化开发模式下导致热更复杂度提高

本示例代码将使用常用通用的方法来演示在“高度解耦、模块化、模板化”的开发模式下对上述问题的解决方案,并提出游戏服务器秒启动的辅助方案。同时给出了两种方案的完整示例代码下载连接(见后)。

二、异步线程加载/重载方案

异步加载可以完美解决主线程重载大配置文件时可能引起游戏卡顿的现象。见下载连接1

图1

三、配置表碎片化方案

由多行电子表格或者xml格式自动导出一行对应一个ini文件的ini格式,重载时可大大减少重载时间。另外此项方案可应用于游戏秒启动,游戏启动时仅加载必要配置,场景等玩家相关的配置,在玩家登录进入场景以后创建场景对象时再在主线程里同步加载碎片化的配置,碎片化的配置加载时所需时间极短,玩家几乎没有太明显的卡断感知。见下载连接2

当然秒启动还有一个重要方案:主从机方案,即采用主从机方式,在主机崩溃释放所占用端口号后,从机立即夺得相同端口的控制权,从机角色瞬间转变为主机角色

图2

四、指针间接引用

配置对象Cfg引用配置项Item(真正记载配置信息的地方),场景对象Map引用配置对象Cfg,每次Map使用配置信息时间接访问Cfg.Item。配置加载模块执行重载后,在主线程的回调中重置Cfg对象的Item字段,这样既不不影响主线程复杂的场景应用逻辑,又能让已存在的场景对象Map更新到最新的配置信息

图3

五、重载通知

针对部分需要复制配置信息的场景对象,通过主线程同步执行重载回调函数OnReload,这样每个场景对象实例Map1~N都能及时更新到最新的配置信息。

图4

六、示例代码

(一)示例代码下载连接及运行效果

1、示例代码(golang)下载链接:

线程异步加载方案示例代码(1):

游戏服务端配置“热更”终极方案icon-default.png?t=N7T8https://download.csdn.net/download/GuestCode/88977874配置表碎片化加载方案示例代码(2):

游戏服务端配置“热更”及“秒启动”终极方案icon-default.png?t=N7T8https://download.csdn.net/download/GuestCode/88979391

2、示例代码运行效果

重载后会通知所有场景实例更新最新的配置信息。

图5 线程异步加载效果

图6 配置表碎片化重载效果

(二)示例代码结构及源码文件

1、示例代码模块化目录结构

图7 

2、主线程队列代码(异步加载方案)

主线程队列采用了匿名函数队列

package queue/*******************************************************************************Author: Yigui Lu (卢益贵)Contact WX/QQ: 48092788Blog: https://blog.csdn.net/guestcodeCreation by: 2024-3-16*******************************************************************************/// 主线程队列(匿名函数),仅主线程调用,无需同步
var MainQ = make(chan func())// 主线程事件响应函数列表
var events = make(map[string]func())// 触发主线程事件
func TriggerEvent(name string) {MainQ <- func() {on := events[name]if on != nil {on()}}
}// 设置事件监听(在主线程中执行onEvent)
func ListenEvent(name string, onEvent func()) {events[name] = onEvent
}

3、主线程代码(异步加载方案)

package main/*******************************************************************************Author: Yigui Lu (卢益贵)Contact WX/QQ: 48092788Blog: https://blog.csdn.net/guestcodeCreation by: 2024-3-16*******************************************************************************/import (_ "cfgload/mapcfg"_ "cfgload/mapmgr""cfgload/queue"
)func main() {// 模拟游戏主线程for {// 匿名函数队列proc := <-queue.MainQ// 出列并执行proc()}
}

4、地图配置模块示例代码(异步加载方案)

加载和重载共一份逻辑代码。

package mapcfg/*******************************************************************************Author: Yigui Lu (卢益贵)Contact WX/QQ: 48092788Blog: https://blog.csdn.net/guestcodeCreation by: 2024-3-16*******************************************************************************/// 本配置单元可以作为配置模板加载所有配置import ("cfgload/queue""io/ioutil""log""time"
)const ModuleName = "地图配置模块"// 地图配置项,一个对应一个
type Item struct {Name    string // 地图名ResName string // 地址资源名ResData []byte // 资源数据Attrs   []int  // 地图属性
}// 外部类型:地图配置类
type Cfg struct {Item      *Item    // 真正的配置对象是ItemLoadCount int      // 加载次数,演示用onReloads []func() // 触发重载回调,部分场景需求用
}func (c *Cfg) AddOnReload(onReload func()) {c.onReloads = append(c.onReloads, onReload)
}// 配置表
type cfgs = map[string]*Cfg// 配置表(全局变量/外部接口,仅主线程调用无需同步)
var Cfgs cfgs// 配置异步加载协程
var loadcount int// 异步加载/重载通用函数,无需两者区分而额外编写代码
func loadFunc(ch chan bool) {for {// 等待加载通知<-ch// 以下在加载线程中执行 -->isReload := Cfgs != nilloadcount++if isReload {log.Println("地图配置模块(加载线程) => 正在重载......", loadcount)} else {log.Println("地图配置模块(加载线程) => 正在加载......")}var items []*Itemfor {// 模拟配置文件加载过程item := &Item{Name:    "南天门",ResName: "res001.map",}item.ResData, _ = ioutil.ReadFile(item.ResName)items = append(items, item)break // 仅加载一行}// <-- 以上在加载线程中执行// 匿名函数将在主线程执行,达到线程同步目的onModuleLoadedInMain := func() {if Cfgs == nil {// 首次加载Cfgs = make(cfgs)}for _, item := range items {cfg := Cfgs[item.Name]if cfg == nil {// 新增配置cfg = &Cfg{}cfg.Item = itemcfg.LoadCount = 1Cfgs[item.Name] = cfg} else {// 替换旧的配置cfg.Item = itemcfg.LoadCount++// 在主线程调用重载通知回调(只有部分场景需求才需要通知)for _, onReload := range cfg.onReloads {onReload()}}}}if isReload {log.Println("地图配置模块(加载线程) => 重载完毕", loadcount)} else {log.Println("地图配置模块(加载线程) => 加载完毕")}// 给主消息队列压栈// 主线程会调用onModuleLoadedInMain执行,达到线程同步目的queue.MainQ <- onModuleLoadedInMain//  首次加载,触发事件告诉主线程模块加载完毕if !isReload {queue.TriggerEvent(ModuleName)}}
}func reloadTrigger(ch chan bool) {// 模拟5秒钟触发一次重载请求for {ch <- truetime.Sleep(time.Second * 5)}
}func init() {ch := make(chan bool)go loadFunc(ch)go reloadTrigger(ch)
}

5、地图管理模块示例代码(异步加载方案)

package mapmgr/*******************************************************************************Author: Yigui Lu (卢益贵)Contact WX/QQ: 48092788Blog: https://blog.csdn.net/guestcodeCreation by: 2024-3-16*******************************************************************************/import ("cfgload/mapcfg""cfgload/queue""fmt""log"
)type Map struct {cfg   *mapcfg.CfgAttrs []int
}// 间接引用转为直接引用:Map.CfgItem
func (m *Map) CfgItem() *mapcfg.Item {return m.cfg.Item
}// 直接引用配置对象字段示例
func (m *Map) Name() string {return m.cfg.Item.Name
}// 复制配置信息示例(模拟部分需求场景,无需求则可以省略)
func (m *Map) onReloadCopyInfo() {const txt = "地图管理模块(主线程) => 复制配置信息,地图名称:%s,加载次数:%d"log.Println(fmt.Sprintf(txt, m.Name(), m.cfg.LoadCount))// csdn资源未修复此项bugm.Attrs = nilfor _, attr := range m.CfgItem().Attrs {m.Attrs = append(m.Attrs, attr)}
}var Maps = make(map[string]*Map)func createMap() {log.Println("地图管理模块(主线程) => 正在创建地图......")for _, cfg := range mapcfg.Cfgs {mp := &Map{cfg: cfg,}// 无复制配置信息需求时可以省略此步骤cfg.AddOnReload(mp.onReloadCopyInfo)// 为避免代码冗余,首次加载自己调用onReloadCopyInfo复制配置信息mp.onReloadCopyInfo()}log.Println("地图管理模块(主线程) => 创建地图完毕")
}func init() {// 待地图配置首次加载完毕后创建地图queue.ListenEvent(mapcfg.ModuleName, createMap)
}

七、相关连接

对比脚本型和编译型游戏服务器的热更新方案 - codedump的网络日志icon-default.png?t=N7T8https://www.codedump.info/post/20191206-gameserver-hot-refresh/

聊聊Golang游戏服务器的热更 | wudaijun's blogicon-default.png?t=N7T8https://wudaijun.com/2022/08/golang-gameserver-hotfix/

一种基于so的C/C++服务热更新方案_mob604756fea1c5的技术博客_51CTO博客icon-default.png?t=N7T8https://blog.51cto.com/u_15127648/4542189

游戏开发(九) 之 纯 lua 版 热更新 方案_纯lua的热更新方案-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/zyxjx1314/article/details/106045843

lua游戏服务器热更新_lua热更函数但不修改变量-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/peter_teng/article/details/52751231

游戏开发中的热更新:一_热更新从服务器上下载的是什么文件-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/weixin_40695640/article/details/129463767

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/283902.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字乡村引领新风尚:科技赋能农村实现全面进步

随着信息技术的迅猛发展&#xff0c;数字乡村正成为引领农村全面进步的新风尚。科技作为推动农村发展的强大引擎&#xff0c;正在深刻改变着传统农业的生产方式、农村的社会结构以及农民的生活方式&#xff0c;为农村经济社会的全面进步注入了新的活力和动力。本文将从数字乡村…

靶场拿下目标控制权

目标&#xff1a;登录目标网页的服务器&#xff0c;获取控制权原理&#xff1a;在网页上传大马来执行 网页&#xff1a;自己搭建的网站 网页的原本摸样 发现是metinfo 5.0.4版本&#xff0c;在网上搜索该版本建站的漏洞&#xff0c;搜索到有文件上传漏洞。 写一个html文件&a…

PwnLab靶场PHP伪协议OSCP推荐代码审计命令劫持命令注入

下载链接&#xff1a;PwnLab: init ~ VulnHub 安装&#xff1a; 打开vxbox直接选择导入虚拟电脑即可 正文&#xff1a; 先用nmap扫描靶机ip nmap -sn 192.168.1.1/24 获取到靶机ip后&#xff0c;对靶机的端口进行扫描&#xff0c;并把结果输出到PwnLab文件夹下&#xff0c;命名…

计算机网络——物理层(物理传输介质和物理层的设备)

计算机网络——物理层&#xff08;物理传输介质和物理层的设备 物理传输介质导向性传输介质双绞线同轴电缆光纤 非导向性传输介质无线电波多径效应 微波地面微波通信ISM 频段 卫星通信 物理层设备中继器集线器中继器和集线器的区别 我们今天进入物理层的物理传输介质和物理层的…

uniapp+uview 学习笔记(二)—— H5开发

文章目录 前言一、开发步骤1.创建项目2.安装组件库并导入使用3.封装请求4.国际化5.打包 总结 前言 本文主要介绍使用uniapp框架和uview组件库进行H5开发&#xff0c;需要用到的开发工具为HBuilder X。 一、开发步骤 1.创建项目 打开HBuilder X&#xff0c;在顶部栏目选择 新…

6、kubenetes 卷

1、什么是卷 在某些场景下&#xff0c;我们可能希望新的容器可以在之前容器结束的位 置继续运⾏&#xff0c;⽐如在物理机上重启进程。可能不需要&#xff08;或者不想要&#xff09; 整个⽂件系统被持久化&#xff0c;但又希望能保存实际数据的⽬录。 Kubernetes通过定义存储…

基于华为ensp的企业网络规划(新版)

基于华为ensp的企业网络规划&#xff08;新版&#xff09; 第一章 项目概述1.1 项目总体描述1.2 项目总体功能要求 第二章 可行性分析2.1 经济效益分析2.2 项目分析2.3 技术可行性分析2.4 项目风险分析 第三章 需求分析3.1 总体需求3.2 具体需求3.3 非功能需求 第四章 总体设计…

你是不是MySQL老司机?来看看这些explain结果你能解释吗?[害羞]

表结构表数据行数 这里Extra为什么是Filesort? 这里Extra为什么Using index 从这儿你可以猜出我MySQL的版本吗&#xff1f; 这里Extra为什么是NULL? 这里Extra为什么是Filesort? 你知道平时SQL该怎么写了吗&#xff1f;

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i 运行测试

【ORB-SLAM3】在 Ubuntu20.04 上编译 ORM-SLAM3 并使用 D435i 运行测试 1 Prerequisites1.1 C11 or C0x Compiler1.2 Pangolin1.3 OpenCV1.4 Eigen3 2 安装 Intel RealSense™ SDK 2.02.1 测试设备2.2 编译源码安装 (Recommend)2.3 预编译包安装 3 编译 ORB-SLAM34 使用 D435i …

【PHP + 代码审计】数组函数

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

【并查集专题】【蓝桥杯备考训练】:网络分析、奶酪、合并集合、连通块中点的数量、格子游戏【已更新完成】

目录 1、网络分析&#xff08;第十一届蓝桥杯省赛第一场C A组/B组&#xff09; 2、奶酪&#xff08;NOIP2017提高组&#xff09; 3、合并集合&#xff08;模板&#xff09; 4、连通块中点的数量&#xff08;模板&#xff09; 5、格子游戏&#xff08;《信息学奥赛一本通》…

流畅的 Python 第二版(GPT 重译)(五)

第九章. 装饰器和闭包 有人对将这个功能命名为“装饰器”的选择提出了一些抱怨。主要的抱怨是该名称与其在 GoF 书中的用法不一致。 名称 decorator 可能更多地归因于其在编译器领域的用法—语法树被遍历并注释。 PEP 318—函数和方法的装饰器 函数装饰器让我们在源代码中“标记…

【Linux】线程控制{fork() / vfork / clone/pthread_join()/pthread_cancel()}

文章目录 1.fork() / vfork / clone2.线程等待2.1pthread_join()2.2pthread_tryjoin_np() 3.pthread_exit()4.pthread_cancel()5.一些线程相关的问题6.pthread_detach()7.pthread_self()8.认识线程标识符&#xff1a;pthread_self()获取线程标识符9.POSIX线程库 1.fork() / vfo…

2024年全球生成人工智能全景图【中文】

2024年全球生成人工智能全景图【中文】 在过去的一年中&#xff0c;产生式人工智能&#xff08;GenAI&#xff09;无疑成为了全球各行各业的热门话题。特别是ChatGPT的发布&#xff0c;激发了公众对GenAI强烈的兴趣和激动&#xff0c;唤醒了我们对其变革潜力的认知。 虽然我们…

漫谈微服务网关

一、什么是服务网关 服务网关 路由转发 过滤器 1、路由转发&#xff1a;接收一切外界请求&#xff0c;转发到后端的微服务上去&#xff1b; 2、过滤器&#xff1a;在服务网关中可以完成一系列的横切功能&#xff0c;例如权限校验、限流以及监控等&#xff0c;这些都可以通过…

GO-初识包管理

初识包管理&#xff0c;知道项目中文件和文件夹之间的关系 输出&#xff0c;代码&#xff0c;在go编译器运行时会显示在屏幕中 初识数据类型 整型&#xff0c;数字。例如&#xff1a;1、2、3、4 字符串类型&#xff0c;表示文本信息的。例如:“张三”“李四” 布尔类型&#x…

【嵌入式——QT】Charts常见的图表的绘制

【嵌入式——QT】Charts常见的图表的绘制 柱状图QBarSetQBarSeriesQBarCategoryAxis图示 饼图堆叠柱状图百分比柱状图散点图和光滑曲线图代码示例 柱状图 QBarSet 用于创建柱状图的数据集。 主要函数 setLabel()&#xff1a;设置数据集标签 &#xff1b;setLabelBrush()&am…

AI新工具(20240322) 免费试用Gemini Pro 1.5;先进的AI软件工程师Devika;人形机器人Apptronik给你打果汁

✨ 1: Gemini Pro 1.5 免费试用Gemini Pro 1.5 Gemini 1.5 Pro是Gemini系列模型的最新版本&#xff0c;是一种计算高效的多模态混合专家&#xff08;MoE&#xff09;模型。它能够从数百万个上下文Token中提取和推理细粒度信息&#xff0c;包括多个长文档和数小时的视频、音频…

LabVIEW飞行器螺旋桨性能测试与数据监控

LabVIEW飞行器螺旋桨性能测试与数据监控 开发LabVIEW的电动飞行器螺旋桨性能测试与数据监控系统&#xff0c;专门针对电动飞行器螺旋桨在运行过程中的性能测试和监控需求。通过采集转速、转矩、拉力和温度等关键参数&#xff0c;系统能够实时监测和分析螺旋桨的状态&#xff0…

「渗透笔记」致远OA A8 status.jsp 信息泄露POC批量验证

前言部分 在本节中&#xff0c;我会分两部分来说明致远OA A8 status.jsp 信息泄露的验证问题&#xff0c;其实就是两种验证方式吧&#xff0c;都一样&#xff0c;都是批量验证&#xff0c;主要如下所示&#xff1a; 通过Python脚本进行批量验证&#xff0c;但是前提是你可以收…