告别 Redis/MQ —— ionet 分布式事件总线实战

一个熟悉的场景

你刚接到一个需求:玩家登录后,系统需要做以下事情------

  1. 记录登录时间
  2. 发放离线奖励
  3. 发送欢迎邮件
  4. 推送今日活动信息
  5. 更新排行榜在线状态

你的第一反应可能是:上 Redis pub/sub 或 MQ。

但这意味着:安装 Redis/RabbitMQ 服务、维护连接池、处理消息序列化、配置消费者组、担心消息丢失......原本一个简单的"通知"需求,变成了一场中间件战争。

ionet 的答案是:不需要安装任何东西。


三个概念,全部学完

ionet 的分布式事件总线只有 3 个概念:

概念 说明 类比
EventSource(事件源) 业务数据载体 MQ 中的消息体
Subscriber(订阅者) 接收事件并处理业务 MQ 中的消费者
Fire(发布事件) 发送事件给订阅者 MQ 中的 publish

学完这三个概念,你就可以开始使用了。


实战:玩家登录事件

第一步:定义事件源

java 复制代码
@ProtobufClass
public class UserLoginEventMessage {
    public long userId;

    public static UserLoginEventMessage of(long userId) {
        var message = new UserLoginEventMessage();
        message.userId = userId;
        return message;
    }
}

事件源需要添加 @ProtobufClass 注解,因为事件可能跨进程传输,需要序列化支持。

第二步:编写订阅者

java 复制代码
@EventBusSubscriber
public class EmailEventBusSubscriber {
    @EventSubscribe
    public void mail(UserLoginEventMessage message) {
        log.info("发送欢迎邮件给用户 {}", message.userId);
        // 实际业务:调用邮件系统发送欢迎邮件
    }
}

@EventBusSubscriber
public class RewardEventBusSubscriber {
    @EventSubscribe
    public void calcReward(UserLoginEventMessage message) {
        log.info("计算离线奖励给用户 {}", message.userId);
        // 实际业务:查询上次登录时间,计算奖励
    }
}

订阅者的编写规则非常简单:

  1. 方法必须是 public void
  2. 方法只能有一个参数(事件源)
  3. 方法需要添加 @EventSubscribe 注解

第三步:注册订阅者到逻辑服

java 复制代码
public final class EmailLogicServer implements LogicServer {
    @Override
    public void settingBarSkeletonBuilder(BarSkeletonBuilder builder) {
        builder.addRunner((EventBusRunner) (eventBus, _) -> {
            eventBus.register(new EmailEventBusSubscriber());
        });
    }
}

第四步:在业务中发布事件

java 复制代码
@ActionMethod(0)
private UserMessage login(FlowContext flowContext, LoginMessage message) {
    // 处理登录逻辑...

    // 发布登录事件
    var event = UserLoginEventMessage.of(flowContext.getUserId());
    flowContext.fire(event);

    return new UserMessage("登录成功");
}

完成。 就这么简单。登录方法只关心登录本身,邮件、奖励等逻辑在各自的订阅者中实现,分散在不同的逻辑服中。


四种发布粒度

ionet 提供了 4 种事件发布方式,适用于不同场景:

fireMe:仅当前逻辑服

java 复制代码
flowContext.fireMe(event);    // 异步
flowContext.fireMeSync(event); // 同步

只通知当前逻辑服的 EventBus 中的订阅者。适合逻辑服内部的模块解耦。

fireLocal:当前进程所有逻辑服

java 复制代码
flowContext.fireLocal(event);
flowContext.fireLocalSync(event);

如果用户逻辑服和邮件逻辑服在同一进程中启动,fireLocal 会通知两者的订阅者,但不会通知其他进程的订阅者。

fire:全局发布

java 复制代码
flowContext.fire(event);
flowContext.fireSync(event);

所有订阅者都能收到------包括当前进程的、其他进程的、甚至其他机器的。

fireAny:同类型只发一个

java 复制代码
flowContext.fireAny(event);
flowContext.fireAnySync(event);

当有多个同类型逻辑服实例(比如 3 个邮件逻辑服)时,fireAny 只会给其中一个发送事件。适合"只需要一个实例处理"的场景,如发放奖励------防止重复发放。


杀手级特性:零订阅者 = 零开销

这是 ionet EventBus 最精妙的设计:

如果没有任何远程订阅者,将不会触发网络请求。

这意味着什么?

假设你在登录业务中埋了一个事件发布点。即使所有相关的逻辑服都没有上线(没有任何订阅者),这行 fire 代码也不会产生任何网络开销。它只是在内存中检查:有订阅者吗?没有。结束。

这是 Redis pub/sub 和 MQ 做不到的------它们无论有没有消费者,消息都会发送到中间件服务器。


高级用例:可插拔的临时活动

利用"零订阅者 = 零开销"这个特性,你可以实现可插拔的业务逻辑

场景:春节活动期间,玩家每日在线 60 分钟奖励一些物品。

实现方式

  1. 在登录 Action 中发布事件(这个代码永远不变)
  2. 为活动创建一个独立的【春节活动逻辑服】,注册活动订阅者
  3. 活动期间:启动【春节活动逻辑服】→ 订阅者上线 → 开始处理事件
  4. 活动结束:关闭【春节活动逻辑服】→ 订阅者消失 → 零开销

你不需要修改任何主业务代码。 只是通过启动或关闭一个逻辑服,就实现了功能的上线和下线。

同样的思路还可以用于:

  • 热更:通过事件批量推送新的配置到所有逻辑服实例
  • 全局配置更新:GM 后台发布配置变更事件
  • 统计数据收集:单独的统计逻辑服订阅各种业务事件

订阅者线程执行器

对于有并发安全要求的场景,ionet 允许你为订阅者指定线程执行器:

java 复制代码
@EventBusSubscriber
public class MySubscriber {
    // 默认策略:使用用户线程执行器(与 Action 共用线程,线程安全)
    @EventSubscribe
    public void onLogin(UserLoginEventMessage message) { ... }

    // 虚拟线程策略:适合 IO 密集型操作
    @EventSubscribe(ExecutorSelector.userVirtualExecutor)
    public void saveToDB(UserLoginEventMessage message) { ... }

    // 方法级线程策略:同一订阅者方法永远在同一线程
    @EventSubscribe(ExecutorSelector.methodExecutor)
    public void updateRank(UserLoginEventMessage message) { ... }
}

5 种可选策略:userExecutor(默认)、userVirtualExecutormethodExecutorsimpleExecutorcustomExecutor


与 Redis pub/sub、MQ 的全面对比

特性 ionet EventBus Redis pub/sub MQ (RabbitMQ 等)
安装依赖 Redis 服务器 MQ 服务器
服务器费用 免费 需要 需要
跨进程通信
跨机器通信
全链路追踪
零订阅者零开销
线程执行器控制
使用复杂度 3 个概念 需要配连接、序列化 需要配交换器、队列

小结

ionet 的分布式事件总线用 3 个概念替代了一整套中间件生态。它不只是"功能上的替代",在性能(零网络开销)、可观测性(全链路追踪)和运维成本(零安装)上都有显著优势。

更重要的是,它让"事件驱动"这种强大的架构模式变得真正低门槛------你不需要理解 Exchange、Binding、Queue、Consumer Group 这些概念,只需要知道:定义事件、写订阅者、发布事件。


更多资源

下一篇预告:[无锁并发不再难 ------ ionet 线程执行器设计哲学]

相关推荐
2501_918126912 小时前
学习所有6502游戏的系统
java·汇编·嵌入式硬件·学习·游戏
智算菩萨2 小时前
与AI一起记忆:从分布式记忆到AI策划记忆与人机共忆——文献精读
论文阅读·人工智能·分布式·深度学习·ai·文献
Mr Aokey2 小时前
快速入门 Spring Boot 拦截器、统一响应格式和全局异常处理
java·开发语言·aop·拦截器
鬼蛟2 小时前
Spring_MVC
java·spring·mvc
珠海西格2 小时前
4 月 1 日起执行分布式光伏监控新规,直接影响从业者与项目收益
大数据·运维·服务器·分布式·能源
中议视控3 小时前
会议室和展厅分布式网络中控系统主机的选购思路
网络·分布式
怀旧诚子3 小时前
timeshift之Fedora43设置,已在VM虚拟机验证,待真机验证。
java·服务器·数据库
1104.北光c°3 小时前
滑动窗口HotKey探测机制:让你的缓存TTL更智能
java·开发语言·笔记·程序人生·算法·滑动窗口·hotkey
sdm0704275 小时前
yum和开发工具vim/gcc
linux·服务器·centos