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

一个熟悉的场景

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

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

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

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

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


三个概念,全部学完

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

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

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


实战:玩家登录事件

第一步:定义事件源

@ProtobufClasspublicclassUserLoginEventMessage{publiclong userId;publicstaticUserLoginEventMessageof(long userId){var message =newUserLoginEventMessage(); message.userId = userId;return message;}}

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

第二步:编写订阅者

@EventBusSubscriberpublicclassEmailEventBusSubscriber{@EventSubscribepublicvoidmail(UserLoginEventMessage message){ log.info("发送欢迎邮件给用户 {}", message.userId);// 实际业务:调用邮件系统发送欢迎邮件}}@EventBusSubscriberpublicclassRewardEventBusSubscriber{@EventSubscribepublicvoidcalcReward(UserLoginEventMessage message){ log.info("计算离线奖励给用户 {}", message.userId);// 实际业务:查询上次登录时间,计算奖励}}

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

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

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

publicfinalclassEmailLogicServerimplementsLogicServer{@OverridepublicvoidsettingBarSkeletonBuilder(BarSkeletonBuilder builder){ builder.addRunner((EventBusRunner)(eventBus, _)->{ eventBus.register(newEmailEventBusSubscriber());});}}

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

@ActionMethod(0)privateUserMessagelogin(FlowContext flowContext,LoginMessage message){// 处理登录逻辑...// 发布登录事件var event =UserLoginEventMessage.of(flowContext.getUserId()); flowContext.fire(event);returnnewUserMessage("登录成功");}

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


四种发布粒度

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

fireMe:仅当前逻辑服

flowContext.fireMe(event);// 异步 flowContext.fireMeSync(event);// 同步

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

fireLocal:当前进程所有逻辑服

flowContext.fireLocal(event); flowContext.fireLocalSync(event);

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

fire:全局发布

flowContext.fire(event); flowContext.fireSync(event);

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

fireAny:同类型只发一个

flowContext.fireAny(event); flowContext.fireAnySync(event);

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


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

这是 ionet EventBus 最精妙的设计:

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

这意味着什么?

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

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


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

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

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

实现方式

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

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

同样的思路还可以用于:

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

订阅者线程执行器

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

@EventBusSubscriberpublicclassMySubscriber{// 默认策略:使用用户线程执行器(与 Action 共用线程,线程安全)@EventSubscribepublicvoidonLogin(UserLoginEventMessage message){...}// 虚拟线程策略:适合 IO 密集型操作@EventSubscribe(ExecutorSelector.userVirtualExecutor)publicvoidsaveToDB(UserLoginEventMessage message){...}// 方法级线程策略:同一订阅者方法永远在同一线程@EventSubscribe(ExecutorSelector.methodExecutor)publicvoidupdateRank(UserLoginEventMessage message){...}}

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


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

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

小结

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

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


更多资源

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

Read more

人工智能:自然语言处理在金融领域的应用与实战

人工智能:自然语言处理在金融领域的应用与实战

自然语言处理在金融领域的应用与实战 学习目标 💡 理解自然语言处理(NLP)在金融领域的应用场景和重要性 💡 掌握金融领域NLP应用的核心技术(如文本分类、情感分析、风险评估) 💡 学会使用前沿模型(如BERT、GPT-3、Transformer)进行金融文本分析 💡 理解金融领域的特殊挑战(如数据敏感性、实时性要求高、语言专业性强) 💡 通过实战项目,开发一个金融新闻情感分析应用 重点内容 * 金融领域NLP应用的场景 * 核心技术(文本分类、情感分析、风险评估) * 前沿模型(BERT、GPT-3、Transformer)在金融领域的使用 * 金融领域的特殊挑战 * 实战项目:金融新闻情感分析应用开发 一、金融领域NLP应用场景 1.1 金融文本分析概述 金融领域是NLP技术应用的重要领域之一。金融文本数据包括新闻报道、公司公告、分析师报告、社交媒体评论等,这些数据蕴含着丰富的信息,可以帮助金融机构和投资者了解市场动态、评估风险、做出决策。 1.1.

By Ne0inhk

Java List 根据List中对象的属性值是否相同作为同一组,分割成多个连续的子List

需求:Java List 根据List中对象的属性值是否相同作为同一组,分割成多个连续的子List package com.suncd.trs.provider.controller; import java.util.ArrayList; import java.util.List; import java.util.function.Function; public class ListGrouping { /** * 将List按照对象属性值是否相同进行分组,分割成多个连续的子List * @param list 原始List * @param keyExtractor 提取对象属性值的函数 * @param <T> List中对象的类型 * @param <K> 属性值的类型 * @return 分割后的子List集合 */ public static <

By Ne0inhk

A2UI 技术原理深度解析:AI Agent 如何安全生成富交互 UI

本文深入解析 Google 开源的 A2UI 协议,探讨其核心架构、数据流设计以及为何它是 LLM 生成 UI 的最佳实践。 一、A2UI 是什么? A2UI (Agent-to-User Interface) 是 Google 于 2025 年开源的声明式 UI 协议。它解决了一个核心问题: 如何让 AI Agent 安全地跨信任边界发送富交互 UI? 传统的 Agent 交互往往是纯文本对话,效率低下。而直接让 LLM 生成 HTML/JS 代码又存在严重的安全风险。A2UI 提供了一个中间方案:Agent 发送声明式 JSON 描述 UI 意图,客户端使用自己的原生组件渲染。 安全性:

By Ne0inhk
深入解析list:一个完整的C++双向链表实现

深入解析list:一个完整的C++双向链表实现

概述         这是一个完整的模板类 yyq::list 的实现,模仿 C++ 标准库中的 std::list。作为STL中最经典的双向链表容器,list的实现展示了C++模板编程、迭代器设计、链表操作和内存管理的核心技术。本文将完整分析所有代码,包括被注释的部分,不遗漏任何细节。 目录 概述 一、整体架构与设计 1.1 命名空间与头文件保护 1.2 链表节点设计 二、迭代器设计(核心部分) 2.1 第一阶段:两个独立的迭代器类(被注释的初始设计) 2.1.1 普通迭代器 list_iterator 2.1.2 const迭代器 list_const_iterator 2.

By Ne0inhk