Skip to content

性能优化实战 ​

网络服上线后能扛多少人,取决于这几个层面:性能开关(省 CPU)、快速切服(提体验)、Redis 与数据库(省 IO)、部署调优(榨机器)。加上编码层面的高效写法,才能稳住高并发。

性能开关 ​

关闭用不到的原生游戏逻辑能显著提升承载力,但会让部分生存玩法失效。分统一开关和单独开关,默认全开(is_disable=False),调用接口才关。

只在初始化时调用

强烈建议在服务器初始化时设置性能开关,不要在运行中途修改。小游戏服可以关掉大量生存逻辑,把承载从 20~30 人拉到 100~200 人。

快速切服 ​

频繁切服的玩法(如小游戏)用它消除跳转等待。

场景方案
目标服 mod 相同SetKeepResourceWhenTransfer(最快)
目标服 mod 不同方案1 SetResourceFastload(无一致性前提,稍慢);方案2 合并资源包后仍用 SetKeepResourceWhenTransfer

方案2 操作:右键服务器 →【应用快速切服】→ 生成快切网络(大厅/游戏服自动生成 commonRes Mod 并勾选)→ 调 SetKeepResourceWhenTransfer → 部署。注意:会改变原网络服 mod 结构,建议在新生成的 mod 上开发;不同服若有相对路径相同的资源文件会合并失败并报错。

Redis 的三种用法 ​

Redis 是单线程、基于内存的键值存储,能干 service 的活但不占额外进程。

  • 分布式锁:跨进程业务保原子性——业务前 setkey 获锁,完成后删 key 释放(参考 neteaseChunkRes)。
  • 全局数据:多服频繁读写的数据(玩家在线状态、全局弹幕)放 Redis,多条操作时配分布式锁(参考 neteaseFriend、neteaseDanmu)。
  • SQL 缓存层:内存→Redis→SQL 分级落盘。比直接用 server 内存好在:避免崩溃丢大量数据、更少 SQL 请求、降低内存峰值。参考 neteaseQuest:进度先入内存,每 4 秒写 Redis,每 444 秒写 SQL。

数据库优化 ​

存储方案设计(比编码优化更重要) ​

把日期编进 key,规避定时清理。如记录每日杀怪数:

python
# 好:key 含日期,设 1 天过期,无需零点批量清零
key = "killMob:{}:{}-{}-{}".format(uid, y, m, d)
dbIncrby(key, number); dbExpire(key, 86400)

坏方案在零点遍历全部玩家清零,耗时与当日活跃玩家数成正比——这就是瓶颈。

定时+离线存档代替实时存档:高频变化、丢失可容忍的数据(金币)只在内存更新,每几分钟+离线时存一次;低频、丢失不可接受的数据(物品栏)才每次同步。

建表与查询红线 ​

项建议/红线
字符集统一 utf8mb4、引擎 InnoDB
精确浮点用 DECIMAL 而非 FLOAT(如 DECIMAL(19,4) 精确到分)
单表数据量建议 ≤ 5 千万;必须 ≤ 1 亿,超了自行分表(按 uid%N)
单表字段数建议 ≤ 30,太多考虑垂直分表
主键每表显式指定
字段显式 NOT NULL;类型最短原则;别存二进制(转 base64)
  • 加索引:针对常见查询加,单索引字段 ≤ 5,单表索引 ≤ 20,选区分度高的列(性别这种没用)。新 SQL 上线前先 EXPLAIN。
  • 查询:避免 SELECT *(显式列字段);IN 代替 OR(超 1000 拆批);避免 SELECT COUNT(用 SHOW TABLE STATUS 的 rows);避免左/全模糊 LIKE '%x'(用不上索引)。
  • 大表遍历:用 ORDER BY updateTime + LIMIT 分段查,WHERE updateTime>=maxUpdateTime 续查(用 >= 防漏,注意去重取最新)。
  • 连接数:单进程连接数 × 进程数 + 300~500 余量 = 预估上限。默认上限 5000,超了上线前通知运营调整。

部署调优 ​

先按经验值铺,再按监控调。

承载经验值:每 proxy ~500 人;无性能开关的生存服 game/lobby 20~30 人,开了性能开关可到 100~200 人。

线程/核心:master、service、game、lobby 各占 ~1 核;proxy 占 ~3 核(2 加解密 + 2 raknet + 1 主,忽略次要线程)。32 核物理机可部署 6 proxy + 14 game/lobby,或 32 个 game/lobby。

上线后调优:周末晚 8~9 点高峰,看 Grafana 挑人数最多的服,SSH 用 top -Hp <pid> 看线程占用。最高线程常驻 CPU 控制在 70% 左右、不长期超 80%:低于就加最大人数,高于就别加、卡了就降。

高效 Python 编码 ​

Apollo 服务端跑 Python,这些微优化在热点循环里累积可观:

做法提升
临时变量缓存 ./[] 属性访问~50%+
xrange 代替 range~43%
分支逻辑改 dict 分发 _FuncMap.get(k, default)分支越多差距越大
分支把高命中判断放前面截断后续判断
in 代替 has_key~52%
直接 a.name 代替 getattr~60%
热点循环里避免 map/zip/filter~50%
减少小粒度函数调用、少用默认/拓展参数明显
属性多且固定、实例众多的类用 __slots__内存降至 1/3~1/4

已知性能深坑 ​

  • 地图物品过多(几百几千张 filled_map)拖垮服务器:禁用地图物品,或 ChangePerformanceSwitch 关闭地图信息同步。
  • 复活点离末地传送门太近:复活点随机逻辑死循环——地图设计时避开。
  • RegisterEntityAOIEvent 区域过大:每帧扫描太耗 CPU,慎用。
  • SetAddArea 常驻区块:额外加载实体带来运算量,慎用。

到这里网络服已经能稳定扛量了。下一章上线运营:平台发布、测试、商业化、监控。回到基岩版网络游戏首页。