![]()
一个巴西开发团队正在搭建股票交易系统,他们的Kafka消费者处理B3交易所(巴西证券交易所)行情数据时,端到端延迟做到了3毫秒。没有用什么高端消息中间件,就是Spring Boot加Redis——但实现方式有点反直觉。
这套系统的核心叫Broker Asset API,负责管理股票代码、实时价格和资产状态。上一篇他们讲了怎么用Python抓B3数据塞进Kafka,这篇解决更麻烦的事:怎么让Java服务把数据吐出来,还要快。
Flyway管数据库:先解决"以后谁记得改了什么"
团队选了MySQL存资产主数据,但一开始就埋了个雷: schema怎么版本控制?
他们用了Flyway。每次数据库结构变更变成可执行的SQL脚本,按版本号排队执行。新成员拉代码就能还原完整表结构,CI/CD流水线也能自动跑迁移。
资产表设计很克制:ticker代码、名称、当前价格、状态字段。没有冗余,因为MVP阶段每多一个字段都是未来的技术债。
这个选择背后是血泪教训。很多金融系统早期图快,手写DDL(数据定义语言)语句,半年后没人记得哪张表为什么加了那个索引。Flyway的代价是多写几行配置,收益是schema变更可审计、可回滚。
Kafka消费者:故意写得"笨"一点
![]()
监听topic的代码简单到像示例程序:
@KafkaListener配置硬编码了topic名称trading-assets-market-data-v1,groupId设为broker-asset-api。收到消息后直接调service层,没有复杂的路由,没有中间状态机。
这种"笨"是设计出来的。作者明确说:现阶段目标是保证端到端流程跑通,而不是优雅。异常处理、重试策略、死信队列——这些全留给未来迭代。
一个细节:日志只打了ticker代码,没打完整消息体。生产环境这么干能省不少磁盘IO,但排查问题时会想骂人。他们显然选了性能优先。
对比国内某些券商的中台系统,喜欢把消费者层做得无比厚重,抽象出七八个接口适配器。巴西这个团队反着来:先让数据流动起来,再谈架构美感。
混合持久化:SQL+Redis的"双写"陷阱
AssetService是业务逻辑核心。收到新价格后,它干两件事:写MySQL做持久化,同步刷Redis做缓存。
这个模式在金融系统里极其常见,也极其容易翻车。双写没有分布式事务,MySQL成功了Redis挂了,或者反过来,数据就不一致。团队现在没解决,作者直接承认:未来要回来加单元测试、细化异常处理、增强韧性。
![]()
Redis在这里的角色不是"加速查询"那么简单。行情数据的特点是读远大于写,但写必须极快。把热点数据放内存,查询延迟从毫秒级降到微秒级,对交易终端的体验是质变。
他们没提Redis的过期策略和淘汰机制。这是隐藏的技术选型:如果用了allkeys-lru,内存满时会踢掉冷门股票的数据——对散户没影响,但对持有那些股票的机构客户,下次查询就要穿透到MySQL。
REST端点:给其他服务"喂数据"
暴露的HTTP接口让前端或其他微服务能查资产目录。设计原则同样是MVP思维:先保证数据能拿到,再谈GraphQL还是gRPC。
一个值得注意的产品决策:资产状态字段是独立维护的。股票可能停牌、退市、限制交易,这个状态会影响下游所有业务逻辑。把它和实时价格放同一个服务,避免了跨服务调用的延迟,但也让这个服务成了单点。
作者用了一个类比:这个资产服务是地基,让系统知道"在交易什么"和"多少钱"。但光有地基建不成房子——资产需要属于某个账户,账户需要有钱。
下一篇他们要讲Broker Wallet API,处理持仓和资金。复杂度会跳一个台阶:并发锁、事务隔离、余额校验,每个都是能写进故障案例库的经典场景。
这种" piece by piece "(逐块搭建)的策略,和国内很多团队"先画完整架构图再动手"的风格截然相反。你更倾向哪种?如果让你选,会先保证核心链路通,还是先把异常分支想全?
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.