去年有个做量化交易的朋友跟我吐槽,说他们系统行情更新延迟飙到800毫秒,交易员差点把键盘砸了。后来我看了眼架构——MySQL单表硬扛实时写入,Redis当摆设。这种配置放在2024年,约等于用自行车送外卖。
今天这篇是个技术流水账,但背后的问题很典型:当Kafka里的行情数据涌进来,你怎么保证下游既不掉链子、又能被业务方秒级读到?作者用Spring Boot搭了个Broker Asset API,核心就四个字—— hybrid persistence(混合持久化)。SQL管账本,Redis管门面,Flyway管版本。听起来像标准答案?执行细节里全是坑。
Flyway:Schema版本控制的"后悔药"
作者第一件事不是写业务代码,而是给MySQL上了Flyway。这个选择本身说明团队吃过亏——早期项目里我见过太多"本地能跑、上线就炸"的惨案,根因多半是数据库Schema没同步。
具体实现很朴素:assets表存ticker代码、资产名称、当前价格、状态字段。四个字段,没搞花哨的扩展字段设计。MVP阶段这种克制是对的,但作者也留了口子——「未来会回来补单元测试、异常处理和韧性机制」。翻译成人话:现在能跑就行,先别崩。
Flyway的迁移脚本长什么样?原文没贴,但从上下文推断,大概率是V1__Create_assets_table.sql这种命名规范。好处是CI/CD pipeline里能自动执行,坏处是团队得约定好"谁改Schema谁负责评审"。我见过有团队把Flyway当黑盒用,结果生产环境执行到一半锁表,交易时段直接停摆。
Kafka消费者:从"能收到"到"敢消费"
代码片段里那段@KafkaListener很干净,就三行:收消息、打日志、调Service。但隐藏的信息密度不低。
topic名称trading-assets-market-data-v1带版本号,这是Event Streaming里的防御性设计。v1意味着将来可能有v2,消费者可以灰度迁移。groupId用broker-asset-api,确保同一服务多实例时不会重复消费。这些命名规范没写在代码注释里,但懂行的一眼能看出团队有SRE背景。
真正有意思的是消费逻辑的选择。作者没用Kafka Streams做实时计算,也没甩给Flink,而是最简单的"收到即写"。这个决策背后是个权衡:行情数据的价值衰减极快,延迟超过100毫秒就可能被套利算法捡漏。但MVP阶段,先保证端到端通,比优化单点延迟更重要。
我好奇的是offset提交策略。原文没提是自动提交还是手动提交,也没说有没有做幂等。如果updateAsset里MySQL事务失败,这条消息是重试还是丢弃?这些问题现在被压在TODO里,但上线第一周就会冒出来咬人。
Redis+MySQL:双写的甜蜜与负担
Service层的实现是全文最值得关注的设计。作者没说具体代码,但明确点了两个操作:写MySQL、刷Redis。这就是典型的Cache-Aside模式,也是最容易埋雷的地方。
双写的时序怎么保证?先写库再刷缓存,还是反过来?如果Redis挂了,MySQL还写不写?原文没给答案,但给了个线索——「ultra-low latency serving」。说明Redis在这里不是可选优化,是硬性SLA要求。下游查询资产价格时,大概率直接走Redis,MySQL只是持久化兜底。
这种架构下,数据一致性是个选择题。强一致性需要分布式事务,性能代价高;最终一致性需要容忍短暂的不一致窗口,金融场景里可能触发风控误报。作者选了哪条路?从MVP的定位推测,应该是后者,但留了条注释说未来要「increase resilience」。
有个细节值得玩味:REST endpoints是给"other services or the front-end"用的。微服务架构里,这种表述通常意味着还没想好要不要暴露公网API,先内网用着。网关层、限流、鉴权,这些都没出现在当前版本里。
MVP的诚实与代价
作者反复提MVP策略,这种坦诚在技术博客里不多见。很多团队会把半成品包装成"云原生最佳实践",结果读者抄回去发现坑比功能多。
但MVP的代价也很实在。现在这套系统能扛多少TPS?Redis内存上限多少?MySQL连接池配了多大?这些数字一概没有。不是作者不想写,是确实没跑到那一步。就像你刚搭好厨房灶台,还没开火,就问能同时出多少道菜——没意义。
下篇预告里提到的Broker Wallet API,会把复杂度再抬一档。资产有了,得有人持有,得有账户体系,得处理并发扣款。那时候今天埋的坑——异常处理、幂等性、分布式事务——会集体浮出水面。
作者最后抛了个问题:「What do you think of this step-by-step approach to building an ecosystem?」
我的反问是:当你的Kafka lag突然飙到10万条,而Redis实例刚好在这个窗口挂了,你的fallback策略是什么?是先返回 stale 数据让交易继续,还是直接拒绝服务保数据正确性?这个选择没有标准答案,但必须在写第一行代码前就想清楚。你们团队遇到过类似的权衡吗?
热门跟贴