你是否想要开发一个高性能、稳定、易用、自带负载均衡、避免类爆炸设计、可跨进程跨机器通信、有状态多进程的分布式的网络通信服务器呢? 如果是的话,这里向你推荐一个由 java 语言编写的分布式网络编程框架 ionet。
ionet 是一个开源的轻量级基于 Aeron 的分布式网络编程框架,框架能够做到纳秒级别的端到端延迟。
框架内部消息传输层采用了 Aeron + SBE 组合,真.零拷贝、零回环、零反射、零GC、零运行时解析、编解码开销几乎为零。 通过无锁、基于共享内存的环形缓冲区实现,彻底避免了内核态切换和锁竞争,这是达到极低延迟的关键。 极致的 CPU 效率,它让消息处理的速度几乎可以达到底层硬件的极限。
ionet 是一个开源的轻量级分布式网络编程框架,适用场景:
框架有以下特点:
真轻量级、无锁异步化、事件驱动的架构设计。 包体小、内存占用少、启动速度快。 框架是纯 javaSE 的,使得 ionet 能与其他框架方便的进行集成、融合,如 Spring、Vert.x、Quarkus、Solon ...等,从而使用这些框架的相关生态。 在学习成本方面非常低,可以说是零学习成本,即使没有游戏编程经验,也能轻松上手。开发者只需掌握普通的 java 方法或 WebMVC 相关知识,就能用框架开发业务。 在轻量级方面,框架不依赖任何第三方中间件就能支持纳秒级的分布式网络通信,只需要 java 环境就可以运行。 架构是可以动态扩缩的,对外服、逻辑服支持动态增加和减少。 在分布式开发体验方面,ionet 支持多服单进程的启动方式,这使得开发者在开发和调试分布式系统时更加简单。 在生态规划方面,逻辑服是支持独立运行,从而实现功能模块化的可能性。 具备全链路调用日志跟踪特性。 在通信方式方面,提供多种通信方式,且逻辑服之间可以相互跨机器通信。 在编码风格上,提供了类 MVC 的编码风格(无入侵的 Java Bean ),这种设计方式很好的避免了类爆炸。 在线程安全方面,框架为开发者解决了单个用户的并发问题。 在连接方式方面,允许开发者使用一套业务代码,同时支持 TCP、WebSocket、UDP 等多种连接方式,无需进行任何修改,并且可扩展。 在数据协议方面,让开发者用一套业务代码,就能轻松切换不同的数据协议,如 Protobuf、JSON 等,并且可扩展。 在增减协议方面,可以让你在新增或减少协议时,无需重启对外服。这样既能避免用户断线,又能避免因新增、减少协议而重启所有机器的痛点。 action 支持自动装箱、拆箱基础类型,用于解决协议碎片的问题。 业务框架提供了插件机制,插件是可插拨、可扩展的。 在部署方面,支持多服单进程的方式部署,也支持多服多进程多机器的方式部署,在部署方式上可以随意的切换而不需要更改代码。 在安全方面,所有的逻辑服不需要开放端口,天然地避免了扫描攻击。 在模拟客户端测试方面,提供了压测&模拟客户端请求模块。该模块可以模拟真实的网络环境,并且在模拟测试的过程中与服务器的交互是可持续的、可互动的,同时也是支持自动化的。 框架为开发者提供了同步、异步、异步回调的方法,用于逻辑服之间的相互访问。 分布式事件总线支持(类似 MQ、Redis 发布订阅机制,可跨多个机器通信、可跨多个进程通信)。 提供优雅的路由访问权限控制。 具备智能的同进程亲和性。 JSR380 验证、断言 + 异常机制 = 更少的维护成本。 一次编写到处对接,提升巨大的生产力,能为各客户端生成可交互的代码。你只需要编写一次 java 代码,就能为 Godot、UE、Unity、CocosCreator、Laya、React、Vue、Angular ...等项目生成统一的交互接口。
ionet 是一个开源的轻量级分布式网络编程框架,框架能够做到亚微秒甚至纳秒级别的端到端延迟。 极致的 CPU 效率,它让消息处理的速度达到硬件极限。
框架在打包、内存占用、启动速度等方面也是优秀的。 打 jar 包后大约 15MB,应用通常会在 0.x 秒内完成启动,内存占用小。
在生态融合方面,框架可以很方便的与 Spring 集成(4 行代码)。 除了 Spring 外,还能与任何其他的框架做融合,如 Vert.x、Quarkus、Solon ...等,从而使用其他框架的相关生态。
在学习成本方面非常低,可以说是零学习成本,即使没有网络编程经验也能轻松上手。 开发者只需掌握普通的 java 方法或 webMVC 相关知识,就能使用框架开发业务。
在编码风格上,框架为开发者提供了类 MVC 的编码风格(无入侵的 Java Bean ),这种设计方式很好的避免了类爆炸。 同时,框架为开发者提供了同步、异步、异步回调的方法,用于逻辑服之间的相互访问。 这使得开发者所编写的代码会非常的优雅,并且具备全链路调用日志跟踪。
与客户端对接方面,框架具备一次编写到处对接的能力,为客户端提供了代码生成的辅助功能,能够帮助客户端开发者减少巨大的工作量。 这将意味着,你只需要编写一次 java 代码,就能为 Godot、UE、Unity、CocosCreator、Laya、React、Vue、Angular ...等项目生成统一的交互接口。 框架提供了多种语言的 SDK 支持及相关语言的代码生成,分别是 C#、TypeScript、GDScript、C++、Lua,并支持扩展。
框架在架构上解决了传统框架所产生的 N*N 问题(与传统架构对比)。 传统架构在扩展机器时,需要借助很多第三方中间件,如:Redis、MQ、ZooKeeper ...等,才能满足整体架构的运作。 通常,只要引入了需要安装的中间件才能做到扩展的,那么你的架构或者说框架,基本上与轻量级无缘了。
在轻量级方面,框架不依赖任何第三方中间件就能支持分布式网络通信,只需要 java 环境就可以运行。 这意味着在使用上简单了,在部署上也为企业减少了部署成本、维护难度。 使用 ionet 时,只需一个依赖即可获得整个框架,而无需安装其他服务,如 Nginx、Redis、MQ、Mysql、ZooKeeper、Protobuf 协议编译工具 ...等。
在架构灵活性方面,架构由对外服和逻辑服组成, 两者既可相互独立,又可相互融合。 这意味着框架可以适应任何类型的游戏,因为只需通过调整部署方式,就可以满足不同类型的游戏需求。 在框架中进行这些调整工作非常简单,而且不会对现有代码产生不良影响。
架构是可以动态扩缩的,对外服和逻辑服支持动态增加和减少。 无论未来用户数量增加或减少,我们都能够轻松应对。 同时,架构是支持用户无感知更新的,这得益于分布式设计。 举例来说,如果 A 类型的逻辑服需要增加一些新功能,我们可以启动 A-3、A-4 等已经支持了新功能的服务器, 然后逐步将之前的 A-1 和 A-2 下线,从而实现了无感知的更新。
在分布式方面,框架的逻辑服使用了分布式设计思想,将服务器分为对外服、逻辑服等不同层次, 并且每一层都有明确的职责和接口。这样可以提高代码可读性和可维护性,并且方便进行水平扩展。
在分布式开发体验方面,通常在开发分布式应用时是需要启动多个进程的。 这会让调试与排查问题变得非常困难,从而降低开发者的效率、增加工作量等,这也是很多框架都解决不了的问题,但 ionet 做到了! ionet 支持多服单进程的启动方式,这使得开发者在开发和调试分布式系统时更加简单。
在生态规划方面,我们的逻辑服是支持独立运行的,启动后就可以为用户和其他逻辑服提供功能上的扩展与增强。 我们可以将一些逻辑服组件化,并制作成相对通用的组件,从而实现功能模块化的可能性。这么做有几个优点
框架具备全链路调用日志跟踪特性,这在分布式下非常的实用。 该特性为每个请求分配一个唯一标识,并记录在日志中,通过唯一标识可以快速的在日志中过滤出指定请求的信息。 框架提供的全链路调用日志跟踪特性更是强大,支持跨机器、跨进程。 简单的说,从用户的请求进来到结束,无论该请求经过了多少个逻辑服,都能精准记录。
在通信方式方面,大部分框架只能支持推送(广播)这一类型的通信方式。 框架则提供了多种通信模型, 通过对各种通信方式的组合使用,可以简单完成以往难以完成的工作, 并且这些通信方式都支持跨进程、跨机器通信,且具备全链路调用日志跟踪。
在线程安全方面,框架为开发者解决了单个用户的并发问题。 即使用户重新登录后,也会使用相同的线程来消费业务,并推荐使用领域事件来解决同一房间或业务内多个用户的并发问题。 框架在线程的扩展性上提供了友好的支持,开发者可以很容易的编写出无锁并发代码,这得益于框架独有的线程执行器设计与扩展。 换句话说,你不会因为并发问题烦恼。
在无锁并发方面,框架提供了优雅、独特的线程执行器设计。通过该特性,开发者能轻易的编写出无锁高并发的代码。
在连接方式方面,框架允许开发者使用一套业务代码,同时支持多种连接方式,无需进行任何修改。 框架已经支持了 TCP、WebSocket 和 UDP 连接方式,并且也支持在这几种连接方式之间进行灵活切换。 连接方式是可扩展的,并且扩展操作也很简单,这意味着之后如果支持了 KCP、QUIC, 无论你当前项目使用的是 TCP、WebSocket、UDP,都可以切换成 KCP、QUIC。 即使切换到 KCP、QUIC 的连接方式,现有的业务代码也无需改变。
在通信协议方面,框架让开发者用一套业务代码,就能轻松切换和扩展不同的数据协议, 如 Protobuf、JSON 等。只需一行代码,就可以从 Protobuf 切换到 JSON,无需改变业务方法。
在增减协议方面,框架可以让你在新增或减少协议时,无需重启对外服。 这样既能避免用户断线,又能避免因新增、减少协议而重启所有机器的痛点。
在协议碎片方面,action 支持自动装箱、拆箱基础类型特性,用于解决协议碎片的问题。 同时该特性除了能使你的业务代码更加清晰以外,还能大幅提高开发者在该环节的生产力。
在开发体验方面,框架非常注重开发者的开发体验。 框架提供了 JSR380 验证、断言 + 异常机制、业务代码定位, action 支持自动装箱、拆箱基础类型,用于解决协议碎片的问题 ...等。 诸多丰富的功能,使得开发者的业务代码更加的清晰、简洁。
业务框架提供了插件机制,插件是可插拨、可扩展的。 框架内置提供了 DebugInOut、action 调用统计、业务线程监控插件、各时间段调用统计插件...等插件。 不同的插件提供了不同的关注点,比如我们可以使用调用、监控等插件相互配合,可以让我们在开发阶段就知道是否存在性能问题。 合理利用好各个插件,可以让我们在开发阶段就能知道问题所在,提前发现问题,提前预防问题。
在部署方面,框架支持多服单进程的方式部署,也支持多服多进程多机器的方式部署,在部署方式上可以随意的切换而不需要更改代码。 日常中我们可以按照单体思维开发,到了生产可以选择性的使用多进程的方式部署。
在安全方面,所有的逻辑服不需要开放端口,天然地避免了扫描攻击。 由于不需要为每个逻辑服分配独立的端口,那么我们在使用诸如云服务器之类的服务时,就不需要担心端口开放权限的问题了。 别小看这一个环节,通常这些小细节最浪费开发者的时间。 由于我们不需要管理这些 IP:Port,这部分的工作量就自然地消失了。
在模拟客户端测试方面,框架提供了压测&模拟客户端请求模块。 此模块是用于模拟客户端,简化模拟工作量,只需要编写对应请求与回调。 除了可以模拟简单的请求外,通常还可以做一些复杂的请求编排,并支持复杂业务的压测。 与单元测试不同的是,该模块可以模拟真实的网络环境,并且在模拟测试的过程中与服务器的交互是可持续的、可互动的,同时也是支持自动化的。
使用 ionet,可以显著的帮助企业减少巨额成本。 文档中,成本关键字提到了很多次,各个阶段均有关联,包括了学习、研发、测试、部署、扩展、投入 ...等各阶段。 在同等资源的竞争下,使用 框架能为公司节省更多的资源,从而提高了自身的生存率。 更重要的是避免了为其他公司做嫁衣的可能性,具体可阅读成本分析案例。
开发者基于 框架编写的项目模块,通常是条理清晰的,得益于框架对路由的合理设计,同时也为路由提供了优雅的访问权限控制。 当我们整理好这些模块后,对于其他开发者接管项目或后续的维护中,会是一个不错的帮助(代码组织与约定)。 或许现阶段你感受不到这块的威力,随着你深入地使用实践就能体会到这么设计的诸多好处与优势。
开发者基于 框架编写的项目,通常是语法简洁的、高性能的、低延迟的。 框架最低要求使用 JDK25,这样即可以让项目享受到分代 ZGC 带来的改进,还能享受语法上的简洁。 分代 ZGC 远低于其亚毫秒级暂停时间的目标,可以在不影响速度的情况下,清理掉多余的内存。 这样就不会出现卡顿或者崩溃的问题了,相当于在项目中变相的引入了一位 JVM 调优大师。
综上所述,框架是一个非常适合网络游戏开发的框架。可以让你轻松地创建高性能、低延迟、易扩展的网络服务器,并且节省时间和资源。 如果你想要快速地开发出令人惊艳的网络游戏,请不要犹豫,立即选择 框架吧! 框架屏蔽了很多复杂且重复性的工作,并可为项目中的功能模块结构、开发流程等进行清晰的组织定义,减少了后续的项目维护成本。
框架在开发、部署、与客户端对接、压测&模拟测试 ...等,各个阶段都提供了很好的支持。 相信你已经对框架有了一个初步的了解,虽然还有很多丰富的功能与特性没有介绍到,但你可以通过后续的实践过程中来深入了解。 感谢你的阅读,并期待你使用 框架来打造自己的游戏服务器。
ionet 是非常注重开发体验的,代码注释即文档、方法即交互接口的原则。
框架具备一次编写到处对接的能力,从而让你们团队提升巨大的生产力。 一次编写指的是编写一次 java 业务代码,而到处对接则是指为不同的前端项目生成与服务器交互的代码。
你只需要编写一次 java 代码,就能为 Godot、 UE、 Unity、 CocosCreator、 Laya、 React、 Vue、 Angular ...等项目生成统一的交互接口
框架能为各种前端项目生成 action、广播、错误码 相关接口代码。 这将意味着,你只需要编写一次业务代码,就可以同时与这些游戏引擎或现代化的前端框架交互。
前端代码生成的几个优势
无锁异步化、事件驱动的架构设计;真轻量级,无需依赖任何第三方中间件就能搭建出一个分布式的网络通信服务器。
自带负载均衡、分布式支持、可动态增减机器。
| 名称 | 扩展方式 | 职责 |
|---|---|---|
| ExternalServer | 分布式 | 对外服的职责是与用户连接、交互 |
| LogicServer | 分布式 | 逻辑服的职责是处理具体业务逻辑 |

从架构简图中,我们知道了整体架构由对外服和逻辑服组成,两者既可相互独立,又可相互融合。
更详细的介绍请阅读架构介绍。
对外服、逻辑服使用分布式设计,支持启动多个相同类型的服务。这意味着,当用户数量增加时,我们可以轻松增加相应类型的逻辑服以处理更多请求。
以逻辑服为例,假设我们启动了两个 A 类型的逻辑服,分别为 A-1 和 A-2。当用户向 A 类型的逻辑服发起多次请求时,框架会使用默认的随机负载策略将请求分配给 A-1 和 A-2 来处理。
现在我们明白,对外服和逻辑服都支持动态增加和减少。无论未来用户数量增加或减少,我们都能够轻松应对。架构是支持用户无感知更新的,这得益于分布式设计。举例来说,如果 A 类型的逻辑服需要增加一些新功能,我们可以启动 A-3、A-4 等已经支持了新功能的服务器,然后逐步将之前的 A-1 和 A-2 下线,从而实现了无感知的更新。
此外,框架还支持用户动态绑定逻辑服。当用户与逻辑服绑定后,之后的请求都由该逻辑服来处理。
ionet 也适用于物联网相关项目。只需将图中的用户视为具体的设备,即使存在数亿个设备,ionet 的架构也可以轻松支持。
对外服
对外服的主要职责是与用户的建立长连接。 假如我们的一台硬件支持我们建立用户连接的上限是 5000 人,当用户量达到 7000 人时,我们可以多加一个对外服务器来进行分流减压。
通过增加对外服的数量,可以有效地进行连接的负载均衡和流量控制,使得系统能够更好地承受高并发的压力。 由于对外服扩展的简单性,意味着支持同时在线用户可以轻松的达到百万、千万甚至更多。
即使我们启动了多个对外服,开发者也不需要关心这些用户连接到了哪个对外服的问题, 这些用户总是能接收到广播(推送)消息的,因为框架已经把这些事情给做了。 在用户的角度我们只有“一个”服务器,同样的,在开发者的角度我们只有“一个”对外服。
通常,有些开发者想知道对外服最大支持多少用户连接。 关于这个问题,只需要搜索 Netty 相关知识即可,因为对外服与用户建立连接部分使用的 Netty 实现。 同样的,如果开发者已经熟悉了 Netty 相关知识,那么在对外服的扩展上也会变得非常的容易。
下面是游戏引擎与游戏服务器的业务交互简图。

抽象的说,游戏前端与游戏服务器的的交互由上图组成。 前端与服务器可以自由地双向交互,即发送和接收业务数据。 业务数据由 .proto 文件作为载体,在前端和后端之间进行编码和解码。 .proto 文件是对业务数据的描述载体,定义了数据类型和消息类型,以及它们的属性和规则。
通过这种方式,前端和服务端可以建立连接,并开始相互传递业务数据,处理各自的业务。 以上是对前端与服务器之间交互方式的介绍。 接下来,我们将编写一个简单的业务处理示例,并定制一个适合我们需求的业务数据协议。
协议文件是对业务数据的描述载体,用于前端与服务器的数据交互。 Protocol Buffers 是 Google 开发的一种数据描述语言,也简称 PB。 协议文件描述还可以是 json、xml 或者任意自定义的,因为最后传输时会转换为二进制,但游戏开发中 PB 是目前的最佳选择。
游戏前端的展现可以是 Godot、 Unity、 UE、 Cocos Creator、 Laya、 FXGL 或者其他的游戏引擎。 这些游戏引擎只是展现游戏画面的一种形式,数据交互则由通信来完成(TCP、UDP ...等)。
数据协议
现在,我们定义数据协议,用于客户端与服务器的数据交互。 如果你只做过 web 开发而没有游戏服务器开发经验的,可以把这理解成 DTO、业务数据载体等,其主要目的是用于业务数据的传输。
由于原生的 PB 使用起来比较麻烦,这里我们使用 JProtobuf。 这是对 PB 的简化使用,性能与原生的同等。
在普通的 java 类上添加 ProtobufClass 注解,就表示这是一个业务数据协议。
<span style="color:#393a34"><span style="color:#393a34">@ProtobufClass</span>
</span><span style="color:#393a34"><span style="color:#00009f">public</span><span> </span><span style="color:#00009f">class</span><span> </span><span>UserMessage</span><span> </span><span style="color:#393a34">{</span>
</span><span style="color:#393a34"><span> </span><span style="color:#00009f">public</span><span> </span><span style="color:#00009f">int</span><span> id</span><span style="color:#393a34">;</span>
</span><span style="color:#393a34"><span> </span><span style="color:#00009f">public</span><span> </span><span>String</span><span> nickname</span><span style="color:#393a34">;</span>
</span><span style="color:#393a34"><span style="color:#393a34">}</span>
</span>
Action
服务器接收业务数据后,对业务数据进行处理。 下面这段代码可以同时支持 TCP、WebSocket、UDP 通信方式。
<span style="color:#393a34"><span><span style="color:#393a34">@Slf4j</span></span>
</span><span style="color:#393a34"><span><span style="color:#393a34">@ActionController</span><span style="color:#393a34">(</span><span style="color:#36acaa">1</span><span style="color:#393a34">)</span></span>
</span><span style="color:#393a34"><span><span style="color:#00009f">public</span><span> </span><span style="color:#00009f">class</span><span> </span><span>HallAction</span><span> </span><span style="color:#393a34">{</span></span>
</span><span style="color:#393a34"><span><span> </span><span style="color:#393a34">@ActionMethod</span><span style="color:#393a34">(</span><span style="color:#36acaa">0</span><span style="color:#393a34">)</span></span>
</span><span style="background-color:rgba(0, 0, 0, 0.1); color:#393a34"><span><span> </span><span style="color:#00009f">private</span><span> </span><span>UserMessage</span><span> </span><span style="color:#d73a49">loginVerify</span><span style="color:#393a34">(</span><span>String</span><span> message</span><span style="color:#393a34">)</span><span> </span><span style="color:#393a34">{</span></span>
</span><span style="color:#393a34"><span><span> </span><span style="color:#00009f">var</span><span> userMessage </span><span style="color:#393a34">=</span><span> </span><span style="color:#00009f">new</span><span> </span><span>UserMessage</span><span style="color:#393a34">(</span><span style="color:#393a34">)</span><span style="color:#393a34">;</span></span>
</span><span style="color:#393a34"><span><span> userMessage</span><span style="color:#393a34">.</span><span>nickname </span><span style="color:#393a34">=</span><span> </span><span style="color:#e3116c">"Jack"</span><span style="color:#393a34">;</span></span>
</span><span style="color:#393a34"><span><span> </span><span style="color:#00009f">return</span><span> userMessage</span><span style="color:#393a34">;</span></span>
</span><span style="color:#393a34"><span><span> </span><span style="color:#393a34">}</span></span>
</span><span style="color:#393a34"><span><span style="color:#393a34">}</span></span>
</span>一个方法(loginVerify)在业务框架中表示一个 Action(业务动作)。 方法声明的参数是用于接收请求端传入的业务数据,而 return 的数据则会发送给请求端。 这样,开发者就不需要关心业务框架的内部细节了。
从上面的示例可以看出,这和普通的 java 类并无区别,同时这种设计方式避免了类爆炸。 如果只负责编写业务,那么对于业务框架的学习可以到此为止了。
源码地址:点击下载
以上就是ionet 25.2 发布,纳秒级延迟的分布式网络通信框架的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号