ioGame 网络游戏服务器框架 v1.4.0 自动装箱、拆箱基础类型、业务线程编排

主要更新

  1. 业务参数自动装箱、拆箱基础类型 (I5C57I
  2. 业务框架处理请求时,开发者可以自定义业务线程编排 (I5DTZN

1 业务参数自动装箱、拆箱基础类型

在线文档说明 https://www.yuque.com/iohao/game/ieimzn

在实际开发中,会有一些基础类型的业务参数,比如需要经常用到下面类似的,如:通过 装备-衣服-id 得到衣服装备详细、通过 装备-头盔-id 得到头盔装备详细、通过 xx-id 得到xx数据 等。

这些参数基本都是相同的,如果每一个类似这样的请求都创建一个数据协议,会产生比较多的碎片协议,如

// 装备-头盔-id pb
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class EquipHelmetIdPb {
    int id;
}

// 装备-衣服-id pb
@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class EquipClothesIdPb {
    int id;
}

// 业务action
@ActionController(1)
public class DemoAction {
    @ActionMethod(0)
    public xxx getEquipPb(EquipClothesIdPb equipClothesIdPb) {
        // 通过装备id , 查询装备
        int equipId = equipClothesIdPb.id;
        return ...
    }
}

对于这种情况,业务框架将提供一些较好的支持;首先,业务框架会提供一个通用的 pb 类型,如下

@ProtobufClass
@FieldDefaults(level = AccessLevel.PUBLIC)
public class IntPb {
    int intValue;
}

在代码中的使用,如下伪代码

@ActionController(1)
public class DemoAction {
    @ActionMethod(0)
    public xxx getEquipPb(IntPb equipIdPb) {
    	// 通过装备id , 查询装备
    	int equipId = equipIdPb.intValue;
        return ...
    }
}

由于是业务参数基础包装类型-int,实际上我们还可以这样使用,下面这种用法与上面是等价的。这种实际上就是有点像是 java 基础类型的自动装箱和拆箱

@ActionController(1)
public class DemoAction {
    @ActionMethod(0)
    public xxx getEquipPb(int equipId) {
    	
        return ...
    }
}

框架支持的自动装箱、拆箱基础类型如下

 

基础类型

对应的 PB 类

等价的 int

IntPb

等价的 long LongPb
等价的

List<Integer>

IntListPb

等价的 List<Long> LongListPb

2 业务框架处理请求时,开发者可以自定义业务线程编排,业务线程编排-钩子接口

在线文档说明 https://www.yuque.com/iohao/game/eixd6x

由于 bolt 处理业务时是多线程的,当多个逻辑服同时修改一个共享的数据逻辑服,会有并发问题;对于这种情况有两种处理方式

  1. 使用 synchronized 关键字 加锁
  2. 使用其他的并发框架,做无锁化编程

这里推荐使用 Disruptor 并发框架来做线程的编排,这样可以做到无锁化编程。框架内提供了一个 Disruptor 相关的模块 light-domain-event 领域事件,开发者可按需选择;

在框架中,给逻辑服编排业务线程是很简单的事、而且足够的灵活。

下面是一个游戏逻辑服编排业务线程的示例

public class WrapperLogicServer extends AbstractBrokerClientStartup {
    ... ... 省略部份代码
    
    @Override
    public BrokerClientBuilder createBrokerClientBuilder() {
        // bolt 业务处理器的钩子管理器
        ClientProcessorHooks hooks = getClientProcessorHooks();

        BrokerClientBuilder builder = BrokerClient.newBuilder();
        builder
                .appName("业务参数自动装箱和拆箱-逻辑服")
                // 设置 bolt 业务处理器的钩子管理器
                .clientProcessorHooks(hooks)
        ;
        
        return builder;
    }

    private ClientProcessorHooks getClientProcessorHooks() {
        // bolt 业务处理器的钩子管理器
        ClientProcessorHooks hooks = new ClientProcessorHooks();

        // 设置逻辑服业务处理钩子接口
        hooks.setRequestMessageClientProcessorHook((barSkeleton, flowContext) -> {

            // 这里做线程编排相关的逻辑

            CmdInfo cmdInfo = flowContext.getCmdInfo();
            // 得到当前请求路由
            int cmdMerge = cmdInfo.getCmdMerge();
            // 如果是这个路由,就给到其他并发框架
            if (cmdMerge == CmdKit.merge(14, 10)) {
                // 注意,这里是伪代码;
                // 开发者放到 disruptor 或其他并发框架中执行,这样可以做到无锁化编程。
                barSkeleton.handle(flowContext);
                return;
            }

            // 默认正常执行
            barSkeleton.handle(flowContext);
        });

        return hooks;
    }
}

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

  • 国内首个基于蚂蚁金服 SOFABolt 的 java 网络游戏服务器框架;无锁异步化、事件驱动的架构设计;
  • 通过 ioGame 可以很容易的搭建出一个集群无中心节点、分步式的网络游戏服务器!
  • 轻量级、更节约、更简单、开箱即用、无配置文件、启动快、超高性能
  • 业务框架平均每秒可以执行 1152 万次业务逻辑
  • 对webMVC开发者友好
  • 代码即文档

ioGame 是一个由 java 语言编写的网络游戏服务器框架。支持 websocket、tcp ,适用于全球同服、回合制游戏、策略游戏、即时战斗等游戏服务器的开发。具有高性能、稳定、易用易扩展、超好编程体验等特点。可做为 H5、手游、端游的 java 游戏服务器。

ioGame 是轻量级的网络游戏服务器框架,在使用 ioGame 时,无需安装其他服务,如: Nginx、Redis、MQ、Mysql、ZooKeeper、Protobuf协议编译工具 ... ...等。简单点说,就是无需安装其他产品就能使用;这意味着在使用上简单了,在部署上也为企业节约了成本。

通过 ioGame 你可以很容易的搭建出一个稳定、高性能、集群无中心节点、分步式、自带负载均衡、跨进程通信、避免类爆炸设计的网络游戏服务器。游戏框架借助于蚂蚁金服 sofa-bolt 通信框架来提供通信方面的稳定与高性能

在 ioGame 中能让你遗忘 Netty,你几乎没有机会能直接的接触到 Netty 的复杂,但却能享受 Netty 带来的高性能。对开发者要求极低,为开发者节约开发时间。

即使之前没有游戏编程的经验,也能参与到游戏编程中。如果你之前具备一些游戏开发或者 webMVC 相关的知识,则会更容易上手游戏服务的开发。

ioGame 可以很方便的与 spring 集成(5 行代码)。在部署上支持多服单进程的方式部署(类似单体应用)、也支持多服多进程多机器的方式部署。在部署方式上可以随意切换,而不需要更改代码;日常中按照单体思维开发,在生产上可以使用多进程的方式部署;当然,也可以使用单进程的方式部署。

ioGame 框架职责清晰、业务开发几乎零学习成本、源码有高质量注释、示例多、使用文档多,开发体验最佳、对接文档自动生成、逻辑服之间可跨进程跨机器通信、业务代码定位--神级特性、异常机制。


ioGame 是国内首个基于蚂蚁金服 sofa-bolt 的网络游戏框架,游戏框架由 [网络通信框架] 和 [业务框架] 组成。

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

网络通信框架 - SOFABolt

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

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

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

业务框架

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

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

业务框架平均每秒可以执行 1152 万次业务逻辑。

架构简图

 

通过 ioGame 你可以很容易的搭建出一个集群、分步式的网络游戏服务器!

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

图中的每个对外服、每个游戏逻辑服、每个 broker (游戏网关)都可以在单独的进程中部署,逻辑服之间可以跨进程通信(对外服也是逻辑服的一种)。

游戏网关集群

broker (游戏网关)可以集群的方式部署,集群无中心节点、自带负载均衡。ioGame 本身就包含服务注册,你不需要外接一个服务注册中心,如 Eureka,ZooKeeper 等(变相的节约服务器成本)。

通过 broker (游戏网关) 的介入,之前非常复杂的负载均衡设计,如服务注册、健康度检查(后续版本提供)、到服务端的连接维护等这些问题,在 ioGame 中都不需要了,结构也简单了很多。实际上单台 broker (游戏网关) 性能已经能够满足了,因为游戏网关只做了转发。

逻辑服

逻辑服通常说的是游戏对外服和游戏逻辑服。逻辑服可以有很多个,逻辑服扩展数量的理论上限是 netty 的连接上限。

游戏对外服

对外服保持与用户(玩家)的长连接。先来个假设,假如我们的一台硬件支持我们建立用户连接的上限是 5000 人,当用户量达到 7000 人时,我们可以多加一个对外服务器来进行分流减压。由于游戏对外服扩展的简单性,意味着支持同时在线玩家可以轻松的达到百万、千万甚至更多。

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

Proto 协议文件定义

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

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

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

Action

游戏服务的编程,游戏服务接收业务数据后,对业务数据进行处理

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

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

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

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

 

游戏编程就是如此简单

 

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

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

 

访问示例(控制台)

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

┏━━━━━ Debug. [(DemoAction.java:4).here] ━━━ [cmd:1 - subCmd:0 - cmdMerge:65536]
┣ userId : 888
┣ 参数: helloReq : HelloReq(name=塔姆)
┣ 响应: HelloReq(name=塔姆, I'm here )
┣ 时间: 0 ms (业务方法总耗时)
┗━━━━━ Debug [DemoAction.java] ━━━

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

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

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

 

适合人群?

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

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

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

 

猜你喜欢

转载自www.oschina.net/news/200881/iogame-1-4-0-released