iohao / ioGame

无锁异步化、事件驱动架构设计的 java netty 网络编程框架; 轻量级,无需依赖任何第三方中间件或数据库就能支持集群、分布式; 适用于网络游戏服务器、物联网、内部系统及各种需要长连接的场景; 通过 ioGame 你可以很容易的搭建出一个集群无中心节点、集群自动化、分布式的网络服务器;FXGL、Unity、UE、Cocos Creator、Godot、Netty、Protobuf、webSocket、tcp、socket;java Netty 游戏服务器框架;

Home Page:http://game.iohao.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

新增通讯方式 - 分布式事件总线

iohao opened this issue · comments

简单介绍

分布式事件总线是 ioGame 提供的通讯方式之一。该通讯方式与 Guava EventBus、Redis 发布订阅、MQ ... 等产品类似。

如果使用 Redis、MQ ...等中间件,需要开发者额外的安装这些中间件,并支付所占用机器的费用;使用 Guava EventBus 则只能在当前进程中通信,无法实现跨进程。

而 ioGame 提供的分布式事件总线,拥有上述两者的优点。此外,还可以有效的帮助企业节省云上 Redis、 MQ 这部分的支出。

事件发布后,除了当前进程所有的订阅者能接收到,远程的订阅者也能接收到(支持跨机器、跨进程、跨不同类型的多个逻辑服)。可以代替 redis pub sub 、 MQ ,并且具备全链路调用日志跟踪,这点是中间件产品做不到的。

ioGame 分布式事件总线,特点

  • 使用方式与 Guava EventBus 类似
  • 具备全链路调用日志跟踪。(这点是中间件产品做不到的)
  • 支持跨多个机器、多个进程通信
  • 支持与多种不同类型的多个逻辑服通信
  • 纯 javaSE,不依赖其他服务,耦合性低。(不需要安装任何中间件)
  • 事件源和事件监听器之间通过事件进行通信,从而实现了模块之间的解耦
  • 当没有任何远程订阅者时,将不会触发网络请求。(这点是中间件产品做不到的)

ioGame 支持的通讯方式分为两大类,即路由类和主题类,而分布式事件总线属于主题类通讯。主题类通讯方式的特点是可与多种不同类型的多个逻辑服通信。

简图

分布式事件总线简图

图中,【游戏逻辑服-X】发起了一个事件 [a_eventSource],该事件会被所有的订阅者接收到。即使订阅者在不同的机器、不同的进程及不同的逻辑服中,都能接收到事件源。由于【游戏逻辑服-A】和【游戏逻辑服-B】订阅了 [a_eventSource] 事件,所以可以接收到该事件源。

虽然分布式事件总线只强调了跨进程、跨机器的能力,实际上同进程中的订阅者也是生效的。简单的说,你可以把分布式事件总线当作 Guava EventBus 来使用;如果没有跨进程的订阅者,将不会触发任何网络请求。

通讯方式特点:分布式事件总线

文档 - 分布式事件总线

事件发布后,除了当前进程所有的订阅者能接收到,远程的订阅者也能接收到(跨机器、跨进程)。可以代替 redis pub sub 、 MQ ,并且具备全链路调用日志跟踪,这点是中间件产品做不到的。

示例代码中提供了同步、异步的编码风格。

void eventBus() {
    int userId = 100;
    // 事件源
    YourEventMessage yourEventMessage = new YourEventMessage(userId);

    // 异步执行 - 事件发布后,只会交给 flowContext 关联的业务框架中的订阅者处理
    flowContext.fireMe(yourEventMessage);
    // 同步执行 - 事件发布后,只会交给 flowContext 关联的业务框架中的订阅者处理
    flowContext.fireMeSync(yourEventMessage);

    // 异步执行 - 事件发布后,当前进程所有的订阅者都会接收到。(同进程启动了多个逻辑服)
    flowContext.fireLocal(yourEventMessage);
    // 同步执行 - 事件发布后,当前进程所有的订阅者都会接收到。(同进程启动了多个逻辑服)
    flowContext.fireLocalSync(yourEventMessage);

    // 异步执行 - 除了当前进程所有的订阅者能接收到,远程的订阅者也能接收到(跨机器、跨进程)
    flowContext.fire(yourEventMessage);
}

大多数情况下,在发布事件时,使用 fire 方法就足够了。因为除了当前进程所有的订阅者能接收到,远程的订阅者也能接收到(跨机器、跨进程)

需要注意的是,如果没有任何远程订阅者,将不会触发网络请求。简单的说,事件发布后,当其他进程(其他机器)没有相关订阅者时,只会在内存中传递事件给当前进程的相关订阅者。所以,可以将该通讯方式当作 guava EventBus 来使用。


订阅者 - 示例

flowContext.fire(yourEventMessage); ,fire 是发布事件的方法,当事件发布后,下面中的订阅者会接收到事件源。

用户逻辑服的订阅者

public class UserEventBusSubscriber {
    @EventSubscribe
    public void userLogin(YourEventMessage message) {
        log.info("event - 玩家[{}]登录,记录登录时间", message.getUserId());
    }
}

邮件逻辑服的订阅者

public class EmailEventBusSubscriber {
    @EventSubscribe
    public void mail(YourEventMessage message) {
        long userId = message.getUserId();
        log.info("event - 玩家[{}]登录,发放 email 奖励", userId);
    }
}