OpenKruiseGame 的设计理念详解| 学习笔记

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,恶意文件检测 1000次 1年
传统型负载均衡 CLB,每月750个小时 15LCU
简介: 快速学习 OpenKruiseGame 的设计理念详解

开发者学堂课程【云原生游戏最佳实践系列:OpenKruiseGame 的设计理念详解】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/1195/detail/18166


OpenKruiseGame 的设计理念详解

 

内容介绍:

一、云原生游戏解决方案

二、云原生助力游戏行业“高质量”发展

三、云原生游戏负载 OpenKruiseGame

四、OpenKruiseGame demo 演示

 

一、云原生游戏解决方案

后疫情时代,游戏行业步入高质量发展期,“效率”、“成本”、“安全成为游戏开发者关注的三大因素。

“效率”-快速开服、测试、发布是游戏成功的重要因素

“成本”-游戏峰谷容量差异较大,弹性平均降本30%

“安全”-上线新游是 DDOS、BotAttackCC 攻击的重灾区

1、免费开源的游戏云原生负载

image.png

OpenKruiseGame 是阿里云开源的面向(PVP/PVE等)游戏工作负载,旨在解决游戏容器化过程中游戏业务/运维管理与云原生基础设施的感知与融合,核心能力如下:

游戏发布-支持原地热更新,配置热重载,定向/定序更新

游戏网络-支持网络直连、IP/端口不变、支持端口段映射

游戏运维-支持快速开服/合服,设置运维状态隔离故障

弹性伸缩-支持横向/定时伸缩策略,支持ECS/ECI等多种弹性资源

成本控制-支持成本分析、费用分摊、成本预测、成本优化

多云/多集群管理-云服务商无关,支持多云/混合云一致性管理

2、敏捷弹性的游戏基础设施

接入层

NAT 网关 EIP 直连 MSE 云原生网关 GA(全球接入)

业务层  

ACK (弹性调度自动伸缩智能运维全地域发布)

数据层

PolarDB (异地灾备备份闪回秒级扩容6倍写入效率)

运维

日志

审计

监控

拓扑

APM

Tracing

成本治理

多云管控

3、安全稳定的游戏安全策略

image.png

容器安全中心

镇像安全扫描,AK 防泄漏,安全风粉检测,CVE-键修复

游戏盾

DDoS/CC 攻击防御多平台 SDK 接入8线独家防物

之前主要做容器相关的业务研发,主要负责弹性,监控,大数据等相关功能的开发,从2015年左右开始做 DK,到17、18年的时候开始做 K8S,整个国内容器兴起从2015年左右开始,大部分接触到的的业务场景一般都是以 API 或者网站类型的业务为主,但是随着容器化和原生化的展开,越来越多不同类型的业务开始向容器方向去做一些探索,比如早些年的 AI、大数据、最近比较火的自动驾驶、仿真都可以看到云原生在承载越来越多的业务类型和业务方向,云原生也逐渐成为很多行业上云、用云和技术架构升级个最佳弯道超车的一个方式,提到云原生脑海的关键字是比如容器带来的一致性交付,k8s带来的编排能力可以提高整个应用交付的效率,云原生场景之下比较常见提到的 feature 弹性能力、深度的可观测性能力包括容器的一些隔离性可以带来更高的安全功能等等,都是云原生能够给不同的行业、不同的业务带来增值价值的一些内容。

游戏行业接触比较早,早在 swap 或者更早一点像 mes 游戏的时候已经有一些客户在尝试用容器化的方式去解决游戏场景的一些问题。游戏场景和其他的行业相比有太多自己的特殊性,比如游戏行业早些年的时候,因为行业发展的比较快,所以很多游戏公司在游戏基础建设上的投入不太够,很多时候游戏公司以工作室的方式来运作,工作室很多时候看重的是内在一些空间的建设或者游戏引擎的建设,对于平台架构的投入相对来讲比较少,所以很多的游戏不论是开服还是快速的发布,都是通过人肉的方式或者是通过运维人员通过配备工具,ice ballra、southat配本工具自动化管理和运维,很多游戏公司在接触过程中给的游戏行业的一个现状,国内的游戏行业和国外游戏行业有非常大的不同,国内的游戏行业很多时候开发者都使用自己内部的一些游戏引擎,或者针对一些开源引擎做一些二次定制和二次开发,国外的游戏客户很多时候都会用比如 LV 或者 unity,国内比较火的 cocos 还可以用,海外的用户更喜欢的是一种类似于 SaaS 化的 delicate nameserver 模型,所以是国内游戏场景和国外游戏场景比较典型的一些差异和现状,特别对于云原生的场景国内和国外也有非常多的不同,比如游戏原生化话题在国外兴起的时间非常早,大概14年、15年左右的谷歌和育碧联合推游戏云原生化的方案 Agones。但是Agones 方案更倾向于解决一些 pvp 场景游戏的快速开服弹性,然后包括一些 SaaS 化托管的代理 gameserver 的一个包装问题。所以在海外标准化程度比较高的场景之下,Agones 的收入非常多,特别是在亚太区日本,Agones 方案可以是大家上云使用云原生的一个统一的标准模式。早期的时候 ACK 也尝试把 Agones 引进国内,把 Agones 也作为是国内游戏原生化的一个最佳方式来交付给开发者,但是真实的和国内的游戏公司去交流和沟通之后,发现国内的现状和海外还是有非常大的不同。

国内有几个比较典型的特点:第一个是国内做游戏的时候 pvp 和 pve 两种类型是各占半壁江山的,但是 Agones 场景对于 pve 的支持相对来讲会弱一些。第二个点是国内很多时候游戏的发布或者游戏的更新,更倾向于使用热更新的方式去实现快速不停服的更新策略,但是在 Agones 场景之下对热更新的配置实际上没有过多的支持,更多的是通过 graceful、shutdown 、recreate 的方式支持,所以这些都是国内的游戏发展阶段和海外游戏发展状态之间的差异造成的,对游戏原生化会有比较多不同的诉求。

基于这一个点开始考虑,既然国内的游戏发展状态和海外有差异,Agones 又不能够直接很好的在国内的场景之下去落地,有没有什么方式能够让国内的开发者更好地去使用原生化的能力去解决现在阶段的问题,实际上是最关心和最希望去解决的一个点,云能够给各种行业带来很多不同增值的能力,比如游戏行业里很多时候,需要类似一些高性能网络的方案,无论是直连的方案还是网关的方案,云都有对应的产品或者是对应的能力来支撑,但它业务层比如 PVP 场景之下需要有太阳伸缩,可能需要有深度的可视化和智能的运维,对于一些全球化的游戏可能会涉及到多地域的发布,有就近接入的一些场景,很多的云厂商也都有相关功能的支撑,数据层很多游戏面临的场景,扩容的时候怎样保证玩家数据在激增的情况之下,DB 层可以在不修改价格的情况之下,能够实现一个水平的扩展,对于一些有 breakchange 场景的发布怎样做到快速数据层的回滚,然后怎么能够做到更高效的写入和读取,这些都是很多云服务数据库和开源数据库的解决方案之间声称的自己所具备高级的 feature,与此同时云上可能还有大量的中间件。

可能还会有安全的东西,表面上来看这些逻辑都能够给游戏行业带来很大的助力,但是为什么在实际上看到的情况是,国内大部分的游戏公司都没有把自己的玩家服放在云原生的 K8S 之上,基本上 K8S 的都是所谓的平台,这个现象非常奇怪,然后去深度探究里边的一些原因发现,缺了非常重要的是负载,k8s 里边有大量的负载抽象,不论是内置的抽象,还是外边 CRD 类型,针对不同类型的业务都会有一个类似工作负载的抽象,工作负载的抽象重要程度像是一个枢纽,枢纽的作用点比如需要网络实际上网络和客户业务之间的对接,需要负载,比如需要弹性能力,弹性扩缩容扩的是负载,比如需要去做全地域的就近发布,需要去找到地域哪个业务能够去就近接入,实际上需要和负载一层打交道,更多的像中间件,中间件一层表面上看可能和负载没有太多的关系,实际上特别是在游戏场景很多时候 DB 也是跟着业务走,会涉及到有很多大量配置的功能,比如 PVE 的 server 的数据库是谁,有很多配管逻辑,配管逻辑做自动化处理、自动化配置管理起来非常复杂,容易出现需要手动运维的场景,核心缺少的是负载一层功能,要解决怎样面对当前场景来去解决负载的问题,负载问题实际上是 OpenKruiseGame 解决比较典型的一些场景,这一点会涉及到 OpenKruiseGame 要解决的问题是什么,游戏发布的时候怎么去做热更新,怎么去做配置的重载,怎么去做定向定序的更新发布策略,向上去跟网络接入,比如在游戏场景之下网络直连 IP 端口不变,这些也都是在负载一层去做支撑,游戏场景之下还有比较多的批量运维和定向运维的场景,批量运维比较适合的是 PVP 类型的游戏,因为 PVP 类型的游戏一般管很多个 gameserver 是统一的批量管理,而 PVE 场景很多时候定向的管理一个曲阜段,一个分区的 PVE 的 server,定向管理,所以在游戏运维场景之下也有很多的操作和负载相关。

弹性伸缩非常直接无论是横向的伸缩还是定时的伸缩,无论是资源层 ECS 的伸缩或者 ECI 的伸缩都和负载是强相关的,游戏场景下要去做成本控制,k8s很多时候宣称的都是做一些降本增效,在游戏下怎样通过 k8s 节约整个游戏公司的成本,实际上也是需要在负载层去做适配和介入的,在多元混合云场景之下,是一致性发布的场景,K8S里面可以通过 yarm 去标准化一些游戏服统一发布的模板,可以实现快速多地联动的滚动画布,可以实现在多地域快速的开服,可以实现多地域多版本的规度,这些都是在负载一层需要去做适配的一个部分。

 

二、云原生助力游戏行业“高质量”发展

针对 OpenKruiseGame 里边要解决的这些问题做一个详细的拆解,来看一下解决问题的一个思路和大概解决问题的一个方法。

1、云原生助力游戏行业“高质量”发展

游戏平台:

平台服游戏支撑服务

玩家服承载玩家对战

服务网关多端统一入口

仿真测试多机型自动化模拟

数据分析 Al/数据化运营

监控运维服务质量巡检

Kubernetes:

计算资源弹性供给

存储存储灵活扩容

网络可编程无损直连

安全海量流量防护

交付统一交付模型

运维一致性运维方式

image.png

这张图基本上是大部分游戏公司目前的状态,特别是国内游戏公司的状态,把除玩家服之外的业务,基本上都已经搬到 k8s 之上,但是玩家服真正承载玩家之间的对战的部分业务,目前大部分还都是在ecs 之上,这个是目前的游戏行业,特别是国内游戏行业的一个现状。

2、Kubernetes 默认负载vs游戏玩家服-设计理念的差异

image.png

在内置的 K8S 负载和游戏行业想要玩家的服所需要具备的能力之间的一些差异。可以分成三个大的类型,分别是生命周期管理、业务变更管理和业务运维管理。生命周期管理是一个游戏服的生命周期,就是一个 pod 的生命周期,比如以前的时候发布,更新都是对生命周期做了一些变更,游戏场景之下目前国内的游戏行业,通常情况下都使用可重启的或者使用热承载方式做一个业务的表格,K8S 标准的业务是通过重建的方式去做实现,所以这是第一个大的差异。

第二个差异是 k8s 里边针对一些故障或者针对一些异常的处理方式,是通过删除重建或者是通过驱逐等等有损的方式去实现的,因为 k8s会认为上次有一个控制器控制,损失一个 pod 实际上是很正常的一个状态,然后只需要 pod 后续拉起就可以。但是游戏场景之下很特殊,游戏场景之下很多时候遇到一些故障、遇到一些异常的时候可能需要通过隔离的方法去做,比如有一个 gameserver 出现了一些被攻击或者是有一个 gameserver 出现了一些玩家数据的异常,不能做的事情是不能够直接把 pod 删了或者是直接把 pod 调走,可能会先摘掉网络去做热修复或者针对数据做一些热更新,挂一个公告,完整的提出了之后再去拉起来,所以这个地方有很多大量的手动故障处理的策略,而手动故障处理策略是 k8s 里面最不擅长或者是 k8s 理念有冲突的一个点。K8s 里边有很多网络的策略,不论比较了解 flash 的网络方案还是 chemical 的网络方案,但是 k8s 的网络设计比较典型的一个设计理念是网络的信息是跟着 pod 走的,也就是说 pod 重建相当于网络的信息需要 refresh ,需要去做重新的更新,但是对于一些 pve 图或者强制链类型的 pvp 图,这种网络电动是不可接受的,因为一般情况下比如 pve 服会有很多上下游的依赖,不论是端的依赖,还是类似一些内部系统的回调勾子依赖,都会对 IP 和端口的固定有强诉求,但是 k8s 里面对于接入层 IP 端口不变的能力做的比较弱,比如可以通过 service 的方式去抽象,但实际上 service 模型对于游戏场景是比较不友好的,因为比如内置提供的 service,比如 IP 方式的 service 或者 load balance 的service 或者 Engrise 网关类型的 service,面向游戏场景都只能去解决一小部分的问题,比如 slb 承载玩家服每个接口的 IP,可以但实际上对于很多游戏来讲是非常浪费的,因为每一个 SLB 是独立计费的,但是很多时候游戏 pve 服的基本策略是需要能够做到一个更节省的逻辑。如果每一个都是一个独立 IP,很多是承载不了费用的话费。

比如通过一个 Engrise 网关做这个事表面上可以,因为 Engrise 网关能够做到统一接入的能力,但是很多游戏公司再去做接入网关的时候,一般会和匹配框架去做整合,比如玩家来的进入统一网关,统一网关里面需要根据玩家信息,去做一些一致性 harsh 或者基于玩家和玩家服务之间的匹配策略,把它转向定向的玩家,会有大量所谓的权限体系或者是认证体系的介入,想在 Engrise 上面去做一个接入层的适配或者接入层插件的支持是非常困难的,而且很多时候也需要可能是一个四层的网关,也不是 Engrise 擅长的一个策略。在业务变更层比如发布的方式,可能有一些游戏特别是 C++ 或csharp 游戏,可能会通过动态链接库的方式来实现游戏的更新,或者是一个传统的二层架构的游戏把引擎测回法测切开了,可能只需要去更新一些配置文件,或者是更新一下 parsh 或者 word 脚本就能够实现游戏的热更新,没必要去通过主键去断连,而且很多游戏的引擎自带了一个规划保持,在游戏更新的过程中,可以保证玩家都可以在不敢去任何网络中断的情况之下就能够实现热更新,这个地方和具体游戏引擎的实现有关系,有一些客户场景之下能力做比较完善的,实际上是有一体内测直接教它,所以能够做到热更新。

这个地方kiss by kiss 可以来去做一些处理。更新顺序比如 PVP 类型的游戏,为什么需要顺序更新或者顺序的下线,因为 PVP 游戏一般情况下生命周期或者是玩家在游戏里面的生命周期,是短于玩家服的周期,玩家服可能一天、五天甚至十天才更新一次,是玩家服生命周期的一个变化,但实际上对于一个玩家来讲,打一局吃鸡、王者荣耀可能只需要20分钟、30分钟,甚至最长两个小时,所以从玩家体验的角度来讲,在一局对战或者是一个房间里的生命周期是远远小于玩家服的,在一级对阵之内只需要让玩家和玩家服绑定就可以,下一局对战可以分配到其他的玩家服之上对,从这个角度来讲很多时候游戏公司里的匹配框架会做一个事情,会根据游戏当前在线的人数,或者是当前在线人数的水位来判断此时应该向哪个 PVP 服务去调玩家,不是一个水平 Robin 的方式去调,而是通过定向的调度给游戏的客户端应该去见哪个 PVP 的服,好处有点像在大数据场景之下去做的 bintig,现在有十个 PVP 服,但是玩家如果按照容量来讲,能承载 1000 个玩家,如果已经是游戏的低谷期,可能有100个玩家,但在100个玩家场景之下,没必要去保留十个 PVP服,让一些 PVP 数据下线最合理或者最理想的情况是把 PVP 服饿死,饿死是上面有玩家在执行的房间,或者是有玩家在进行对战让它执行完,但是新玩家不像 PVP 服去做调度,这就是所谓的 boss 的 PVP 服,很多游戏公司里面其实已经在做类似的事情,在匹配框架内层去感知每一个 PVP 服活跃玩家的数目,再根据数目去做一些倾向性的调度,当玩家比较多的时候增加调度,当买家数比较少的时候压缩调度,压缩的结果是可以实现一些玩家服务的缩容,以前的时候做缩容很多游戏公司并没有去做扩缩容的逻辑,只是保留资源,但实际上保留资源的动作把整个玩家服成本压缩膨胀的比较高。目前在国内做的比较好的一些游戏公司实际上的做法是,玩家数少的时侯做一个 bintig 新的玩家上来哪个玩家多不会往哪个上去调,饿死一些 PVP 的 gameserver,它实际上是通过定向缩容的方式来去把 PVP 的 server 缩掉,在下线产品之下需要具备定向缩容的功能,是 PVP 场景之下非常典型的一个例子。通过这种如果能再配合一下自动伸缩结合起来,节省30%或者50%以上非常容易,特别对于共差别比较大。

变更的时候需要优先级的逻辑,比如有一个客户的 PVE 的服分配表面上来看,最直观的理解来讲一个 PVE 服抽象成一个 pod 就好,PVE 可能有100个服,就抽象成100个 pod,实际上真实的业务场景之下这种非常困难,因为每一个 PVE 服的容量也会有所不同,甚至有的时候比如表面上来看上层一个 PVE服,假如拿标号一来介绍PVE,实际上是业务上的 PVE1 玩家服的逻辑,底下可能承载的并不是一个 pod 去做,可能是多个 pod 去做,有的时候玩家可能异常活跃或者转服的时候,还需要对 PVE1 服做扩容。这个时候非常难受的一个点是如果按照 K8S 的标准抽象逻辑,可能就需要在 PVE层去抽象成一个负载,比如用 sight 每一个 PVE 服就是一个 sight,一个游戏里面像三国志战略版有上千个服装,就有上千的 sight 在管理是非常困难的。其实也是 K8S 里边的一些内置负载和游戏场景之下匹配的典型问题。

 

三、云原生游戏负载 OpenKruiseGame

1、玩家服

image.png

开放式、可扩展的面向游戏玩家服的开源云原生游戏负载

抽象成了生命周期管理,业务变更管理,业务运维管理三个方向。解决问题核心是三个点,在设计 OpenKruiseGame 之前只是想做一个 club meeting gameserver 的一个实现,没有想和社区有什么关系或者有什么联合的想法,但是在和国内头部游戏公司沟通了解的过程中,发现有些游戏公司已经把玩家跑在 k8s 之上。K8s 负载和游戏场景之下有很多的不一致,怎么去拷、怎么去解决像热更新,怎么解决 belief的管理,实际上得到的结果是通过 OpenKruise 做二次开发或者是封装的实现,OpenKruise 是阿里提供的一个针对于 k8s 中负载能力的一些缺陷做了一个增强型的负载,k8s 里面有 hipment,OpenKruise 有 crosset 负载是针对 dcomment 的一个拓展,k8s 里面有 stilset,OpenKruise 里面有Advanced StatefulSet 去针对于 Gameset 场景去做一些扩展支持。实OpenKruise 际上就是一个增强的 k8s 里负载的一个项目,能够去针对不同的场景,来去获得更多的针对于不同领域特定一些 feature 的实现。游戏场景比较典型的热更新 OpenKruise 里面提供热更新的能力。简单的来讲实现的原理就是 k8s 里边的一个 pod 里边有多个 container。逐渐 pod 实际上多个都重建,但是 k8s 里面有一种能力可以做到一个 pod 不重建,只重启其中的一个 Container,其实就是OpenKruise 来实现热更新一个比较典型的方式,比如一些 c++,C sharp 的游戏,可以把引擎放在一个 container,玩法策略更新的时候已经措施没有感觉到任何的变化,但还是保留接入层一系列的信息,还是保留现在处在一个平台,配置的变更或者玩法侧的变更,对于的玩法来看只是一个配置文件热充带,可以实现一些热更新。更新的顺序,指定下线的策略还有一些运维的动作,这些 OpenKruise 有的理论知识其实没有,这个地方是去问游戏公司的第二个问题,实际上得到的答案很多同步的游戏公司把 OpenKruise 作为一个原则性的负载做承载,实际上还有大量的二次开发也是在它的运维平台和在内部的工具来去做实现,所以简单来讲就是大的游戏公司有能力,能够基于社区里面的一些解决方案进行二次定制和二次开发来实现游戏原生化,而是小型一些的游戏公司或者对 k8s 不太熟悉的游戏公司,想要去完成类似的一个实现,或者是通过类似的策略去做定制就非常困难。怎么能够让那些对 k8s 不是特别熟的游戏客户也能够使用 OpenKruise,或者大公司里面对于游戏原生化里边的一些通用场景定制,是否有方式能够标准化之后再交付给开发者,来减少大家对于游戏负载管理上面的定制,或者是游戏负载场景之下的二次开发的工作。去做 OpenKruise 的一个初衷,OpenKruise 能解的是玩家服生命周期管理的问题。在其之上类似定向的更新,定向的下线,然后业务运维其实都是认为的 management 部分。Management 部分是玩家服业务管理和业务运维管理,更像是一个运维动作,是 OpenKruiseGame 在 OpenKruise 上叠加的这一层,这一层加上玩家就是 OpenKruiseGame。OpenKruiseGame 只做两个事,一个事是把游戏原生化的负载能够在 k8s 里面找对应的 CRD 来承载,承载用  OpenKruiseGam。第二个把常见的一些游戏运维动作翻译成原生的一些接口,翻译成原生的一些字段,然后加在 OpenKruiseGame 负载之上,能够减少二次开发的工作,来实现一个游戏原生化比较简单的一个过程。所以这个是做的 OpenKruiseGame 的初衷和一个实现的方式。总结起来 OpenKruiseGame 是一个开放式可扩展的面向游戏玩家服务的开源云原生游戏负载。

2、云原生游戏负载 OpenKruiseGame -规约与抽象玩家服的因素

image.png

做负载要想清楚的是要解决的有哪些游戏服的问题,因为游戏行业游戏类型非常多,比如从题材上来划分有动作类、有竞速类各种各样的类型,但是这些类型和要抽象的玩家服之间有什么关系呢,是要抽象成比如一个竞速类型的 gameserver、一个动作类型的 gameserver 这样来去划分要吸到力度是抽象的,要抽象成什么样的一个负载要在负载上能够适配哪些场景,其实游戏里面最根本的一个差异,最根本要考虑的地方是在于负载对于基础设施上面相互感知的问题,比如 pvp 服是一个短生命周期的一个业务场景,pvp 服很多时候需要网络质量,PVP 服一般情况下玩家之间配置没有差异。变相来讲一个玩家服务对于基础设施的要求,对网络有要求,对弹性有要求,对设备管理要求,这些是不同的游戏类型对于基础设施的要求,按照玩家所对于基础设施的要求,将所有的游戏分成三个类型,分别是 PVP 类型,PVE 类型和 others 类型。PVP 类型玩得最多像吃鸡,王者荣耀都属于 PVP 类型,里面的一般情况下对战属性比较强,然后大家玩的生命周期短一点,十几分钟,二十分钟,半个小时。PVE 服一般是大世界类型的游戏,比如魔兽世界,三国志战略版都属于PVE 类型的游戏,是比较大型游戏的一个特点是一个玩家和特定的 PVE  服之间是一个长周期的绑定关系,只要 PVE 和服不和服或者PVE 服不去做下线,一般情况下玩家和服之间是一个强绑定关系,然后 PVE 服有的时候发布也不是一个批量关系逻辑,也是根据区段或者根据特定的服通过公告,然后再去做停服然后再去做更新,所以这些都是对于基础设施的要求然后进行。

最后一个类型 others,是很多简单类型游戏像一些卡牌、回合对战然、微信小游戏,这些游戏用 k8s 标准的 sight、depoint 就能承载,没有太多的网络要求、没有太多的业务要求,更多的是一个 api 一样或者是一个网站一样,

业务其实也属于这种类型的,唯一需要做的可能是 ui 下陷,需要通过适配 k8s 里的 presstop 一些接口的实践下线,可以实现容器化,对于云原生游戏在游戏元生化三个大的类型的一个分类。

3、云原生游戏负载 OpenKruiseGame-Top10 游戏模型验证

image.png

Top10 的游戏列表,40%左右游戏是 PVP 类型,40% 是 PVE 的,还有一些是单机的,不一定完全准确,因为很多游戏里面既包含 PVP 属性也包含 PVE 属性,划分是根据游戏里面主的场景来去划分的。

4、云原生游戏负载 OpenKruiseGame-设计理念

业务运维管理 EphemeralOpsJob(任务式运维方式支持、自动化运维体系集成与接入 )→EphemeralOpsPod(Shared NS故障诊断、高权限运维脚本/动作、交互式运维方式支持)→

生命周期管理 Pod→GameServer(支持版本控制的业务热更新/配置热重载、停服/维护/隔离等多种玩家服状态管理、多级服务质量与自动化运维能力支持)

业务变更管理  GameServerSet→ Advanced StatefulSet→Pod

GameServerSet→GameServer(批量变更/运维生命周期管理、  

变更顺序控制与手动合服管理、弹性伸缩与优雅下线支持)

image.png

抽象玩家服,解决问题分成两大块,一个大块是生命周期管理,一个大块是Game management。生命周期管理很多的大型游戏公司是通过 OpenKruise 里面的负载来实现的,通常情况下使用的负载叫  Advanced StatefulSet,游戏里边很多时候需要有原地更新,需要有 podname 不变,需要能够去做到热更新热重启,需要能够去做到一些定向的隔离或者定向的下线,在 Advanced StatefulSet 层也就是生命周期管理一层都具备,也是 OpenKruiseGame 一个底层的依赖或者是一个底层的实现,在 OpenKruise 上面增加了 game management 一层,实际上是这一层所谓的GameServer 承载的部分,开发者去下发一个比如 Eph 的时候 gameserverset 会自动生成 Advanced StatefulSet,然后 Advanced StatefulSet 会生成 Pod,每一个 Pod 上会增加一个 shame 层,会增加一个薄薄一层的接口层,接口层实际上就是一个独立的 crd 叫 gameserver。比如现在有十个 PVP 服的一个游戏要上线,在 gameserverset 里面定义一个十个 rapbka 的 PVP 服,会生成一个Advanced StatefulSet,会生成十个 pod,同时会生成十个 gameserver,每一个 pod 会对应其中的一个 gameserver,如果想去批量操作只需要在 gameserverset 的一层来做一些变更,比如镜像的变更,默认版本的变更,全地域的发布,扩容,缩容,隔离特定的服务都可以在 gameserverset 做,但是当想要去对特定的一个服务做处理的时候,类似要去变更特定的一个服网络的情况,变更特定的一个服的服务状态从运行中变成维护中,要去针对于特定的服做一些上线,下线,去针对特定的一个服来去做一些和服处理,都可以通过定向 gameserver 一层来做。批量操作在 gameserverset 层去做的适配,定向操作在 gameserver 层做支持,所以两者结合起来分别解决了游戏场景之下的批量操作、定向操作两个核心场景。游戏曾经比较特殊的是会有比较多的运维动作,传统的时候运维动作可能是通过 sosthat 或者 isabe 的方式去做,两种方式都会或多或少有一些隐患,隐患有一些可能是安全方向、有一些可能是由于管理方向或者是一些一致性的问题,ack 是抽象的独立 CRD 叫 EphemeralOpsJob 和 EphemeralOpsPod,简单理解就是一个运维动作的发起方,比现在有一个 pve 的服出现了一些故障,对它做处理的时候传统模型要登到这台主机上去做一些自动化脚本的执行,然后可能会 db 的数据,可能去备份,可能会去做一些相应的故障处理,但是这些逻辑在容器里面可以通过 OpsJob、OpsPod 来自动化的实现对应的逻辑,基础能力比较强的客户可以变成一个像 Ops 一样,当收到一条报警,可以自动去下载一个 OpsJob 去自动执行一些运维的动作和运维管理,也是很多开发者可以去做二次开发比较空间大的地方。

5、云原生游戏负载 OpenKruiseGame-整体架构

image.png

是 OpenKruiseGame 整体的一个架构,分成几个大的部分,实际上是在集群内的一个 OpenKruise 和 OpenKruiseGame 大概的一个原理图,安装 OpenKruiseGame 需要安装两个组件,一个是 OpenKruise 青色的部分,是一个harmchard, OpenKruiseGame 也是一个 harmchard,装完了之后可以使用 GameServerSet,然后 StatefulSet 就带好了可以直接用。左侧有一个 club provider的字段,现在的游戏公司在上云的过程中的一个痛点,因为接触到的大部分的游戏客户都是有多地域开服的,可能有国内的地域,有国外的地域,国外的地域很多客户会选择 adbance 或者是 GCP 来去承载业务,它有很大的策略是在使用一种多余的架构来去适配游戏的场景,在游戏里面和云相关最紧密的场景一般是和网络相关,比如 ACK提供网络的方案,但是在海外可能有类似的网络实践方案,但是它实现的网络之间的方案和 ACK 里面实现网络的方案可能大概率是不同的。ACK 是通过 education 上面去打一些标识,然后让 pod 自动就能够具备一个 delight 的策略,但是如果是在 GDP 上,可能是通过绑定 IP 的方式实现对应的质点,带来一个问题是不同的云对于一些基础设施的处理方式是有差异的,对于一个游戏想要做到多云之间的统一管理或者是多云之上跨地域的一致性策略,需要考虑一个点怎么去适配之间的差异,cloud provider 是填品不同云上差异的一个点。API Server 和 API Service,API Service 非常简单是一个集群内管理 gameserver 的一个 API,用 API 层,gameserverset 层是批量管理,变更一些业务逻辑去更新 OVP 服的时候都是批量管理,gameserver 层是定向管理,什么东西是介于批量管理和定向管理之间,比如 PVE 的一个架构,比如是 PVE 1服,PVE 2 服里面的玩家数不同,PVE1 服可以由3个 pod 承载,PVE 2 服可以有两个 pod 承载,从版本的管理的角度来讲,PVE1 服和 PV2 服都是相同的镜像,传统的 k8s 里面的业务逻辑处理实际上必须要把 PVE1 服和二服分成两个负载去管理,对于很多游戏公司负担非常大,云上有上千 PVE1 服,不可能有上千个 serverset 来统一管理。现在有了 OpenKruiseGame 之后可以通过一个 game center 去管两个 PVE1 服,还需要去对 PVE1 服或者二服去做一些定向操作,这个地方就是在同一个负载之下特定的一组 pod 怎么去做一个区域性管理问题,区域性管理的问题实际上在 k8s 里面是没有太好的逻辑可以去抽象,或者是去做相应的管理,而这块是 API 可以去做支持的,PVE1 服现在是三个 pod,PVE2 服是两个 pod,如果 PVE2 服玩家数增加想去扩容一个 PVE2 服,表面上是给 gameserverset 做一个扩容操作,从五个副本升到六个副本,必须要让新生成的 pod 知道是属于 PVE2 服的而不是 PVE3 服或者PVE1 服,绑定关系生效实际上是通过在 API 层,去向 pod 上面动态的去注入一些标签,然后来形成一个独行信息来实现逻辑,在游戏场景之下比较特殊,但是在负载层又不太好去解决的一个地方。这种的逻辑目前都是放在 API 层做实现上。有一些客户对于 K8S 的了解不是很深,在场景之下想去用 OpenKruiseGame,可以通过 Dashboard 使用,做一个 UI 的可视化管理方式实现游戏的原生化过程,是整个 openkruisegame 完整的一个架构和大概的一个形态。

6、云原生游戏负载 OpenKruiseGame-IP 端口固定(ACK)

image.png

OpenKruiseGame 提供的一些核心能力,最重要的一个能力是网络层,像 PVP 服有很多的网络直连的要求,介绍 ACK 对于网络直连的支持策略是怎么做的,图里面画的是 PVE 服务的一个案例,每一个 PVE 服都有内部的构造和外部直达的需求,内部的构造比如几天之内可能会有一些汇金,可能有一些注册充值的服务,需要能够拿到 PVE 服务的回调地址都是内部东西,内部东西有的时候可能连健全都不做,所以有一些特殊的公司可能健全都没有,所以这块必须要通过一些内部的 IP 来去识别 IP 云端客户。但是对于外部的访问需要一个工行的 IP 和端口的固定,本质上在游戏场景之下接入层的地址不变是两个逻辑,一个是内部的端口怎么去做不变,一个是外部的 IP 端口怎么不变,实际上要依赖于 AVK 里边的一个网络插件,网络插件里面能做的事情只要 gameserver 名字不变就能做到,无论是在这个节点上启动,还是在另一个节点启动,都可以保证对应的 IP 是固定不变的。实践方式是像 flash 的网络方式,实际上是一个抽象适宜的二层的网络实现,它里面其实没有所谓真实的物理设备去承载网卡,tev 网络模型有真实的网卡,网卡是分配在交换机上,比如今天玩家不是在这个点上,明天这个玩家可能由于一些故障,或者是由于进入服之后再去更新重掉度这个点上,IP 端口变化实际上界面和交换机上面分配出来的网卡会做一个重新的绑定,来保证内部的 IP 端口不变。外部的端口不变是通过 nat 网关做的,nat 网关入网的时候可以用第二个柜子,出网的时候可以 nat 的柜子,实际上已经做到一个动态绑定的逻辑。在你的 gameserver 上面只需要去声明当前需要使用 nat 网关 IP 固定的能力就可以,然后nat 网关会自动根据 pod 端口的情况,在nat 网关上分配出两条路,由规则分别是 denied 的指导规则和 adnat 的回报规则的方式就可以做到,一个战斗服此时就会继承上边一个阶层的信息,以后外部的访问就直接通过供网 IP 端口就可以直达,内部比如不同专家之间的互访,或者是一些会接口去访问战斗服,直接用分类在交换机上的 IP 端口直接能够生效,所以这个是 IP 端口固定的一种实现,不同的云上有不同网络实现的方案,Openkruisegame 适配或者识别差异是因为 Openkruisegame 里边的定义了一套网络的接口,通过特定的一些字段声明需要的参数,比如在 stat 里面生成了一个 network 的资料,但是 network 具体由谁实现际上是由 cloud provider 上报, 由 cloud provider 执行,当 cloud provider 里面生成比如阿里云生成的 dnet 或者 understad 规则之后,会在 gameserverset 里面上报一个接入端口的地址,然后再用端口的地址去交给前面的 PV框架或者端上面的负载均衡器,再由它去真实的访问从而来实现 IP和端口固定的操作。

7、云原生游戏负载 OpenKruiseGame-游戏热更新/配置热重载

脚本层

引擎层        配置层

守护进程管理器

apiVersion:v1

kind:Pod

metadata:

name:pod-8

uid:xxx spec:

containers:

-name:app

image:app:v1

-name: sidecar

image:sidecar:v1

nodeNane:node1

status:

podiP:192.168.0.50

Update to appv2

ReCreate Update(Pod delete and create)

apiversion:v1

kind: Pod

metadata:

Name:pod-b

Uid:yyy

spec:

containers:

-name:app

image:app:v2

-name: sidecar

image: sidecariv1

nodeName:node2

status:

podiP:192.168.0.55

InPlace Update(Modify the same Pod)

apiversion:v1

kind:Pod

netadata:

nane:pod-a

uid:XXX

Spec:

containers:

-nane:app

image:app:v2

- name: sidecar

image:sidecar:v1

nodeName:nodel

status:

podIP:192.168.0.50

通过 Sidecar 实现动态链接库的热更新,通过动态存储的方式支持信号量的进程重载

image.png

左边图是很多传统一点的游戏公司会实现的一个架构,分成四个部分分别是脚本层、引擎层、配置层和守护进程管理器,大概的逻辑是以前的时候有一些客户是通过 c++ 或者 cshap 写了一个gameserver 的引擎,然后上层通过 python 或者 lower 写了一些对战的脚本,然后通过配置文件来去声明自己的 PVP 服或者 PVE服的一个策略,有的时候比如挂公告或者去做一些丰富和服是去改的配置,有的时候更新一些玩法,比如更新一个战法或者是更新一个形象都是属于脚本在做的事情,以前的逻辑一般是通过推广工具直接就从 OSS 或者是从 dit 上拉下来,然后再给进程管理器发一个信号量去做一个 vstar,有一些引擎可能比较强自己就去监听变化,然后自己就继承热重载,不管怎么做基本上这几层的分配是大部分目前国内的游戏比较常见的架构和体系,怎样放在 openkruise 里面去适配,怎样在 openkruise 里面实现一个热更新,通过 openkruisegame 实现非常简单,只需要去做一个改造就可以。

Sidecar

脚本层

oss

引擎层        Container Volume配置层

守护进程管理器

image.png

可以把游戏的玩法策略或者游戏的脚本层单独成一个 second container,把配置文件可以放在 OSS 里,然后把引擎侧或者守护进程器放在一个 container 里,然后总的地方是特定的一个 pod,里面也包含了 container 和 sidecar,在 openkruise 里面可以做的是比如脚本侧是下面 sidecar v1,可以做到直接去更改 sidecar v1 变成 sidecar v2,可以自动的去重启上面的 pod 去更新,而此时不影响以前热承载底下的守护进程管理器,游戏场景之下的玩法层的热更新,同样如果是配置层热度器的时候,需要做的事情是可以把配置文件放在 OSS 上,OSS 的地方会自动把对应的配置文件转换成一个对应 pon 侧 fs 的一个挂载,有了挂载之后能做的事情是 OSS 里面只要一个对应的容器内特定的目录下的文件就能够实现一个变化,从而就可以实现配置上面的一个热更新,在游戏场景之下的热更新。

8、云原生游戏负载 OpenKruiseGame-PVP 玩家服自动伸缩

伸缩指标类型

image.png

自动伸缩里面要考虑的核心很多,比如什么时候或者要依赖于什么因素来去做热更新,也就是伸缩的指标类型主要有哪些;第二个是伸缩的方式是什么样的,有可能是做横向的伸缩,也可能是做根据一些事件来去做一些批注的绳索,也可能是根据时间来做一些预判,这些都有可能,同样做完之后会到一个问题是承载生存资源是什么,有可能是 ECS,也可能是 ECI,就是弹性的资源供给。缩的时候涉及到一个问题是应该先缩谁,后缩谁,怎么去确认服能缩,哪个服不能缩,这些都是在游戏场景之下去做弹性伸缩非常重要的一些点,OpenKruiseGame 解决这个问题首先 OpenKruiseGame 在生指标这边只是四类指标,分别是资源指标,性能指标,业务指标,事件类型的指标,最好理解或者是最常见的一个是根据玩家数在 PVP 服一般每一个服都会有一个,比如房间数或者是容量上限的概念,可以基于比如每个服上限100个玩家,可以把玩家的数目作为一个申诉的指标,然后每100个玩家生成一个 pod,然后可以做到一些预扩容,比如可以弄余两百个玩家的容量,因为扩缩容有时间的要求,在补充过程中还有新玩家用户是可以实现的,但是可以通过比如玩家数和 pod 之间的一个关系,然后声明到底需要多少 pod 来实现,这是伸缩指标。业务层两个场景,第一个场景是无论通过什么指标来做都是水平伸缩,或者是事件伸缩,有一些伸缩由业务驱动,涉及到的问题是业务驱动的场景怎么去介入到自动伸缩的空间里面去,提供一个事件驱动伸缩器,可以去对接客户自己的 API,比如不想用伸缩的逻辑,就想自己控制多少副本,可以非常简单地提供一个 API 声明大概需要几个副本,事件伸缩器就可以做监听直接给库存 pod,然后再根据提供的每一个 pod 上面每个 gameserver 状态来确认优先做哪个后做哪个。有的时候有一些业务有明显的周期性,特别是 一些 mmo 类型的游戏是一种非常典型的勾股。当波峰到来的时候临时去准备业务的弹性资源有一点滞后,甚至有的时候可能会出现一些异常,这个时候一些定时的策略对大家来讲是非常有帮助的,同样 HPA 定时做这个策略,还可以和 HPA 和事件伸缩器 keda 做一个相应的整合,可以在定时的时候用 HPA,同样也可以保留针对于峰值负载到来的时候的资度适存,它们两个是可以有机地融合在一起实现。在缩容的时候怎样控制它的顺序或者怎样去指定哪一个 gameserver 应该优先的被回收,或者是优先的被释放。在 gameserver 上面定义了一个叫 updatepriority 和 deletepriority 两个概念,两个概念能做的事情是当出现特定的一些玩家所需要的优先更新,或者特定的一些玩家不需要被优先删除的时候,可以去手动去设置 gameserver 的权重,权重高的 gameserver 优先删除或者更新,权重低的优先保留。在底层的时候也会有一些状态的因素去介入到考量。台机有两种资源的供给策略分别是 ECS 和 ECI 是阿里云提供的,ECS 能够做到千节点分钟级供给,ECI 大约能做到十秒钟上千 POD 交付,是云厂商提供,每个云都有类似的功能,对于 gameserver 一层是500,gameserver 只是生成 pod,底层怎么去承担要和特定的云营商确认整体的方案和策略。

9、云原生游戏负载 OpenKruiseGame-PVE 玩家服分区/合服

image.png

定向管理的策略,定向管理最典型的一个 case 就是 PVE 的合服、分服,以前的时候合服、分服,一般情况下确认一些 gameserver 要去合服 或者是一些 gameserver 要去下线,需要先挂公告,然后去做一系列网络设施的变更,然后再去把对应的上层的游戏服务做一个停机下线,然后再去回收上面的 VM 去做资源层的销毁,可能中间还会有 DB 上面的一些 gracious 或者订正,这些是传统的 PVE 和分服的一个动作,上了 K8S 之后 DB 的部分该怎么做还怎么做,每一个 gameserver 之上都可以有一个状态叫做 makeni,可以直接去打特定的几个 gameserver 设置成 makeni,可以声明玩家服可以处在一个维护中,维护中的玩家服可以做到网络的摘除,可以做到在伸缩扩容的时候优先隔离,可以做到和匹配框架的不调度玩家,和特定的匹配框架有关的,比如 openmach 有对接,如果客户有自己的框架也可以去感知 gameserver 状态来实现一个定向的gameserver 维护逻辑,两个服已经做好了数据 duration,做好了网络层的隔离之后直接去调整 gameserverset 的叫 resolvedtheid 的一个字段,然后把两个服的 IP 写上,自动缩回去,同时承载两个服的节点,如果开启自动伸缩之后,也可以自动缩回去,成本就非常低,而且自动化的成本包括和自己后台结合的这成本非常低。

10、云原生游戏负载 OpenKruiseGame-运维状态与多级服务质量

image.png

OpenKruiseGame 另外一个能力叫运维状态与多级服务质量,划分游戏类型的时候有一个概念,叫游戏玩家服和基础设施之间的相互感知问题,去抽象玩家服或者是定义上 game 里面有哪些的时候,很多时候在解决的一个问题是怎样让业务状态不要影响基础设施或者基础设施的状态变更之后怎么能够让业务层有一个更好的变化,在游戏场景下最特殊和最重要的,在这个地方抽象的一个逻辑是通过运维状态和座机服务质量做的,图片就是解释问题,因为在 k8s 里面一个负载的状态,比如 dpod 什么状态,pod 什么状态决定了很多事情,决定的事情包含弹性的动作,优先谈谁,优先去说谁,网络能不能接,发布应该先发谁,都是 K8S 里面根据负载的状态去做了一系列的自动化的控制,自动化的控制对于游戏场景来讲是非常不友好的,游戏场景之下不是基于负载的状态去做控制,而是应该基于业务的状态来控制业务状态。

业务状态是玩家服当前的状态,比如玩家服上面有多少玩家才能确定是否下线,而不是由于 pod 是否重启来确定下线,比如当前玩家服是否应该摘网络,不是由于朋友的状态是否应该摘网络,而是由于业务的状态是否应该摘网络,这个地方的负载状态影响自动化控制是不准确的,应该把业务状态也变成一个负载状态,然后能够让它去影响在 k8s 里面自己的控制,是通过 gameserver 层抽象来实现的,可以把很多的业务状态通过不论是手动的设置,还是自动化的设置打到顶层上,再有 gameserver 层去联动上层的自动化的控制和逻辑更新、自愈、弹性、扩容,来实现一个游戏业务到基础设施状态之间的处理。

GameServer

应用服务质量健康

应用服务空跑待下线

应用服务质量受损需诊断

应用服务质量受损需隔离

应用服务质量异常

GameServer  ⬅http/exec/script  ←kruise-daemon

Node

image.png

一个比较典型的 case 拿 PVP 玩家服的自动下线举例,调度系统可以做到的是针对玩家人多或者人少的时候,可以去饿死一些 gameserver,饿死 gameserver 之后怎么去判断 gameserver 是能够被释放,或者要怎么去判断应该删除哪个 pod,K8S 里的 HPH具备自动伸缩 pod 的能力,pod 上面的任何一个字段对 HPA 来讲都不知道 pod 里面的玩家有哪些,即便把玩家的数作为一个metrics 交给 HPA,但是 HPA 去选择特定的 pod 的时候也很迷惑,不知道到底是否哪个 pod 可以缩,解决问题的方法是有一个服务质量的概念,类似 K8S 里边的 regioness 或者 ligenessprobe,简单理解是提供一个接口,然后玩家服可以提供一个脚本,或者提供一个 API,Pro可以去掉这个接口或者调一个脚本,然后告诉有没有玩家,或者当前能不能下线,如果能下线上层的服务质量会自动在gameserver 上面打标一个字段说当前的玩家服已经没有活跃玩家,HPA 可以下线这个 gameserver,到 HPA 去缩容上层 gameserverset 的时候,gameserverset 会看到2当前有两个 game server,其中有一个 gameserver 的状态是 we do be delit 或者上面已经没有玩家,就优先去删除这个 gameserver,从而就可以实现一个自动化游戏业务的状态联动的一个机制,通过这种方式 openkruisegame 其实可以做的事情非常多,在设置服务质量的时候提供的是一个泛化的接口,是一个 custom 的接口,玩家可以基于这套逻辑来自己定义什么时候来自动提升删除的权重,更新的权重,服务的状态,网络摘不摘,都可以通过服务质量进行一个定制化。

11、云原生游戏负载 OpenKruiseGame-故障隔离与诊断

image.png

故障 pod 摘除网络【存储】、调用服务质量维护脚本

12、云原生游戏负载 OpenKruiseGame-玩家匹配服务

image.png

玩家的匹配服务,OpenKruiseGame 本身是不做 match service的,Match service 业界有一个非常流行的框架 open match, open match 和 against 框架去做整合,任何一个玩家进入到 game front 的时候,里边会去向 openmatch 做一个请求,match 会根据特定的 mactch function,一些玩家自己定义的匹配策略,返回后端的 gameserver,从而实现一个匹配的框架,匹配的框架在 match 里面也支持自动伸缩,对于一些想要通过 open match 自己定义匹配策略的玩家,或者是开发者。Openkruisegame 也支持和open match 的串联,可以减少自己的开发成本,来实现一个可伸缩的匹配框架,从而降低开发的成本,并且可以去付用社区的一些标准的方式。

相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
测试技术
功能性模型在架构设计中的应用
功能性模型在架构设计中的应用
|
4月前
|
敏捷开发 设计模式 前端开发
实践总结|前端架构设计的一点考究
本文总结了作者在日常/大促业务的“敏捷”开发过程中产生的疑惑,并尝试做出思考得到一些解决思路和方案。在前端开发和实践过程中,梳理了一些简单设计方案可以缓解当时 “头疼” 的几个敏捷迭代问题,并实践在项目迭代中。
|
7月前
|
设计模式 SQL Java
3-1大佬分享:字节跳动代码设计理念
3-1大佬分享:字节跳动代码设计理念
83 1
|
7月前
|
设计模式 开发框架 前端开发
实践总结|前端架构设计的一点考究(下)
作者将【DDD、六边形、洋葱、清洁、CQRS】进行深入学习并梳理总结的一个前端架构设计,并且经历一定应用实践的考验。
183 0
|
7月前
|
SQL 前端开发 JavaScript
实践总结|前端架构设计的一点考究(中)
本文总结了作者在日常/大促业务的“敏捷”开发过程中产生的疑惑,并尝试做出思考得到一些解决思路和方案。在前端开发和实践过程中,梳理了一些简单设计方案可以缓解当时 “头疼” 的几个敏捷迭代问题,并实践在项目迭代中。
98 0
|
7月前
|
敏捷开发 前端开发 JavaScript
实践总结|前端架构设计的一点考究(上)
本文总结了作者在日常/大促业务的“敏捷”开发过程中产生的疑惑,并尝试做出思考得到一些解决思路和方案。在前端开发和实践过程中,梳理了一些简单设计方案可以缓解当时 “头疼” 的几个敏捷迭代问题,并实践在项目迭代中。
146 0
|
数据采集 消息中间件 分布式计算
系统架构+技术选型+用例说明|学习笔记
快速学习系统架构+技术选型+用例说明
系统架构+技术选型+用例说明|学习笔记
|
敏捷开发 开发框架 中间件
「敏捷建模」敏捷设计理念的纪律
「敏捷建模」敏捷设计理念的纪律
|
Java 应用服务中间件
架构:第六章:系统架构
架构:第六章:系统架构
149 0
架构:第六章:系统架构
|
设计模式 弹性计算 运维