netty 分步式游戏服务器框架 & 真轻量级网络编程框架 ioGame 21.10 发布


ioGame 源码完全开放、最新文档阅读完全开放;使用完全自由、免费(遵守开源协议)。

ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。

文档与日志

  • ioGame javadoc api

  • 框架版本更新日志 (yuque.com)

  • ioGame网络游戏服务器框架 (yuque.com)


版本更新汇总

  • [core] #315 ResponseMessage 增加协议碎片便捷获取,简化跨服调用时的使用

  • [core] ActionCommand 增加 containAnnotation、getAnnotation 方法,简化获取 action 相关注解信息的使用。

  • [kit] [动态属性] 增加 ifNull 方法,如果动态属性值为 null,则执行给定的操作,否则不执行任何操作。执行给定操作后将得到一个返回值,该返回值会设置到动态属性中。

  • [kit] TimeKit 增加 nowLocalDate 方法,可减少 LocalDate 对象的创建;优化 currentTimeMillis 方法的时间更新策略。同时,优化 nowLocalDate、currentTimeMillis 方法,不使用时将不会占用相关资源。

  • [EventBus] 分布式事件总线增加 EventBusRunner 接口。EventBus 接口化,方便开发者自定义扩展。fix 订阅者使用自身所关联的 EventBus 处理相关事件。


[core] 315 ResponseMessage 增加协议碎片便捷获取,简化跨服调用时的使用

框架具备协议碎片特性。某些业务中,我们需要跨服访问其他游戏逻辑服,以获取某些业务数据;一些简单的数据,我们可以通过协议碎片来返回,从而避免定义过多的协议。

现为 ResponseMessage 增加协议碎片支持,简化跨服调用时的使用,新增的方法如下

 public void test() {
 ResponseMessage responseMessage = ...;
 
 // object
 responseMessage.getValue(Student.class);
 List<Student> listValue = responseMessage.listValue(Student.class);
 
 // int
 int intValue = responseMessage.getInt();
 List<Integer> listInt = responseMessage.listInt();
 
 // long
 long longValue = responseMessage.getLong();
 List<Long> listLong = responseMessage.listLong();
 
 // String
 String stringValue = responseMessage.getString();
 List<String> listString = responseMessage.listString();
 
 // boolean
 boolean boolValue = responseMessage.getBoolean();
 List<Boolean> listBoolean = responseMessage.listBoolean();
 }

 

示例说明

  • HomeAction 是 【Home 游戏逻辑服】提供的 action

  • UserAction 是 【User 游戏逻辑服】提供的 action

两个逻辑服的交互如下,UserAction 使用跨服方式调用了【Home 游戏逻辑服】的几个方法,并通过 responseMessage 的协议碎片支持,简化跨服调用时的使用。

示例中演示了 string、string list、object list 的简化使用(协议碎片获取时的简化使用)。

 @ProtobufClass
 @FieldDefaults(level = AccessLevel.PUBLIC)
 public class Student {
 String name;
 }
 
 // home 游戏逻辑服提供的 action
 public class HomeAction {
 @ActionMethod(HomeCmd.name)
 public String name() {
 return "a";
 }
 
 @ActionMethod(HomeCmd.listName)
 public List<String> listName() {
 return List.of("a", "b");
 }
 
 @ActionMethod(HomeCmd.listStudent)
 public List<Student> listStudent() {
 Student student = new Student();
 student.name = "a";
 
 Student student2 = new Student();
 student2.name = "b";
 
 return List.of(student, student2);
 }
 }
 
 @ActionController(UserCmd.cmd)
 public class UserAction {
 @ActionMethod(UserCmd.userSleep)
 public void userSleep(FlowContext flowContext) {
 
 flowContext.invokeModuleMessageAsync(HomeCmd.of(HomeCmd.name), responseMessage -> {
 String name = responseMessage.getString();
 log.info("{}", name);
 });
 
 flowContext.invokeModuleMessageAsync(HomeCmd.of(HomeCmd.listName), responseMessage -> {
 var listName = responseMessage.listString();
 log.info("{}", listName);
 });
 
 flowContext.invokeModuleMessageAsync(HomeCmd.of(HomeCmd.listStudent), responseMessage -> {
 List<Student> studentList = responseMessage.listValue(Student.class);
 log.info("{}", studentList);
 });
 }
 }

 


 

[core] ActionCommand 增加 containAnnotation、getAnnotation 方法,简化获取 action 相关注解信息的使用。

 ActionCommand actionCommand = flowContext.getActionCommand();
 
 bool contain = actionCommand.containAnnotation(DisableDebugInout.class);
 var annotation = actionCommand.getAnnotation(DisableDebugInout.class);

 


[EventBus] 分布式事件总线

  1. [增强扩展] 将抽象类 AbstractEventBusRunner 标记为过时的,由接口 EventBusRunner 代替。

  2. [增强扩展] 分布式事件总线 EventBus 接口化,方便开发者自定义扩展。增加总线相关的 javadoc

  3. [fix] 订阅者使用自身所关联的 EventBus 处理相关事件。

 

关于 fix 订阅者使用自身所关联的 EventBus 处理相关事件,在此之前可能引发 bug 的场景如下

  1. 【游戏逻辑服 A】 发布事件。

  2. 【游戏逻辑服 B】 订阅者接收事件并处理,在处理过程中又调用了【游戏逻辑服 A】 某个 action 方法。

 

该业务场景,会在多服单进程下会引发调用超时,但在多服多进程下则不会超时。

 


[kit] TimeKit

增强 TimeKit 增加 nowLocalDate 方法,可减少 LocalDate 对象的创建;

优化 currentTimeMillis 方法的时间更新策略。

优化 nowLocalDate、currentTimeMillis 不使用时将不会占用相关资源。

 @Test
 public void test() {
 long millis = TimeKit.currentTimeMillis();
 Assert.assertTrue(millis > 0);
 
 LocalDate localDate = TimeKit.nowLocalDate();
 Assert.assertTrue(localDate.isEqual(LocalDate.now()));
 }

 


[kit] 动态属性

[动态属性] 增加 ifNull 方法,如果动态属性值为 null,则执行给定的操作,否则不执行任何操作。执行给定操作后将得到一个返回值,该返回值会设置到动态属性中。

 public class AttrOptionDynamicTest {
 // 动态属性 key
 AttrOption<AttrCat> attrCatOption = AttrOption.valueOf("AttrCat");
 
 @Test
 public void ifNull() {
 var myAttrOptions = new MyAttrOptions();
 Assert.assertNull(myAttrOptions.option(attrCatOption));
 
 // 如果 catAttrOption 属性为 null,则创建 AttrCat 对象,并赋值到属性中
 myAttrOptions.ifNull(attrCatOption, AttrCat::new);
 Assert.assertNotNull(myAttrOptions.option(attrCatOption));
 }
 
 private static class AttrCat {
 String name;
 }
 
 @Getter
 private static class MyAttrOptions implements AttrOptionDynamic {
 final AttrOptions options = new AttrOptions();
 }
 }

 


[其他 - 相关库升级]

4.1.111.Final

4.0.5

2.4.23


ioGame 使用趋势数据

关注 ioGame 的游戏服务器开发者持续增多,2022-09 ~ 至今各月的统计数据;

这里的统计信息是关于开发者关注 ioGame 框架相关的,从统计数据中可以看出,由于 ioGame 上手简单,功能强大等优点,得到了众多开发者的关注。如果你想知道 ioGame 有没有人在使用,可以先到这里看下统计数据、开发者的评价与讨论。

https://www.yuque.com/iohao/game/gpxk93#TwVa8

这里展示了每月的统计数据,统计数据来源于语雀后台,这些数据都是真实的、客观存在的、活的

因为成本的原因,某宝某多还没有出现能提供这种服务的商家,所以这样的统计数据也更具真实性。

通过统计数据,我们可以看到每天会有很多开发者在访问 ioGame 的在线文档,并且这些统计数据不是来源于口嗨的,也不是主观创造的。

所以,还在犹豫要不要使用 ioGame 的开发者们,更应该讨论的是 “为什么这些开发者会选择使用 ioGame”,而不是 ioGame 有没有人在使用的问题。

点击我,到语雀后台查看 ioGame 的数据


ioGame 网络游戏服务器框架简介

  • 无锁异步化、事件驱动的架构设计;轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式
  • 通过 ioGame 可以很容易的搭建出一个集群无中心节点、集群自动化、多进程的分布式游戏服务器
  • 包体小、启动快、内存占用少、更加的节约、无需配置文件、提供了优雅的路由访问权限控制
  • 可同时支持多种连接方式:WS、UDP、TCP... 等;框架已支持全链路调用日志跟踪特性
  • 让开发者用一套业务代码,能轻松切换和扩展不同的通信协议:Protobuf、JSON
  • 近原生的性能;业务框架在单线程中平均每秒可以执行 1152 万次业务逻辑
  • 代码即联调文档、JSR380 验证、断言 + 异常机制 = 更少的维护成本
  • 框架具备智能的同进程亲和性;开发中,业务代码可定位与跳转
  • 架构部署灵活性与多样性:既可相互独立,又可相互融合
  • 可同时与同类型的多个游戏逻辑服通信并得到数据
  • 逻辑服之间可相互跨进程、跨机器进行通信
  • 支持玩家对游戏逻辑服进行动态绑定
  • 能与任何其他框架做融合共存
  • 对 webMVC 开发者友好
  • 无 spring 强依赖
  • 零学习成本
  • javaSE

你是否想要开发一个高性能、稳定、易用、自带负载均衡、避免类爆炸设计、可跨进程跨机器通信、集群无中心节点、集群自动化、有状态多进程的分布式的网络编程服务器呢?如果是的话,这里向你推荐一个由 java 语言编写的网络编程框架 ioGame。下面将会从多个方面来对框架做一些简单的介绍。

ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景;

ioGame 有以下特点:

  • 无锁异步化、事件驱动的架构设计
  • 同时支持 TCP、WebSocket、UDP 多种连接方式,并且可扩展
  • 支持 protobuf、json 等不同的通信协议
  • 集群无中心节点、集群自动化、分布式的设计
  • 真轻量级,不依赖任何第三方中间件或数据库就能支持集群、分布式
  • 提供多种通讯方式,且逻辑服之间可以相互跨机器通信
  • 框架为开发者提供了同步、异步、异步回调的方法,用于逻辑服之间的相互访问
  • ioGame 是纯 javaSE 的,使得 ioGame 能与其他框架方便的进行集成、融合;如 spring ... 等
  • 学习成本低,开发体验好
  • 支持多服单进程、多服多进程的启动和部署方式
  • 提供游戏文档生成的辅助功能
  • 包体小、启动快、内存占用少
  • 提供优雅的路由访问权限控制
  • 提供了灵活的线程扩展、设置
  • 具备智能的同进程亲和性
  • 具备全链路调用日志跟踪特性
  • 业务框架提供了插件机制,插件是可插拨、可扩展的
  • JSR380 验证、断言 + 异常机制 = 更少的维护成本
  • action 支持自动装箱、拆箱基础类型,用于解决协议碎片的问题

ioGame 是一个专为网络编程设计的轻量级框架,它可以帮助你快速地搭建和运行自己的网络服务器。ioGame 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。如各种类型和规模的网络游戏,无论是 H5、手游还是 PC 游戏,无论是简单的聊天室,还是复杂的全球同服、回合制游戏、策略游戏、放置休闲游戏、即时战斗、MMORPG 等,ioGame 都可以满足你的需求。

ioGame 在打包、内存占用、启动速度等方面也是优秀的。打 jar 包后大约 15MB,应用通常会在 0.x 秒内完成启动,内存占用小。详细请看 快速从零编写服务器完整示例

在生态融合方面,ioGame 可以很方便的 spring 集成(5 行代码);除了 spring 外,还能与任何其他的框架做融合,如:solon ... 等,从而使用其他框架的相关生态。

ioGame 在架构上解决了传统框架所产生的 N*N 问题与传统架构对比)。传统架构在扩展机器时,需要借助很多第三方中间件,如:Redis、MQ、ZooKeeper ... 等,才能满足整体架构的运作。通常,只要引入了需要安装的中间件才能做到扩展的,那么你的架构或者说框架,基本上与轻量级无缘了。

在轻量级方面,ioGame 不依赖任何第三方中间件或数据库就能支持集群、分布式,只需要 java 环境就可以运行。这意味着在使用上简单了,在部署上也为企业减少了部署成本、维护难度。使用 ioGame 时,只需一个依赖即可获得整个框架,而无需安装其他服务,如: Nginx、Redis、MQ、Mysql、ZooKeeper、Protobuf 协议编译工具 ... 等。

ioGame 具备全链路调用日志跟踪特性,这在分布式下非常的实用。该特性为每个请求分配一个唯一标识,并记录在日志中,通过唯一标识可以快速的在日志中过滤出指定请求的信息。ioGame 提供的全链路调用日志跟踪特性更是强大,支持跨机器、跨进程。简单的说,从玩家的请求进来到结束,无论该请求经过了多少个游戏逻辑服,都能精准记录。

在通讯方式方面,大部分框架只能支持推送(广播)这一类型的通讯方式;ioGame 则提供了多种类型的通讯方式,通过对各种通讯方式的组合使用,可以简单完成以往难以完成的工作,并且这些通讯方式都支持跨进程、跨机器通信,且具备全链路调用日志跟踪。这些通讯方式分别是

  1. 请求响应(单次请求处理)
  2. 广播(推送)
  3. 单个逻辑服间的相互通讯(可跨机器通信、可跨进程通信)
  4. 与同类型多个逻辑服相互通讯(可跨多个机器通信、可跨多个进程通信)
  5. 脉冲通讯(可跨多个机器通信、可跨多个进程通信)
  6. 分布式事件总线(类似 MQ、Redis 发布订阅机制;可跨多个机器通信、可跨多个进程通信)

在编码风格上,ioGame 为开发者提供了类 MVC 的编码风格(无入侵的 Java Bean ),这种设计方式很好的避免了类爆炸。同时,框架为开发者提供了同步、异步、异步回调的方法,用于逻辑服之间的相互访问;这使得开发者所编写的代码会非常的优雅,并且具备全链路调用日志跟踪。

从 ioGame21 开始,框架添加了虚拟线程的相关支持。各逻辑服之间通信阻塞部分使用虚拟线程,这样可以很好的避免阻塞业务线程,并大幅提高了框架的吞吐量。

在线程安全方面,框架为开发者解决了单个玩家的并发问题;即使玩家重新登录后,也会使用相同的线程来消费业务,并推荐使用领域事件来解决同一房间或业务内多个玩家的并发问题。框架在线程的扩展性上提供了友好的支持,开发者可以很容易的编写出无锁并发代码,这得益于 ioGame 独有的线程执行器设计与扩展。换句话说,你不会因为并发问题烦恼。

在无锁并发方面,ioGame 提供了优雅、独特的线程执行器设计。通过该特性,开发者能轻易的编写出无锁高并发的代码。

在连接方式方面,ioGame 允许开发者使用一套业务代码同时支持多种连接方式,无需进行任何修改。ioGame 已经支持了 TCP、WebSocket 和 UDP 连接方式,并且也支持在这几种连接方式之间进行灵活切换。连接方式是可扩展的,并且扩展操作也很简单,这意味着之后如果支持了 KCP,无论你当前项目使用的是 TCP、WebSocket 还是 UDP,都可以切换成 KCP;注意了,即使切换到 KCP 的连接方式,现有的业务代码也无需改变。

在通信协议方面,ioGame 让开发者用一套业务代码,就能轻松切换和扩展不同的通信协议,如 Protobuf、JSON 等。只需一行代码,就可以从 Protobuf 切换到 JSON,无需改变业务方法。

在增减协议方面,ioGame 可以让你在新增或减少协议时,无需重启游戏对外服与 Broker(游戏网关);这样既能避免玩家断线,又能避免因新增、减少协议而重启所有机器的痛点。

在协议碎片方面,action 支持自动装箱、拆箱基础类型特性,用于解决协议碎片的问题。同时该特性除了能使你的业务代码更加清晰以外,还能大幅提高开发者在该环节的生产力。

在集群方面,ioGame 的 Broker (游戏网关)采用无中心节点、自动化的集群设计,所有节点平等且自治,不存在单点故障。集群能够自动管理和弹性扩缩,节点加入或退出时,能够自动保证负载均衡和数据一致性,不影响服务可用性。

在分布式方面,ioGame 的逻辑服使用了分布式设计思想,将服务器分为游戏对外服游戏逻辑服等不同层次,并且每一层都有明确的职责和接口。这样可以提高代码可读性和可维护性,并且方便进行水平扩展

在学习成本方面,ioGame 的学习成本非常低,可以说是零学习成本,即使没有游戏编程经验,也能轻松上手。开发者只需掌握普通的 java 方法或 webMVC 相关知识,就能用框架开发业务。框架不要求开发者改变编码习惯,而是自身适应开发者的需求。

同进程亲和性方面,在同一进程内,不同 Netty 实例之间的通信,是通过内存进行传输的,不需要经过网络传输,数据传输速度极快。同进程亲和性指的是,优先访问同进程内的游戏逻辑服,当同进程内没有能处理请求的游戏逻辑服时,才会去其他进程或机器中查找能处理请求的游戏逻辑服;简单点说,框架对于请求的处理很智能,会优先将请求给同进程内的逻辑服消费。

在开发体验方面,ioGame 非常注重开发者的开发体验;框架提供了 JSR380 验证断言 + 异常机制业务代码定位,action 支持自动装箱、拆箱基础类型,用于解决协议碎片的问题 ... 等。诸多丰富的功能,使得开发者的业务代码更加的清晰、简洁;

业务框架提供了插件机制,插件是可插拨、可扩展的。框架内置提供了 DebugInOutaction 调用统计业务线程监控插件各时间段调用统计插件... 等插件;不同的插件提供了不同的关注点,比如我们可以使用调用、监控等插件相互配合,可以让我们在开发阶段就知道是否存在性能问题。合理利用好各个插件,可以让我们在开发阶段就能知道问题所在,提前发现问题,提前预防问题。

在分布式开发体验方面,通常在开发分布式应用时是需要启动多个进程的。这会让调试与排查问题变得非常困难,从而降低开发者的效率、增加工作量等,这也是很多框架都解决不了的问题,但 ioGame 做到了!ioGame 支持多服单进程的启动方式,这使得开发者在开发和调试分布式系统时更加简单。

与前端对接联调方面,ioGame 提供了游戏文档生成的辅助功能,可以做到代码即对接文档。简单地说,当业务代码编写完后,框架会自动生成最新的文档。如果没有游戏文档的生成,那么你将要抽出一些时间来编写、维护对接文档的工作,而且当团队人数多了之后,文档就会很乱、不同步、不是最新的、忘记更新等情况就会出现。

在部署方面,ioGame 支持多服单进程的方式部署,也支持多服多进程多机器的方式部署;在部署方式上可以随意的切换而不需要更改代码。日常中我们可以按照单体思维开发,到了生产可以选择使用多进程的方式部署。

在安全方面,所有的游戏逻辑服不需要开放端口,天然地避免了扫描攻击。由于不需要为每个逻辑服分配独立的端口,那么我们在使用诸如云服务器之类的服务时,就不需要担心端口开放权限的问题了。别小看这一个环节,通常这些小细节最浪费开发者的时间。由于我们不需要管理这些 IP:Port,这部分的工作量就自然地消失了

在模拟客户端测试方面,ioGame 提供了压测 & 模拟客户端请求模块。此模块是用于模拟客户端,简化模拟工作量,只需要编写对应请求与回调。除了可以模拟简单的请求外,通常还可以做一些复杂的请求编排,并支持复杂业务的压测。与单元测试不同的是,该模块可以模拟真实的网络环境,并且在模拟测试的过程中与服务器的交互是可持续的、可互动的,同时也是支持自动化的

架构灵活性方面,ioGame 的架构由三部分组成:1. 游戏对外服、2.Broker(游戏网关)、3. 游戏逻辑服;三者既可相互独立,又可相互融合。这意味着使用 ioGame 可以适应任何类型的游戏,因为只需通过调整部署方式,就可以满足不同类型的游戏需求。在 ioGame 中进行这些调整工作非常简单,而且不会对现有代码产生不良影响。

架构是可以动态扩缩的,游戏对外服、游戏逻辑服、Broker(游戏网关)都支持动态增加和减少。无论未来玩家数量增加或减少,我们都能够轻松应对。同时,架构是支持玩家无感知更新的,这得益于分布式设计。举例来说,如果 A 类型的游戏逻辑服需要增加一些新功能,我们可以启动 A-3、A-4 等已经支持了新功能的服务器,然后逐步将之前的 A-1 和 A-2 下线,从而实现了无感知的更新。

开发者基于 ioGame 编写的项目模块,通常是条理清晰的,得益于框架对路由的合理设计,同时也为路由提供了优雅的访问权限控制。当我们整理好这些模块后,对于其他开发者接管项目或后续的维护中,会是一个不错的帮助(模块的整理与建议)。或许现阶段你感受不到这块的威力,随着你深入地使用实践就能体会到这么设计的诸多好处与优势。

开发者基于 ioGame 编写的项目,通常是语法简洁的、高性能的、低延迟的。框架最低要求使用 JDK21,这样即可以让项目享受到分代 ZGC 带来的改进,还能享受语法上的简洁。分代 ZGC 远低于其亚毫秒级暂停时间的目标,可以在不影响游戏速度的情况下,清理掉多余的内存;这样就不会出现卡顿或者崩溃的问题了,相当于在项目中变相的引入了一位 JVM 调优大师。

综上所述,ioGame 是一个非常适合网络游戏开发的框架。可以让你轻松地创建高性能、低延迟、易扩展的游戏服务器,并且节省时间和资源。如果你想要快速地开发出令人惊艳的网络游戏,请不要犹豫,立即选择 ioGame 吧!框架屏蔽了很多复杂且重复性的工作,并可为项目中的功能模块结构、开发流程等进行清晰的组织定义,减少了后续的项目维护成本。

框架在开发、部署、压测 & 模拟测试 ... 等,各个阶段都提供了很好的支持。相信你已经对 ioGame 有了一个初步的了解,虽然还有很多丰富的功能与特性没有介绍到,但你可以通过后续的实践过程中来深入了解。感谢你的阅读,并期待你使用 ioGame 来打造自己的游戏服务器。

ioGame 的组成

ioGame 由 [网络通信框架] 和 [业务框架] 组成

  • 网络通信框架:职责是各服务器之间的网络通信
  • 业务框架:职责是业务逻辑的处理方式和编写方式

 

网络通信框架

SOFABolt 是蚂蚁金融服务集团开发的一套基于 Netty 实现的网络通信框架。

  • 为了让 Java 程序员能将更多的精力放在基于网络通信的业务逻辑实现上,而不是过多的纠结于网络底层 NIO 的实现以及处理难以调试的网络问题,Netty 应运而生。
  • 为了让中间件开发者能将更多的精力放在产品功能特性实现上,而不是重复地一遍遍制造通信框架的轮子,SOFABolt 应运而生。

Bolt 名字取自迪士尼动画 - 闪电狗,是一个基于 Netty 最佳实践的轻量、易用、高性能、易扩展的通信框架。

 

业务框架

如果说 sofa-bolt 是为了让 Java 程序员能将更多的精力放在基于网络通信的业务逻辑实现上。而业务框架正是解决业务逻辑如何方便实现这一问题上。业务框架是游戏框架的一部分,职责是简化程序员的业务逻辑实现,业务框架使程序员能够快速的开始编写游戏业务。

业务框架对于每个 action (即业务的处理方法) 都是通过 asm 与 Singleton、Flyweight 、Command 等设计模式结合,对 action 的获取上通过 array 来得到,是一种近原生的方式。

单线程中,业务框架平均每秒可以执行 1152 万次业务逻辑。


架构简图

 

通过 ioGame 你可以很容易的搭建出一个集群无中心节点、集群自动化、分布式的网络游戏服务器!

从图中可以看出,游戏网关支持以集群方式启动多个实例。这个设计选择了集群的方式,因为游戏网关通常是无状态的,主要作用是解耦各逻辑服之间的关系、负载均衡、调度和转发任务。

而游戏对外服、游戏逻辑服使用分布式设计,支持启动多个相同类型的服务。这意味着,当玩家数量增加时,我们可以轻松增加相应类型的游戏逻辑服以处理更多请求。

以游戏逻辑服为例,假设我们启动了两个 A 类型的游戏逻辑服,分别为 A-1 和 A-2。当玩家向 A 类型的游戏逻辑服发起多次请求时,游戏网关会使用默认的随机负载策略将请求分配给 A-1 和 A-2 来处理。

现在我们明白,游戏对外服和游戏逻辑服都支持动态增加和减少。无论未来玩家数量增加或减少,我们都能够轻松应对。架构是支持玩家无感知更新的,这得益于分布式设计。举例来说,如果 A 类型的游戏逻辑服需要增加一些新功能,我们可以启动 A-3、A-4 等已经支持了新功能的服务器,然后逐步将之前的 A-1 和 A-2 下线,从而实现了无感知的更新。

此外,框架还支持玩家动态绑定游戏逻辑服;玩家与游戏逻辑服绑定后,之后的请求都由该游戏逻辑服来处理。

除了游戏之外,ioGame 也适用于物联网相关项目。只需将图中的玩家视为具体的设备,即使存在数亿个设备,ioGame 的架构也可以轻松支持。从 2022 年开始,已经有一些物联网公司开始采用这一解决方案,并得到了很好的体验。

ioGame 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景;

 

无锁异步化与事件驱动的架构设计、集群无中心节点、自带负载均衡、分布式支持、可动态增减机器、避免类爆炸的设计;

名称

扩展方式

职责

游戏对外服

分布式

与玩家连接、交互

游戏逻辑服

分布式

处理具体业务逻辑

Broker(游戏网关)

集群

调度和转发任务;


通过 ioGame 可以使得游戏编程变得简单,下面是一个业务示例

协议文件定义

首先我们自定义一个协议文件,这个协议文件作为我们的业务载体描述。这个协议是纯 java 代码编写的,使用的是 jprotobuf,jprotobuf 是对 google protobuf 的简化使用,性能同等。

可以把这理解成 DTO、POJO、业务数据载体等,其主要目的是用于业务数据的传输;

/** 请求 */
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class HelloReq {
String name;
}

 

Action

游戏服务器的编程,游戏服务器接收业务数据后,对业务数据进行处理;下面这段代码可以同时支持 TCP、WebSocket、UDP 通信方式。

示例代码中展示了玩家的请求与响应处理,还展示了跨服(跨进程、跨机器)的请求处理的示例。无入侵的 Java Bean。

@ActionController(1)
public class DemoAction {
@ActionMethod(0)
public HelloReq here(HelloReq helloReq) {
// 业务数据
var newHelloReq = new HelloReq();
newHelloReq.name = helloReq.name + ", I'm here ";
return newHelloReq;
}

// 注意,这个方法只是为了演示而写的;(ioGame21 开始支持)
// 效果与上面的方法一样,只不过是用广播(推送)的方式将数据返回给请求方
	@ActionMethod(0)
public void here(HelloReq helloReq, FlowContext flowContext) {
// 业务数据
var newHelloReq = new HelloReq();
newHelloReq.name = helloReq.name + ", I'm here ";

flowContext.broadcastMe(newHelloReq);
}

// 跨服调用示例,下面分别展示了同步与异步回调的写法
void testShowInvokeModule(FlowContext flowContext) {
/* * 框架为跨服请求提供了同步、异步、异步回调的编码风格 api。(ioGame21 开始支持) */
var cmdInfo = CmdInfo.of(1,0);
var yourData = ... 你的请求参数

// 跨服请求(异步回调 - 无阻塞)-- 路由、请求参数、回调。
flowContext.invokeModuleMessageAsync(cmdInfo, yourData, responseMessage -> {
var helloReq = responseMessage.getData(HelloReq.class);
 // --- 此异步回调,具备全链路调用日志跟踪 ---
log.info("异步回调 : {}", helloReq);
});


// 跨服请求(同步 - 阻塞)-- 路由、请求参数。
ResponseMessage responseMessage = flowContext.invokeModuleMessage(cmdInfo, yourData);
var helloReq = responseMessage.getData(HelloReq.class);
log.info("同步调用 : {}", helloReq);
}
}

一个方法(here)在业务框架中表示一个 Action(一个业务动作)。

方法声明的参数是用于接收前端传入的业务数据,在方法 return 时,数据就可以被游戏前端接收到。程序员可以不需要关心业务框架的内部细节。

从上面的示例可以看出,这和普通的 java 类并无区别,同时这种设计方式避免了类爆炸。如果只负责编写游戏业务,那么对于业务框架的学习可以到此为止了。

游戏编程就是如此简单

 

问:我可以开始游戏服务的编程了吗?

是的,你已经可以开始游戏服务的编程了。

 

访问示例(控制台)

当我们访问 here 方法时(通常由游戏前端来请求),控制台将会打印

┏━━━━━ Debug. [(DemoAction.java:4).hello] ━━━━━ [cmd:1-0 65536] ━━━━━ [逻辑服 [xxx逻辑服] - id:[76526c134cc88232379167be83e4ddfc]]
┣ userId: 1
┣ 参数: active : HelloReq(id=101, name=塔姆)
┣ 响应: HelloReq(name=塔姆, I'm here )
┣ 时间: 1 ms (业务方法总耗时)
┗━━━━━ [ioGameVersion] ━━━━━ [线程:User-8-2] ━━━━━━━ [traceId:956230991452569600] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 

控制台打印说明

Debug. [(DemoAction.java:4).here] :

表示执行业务的是 DemoAction 类下的 here 方法,4 表示业务方法所在的代码行数。

在工具中点击控制台的 DemoAction.java:4 这条信息,就可以跳转到对应的代码中(快速导航到对应的代码),这是一个开发良好体验的开始!

userId : 当前发起请求的 用户 id。

参数 : 通常是游戏前端传入的值。

响应:通常是业务方法返回的值 ,业务框架会把这个返回值推送到游戏前端。

时间:执行业务方法总耗时,我们可根据业务方法总耗时的时长来优化业务。

路由信息:[cmd - subCmd] 路由是唯一的访问地址。

ioGameVersion:表示当前所使用的 ioGame 版本。

线程:当前执行 action 所使用的线程。

traceId:全链路调用日志跟踪 id,每个请求唯一。(该特性在分布式下非常实用)

逻辑服:当前游戏逻辑服与其 id

有了以上信息,游戏开发者可以很快的定位问题。如果没有可视化的信息,开发中会浪费很多时间在前后端的沟通上。问题包括:

  • 是否传参问题 (游戏前端说传了)
  • 是否响应问题(游戏后端说返回了)
  • 业务执行时长问题 (游戏前端说没收到响应, 游戏后端说早就响应了)

其中代码导航可以让开发者快速的跳转到业务类对应代码中,在多人合作的项目中,可以快速的知道业务经过了哪些方法的执行,使得我们可以快速的进行阅读或修改;


框架内置的其他功能

内置多种可选模块,可按需选择,以方便应用开发:

  • 领域事件 轻量级单机最快 MQ -- disruptor;通过领域事件模块,可为你的系统实现类似 Guava-EventBus、Spring 事件驱动模型 ApplicationEvent、业务解耦、规避并发、不阻塞主线程... 等,各种浪操作)
  • 任务延时器 (将来某个时间可对任务进行执行、暂停、取消等操作,并不是类似 Quartz 的任务调度)
  • 多环境切换 (不同运行环境下的配置支持)
  • light-jprotobuf 补足 jprotobuf 不能让多个对象在单个 .proto 源文件中生成的需求,并简化 jprotobuf 对源文件的注释
  • 分布式锁 (基于 Redisson 的简单实现)
  • room 桌游、房间类,该模块是桌游类、房间类游戏的解决方案。比较适合桌游类、房间类的游戏基础搭建,基于该模型可以做一些如,炉石传说、三国杀、斗地主、麻将 ... 等类似的桌游。或者说只要是房间类的游戏,该模型都适用。比如,CS、泡泡堂、飞行棋、坦克大战 ... 等。

内置的其他功能:

  • 心跳相关
  • 用户上线、离线相关的钩子方法
  • UserSessions (对所有用户 UserSession 的管理,统计在线用户等)
  • UserSession (与 channel 是 1:1 的关系,可取到对应的 userId、channel 等信息。)
  • 登录相关(提供重复登录、顶号等相关增强功能)
  • 业务参数基础类型 自动装箱、拆箱(解决协议碎片)

适合人群?

  1. 长期从事 web 内部系统开发人员, 想了解游戏的
  2. 刚从事游戏开发的
  3. 未从事过游戏开发,但却对其感兴趣的
  4. 对设计模式在实践中的应用和 sofa-bolt 有兴趣的学习者
  5. 可以接受新鲜事物的
  6. 想放弃祖传代码的

推荐实际编程经验一年以上的人员。

ioGame 提供了丰富的在线高质量使用文档,为你的团队助力,带上你们的小伙伴一起,这样就不用手把手的教了。


相關推薦

2024-07-09

全自由、免费(遵守开源协议)。 ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。 文档与日志 ioGame javadoc api 框架版本更新日志 (yuque.com) ioGame 网络游戏服务器

2024-07-25

全自由、免费(遵守开源协议)。 ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。 文档与日志 ioGame javadoc api 框架版本更新日志 (yuque.com) ioGame 网络游戏服务器

2024-08-09

全自由、免费(遵守开源协议)。 ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。 文档与日志 ioGame javadoc api 框架版本更新日志 (yuque.com) ioGame 真.轻量级网络

2024-08-27

全自由、免费(遵守开源协议)。 ioGame 是一个轻量级的网络编程框架,适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景。 文档与日志 ioGame javadoc api 框架版本更新日志 (yuque.com) ioGame 真。轻量级网络

2023-09-07

室   ioGame 使用趋势数据统计 关注 ioGame 的游戏服务器开发者持续增多,2022-09 ~ 2023-08 月统计数据; 这里的统计信息是关于开发者关注 ioGame 框架相关的,从统计数据中可以看出,由于 ioGame 上手简单,功能强大等

2023-07-19

主要更新 [160] 轻量小部件 - 压测&模拟客户端请求模块 文档:https://www.yuque.com/iohao/game/tc83ud   介绍 此模块是用于模拟客户端,简化模拟工作量,只需要编写对应请求与回调。 使用该模块后,当我们与前端同学联调某

2023-08-08

目   ioGame 使用趋势数据统计 关注 ioGame 的游戏服务器开发者持续增多,2022-09 ~ 2023-07 月统计数据; 这里的统计信息是关于开发者关注 ioGame 框架相关的,从统计数据中可以看出,由于 ioGame 上手简单,功能强大等

2023-07-08

主要更新 [#159] 同进程同时支持多种连接方式方式的技巧 public class MyApplication { ... ... 省略部分代码 static int externalCorePort = 10100; public static void main(String[] args) { // 游戏对外服列表 List<ExternalServer> externalServerList = listExtern

2023-11-03

ioGame 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景; 主要更新 优化 FlowContext createRequestMessage #194 可能在 springboot 集成 light-domain-event 时,启动报 java.lang.ClassNotFoundException #198 关于改造现有或

2023-06-09

当路由不存在时,可以起到抵挡的作用,而不必经过其他服务器。   [#114] 支持玩家与多个游戏逻辑服的动态绑定 文档:动态绑定游戏逻辑服   动态绑定游戏逻辑服,指的是玩家与游戏逻辑服绑定后,之后的请求都由

2023-08-19

nbsp;   ioGame 使用趋势数据统计 关注 ioGame 的游戏服务器开发者持续增多,2022-09 ~ 2023-08 月统计数据; 这里的统计信息是关于开发者关注 ioGame 框架相关的,从统计数据中可以看出,由于 ioGame 上手简单,功能强大等

2023-02-04

大小,ioGame 打 jar 包后大约 15MB,演示查看 快速从零编写服务器完整示例。   #36 增加 Banner 打印版本、内存占用、启动耗时等信息。 ioGame 在内存占用、启动速度、打包等方面也是优秀的。 内存方面:内存占用小。

2023-05-09

机制类似于 Spring CommandLineRunner 的启动项,它能够在逻辑服务器启动之后调用一次 Runner 接口实现类,让开发者能够通过实现 Runner 接口来扩展自身的系统。 使用 Runner 机制,开发者可以通过扩展已有模块的功能或提供配置相关

2023-07-26

单登录 模拟登录 项目简介 这是一个基于 ioGame 网络编程框架开发的 MMO 类型的回合制网络游戏项目,这类型的游戏涵盖的点比较多,是 ioGame 的最佳实践。我们会尽可能的在项目中演示框架文档中提及的理论特性。 如