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

news2024/11/25 14:37:58

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

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: 48092788
          Blog: https://blog.csdn.net/guestcode

   Creation 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: 48092788
          Blog: https://blog.csdn.net/guestcode

   Creation 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: 48092788
          Blog: https://blog.csdn.net/guestcode

   Creation 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    // 真正的配置对象是Item
	LoadCount 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 != nil
		loadcount++
		if isReload {
			log.Println("地图配置模块(加载线程) => 正在重载......", loadcount)
		} else {
			log.Println("地图配置模块(加载线程) => 正在加载......")
		}

		var items []*Item

		for {
			// 模拟配置文件加载过程
			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 = item
					cfg.LoadCount = 1
					Cfgs[item.Name] = cfg
				} else {
					// 替换旧的配置
					cfg.Item = item
					cfg.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 <- true
		time.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: 48092788
          Blog: https://blog.csdn.net/guestcode

   Creation by: 2024-3-16

*******************************************************************************/

import (
	"cfgload/mapcfg"
	"cfgload/queue"
	"fmt"
	"log"
)

type Map struct {
	cfg   *mapcfg.Cfg
	Attrs []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资源未修复此项bug
	m.Attrs = nil
	for _, 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.coloradmin.cn/o/1531276.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【CKA模拟题】别再犯难!一文教你用两种方式快速创建Pod!

题干 For this question, please set this context (In exam, diff cluster name) kubectl config use-context kubernetes-adminkubernetesCreate a pod called sleep-pod using the nginx image and also sleep for give any value for seconds. 使用nginx image创建一个名…

探索山海鲸可视化:相较于Excel的独特优势分析

作为一名新用户&#xff0c;我近期开始接触并尝试使用山海鲸可视化工具&#xff0c;这款软件最初吸引我的点在其免费可视化编辑、本地化部署的特点&#xff0c;用了一段时间后&#xff0c;我发现相较于之前使用的Excel来制作可视化看板&#xff0c;两者在多个方面有着显著的区别…

WordPress Plugin NotificationX插件 SQL注入漏洞复现(CVE-2024-1698)

0x01 产品简介 WordPress和WordPress plugin都是WordPress基金会的产品。WordPress是一套使用PHP语言开发的博客平台。该平台支持在PHP和MySQL的服务器上架设个人博客网站。 0x02 漏洞概述 WordPress plugin NotificationX是一个应用插件。2.8.2版本及之前 存在安全漏洞,该…

数据库简介与MySQL编译安装

1数据库基础 什么是数据库 数据库&#xff08;Database&#xff09;是一个有组织的数据存储系统&#xff0c;用于有效地存储、检索、管理和维护数据。数据库系统允许用户以结构化的方式存储和操作大量数据&#xff0c;并提供了一种可靠的方法来管理和维护这些数据&#xff0c…

<地球科学专题>机器学习与灾害风险

<地球科学专题>机器学习与灾害风险 南昌大学黄发明副教授同济大学--张东明教授https://www.koushare.com/lives/room/081366 蔻享直播间,稍后会有快速回放。 南昌大学黄发明副教授

Linux--Ubuntu安装

Linux操作系统时程序员必须要学的操作系统。接下来我们就来看一下Linux操作系统是如何安装的 我们在 Vmware 虚拟机中安装 linux 系统&#xff0c;所以需要先安装 vmware 软件&#xff0c;然后再 安装 Linux 系统。 一.所需安装文件&#xff1a; Vmware 下载地址(现在最新版的…

基于Zigbee技术的智能家居系统(附详细使用教程+完整代码+原理图+完整课设报告)

🎊项目专栏:【Zigbee课程设计系列文章】(附详细使用教程+完整代码+原理图+完整课设报告) 前言 👑由于无线传感器网络(也即是Zigbee)作为🌐物联网工程的一门必修专业课,具有很强的实用性,因此很多院校都开设了zigbee的实训课程;👑同时最近很多使用了我的单片机课…

数据库系统概论(超详解!!!) 第四节 关系数据库标准语言SQL(上)

1.SQL概述 SQL&#xff08;Structured Query Language&#xff09;结构化查询语言&#xff0c;是关系数据库的标准语言 SQL是一个通用的、功能极强的关系数据库语言 SQL的动词 基本概念 基本表 &#xff1a;本身独立存在的表&#xff1b; SQL中一个关系就对应一个基本表&am…

【PostGresql】------ pg多表数据多个条件汇总 使用 union 方法示例代码

1. 示例代码如下&#xff1a; SELECT"ID","DT_DATE","CNAME","RMAN_NAME","DEP_NAME","DEP_ID","INVEST_MAN_NAME","TYPE_NAME","INVEST_LEVEL_NAME","POSITION_NAME",…

常用负载均衡详解

一、介绍 在互联网场景下&#xff0c;负载均衡&#xff08;Load Balance&#xff09;是分布式系统架构设计中必须考虑的一个环节&#xff0c;它通常是指将负载流量&#xff08;工作任务、访问请求&#xff09;平衡、分摊到多个操作单元&#xff08;服务器、组件&#xff09;上去…

Sora 发布的意义能和 ChatGPT 相比吗?

个人觉得&#xff0c;Sora 的发布弥补了ChatGPT语言模型在视频内容领域的不足&#xff0c;简单来说&#xff0c;这两个模型均有自己的优势&#xff0c;ChatGPT是一种语言模型&#xff0c;可以理解和解释自然语言&#xff0c;而Sora是文字到视频转化的应用&#xff0c;将文本内容…

Transformer的前世今生 day04(ELMO、Attention注意力机制)

ELMO 前情回顾 NNLM模型&#xff1a;主要任务是在预测下一个词&#xff0c;副产品是词向量Word2Vec模型&#xff1a;主要任务是生成词向量 CBOW&#xff1a;训练目标是根据上下文预测目标词Skip-gram&#xff1a;训练目标是根据目标词预测上下文词 ELMO模型的流程 针对Wor…

ArmSoM Rockchip系列产品 通用教程 之 RTC 使用

1. RTC 简介​ RTC&#xff1a;(Real_Time Clock)&#xff1a;实时时钟 HYM8563是一种低功耗实时时钟&#xff08;RTC&#xff09;芯片&#xff0c;用于提供精确的时间和日期信息。它提供一个可编程的时钟输出&#xff0c;一个中断输出和一个掉电检测器&#xff0c;所有的地址…

HTML实现卷轴动画完整源码附注释

动画效果截图 页面的html结构代码 <!DOCTYPE html> <html> <head lang=

福克斯2010 1.8L 手动档

老车了记录点东西 好看也便宜 福克斯维修保养费用调查_保养维护_车系文章_空港平行进口汽车交易服务中心 https://tjautoland.net/article-40.html 福克斯自从上市后&#xff0c;凭借其时尚动感的外形、良好的操控性和极佳的驾乘舒适度&#xff0c;在国内紧凑型市场上持续热…

最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作教程

原文链接&#xff1a;最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247598050&idx5&sn70fd3f5946d581ad9c1363295b130ef5&chksmfa823e05cdf5b713baf9cf1381bfb2455ad675a0b21e194bef8b76f35d6aa77…

人工智能快速发展:AI机器人是否能全面替代人工客服?

随着人工智能技术的飞速发展&#xff0c;AI机器人在各个领域的应用越来越广泛。其中&#xff0c;人工客服行业也开始出现了AI机器人的身影。然而&#xff0c;能否完全将人工客服替换为AI机器人仍存在许多争议。 本文将从AI快速发展的背景出发&#xff0c;分析AI机器人取代人工…

SAP SD UKM_ITEMS_READ 信贷风险总额

这几天&#xff0c;业务怀疑 信贷金额不对&#xff0c;来查数据&#xff0c;发现信贷风险总额 是从UKM_ITEMS_READ获取的&#xff0c;但是具体数据在哪里&#xff0c;还是不确认。 最终咨询老师后&#xff0c;提供了文档 SAP S4 HANA信贷管理之信贷未清表_ukm_commts_delete-CS…

Vue3+.NET6前后端分离式管理后台实战(五)

1&#xff0c;Vue3.NET6前后端分离式管理后台实战(五)已经在订阅号发布有兴趣的可以关注一下&#xff01; 2&#xff0c;有兴趣请扫码关注谢谢&#xff01;

阿里云服务器配置openssh-server支持ssh客户端远程终端登陆

登陆云服务器: 成功登陆 更新包: 更新完成 升级最新包 选择YES 空格选中所有并点击ok