第一段职业经历里,我追求「上线经验」而不得,但是又不太在意「上线经验」。
那时我认知简单,ego也很大,认为自己做的东西通过了思想实验,只是缺了一个线上大用户量验证边界作为收尾。
第二段职业经历里,我没有「上线经验」,而身边的同学几乎个个都有。
我发现我们在认知上确实存在
「gap」
,在推行一些技术决策的时候也遇到了阻力。因此我在对自己工作内容的安排上希望更贴近「线上」的状态,关注「上线驱动」会给我的做事心态带来怎么样的变化。
-
能上线的大型项目是少数,死于一次次内部评审的项目是大多数
-
上线后吸到大用户量的游戏项目是少数,吸不到量的游戏项目是大多数
-
吸到大用户量的游戏项目中,成功的游戏项目更是少之又少,不那么成功的游戏项目是大多数
有幸几乎完整参与了一款虽然不那么成功,但是用户量规模还不错的项目。
去年一年,项目先后在港澳台、日本、中国大陆上线,并稳定运维一年有余。
中国大陆上线当天接近百万玩家在线,也成了我个人商业游戏开发职业生涯的高光时刻。
被业务牵引着紧赶慢赶了四年,最近终于可以稍微空下来沉淀一下几年来的一些思考。
每每有阶段性的思考成果,我还会约业内的朋友进行一些深入的交流。
每一次深入交流,也让我对「上线经验」的意义本身产生了更多新的认知。
借本文这个机会,我尝试结构化地组织一下自己的思考
——
关于如何认知
「上线经验」,以及这次上线的经历带给我的,
分享给大家。
「上线经验」的意义
个人层面,「上线经验」需要能转化为知识或技巧的一部分,夯实能力;
团队层面,具备
「上线经验」的
个人能力补齐团队缺失的部分,进而给业务和
项目带来收益。
大型项目、大用户量检验的「上线经验」,可以或多或少在以下几个方面给团队带来收益:
-
-
-
-
更完整的技术视野、上线驱动的技术规划与推进落地能力
具体到对技术细节的影响,我用两个关键词来展开描述:
-
「规模」
-
「稳定」
「规模」
大部分技术方案只有暴露在真实用户的量级与行为下,才能验证正确性;
在正确性的基础之上,进而继续基于线上表现判断投入产出比及改进的方向。
「规模」既包括
直接检验系统设计正确性的并发规模,还包括间接检验流程高效运转的数据规模(例如各类跟用户数量有关的离线流程与操作)。
在一定规模之上,所有的「简单事务」都会乘以一个跟用户规模有关的大系数,变成一个「复杂问题」。
从几个简单、具体的例子来看如何在前置设计中应对
「规模」问题
:
几乎所有技术实现上的细节决策,在上线之后,经历过「用户规模」的考验,判断合理性与不合理性,都可以沉淀为个人能力与技术判断的一部分。
「稳定」
大部分游戏产品的性质决定了「上线」是一个关键节点。
上线之后,先有「规模」的考验,接下来是细水长流的「稳定」考验。
产品开发阶段,做技术方案的时候,就要充分考虑将来如何更好地应对
「稳定」考验。
-
技术驱动的代码质量体系保证代码库及交付版本的质量
-
把容灾恢复机制建设放到高优先级位置上
-
正确性
-
流程正确。关注游戏内的各主流程在容灾恢复后的正确性
-
数据正确。包括自动化的容灾测试与数据层面的diff正确性校验
-
逻辑正确。OBT前的生产环境小规模演练,线上环境验证容灾恢复流程等
-
自动化
-
保证线上无重大技术事故
-
重大技术事故通常有出现前兆,或者由小事故扩大影响产生
-
线上紧急问题的处理与临时修复时,保持良好心态,避免操作变形
-
技术驱动设计各类SOP,通过预案与规范化流程把临时问题转化为标准化问题求解
一些新的思考
做了十年游戏服务端,我关注的事情经历了三个阶段的变化:
-
初入门路。言必称的是架构、系统设计、容灾、去单点、无状态
-
陷入技术瓶颈。开始关注并提升开发者体验、深入静态代码分析与动态代码生成与注入
-
站在交付的视角上,经历了线上运维。开始关注服务端成本、稳定可控与运维友好的服务应该是怎么样的
「
你认为游戏服务端未来应该是怎样的?
」
具体的回答我已经忘了,但是内容大致逃不脱前面两个阶段的关注点。
今天,我对这个
「
未来
」的想象图景可以描绘得更加清晰。
假如继续从事游戏服务端架构工作,我会从三个方面去描绘游戏服务端的
「
未来
」
:
-
-
-
极致的资源利用曲线
服务端技术需要面向这条资源曲线做优化,让它不那么陡峭:
-
-
构建更灵活的扩缩容粒度。
基于中低配置机器工作;
合理的进程角色与各角色进程数量
-
低成本、分钟级、无感知、无损的动态扩缩容能力。
不满足这四个条件,都无法称为「生产环境」级别的扩缩容能力
-
-
-
尽量基于事件,而不是基于帧去驱动逻辑
-
-
闲时主动GC
理想的资源利用曲线不仅需要计算侧的削峰填谷,还需要资源侧足够灵活的容量适配。
-
-
-
native层具备可感知到脚本层错误、阻断、死循环的能力,具备打断能力
-
-
-
警惕复用的对象
-
关注没有与PCU成正比的指标
我们经常能听到一种错误的观点 —— 服务器的资源成本远低于游戏开发中的其他成本。
-
-
-
对稳定运营游戏的成本条目没有清晰的认知
这个说法充满了游戏开发野蛮生长时代的特色,但是在降本增效、精细化运营的大环境下已经不再适用。
让每一部分成本都有所值是每个技术团队目标的一部分。
「SLA」的追求
SLA指应用面向用户承诺的服务级别,同时也是服务端技术团队面向其他职能承诺的服务级别。
在各类云环境已经足够成熟的当下,业务依赖云环境服务商提供的SLA已经足够作为面向用户的承诺下限。但是对于技术来说,需要做的是基于云商的SLA下限,追求更高标准的SLA。
-
-
-
-
-
-
服务探活
-
避免探活决策依赖单一的组件。
网络原因容易导致预期外的大量服务失活
-
一致性存储与探活逻辑分离。
一致性存储依赖成熟的外部组件实现;
探活借助集群内角色实现。gossip protocol是个成熟方案备选
-
-
线上总会遇到各类异常,需要人工巡检识别到并介入调整
-
-
粗暴的熔断容易引起雪崩,需要自恢复或手动恢复机制介入
-
分层服务治理
-
部署方案的稳定性与容灾容错
-
提前应对所有不稳定的要素
-
云环境基建的不稳定
-
VM故障。突然停机、计划重启、热迁移
-
网络环境
/ACL的不稳定
。闪断、超时、重连
-
外部IO的不稳定
-
服务自身的不稳定
-
各类突发事件
-
饱和式的监控、统计、打点、报警、日志、链路追踪机制建设
-
基于业务侧的指标而不是机器层面的指标做决策
-
监控、巡检、报警,针对各类服务的时延、流量/拥塞、错误/异常、负载等关键信号
-
关注运行时各层次的inspect/debug/REPL能力
-
全要素保活机制
「低运维」
对于稳定、长线运营的游戏服务端来说,「运维」是「持续交付」的基础。
「运维」相关框架与工作流的设计,从研发早期就需要重点关注。
除了线上运维工作流之外,「低运维」关注如何在研发阶段就从基建与框架上构建低成本运维的游戏服服务端。
展开看下「低」如何理解:
-
-
通过
「统一」降低心智成本
-
-
统一的隔离环境
-
开发、测试、预发布、小流量、生产,部署发布统一
-
通过「统一」减少不一致风险
-
统一的服务运行环境与依赖
-
统一的静态配置与注入配置
-
「低」运维投入
-
研发设计运维流程
-
发布、外放、更新、维护的运维流程编排
-
设计具备产品意识的流程。把其他技术当作用户
-
减少协作成本损耗
-
复杂且不灵活的配置方案,会带来极高的运维风险及人力成本投
-
尽早评估在庞大集群规模下的潜在问题与风险
-
VM粒度、组粒度、集群粒度的配置项设计,动静分离,与整体架构息息相关
-
配置的维护与协作方式,
不是简单的一句「SA来搞定就好了」,所有的配置都需要研发兜底
-
研发需要深度介入设计,关注落地
-
考虑几百上千组服务器,配置文件通过自动流程渲染下发,仍然会有出错的可能,需要比较深度的介入人肉校验
「
技术建设总是短期内被低估成本,长期内被低估收益
」。
游戏行业的「
项目制
」属性决定了,我们经常在做重复的
「
项目
」层面的业务实现,而少有超越
「
项目
」的
「
技术建设
」
。
在构建想象图景的过程中,我们看到了一些细节,比如:
-
灵活的动态扩缩容
-
完善的服务治理、容灾与自动化恢复
-
低运维甚至无运维,精细发布与持续交付
等等,
都指向了一个关键词 —— 「
云原生
」。
游戏服务端的
「
云原生
」适配,就是一个典型的容易被低估成本,且容易被低估收益的「
技术建设
」。
对于游戏服务端来说,
「
云原生
」不是一个虚无缥缈的概念,确实会带来实实在在的好处。
接下来我通过两个方面分享一下对
游戏服务端
「
云原生
」的思考:
-
-
标准化的服务单元,对游戏服务端的架构提出了两点要求:
-
-
「
服务单元
」,可以简单理解为
将
整体系统在不同层面上,划分为松耦合、可独立发布部署、可独立横向扩缩容的单元为用户提供服务。
「
云原生
」解决方案中,
「
服务单元
」通常会映射为
「
微服务
」。但是
对于游戏服务端来说,微服务不是云原生的唯一解。
以前,我纠结于有状态与无状态,纠结于游戏的服务器形态上的划分。
过去一段经历中,有幸参与并实践了游戏的微服务化,产生了一些新的思考:
-
游戏的后端,不适合按无状态服务去实现,更不能粗暴地划分为有状态服务
-
当作一个native组件集群,更适合游戏服务端的属性
-
不需要盲目追求游戏服务端的微服务架构 —— 与通常的理解不同,其实发展到目前的游戏服务器,或多或少已经不再算是单体应用
「
服务单元
」
更多是从交付与部署的粒度上去拆解整体服务,并不特指微服务。
划分粒度决定了开发与交付的速度,以及对线上服务的影响范围。
基于同构的native应用角色层,构建异构的业务
「
服务单元
」,在我看来,是比
「
微服务
」更适用于游戏服务端的解。
异构的业务
「
服务单元
」,初阶可以实现为共享主线程的逻辑实体形式,进阶可以实现为更高度抽象的actor形式。
接下来看标准化的运行环境。
需要明确的是,技术团队交付的是解决方案而不是一个个孤立的版本。
解决方案理应可以部署在任何环境,包括各类开发环境,各类私有云、公有云或混合云环境等等。
在行业发展的当前阶段,基于容器和容器编排设计应用已经成为事实上的标准化解决方案。
-
资源抽象。基于OS、VM及各类云环境做抽象,只需要关注应用交付而不用关注基建、机器环境、网络访问规则与配置以及云环境特定的资源等
-
集群层面,网络拓扑,内部拓扑,外网
-
运行时隔离。提供比进程粒度更粗,比VM粒度更细的隔离抽象
-
规定交付标准。基于容器,进行整体发布而不是只交付一个二进制版本包
-
跨环境的发布与部署。
架构适配各类云环境,
可部署、可运行,并
不限定为某个公司内部平台整套技术栈与基础设施
-
基于容器的应用发布始终是完整的,基于VM发布则会把整体流程拆分为机器初始化与版本发布。基于容器构建应用版本可以进行更敏捷的发布、部署与回退
-
构建与发布结合在一起,全流程运维环境统一。不再需要传统意义上的打包上传阶段,内外网环境的构建发布可以做到真正统一
-
构建可观测系统时,可以聚焦于应用层的指标,忽略机器层面的指标
-
实现资源的隔离与最大化利用
「DevOps」
的前提之一是「CI/CD」。
如之前所说,技术交付的不仅是一个可执行文件包,而是一整套持续开发迭代、持续集成、持续交付的解决方案。
什么是「持续」?
一个版本从开发完毕,涉及最少的人,以最快的速度和对外部最小的影响上线到生产环境。
接下来从游戏服务端受DevOps理念影响最大的两个方面,来看看如何在架构设计时进行DevOps适配:
-
-
部署
常规的部署流程包括运维资源的规划部署与筹备,具体的事务包括开服与线上扩缩容。
-
-
研发流程编排由研发与SA协同设计流程,研发执行流程并确认流程参数
-
资源筹备与部署研发深度介入并对结果负责,而不是交付一个版本
-
涉及内外网公共服的流程谁设计,谁发起,参数如何确认
-
-
这三个阶段的演化,是
「版本交付」与
「部署」的职能边界从清晰到模糊的过程。
设计部署与扩缩容友好的应用架构需要在以下方面做好适配:
-
-
角色适配通用的服务概念
-
部署和扩容单元最小化与标准化
-
统一部署和扩容层面的最小单元。避免出现按集群部署,按节点扩容的设计
-
扩缩容的最小单元,不能有独立的静态配置。否则扩缩容时的配置变更本身会带来极大风险
-
面相生产环境设计与验证横向扩缩容。开发环境的扩缩容与生产环境的扩缩容是两个维度的问题
-
降低业务和用户侧对扩缩容的感知
游戏作为一种互联网应用,「更新」的理想形态是「渐进式」的、是
「持续性」的
。
但是至今,仍然有大量的新项目在计划用「
stop-the-world
」的机制应对每一次常规更新。
技术决策的依据也令人相当哭笑不得 —— 一款几年前上线的「头部项目」就是这么做的。
对游戏服务端「更新」的思考,在我看来可以简单分为四个阶段:
1. 对「更新」的认知局限在
「
stop-the-world
」,并对新的更新形式产生
「畏惧」。
2. 理解、认知并以实践新技术的心态落地「不停服
更新」,最简单的形式是蓝绿部署
3. 通过实际运维经验,反思
「不停服更新」
的成本与业务需求的适配度
4. 从云原生开发部署一体化的视角去重新设计并实践
「
持续
更新」
在网络游戏单机化的趋势下,之前我认为适配
「
持续更新
」
的业务需求是减少了。但是经过思考之后,我认为反而增加了。
「持续更新」带来的基准提升是让玩家感知不到游戏的维护与更新。
从业务视角来说,单机化网络游戏一个典型的更新策略是大版本更新前会招募测试玩家。并且:
「
持续更新
」可以应对这两点业务需求带来的挑战。
-
同一服务同时部署了新旧两个版本
-
在一段时间窗口内,新旧两个版本的服务同时面向玩家
-
生产环境流量逐步从全量旧版本过渡到部分小流量新版本,最终过渡到全量新版本
要做到适配云原生的「
持续
更新」,需要从架构设计之初就深度定制:
-
各角色本身「必须」具备横向扩容能力
-
外置与集群内置的流量管理机制
-
不同版本间实现互相兼容
-
包括协议层面的兼容与数据层面的兼容
-
通过一定的策略标记流量只要经过了新版本就无法会退
-
业务框架与上层系统的适配
写在最后
-
履历,成为简历中可以写出来的一段项目经历
-
路径,增加了可以依赖的依据与技术储备,在做方案的时候可以有更多的技术自信
-
思考,获得从研发到上线到稳定运维多视角深度思考沉淀的契机
-
认知,可以梳理并完善各类上线前技术决策的预估收益与上线后实际收益的偏差模型,可以基于这个模型继续做新的技术探索
没「上线经验」的时候,我喜欢在技术方案review的时候说,不要过于依赖上线经验;
有「上线经验」了之后,我发现我确实没办法做到默认信任没有经过线上验证的技术方案。
技术方案的选择具备时空属性 —— 在特定时间特定场合下,技术方案的决策是有意义、可参考的;过了时效,不具备可参考价值。
在做全新的技术方案时,「上线经验」不是权威,不应该成为技术判断与决策的绊脚石,一切以事实为依据。
更合适的说法是:某个方案是这么做的且上线验证了,把其中有意义的点和没有意义的点通过线上验证的结果拆出来,并且提出更合理的需要改进的点,综合起来,才是「上线经验」的意义。
「上线经验」对于行业来说,同样意义重大。
对工业界来说,将「上线经验」与背后的知识快速铺开,是整个行业进入工业化的意义。
以好莱坞为例,早期一部大型工业级影视作品的诞生,中间各环节各流程的关键角色在行业内开枝散叶,快速生产出类似体量的一部又一部更优秀的影视作品,这是行业维度看工业化的意义所在。
具体到项目与业务来说,以有限、确定的成本,减少试错,把资源投在需要试错与探索的方向上,无疑会增加项目的成功率。
经历一次又一次的项目开发与「上线」历练,不论是做业务系统,还是基建或框架,还是架构设计,都要沉淀属于自己的「设计语言」与「技术审美」。