游戏服务器开发指南(八):合理应对异常
大家好!我是长三月,一位在游戏行业工作多年的老程序员,专注于分享服务器开发相关的文章。
本文是通用程序设计主题下的第二篇。这个主题主要探讨如何编写高效、健壮、易读的游戏业务代码,每篇从一个小点切入。本次讨论的要点是:如何合理地应对异常。
异常(错误处理)是游戏服务器开发中绕不开的一个话题。合理地处理异常,能够将故障对玩家的影响降到最低水平,快速从错误中恢复,并提供充足的信息,避免以后再出现类似的问题。
有些编程语言(例如Golang)会把异常和错误分开,这里为了方便说明,用异常来统一指代这两种类型。因为这两者在处理方法上是相通的。
总的原则是根据异常的严重程度和影响范围在不同层次处理。对于服务器启动时的严重异常,应向顶层抛出,立即中止服务器运行;而对于仅影响个别玩家的异常,应及时捕获异常,避免影响其他玩家。
看下面一个Java写的例子。服务器在启动时调用start方法做一些初始化工作,其中包括对于Redis客户端的初始化:测试Redis服务器是否可连通,如果可连通初始化连接等。如果发现Redis服务器连接失败,抛出异常,这里不会对异常捕捉,而是逐级抛到顶层,让服务器进程中断运行。
public void serverStart() { // 服务器启动时初始化// do some init work// ...RedisClient.init(); // 初始化Redis客户端,如果失败直接抛出异常,不要捕捉// do other init work// ...
}
这样做的好处是让程序员及时检查问题并做修正,避免后续问题的发生。试想,如果我们改成捕捉异常并恢复程序运行,那么当服务器启动完成后玩家正常进入,可是需要使用到Redis存取数据时才发现功能不可用,必然会引起玩家的不满。所以,对于这种影响全局的严重问题,不如在停服重启的时候就彻底解决好,解决了再对玩家开放服务器。
这种异常处理策略被称为快速失败(fail-fast),即检测到异常后直接抛出并中止程序运行。它适用于严重而且无法恢复的异常情形,好处是能第一时间发现和定位问题,并且避免错误对后续逻辑的影响。JDK中也有对fail-fast思想的运用,例如ArrayList是一个非线程安全的容器,如果在使用for-each遍历元素的同时又修改了它的结构,那么会第一时间抛出ConcurrentModificationException,快速而干净地失败,而不是冒着在未来不确定的时间出现不确定行为的风险。
对于全局性的严重异常,我们固然要fail-fast。但是对于仅影响部分玩家或者部分场合的异常,我们要及时捕捉并恢复,避免不恰当地扩大影响范围。
在游戏中经常会有活动排行榜结算的场景。活动结束时,按照参与活动玩家在排行榜的名次依次发奖。通常这样的操作放在定时任务中执行。如果某一个玩家发奖出现异常,我们需要及时捕捉异常并记录详细的日志,避免影响到其他玩家。
public void giveAwards() { // 为活动结算发奖for (Rank rankData : rankList) {int playerId = rankData.getPlayer();int rank = rankData.getRank();try {giveAwards(playerId, rank); // 为单人发送排名奖励} catch (Exception e) {logger.error(e, "发送奖励失败,角色id是{},排名是{}", playerId, rank); // 错误日志中包含详细的信息}}
}
对比一下,如果我们不对单个玩家发奖捕捉异常,那么出现异常时会导致所有人的发奖失败,势必会引发更多玩家不满,而且需要做更多补偿。由于我们及时捕捉异常,因此发奖失败仅仅被限制在单个玩家范围内,事后处理也要容易得多。
另一个限制异常影响范围的例子是服务器战斗。在逐帧进行的服务器战斗中,每帧运算出现异常时,需要及时捕捉,这样只会影响当前帧,而不会导致战斗直接退出,甚至战斗线程挂掉。
public void frameLoop() { // 开启战斗房间的循环运算while (isStart) {long starTime = System.currentTimeMillis();try {room.update();} catch (Exception e) {logger.error(e, "战斗房间异常"); // 每帧计算有异常则捕捉,不影响下一帧}long endTime = System.currentTimeMillis();long sleepTime = frameInterval - (endTime - startTime);if (sleepTime > 0) {Thread.sleep(sleepTime);}}
}
捕捉异常时,我们要在日志记录充足的信息,以便后续追踪修复问题和做线上处理,不要忽略异常而什么都不记录。要记录的信息应包括完整的异常堆栈、角色id以及其他重要信息。例如上面提到过的发奖失败日志,除了异常堆栈,还应包括角色id和排名,这样方便事后为对应玩家做补偿。
logger.error(e, "发送奖励失败,角色id是{},排名是{}", playerId, rank);
相关文章:
游戏服务器开发指南(八):合理应对异常
大家好!我是长三月,一位在游戏行业工作多年的老程序员,专注于分享服务器开发相关的文章。 本文是通用程序设计主题下的第二篇。这个主题主要探讨如何编写高效、健壮、易读的游戏业务代码,每篇从一个小点切入。本次讨论的要点是&a…...
【g】聚类算法之K-means算法
聚类算法是一种无监督学习方法,它将相似的数据样本划分为一组,同时将不相似的数据样本划分为另一组。这个过程由计算机自动完成,不需要任何人为的干预。 K-means算法是一种经典的聚类算法,它的主要思想是把数据集分成k个簇&#…...
scala内建控制结构
一、条件表达式 (一)语法格式 - if (条件) 值1 else 值2(二)执行情况 条件为真,结果是值1;条件为假,结果是值2。如果if和else的返回结果同为某种类型,那么条件表达式结果也是那种类…...
Linux SSH命令实战教程,提升你的服务器管理基本功!
前言 大家好,又见面了,我是沐风晓月,本文是专栏【linux基本功-基础命令实战】的第62篇文章。 专栏地址:[linux基本功-基础命令专栏] , 此专栏是沐风晓月对Linux常用命令的汇总,希望能够加深自己的印象&am…...
【Python】Python进阶系列教程-- Python3 CGI编程(二)
文章目录 前言什么是CGI网页浏览CGI架构图Web服务器支持及配置第一个CGI程序HTTP头部CGI环境变量GET和POST方法使用GET方法传输数据简单的表单实例:GET方法使用POST方法传递数据通过CGI程序传递checkbox数据通过CGI程序传递Radio数据通过CGI程序传递 Textarea 数据通…...
do..while、while、for循环反汇编剖析
1、循环语句重要特征提取 循环语句最重要的特点就是执行的过程中会往上跳!!! 箭头往上跳的一般都是循环语句,比如下面的for循环: 2、do..while语句反汇编 #include<iostream> using namespace std; #pragma …...
【代码随想录】刷题Day53
1.最长公共子序列 1143. 最长公共子序列 和之前的一道题目的区别就是这个子序列不需要每个字符相邻。那么条件就变成两种了,一种是当前的字符相同,一种是不同。相同跟之前的条件一样;不同则需要继承上次比较的较大值。if (text1[i - 1] tex…...
MySQL 索引及查询优化总结
一个简单的对比测试 前面的案例中,c2c_zwdb.t_file_count表只有一个自增id,FFileName字段未加索引的sql执行情况如下: 在上图中,typeall,keynull,rows33777。该sql未使用索引,是一个效率非常低…...
什么是AJAX?
AJAX是一种基于Web的技术,它允许Web应用程序在不刷新整个页面的情况下与服务器进行交互。通过AJAX,Web应用程序可以使用JavaScript向服务器发送异步请求并在不干扰用户的情况下更新页面的部分内容。 AJAX是Asynchronous JavaScript and XML的缩写。尽管…...
报表生成器FastReport .Net用户指南:显示数据列、HTML标签
FastReport .Net是一款全功能的Windows Forms、ASP.NET和MVC报表分析解决方案,使用FastReport .NET可以创建独立于应用程序的.NET报表,同时FastReport .Net支持中文、英语等14种语言,可以让你的产品保证真正的国际性。 FastReport.NET官方版…...
bootstrap-dialog弹框,去掉遮盖层,可移动
1.去掉遮盖层的设置data-backdrop"false" <div class"modal fade" id"modal" aria-modal"true" role"dialog" data-backdrop"false" style"width:50%"><div class"modal-dialog modal-l…...
7. user-Agent破解反爬机制
文章目录 1. 为什么要设置反爬机制2. 服务器如何区分浏览器访问和爬虫访问3. 反爬虫机制4. User-Agent是什么5. 如何查询网页的User-Agent6. user-agent信息解析7. 爬虫程序user-agent和浏览器user-agent的区别8. 代码查看爬虫程序的user-agent9. 在代码中加入请求头信息 1. 为…...
3.Nginx+Tomcat负载均衡和动静分离群集
文章目录 NginxTomcat负载均衡和动静分离群集Nginx作用实验七层反向代理nginx动静分离四层反向代理负载均衡 NginxTomcat负载均衡和动静分离群集 Nginx是-款非常优秀的HTTP服务器软件 支持高达50 000个并发连接数的响应拥有强大的静态资源处理能力运行稳定内存、CPU等系统资源…...
数据结构与算法之树结构
目录 为什么要使用树结构树结构基本概念树的种类树的存储与表示常见的一些树的应用场景为什么要使用树结构 线性结构中不论是数组还是链表,他们都存在着诟病;比如查找某个数必须从头开始查,消耗较多的时间。使用树结构,在插入和查找的性能上相对都会比线性结构要好 树结构…...
【python】 用来将对象持久化的 pickle 模块
pickle 模块可以对一个 Python 对象的二进制进行序列化和反序列化。说白了,就是它能够实现任意对象与二进制直接的相互转化,也可以实现对象与文本之间的相互转化。 比如,我程序里有一个 python 对象,我想把它存到磁盘里ÿ…...
【博客654】prometheus配置抓取保护以防止压力过载
prometheus抓取保护配置以防止压力过载 场景 担心您的应用程序指标可能突然激增,以及指标突然激增导致prometheus压力过载 就像生活中的许多事情一样,标签要有节制。当带有用户 ID 或电子邮件地址的标签被添加到指标时,虽然它不太可能结束…...
Backtrader官方中文文档:第十三章Observers观察者
本文档参考backtrader官方文档,是官方文档的完整中文翻译,可作为backtrader中文教程、backtrader中文参考手册、backtrader中文开发手册、backtrader入门资料使用。 本章包含 backtrader 官方Observers章节全部内容,入口 : https://backtrader.com/docu/observers-and-sta…...
算法leetcode|54. 螺旋矩阵(rust重拳出击)
文章目录 54. 螺旋矩阵:样例 1:样例 2:提示: 分析:题解:rust:go:c:python:java:每次循环移动一步:每次循环完成一个顺时针:…...
单容水箱建模(自衡单容水箱+无自衡单容水箱)
自衡单容水箱Simulink建模和PLC源代码请参看下面文章链接: 单容双容水箱建模(simulink仿真+PLC代码)_RXXW_Dor的博客-CSDN博客PLC通过伯努利方程近似计算水箱流量详细内容请参看下面的文章博客PLC通过伯努利方程近似计算水箱流量(FC)_怎么用伯努利方程求某水位流量_RXXW_Dor的…...
分享Python7个爬虫小案例(附源码)
本次的7个python爬虫小案例涉及到了re正则、xpath、beautiful soup、selenium等知识点,非常适合刚入门python爬虫的小伙伴参考学习。注:若涉及到版权或隐私问题,请及时联系我删除即可。 1.使用正则表达式和文件操作爬取并保存“某吧”某帖子…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
Appium+python自动化(十六)- ADB命令
简介 Android 调试桥(adb)是多种用途的工具,该工具可以帮助你你管理设备或模拟器 的状态。 adb ( Android Debug Bridge)是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
针对药品仓库的效期管理问题,如何利用WMS系统“破局”
案例: 某医药分销企业,主要经营各类药品的批发与零售。由于药品的特殊性,效期管理至关重要,但该企业一直面临效期问题的困扰。在未使用WMS系统之前,其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...
