skynet 这个还没有看过
游戏服务器端
热更
- 函数替换
- 配置热更
inject替换函数,配置热更
日志
- 日志压缩
- 战斗回放
尽量详尽的日志
监控和报警
服务器是否有卡顿的现象
客户端请求的平均响应速度
玩家行为和投放监控
某些操作是否超过了预期的设定,比如奖励获取等
容错
架构容错(服务器和进程挂掉了),外部服务挂掉(DB),异常情况下的保底逻辑,保证服务的整体可用
功能开关,关闭异常功能 修复后再打开。
玩家行为超出预期(所有列表都加个上限,操作频率上限)
系统行为超出预期(封号频率超过预期后需要预警)
异步
不需要实时的系统,可用做成异步。(原神的抽卡记录就是非实时的)
一些排行榜更新也不一定需求实时,可以收集数据后每隔一段排行一次,(小优化?玩家本人的排行榜可以前台坐下处理进行预排行 让玩家以为看到的数据实时更新了?)
消除单点和水平扩展
集群的承载上限是集群中逻辑单点的承载上限,游戏架构设计中要尽可能的消除单点。存在单点是由于一些数据需要统计进行处理。水平拓展的方式能够增强稳定性,一个node挂掉不影响其他node。
消除单点的方式
- 加一层分发逻辑,使用master服务器将请求分发到不同的node上,master服务器处理的逻辑简单、承载能力强,具体的操作交由node服务器处理
- 使用无状态,将数据和逻辑分离,逻辑执行时去db读取数据。上面的master服务器虽然依然是单点,但由于数据处理简单可以使用无状态的方式组建多组master-node服务器。
游戏服务器中不需要消除所有的单点,只需要服务器的性能满足要求即可,避免过度优化。优化是需要开发和运维成本的。
功能解耦和隔离
对于互不影响的功能(登录和创建队伍)可以拆分成多个服务。对于互相影响的功能(玩家个人逻辑,强化装备、锻造装备都需要操作玩家背包的多个数据)存在同一服务中,使用服务中模块的方式将这些操作隔离开。
服务之间进程隔离和线程隔离。
- 线程隔离的不同服务之间可以通过函数调用的方式交互,不会存在RPC请求可能出现的失败情况。但是服务之间的隔离不是很强。
- 进程隔离的不同服务之间交互复杂,可能存在失败的情况,进程数量过多,增加管理和维护成本。但是隔离程度很高。
隔离
- 将服务分组,同组服务器放在同一进程中,不同组服务放到不同的进程中。
- 对于性能消耗高的服务,进行隔离,防止CPU打满影响到本线程的其他服务。
- 低于不稳定的服务器进行隔离,减少对稳定服务的影响。
超时
对于可能卡死服务的调用,应该使用超时机制,否则A服务出现问题B服务卡死,B服务卡死C服务器跟着卡死,就会出现雪崩影响到众多的功能。
超时的情况
- 接受方没有接收到请求
- 接受方接收到了但是没有回应
- 请求放没有收到接受方的回应
超时的处理方法
- 忽略
- 重试
由于要保证幂等性,重试逻辑很复杂。所以对于重要的服务才需要考虑重试,不重要的服务还是尽量选择忽略。使用超时后应该将游戏系统进行分割,对于核心的功能还是不要使用,非核心功能可以使用超时。
回档
使用了Redis的时候回档怎么解决。
灰度发布
多级灰度环境,范围较大的改动 先在在灰度环境中上线 一段时间后 没有问题就可以正式上线了。
这里就涉及到了如何让部分玩家不进入正式环境而是进行灰度环境(测试服?直接修改玩家连接的服务器?)
如第一级灰度环境-公司内测试人员,第二级灰度-在线随机挑选。
压测
- 开服,创建和登录账号 排队系统
- 广播,开服的时候人非常多 可以减少范围或者服务降级
- 玩家聚集,优化同步策略,逻辑分线
- 单点服务,会将部分CPU跑满并且出现一核有难八核围观的情况。
- 数据上限,各种列表设置上限,否则可能出现预期外的情况,好友列表爆满
- 全服玩家操作,如全服发送邮件等
动态扩容和缩容
最好的情况是根据负载情况动态缩扩容,但目前的情况是冗余的服务器也是需要开销的,所以需要考虑的还是有部分的。
- 云服务器可用区限制,同一个区域的机器可以使用内网IP访问,跨区域只能使用公网IP,这就涉及到了跨区域支持
- 动态缩容,将服务器标记为不可用,同时等到其中的玩家减少到一定程度后踢玩家下线(无感知),最后极少的玩家可以选择强制下线(可能有感知),也是分级的策略
- 自动化流程支持
服务端架构
全区全服
战斗服多地区混合部署, 玩家自动选择最优地区的服务器进行连接.
战斗机房多Central共享使用
各个Central使用匹配服决定战斗地区(同地区, 同语言文化区域, 同首选战斗, 扩大匹配区域, 同Central)
- 战斗机房网络中断: Central间心跳探测
- 客户端连接失败: 客户端到pingsvr的探测
测不准
- 机房到机房的探测数据不能代表用户到机房
- 历史数据变动大, 可信度不高
合作难
- 中小运营商众多
- 基建参差不齐
变量多
- 用户网络问题
- 手机杂乱
- 网络跨地区
- 物理故障
客户端到服务器
- 预表现: 位置同步 技能前摇 拉扯. (降低抖动影响)
- 帧缓存: 针对网络环境动态调整缓存帧数量. (降低抖动影响)
- 协议优化. (减少下行包大小)
- 精简帧: 减少不必要发包
- 数据压缩
- 上行包优化. (降低丢包影响)
- 根据重要程度对重要包使用可靠传输, 对不重要包采用非可靠传输
- 预测丢包, 进行快速ARQ
- 下行包优化
- 根据网络情况, 动态调整冗余端口. (降低抖动影响)
- 对网路丢包 拥塞进行也测, 动态调整补帧策略. (降低抖动影响)
- 网络不稳定时, 提高发包帧率. (降低抖动影响)
- 空帧合并通知. (改善传输效率)
- 不需要的重复操作包, 服务器进行合并或过滤. (减少下行包大小)
- 采用占用流量更小的冗余算法(FEC, Erasure Coding)(减少下行包大小)
- 手机系统优化 (提升特定机型流畅度)
- 厂家硬件优化 (提升特定机型流畅度)
- 天线, 网卡, 驱动, CPU调度等
- Linux系统调优 (降低抖动概率)
- 绑定核心, 避免跨NUMA, 利用cpu cache, 网络多队列, 进程
- 多机房部署 (降低延迟和丢包)
- 多机房部署, 就近连接
从TCP/IP四层来看
- 应用层
- 表现层
- 预表现
- 帧率优化
- 逻辑层
- 帧缓存
- 帧同步网络层
- 协议优化
- 上行包优化
- 下行包优化
- 表现层
- 系统调度层
- 手机系统调优
- Linux系统调优
- 网络层
- MTU探测
- 传输层
- 网路诊断
- TCP/UDP双发
- 硬件层
- 厂家硬件优化
- 多机房部署
- 云硬件优化
预表现
- 安全
- 流畅
- 多客户端一致
位置
服务器每帧发送物体的速度和位置. AB帧之间, 客户端使用A帧的速度进行平滑移动. 收到B帧的时候, 使用B帧的位置以及时间偏差x速度计算物体真实位置. 时间偏差是服务器B帧结束到客户端收到B帧的时间差当前时间 - (游戏开始时间 + 帧号 * 每帧时间)
.
子弹
只需要子弹的出生位置和速度就可以同步计算. 客户端负责计算特效, 服务器负责计算受伤信息.
优化
减少移动包: 从每个操作都发送 -> 状态改变的时候发送
弱网处理
延迟过大的时候进行提示
游戏开始时间受游戏开始包控制, 然而这个包的延迟是不确定的. 可以反推游戏开始时间,
当前时间 - 帧号 * 每帧时间
, 多次计算求平均值.
表现统一
A输出, 做预表现后, 会导致A的表现时长比B多一段(RTT+帧时间), 预表现要考虑这段的平滑处理.
同步
- 服务器只做转发, 客户端读取操作进行计算.
- 网络卡顿, 容易出现不一致 ?
- 相信客户端输入, 导致容易出现作弊.
- 服务器计算后将结果发送给客户端
- unity放到服务器
- 重新开发碰撞计算, 位置计算
服务器发送战斗开始, 开始计算服务器帧. 客户端收到开始后计算客户端帧. 客户端将输出和所属帧发送给服务器, 服务器判断是否是当前帧, 如果是则计算输入, 如果过期则丢弃.
- 延时过大容易导致客户端的输入被大量丢弃
服务器接收客户端输入, 收到输入后保存. 如果帧没有结束则继续等待, 结束后则运算此帧, 并将结果发送给客户端.
- 服务器接收客户端输入, 将输入保存到队列A中, 服务器在帧中执行队列B结束后, 切换AB队列. 服务器没帧结束后, 将变更推送给客户端.