架构

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双发
  • 硬件层
    • 厂家硬件优化
    • 多机房部署
    • 云硬件优化

预表现

  1. 安全
  2. 流畅
  3. 多客户端一致

位置

服务器每帧发送物体的速度和位置. AB帧之间, 客户端使用A帧的速度进行平滑移动. 收到B帧的时候, 使用B帧的位置以及时间偏差x速度计算物体真实位置. 时间偏差是服务器B帧结束到客户端收到B帧的时间差当前时间 - (游戏开始时间 + 帧号 * 每帧时间).

子弹

只需要子弹的出生位置和速度就可以同步计算. 客户端负责计算特效, 服务器负责计算受伤信息.

优化

减少移动包: 从每个操作都发送 -> 状态改变的时候发送

弱网处理

  1. 延迟过大的时候进行提示

  2. 游戏开始时间受游戏开始包控制, 然而这个包的延迟是不确定的. 可以反推游戏开始时间, 当前时间 - 帧号 * 每帧时间, 多次计算求平均值.

表现统一

A输出, 做预表现后, 会导致A的表现时长比B多一段(RTT+帧时间), 预表现要考虑这段的平滑处理.

同步

  • 服务器只做转发, 客户端读取操作进行计算.
    • 网络卡顿, 容易出现不一致 ?
    • 相信客户端输入, 导致容易出现作弊.
  • 服务器计算后将结果发送给客户端
    • unity放到服务器
    • 重新开发碰撞计算, 位置计算

服务器发送战斗开始, 开始计算服务器帧. 客户端收到开始后计算客户端帧. 客户端将输出和所属帧发送给服务器, 服务器判断是否是当前帧, 如果是则计算输入, 如果过期则丢弃.

  • 延时过大容易导致客户端的输入被大量丢弃

服务器接收客户端输入, 收到输入后保存. 如果帧没有结束则继续等待, 结束后则运算此帧, 并将结果发送给客户端.

  • 服务器接收客户端输入, 将输入保存到队列A中, 服务器在帧中执行队列B结束后, 切换AB队列. 服务器没帧结束后, 将变更推送给客户端.