架构介绍
介绍
无锁异步化、事件驱动的架构设计;真轻量级,无需依赖任何第三方中间件就能搭建出一个分布式的网络通信服务器。
自带负载均衡、分布式支持、可动态增减机器。
| 名称 | 扩展方式 | 职责 |
|---|---|---|
| ExternalServer | 分布式 | 对外服的职责是与用户连接、交互 |
| LogicServer | 分布式 | 逻辑服的职责是处理具体业务逻辑 |
从架构简图中,我们知道了整体架构由对外服和逻辑服组成,两者既可相互独立,又可相互融合。
- 对外服和逻辑服,在一个进程中。(单体应用,在开发分布式时,调试更加方便)
- 对外服和逻辑服,在多个进程中。(分布式)
- 甚至可以不需要对外服只使用逻辑服,用于其他系统业务的内部通信。
因为 ionet 遵循面向对象的设计原则(单一职责原则、开闭原则、里式替换原则、依赖倒置原则、接口隔离原则、迪米特法则)等, 所以使得架构的职责分明,可以灵活的进行组合。
开发人员几乎都遇见过这么一种情况,在项目初期阶段,通常是以单体项目的方式进行开发,随着需求不断的增加与迭代,会演变成一个臃肿的项目。 此时在对一个整体进行拆分是困难的,成本是极高的。甚至是不可完成的,最后导致完全的重新重构。
ionet 提供了在结构组合上的部署多样性,通过组合的方式,在项目初期就可以避免这些拆分问题。 在开发阶段中,我们可以使用单体应用开发思维,降低了开发成本。 通过单体应用的开发方式,在开发分布式项目时,调试更加的方便。 这既能兼顾分布式开发、项目模块的拆分,又能降低团队的开发成本。
架构优点
架构有很高程度的抽象,可以让设计者更加关注于业务,而无需考虑底层的实现、通信参数等问题。
我们采用模块化、抽象化的架构,显著降低了各服务器间的耦合度。 逻辑服可以动态地增加、删除或修改,这极大地提升了系统的伸缩性与可维护性,使得动态扩展变得简单高效。 此外,逻辑服务器之间较低的耦合度也使得调试和测试工作更易于管理。
架构比较清晰的就是,对外服负责维护客户端的接入(用户、玩家的连接),逻辑服专心负责业务逻辑。 因为架构拆分的合理,所以特别方便用 k8s 来自由伸缩部署,哪个服水位高就扩容哪个,水位过去了又可以缩容。
同进程亲和性
同进程亲和性是框架的特性之一,可以让同一进程内的服务器之间拥有相互访问优先权。 当有请求需要处理时,会优先将请求交给同进程的逻辑服来处理。
- 比如在 P-1 进程中启动了 External-A-1,LogicServer-B-1
- 比如在 P-2 进程中启动了 External-A-2,LogicServer-B-2
当 External-A-1 需要请求 LogicServer-B 时,只会把请求优先交给 LogicServer-B-1 来处理,而不是 LogicServer-B-2。
部署简图
- pid : 表示在同一个进程内。
- External : 对外服。
- LogicServer : 逻辑服。
- CommonGameLogic : 是一些公用的逻辑服。
图中,我们启动了 3 个进程。
- pid:1111,启动了对外服、逻辑服[A-1、B-1]。
- pid:2222,启动了对外服、逻辑服[A-2、B-2]。
- pid:3333,启动了多个公共的逻辑服。
由于在同一个进程中,当 pic:1111 有 action 请求需要处理时,会优先交给 A-1 处理。 而一些跨服的公共业务,则会将请求交给 pic:3333 来处理。
合理利用同进程亲和性,可以让各服务器之间通过进程来做微隔离。
使用场景
开发者可以利用同进程亲和性的特点,按照上图中的部署方式,可以让各服务器之间通过进程来做微隔离。 此外,又能提供一些逻辑服来处理公共业务。 如一些跨服活动、跨服战...等,各种跨服业务。
如下类型的游戏,可以考虑使用该部署方式
- 滚服类型的游戏
- RTS(Real Time Strategy)实时战略游戏,例如星际争霸、红色警戒。
- MOBA(Multiplayer Online Battle Arena)多人在线竞技场游戏,例如英雄联盟、DOTA2。
- ARPG(Action Role-playing Game)动作角色扮演游戏,例如暗黑破坏神、无尽之剑。
- FPS(First-person Shooter)一人称射击游戏,例如使命召唤、绝地求生。
- TPS(Third-person Shooter)第三人称射击游戏,例如疾速前进、战地。
- ...
架构部署灵活
从为什么快这篇文档中我们知道了框架具备 IPC 机制,该机制可以让同一机器上不同进程间实现纳秒级通信。 这将意味着我们可以通过不同的组合调整,几乎可以适配任意游戏及场景。比如
- 同机器,不同进程之间的网络通信,会使用 IPC。
- 同进程,不同逻辑服实例之间的网络通信,会使用 IPC。
- 同局域网,不同机器之间的网络通信,会使用 UDP。
- 不同局域网之间的网络通信,会使用 UDP。
ionet 支持以上的几个场景,同时这也是覆盖了所有通信相关的场景了。
不同局域网之间的网络通信
在生产中几乎不会使用到不同局域网之间的网络通信,但在一些特殊的场景中会用到。 比如在疫情期间或大家集体远程办公时,几个服务端和前端工作在该模式下,可以很好的展开工作。
将对外服部署到云服务器上,而逻辑服在本地启动。 注意了,你并不需要将你负责的逻辑服部署到云端后,前端的哥们才能访问。 你可以使用本地启动的方式,将逻辑服连接到云端,这样前端就能访问你所编写的业务了。
在联调过程中,通常需要多次修改代码和重启服务器。 在这个过程中,你只需在本地修改与重启,重启逻辑服这个过程前端是不会断开连接的。 因此,在联调的过程中,前端哥们并不需要反复的登录,这样就避免了各种繁琐的操作(如:输入账号、密码等操作), 这个过程对前端来说完全是无感知的,这是一个极为优秀的开发体验。
ionet 可以快速地完成启动,通常仅需 0.x 秒即可完成。 在我们完成修改并启动过程时,前端哥们甚至来不及反应,就已经搞定了。
小结
从上面几个例子中我们可以看出,ionet 的架构是具备多样性的、可适应性的。 想要适应不同类型的游戏,可以通过调整部署方式就能支持任意类型的游戏,并且是简单的。
在使用框架开发业务时,你并不需要担心框架能不能做某种类型的游戏, 因为这可以通过部署方式来解决,从而适应任意类型的游戏。
如何选择
从上面的内容我们可以分析出,没有固定的一套最优解,只有结合项目自身需要的最优解。
如果你的某些逻辑服业务变化快,并且需要经常重启的, 那么单进程中这种方式并不适合你目前的业务,通常这种情况选择分开部署会比较好。
当你选择分开部署后,逻辑服的重启不会影响现有的在线玩家, 因为在线的玩家还会和对外服保持连接,所以这个过程是无感知的。 无感知对玩家有着极好的体验,我想你并不愿意玩一款时不时就断线的游戏吧。
所以,这里的结论是结合项目当前发展的情况来做调整。