AI 后端的可观测性:Trace ID 怎么从 MySQL 串到 Doris
问题:一条请求穿过了 6 个系统,日志散落在 6 个地方在 MySQL / Doris / ES 三角选型 描述的架构中,一条用户请求的链路是这样的:
12345用户请求 → Spring AI 应用 → MySQL(写入订单) → Canal(监听 binlog) → Kafka(消息队列) → Doris Routine Load(消费写入) → ES(双写更新索引)
加上 AI 调用:
123→ Spring AI ChatClient → LLM API(OpenAI/Anthropic) → RAG 检索(ES kNN 查询) → Tool 调用(查 MySQL)
一条请求可能穿过 8 个系统。 当用户反馈”我的订单查不到”时,你怎么定位是哪一环出了问题?
日志在每个系统里:
Sprin ...
Doris 4.x 存算分离:什么时候上、怎么上、成本怎么算
存算分离不是”升级”,是架构选择Apache Doris 从 3.0 开始支持存算分离(Cloud 模式),到 4.0/4.1 已经有 2000+ 家公司在生产环境使用。但”2000 家在用”不等于”你该上”。
先搞清楚一个核心问题:存算分离不是存算一体的”升级版”,而是一种不同的架构选择,有不同的适用场景。
存算一体(Shared-Nothing)123BE 节点 1: [计算 + 本地存储] ← 数据分片 1BE 节点 2: [计算 + 本地存储] ← 数据分片 2BE 节点 3: [计算 + 本地存储] ← 数据分片 3
每个 BE 节点既负责计算也负责存储,数据存在本地磁盘。查到哪个节点,就在哪个节点本地计算。
优势: 计算和存储在同一台机器上,数据读取零网络开销,查询延迟最低。
劣势: 计算和存储耦合,扩容时必须同时加计算和存储资源。存储不够了但计算够用?也必须加整台机器。
存算分离(Cloud 模式)1234计算集群 A: [计算] ←→ 计算集群 B: [计算] ←→ 对象存储 (S3/OSS/MinIO) ↕ ...
Spring AI MCP Server 实战:把现有系统暴露给 AI Agent
为什么 MCP 突然重要了如果你一直在跟 Spring AI,可能已经注意到了一个变化:从 Spring AI 2.0 GA 开始,MCP(Model Context Protocol)不再是社区孵化项目,而是被合并进了 Spring AI 核心。
这意味着什么?
你的 Spring Boot 应用现在可以同时扮演两个角色:
MCP Client:连接外部 MCP Server(文件系统工具、数据库访问、第三方 API)
MCP Server:把自己的业务逻辑暴露为 MCP 工具,供任何 MCP 兼容的 AI 客户端调用
以前你写一个 @Tool 方法,只有你自己的 ChatClient 能调用。现在写一个 @McpTool 方法,任何支持 MCP 的 AI 客户端都能调用——Claude Desktop、Cursor、Windsurf,或者另一个 Spring AI 应用的 MCP Client。
这不只是 API 变了,是架构选择变了。
@McpTool 和 @Tool 有什么区别先搞清楚边界。
维度
@Tool(Spring AI 1.x / 2.0)
@Mc ...
数据三角对账兜底:MySQL + Doris + ES 不一致怎么办
问题在 MySQL / Doris / ES 三角选型 一文中,我给出了”MySQL 做事务、ES 做搜索、Doris 做分析”的分工框架。在 ES 与 MySQL 双写一致性 和 Outbox 模式 中,我写了怎么用 MQ 和 Outbox 尽量保证数据同步的一致性。
但有一个问题一直没正面回答:
同步链路再完善,最终也会不一致。怎么办?
CDC 可能丢消息、MQ 可能重复投递、消费者可能超时、ES 的 refresh interval 可能导致刚写入的数据查不到、Doris 的 Routine Load 可能因为数据格式错误跳过一批。这些不是”如果”,是”什么时候”。
当不一致发生时,你的系统需要一个兜底机制——对账。
先定义”不一致”是什么意思三个系统的数据不一致,有几种典型表现:
不一致类型
表现
典型原因
MySQL 有、ES/Doris 没有
新数据在 MySQL 但搜索/分析查不到
CDC 延迟、MQ 丢消息、消费者宕机
MySQL 没有、ES/Doris 有
已删除的数据在搜索/分析里还在
删除 ...
Canal 替换方案:Debezium / Maxwell / DTS — CDC 选型的真实取舍
问题在 从 Canal 到 Doris 的数据同步链路 一文中,我写了用 Canal 做 MySQL → Kafka → Doris 的同步。但有一个问题一直没展开:
Canal 一定是对的选择吗?
如果你在做 MySQL → Doris 的实时同步,可选的 CDC 工具至少有四个:Canal、Debezium、Maxwell、阿里云 DTS。它们都能读 MySQL binlog,都能把变更发到 Kafka。但选错了,运维成本和踩坑深度完全不同。
四个工具各自是什么Canal(阿里)阿里开源的 MySQL binlog 增量订阅组件。国内 Java 生态使用最广泛。
架构:伪装成 MySQL Slave,接收 binlog 事件
数据格式:自定义 protobuf + JSON
部署模型:Server-Client 模式,Canal Server 作为独立进程
管理界面:Canal Admin(Web UI)
社区活跃度:国内活跃,国际几乎无人用
Debezium(Red Hat)Red Hat 开源,基于 Kafka Connect 框架,国际化标准 CDC 方案。
架构:Ka ...
Spring AI 2.0 Advisor 链顺序:为什么 Memory 要在 Tool 前面
一个被忽略的问题在 Spring AI 2.0 GA 升级清单 一文中,我提到了 Advisor 是 Spring AI 2.0 的核心抽象。但有一件事当时没有展开——Advisor 的顺序。
用 Spring AI 的 ChatClient 写一个带对话记忆 + 工具调用的 AI 助手,你可能会这样写:
1234567ChatClient chatClient = ChatClient.builder(chatModel) .defaultAdvisors( new MessageChatMemoryAdvisor(chatMemory), new ToolCallingAdvisor(toolCallbackProvider), new QuestionAnswerAdvisor(vectorStore) ) .build();
看起来没问题。但这个顺序——Memory → Tool → QA——真的是对的吗?
顺序不同,结果可能完全不同。
Advisor 链是怎么工作的先理解 Spring AI 的 Advisor 机 ...
RocketMQ 事务消息 vs Outbox 模式:AI 后端的一致性选择
问题在 之前的文章 里,我写了用 Outbox 模式保证 RAG 数据一致性。核心思路:业务数据和 outbox 记录在同一个数据库事务里写入,然后用 CDC(Canal/Debezium)把 outbox 记录搬到 MQ,消费者再去同步 ES/Doris。
但有一个问题一直被绕开了:
如果你的 MQ 是 RocketMQ,你还需要 Outbox 吗?
RocketMQ 原生支持事务消息——半消息 + 本地事务 + 回查机制。这本身就是”保证本地事务和消息发送原子性”的方案。既然 MQ 原生就能做,为什么还要写一张 outbox 表?
这是做 AI 后端时真实会碰到的选择。两条路都能到终点,但代价不同。
先搞清楚两个方案各自在做什么Outbox + CDC1应用 → MySQL 事务 { 业务表 + outbox 表 } → CDC 监听 binlog → 发送到 MQ → 消费者
核心思想:把”发消息”变成”写数据库”。 只要业务数据和 outbox 记录在同一个事务里,要么一起成功,要么一起失败。消息的发送由独立的 CDC 组件异步完成,与 ...
ES Columnar Mode:当搜索引擎开始做列式分析,数据栈怎么变
Elastic 自己承认了什么2026 年 7 月 9 日,Elastic 官方工程博客发了一篇文章,标题是 Why Elasticsearch is becoming a columnar database。
这篇文章里有一句话值得反复读:
“When your job is to read and reason about a lot of data, columnar storage turns nearly every dimension of cost and performance in your favor.”
这是一个做了 16 年文档搜索引擎的团队,在自己的工程博客上承认:他们最初选择的架构,对于今天大部分用户真正在跑的工作负载(日志、指标、遥测、分析),是错误的选择。
ES 9.5 将引入 Columnar Mode(列式模式),9.6 GA。数据只存一份,按列组织,不需要的索引不建。
这不是”ES 加了个新功能”很多人第一反应是”ES 又加了个存储引擎,跟以前加 doc_values、加 kNN 一样”。
不一样。
之前 ES 每加一个能力,都是在文档模型上” ...
Agent 安全治理:为什么 Agent 必须先"挣得"自主权
一个正在形成的共识UberConf 2026 的安全议题中出现了一句话:
Agents must earn autonomy rather than start with it.(Agent 必须挣得自主权,而不是一开始就拥有它。)
这句话来自 UberConf 2026 的 Agent Governance 分享。它不是技术建议,而是工程原则——和”最小权限原则”一样,正在成为 Agent 工程的默认约束。
为什么”挣得自主权”是正确的原则1. Agent 的 blast radius 比传统服务大得多传统微服务的 blast radius 是可预测的:一个 API 调用失败,影响范围是调用链上的下游服务。
Agent 的 blast radius 是不可预测的:
Agent 可以调用任意工具(包括写数据库、删文件、执行 shell)
Agent 的行为路径不是预定义的,而是模型推理出来的
Agent 可以在”推理”中决定改变自己的行为目标
这意味着:Agent 的权限边界不能用 API gateway 那种”路径+方法”模型来管。
2. OAuth 2.1 token 生命 ...
Spring Boot 3.5 停止支持:Spring AI 2.0 用户的迁移清单
一个被忽视的截止日期2026 年 6 月 30 日,Spring Boot 3.5 正式停止维护(End of Life)。
这意味着什么?
运行 Spring Boot 3.5 的系统不再收到任何安全补丁。Spring Security 和 Spring Cloud Gateway 中已知的可利用漏洞将不再被修复。
而 Spring AI 2.0 GA 要求 Spring Boot 4.0+。
也就是说:如果你在用 Spring AI 2.0,你已经在 Spring Boot 4.0 上了。但如果你还在 3.x,你需要知道这个时间窗口已经关闭了。
为什么这不是”可以慢慢迁”的事在 UberConf 2026 的安全议题中,有一个被反复强调的观点:
Spring Boot 3.5 EOL 不是一个”建议升级”通知,而是一个”安全暴露窗口已打开”的警告。运行未打补丁的 post-EOL 版本面临的是已文档化的、可利用的漏洞,且无法获得后续 CVE 修复。
这不是理论风险。Spring Security 和 Spring Cloud Gateway 的漏洞历史已经证明:公开的 CV ...
AgentScope Java 2.0 vs Spring AI Alibaba Graph:Java Agent 框架的两条路
一个新选手进入了 Java Agent 竞技场2026 年 7 月,阿里巴巴正式发布了 AgentScope Java 2.0 GA。经过 5 个 RC 版本迭代,这个框架从实验性项目升级为生产级 Agent 框架。
但它不是 Spring AI Alibaba Graph 的替代品——它是同一个公司开源的另一条路径。
这让我重新思考一个问题:当阿里同时维护两个 Java Agent 框架时,它们到底在解决什么不同的问题?
AgentScope Java 2.0 的核心设计:Harness 优先AgentScope 2.0 的核心思路可以用一句话概括:
在 ReActAgent 推理内核基础上,增加 Harness 工程化层。
“Harness”这个词很关键。它来自 Claude Code 的设计理念——Agent 不只是”推理 + 工具调用”,还需要一套工程基础设施来支撑它在企业环境里运行。
AgentScope 2.0 内置了 6 个 Harness 组件:
组件
解决什么问题
Workspace
Agent 的文件工作空间,隔离不同 Agent 的文件操作
P ...
MySQL 向量搜索的发行版陷阱:社区版、企业版、Percona、MariaDB 各支持什么?
一个容易被忽略的前置问题前面写”MySQL 9.2 做向量搜索”的时候,默认了一个前提:你用的 MySQL 支持 HNSW 索引和 VECTOR_DISTANCE 函数。
但这其实是个陷阱。
不是所有 MySQL 都能做向量搜索。 甚至不是所有 MySQL 9.x 都能做。你在网上看到的教程可能跑在你本地就报错,原因不是你的 SQL 写错了,而是你的 MySQL 发行版根本不支持这个功能。
这篇文章把这个盲点补上。
MySQL 向量搜索的版本碎片化MySQL 9.0:VECTOR 类型有了,但社区版是残缺的MySQL 9.0 创新版引入了原生的 VECTOR 数据类型。但关键问题是:
社区版(Community Edition):只有 VECTOR 类型本身,没有 HNSW 索引,连 DISTANCE 函数都没有。
企业版 / HeatWave / MySQL AI:才有完整的向量索引和距离计算功能。
这意味着什么?如果你用 MySQL 9.0 社区版,你能建一个 VECTOR(768) 的列,往里面存向量数据,但你没法高效检索——没有索引就是全表扫描,没有 D ...
RAG 召回率从 68% 到 91%:混合检索 + 重排序的完整方案
纯向量搜索的天花板在之前的文章里,我讨论过用 ES 的 kNN 做语义检索,以及用 MySQL 9.2 的 VECTOR 类型做 RAG。这些方案在中小规模场景下够用,但有一个容易被忽略的问题:纯向量搜索的召回率不够高。
举一个真实的例子。用户问:”Spring Cloud 微服务网关的限流策略”。
向量检索召回:理解了”微服务”和”限流”的语义关系,但可能漏掉了精确匹配”Spring Cloud Gateway”这个词的文档。
BM25 关键词检索召回:精确匹配了”限流”这个词项,但无法理解”网关”和”Gateway”是同一个东西。
两条路各有盲区。在企业知识库场景,80% 的查询同时需要语义理解和关键词精确匹配。
参考数据(基于某企业客服知识库,5 万文档):
检索方式
Recall@10
Precision@5
纯向量检索
~68%
~64%
纯 BM25
~72%
~78%
混合检索
~91%
~87%
混合检索把召回率从 68% 提到 91%,提升 31%。这就是为什么”混合检索 + 重排序”正在成为企业级 RAG 的标配。
混合检索:BM25 + ...
Spring AI 的 Agent 野心:从 Recursive Advisors 到 ACP / A2A
一个判断需要修正在之前的文章里,我写过一句结论:
“Spring AI 官方定位是’连接企业数据和 API 与 AI 模型’——让 LLM 像 JDBC、JMS 那样成为企业系统里一个可插拔的中间件。Spring AI 刻意不做 Agent Framework。”
前半句仍然成立。但后半句——“刻意不做 Agent Framework”——需要修正。
证据来自 Spring I/O 2026。Broadcom 团队(Mark Pollack、Christian Tzolov、Dariusz Jędrzejczyk)在演讲中公开了 Spring AI 的 Agent 路线图,三个关键词:
Recursive Advisors — 受控迭代框架,Agent 的核心是上下文编排器
ACP(Agent Client Protocol) — 标准化 client → agent 通信
A2A(Agent-to-Agent) — 直接 Agent 协作
目标是构建生产级 Agent 系统,包括编码 Agent(类似 Claude Code)。
这不是”可能做”,是”正在做”。判断 ...
Spring AI 2.0 ToolSearch 实战:100 个工具只发 5 个,token 节省 64%
100 个工具的 Prompt 危机你接了一个企业级 AI 助手项目,把公司所有内部系统都包装成了工具:
订单系统:5 个工具(查订单、改订单、退款、发货状态、物流跟踪)
产品系统:4 个工具(查产品、改产品、查库存、上下架)
用户系统:3 个工具(查用户、改用户、注销用户)
财务系统:6 个工具(查账单、开发票、收款、退款、报表、流水)
CRM:5 个工具
ERP:8 个工具
HR:4 个工具
工单系统:6 个工具
BI 报表:10 个工具
知识库:3 个工具
日志系统:5 个工具
数据库直查:12 个工具
第三方 API:28 个工具
合计 100+ 工具。
第一版:”把所有工具描述塞进 Prompt,让 LLM 自己选”。
123456@BeanChatClient chatClient(ChatModel chatModel, List<ToolCallback> allTools) { return ChatClient.builder(chatModel) .defaultTools(allTools.toArray(new T ...
MySQL 9.2 向量搜索内存真相:6KB/行 × 100 万行 = 6GB,你的 BufferPool 撑得住吗?
一个被忽视的容量问题“MySQL 9.2 有原生向量搜索了”——这消息传开之后,很多团队的迁移冲动来了:
“我们之前用的 Milvus 太重了,把向量数据迁回 MySQL 吧,运维简单很多。”
然后开干:
创建 embedding VECTOR(1536) 列
把 100 万条文档的 embedding 灌进去
跑了一次相似度查询
应用层开始抖动
查 MySQL 监控:Innodb_buffer_pool_wait_free 飙到 50+
内存告警
MySQL 9.2 真的能扛百万级向量吗?能。但你必须算清楚内存。
先算账:1536 维 × 4 字节 = 6KB/行向量的物理大小:
12345embedding VECTOR(1536)= 1536 个 float32= 1536 × 4 bytes= 6144 bytes= 6 KB
这只是纯向量数据。加上 InnoDB 的页结构(默认 16KB 一页)、行头(compact 格式约 27 字节)、主键索引、二级索引,每行实际占 7-8KB。
向量规模
向量数据本身
含索引和行结构
10 万行 ...
Spring AI Alibaba Graph 4 大模式实战:顺序、并行、路由、监督
单 Agent 的天花板你写了一个 Agent,注册了 7-8 个工具:查订单、查用户、查产品、生成 Excel、发邮件、生成报告、发送通知……
Prompt 写了几百字描述每个工具的用途。LLM 跑起来。
第一次跑:基本能用。第三次跑:LLM 选了”知识库搜索”而不是”SQL 查询”,因为”查数据”两个工具都沾边。第十次跑:你开始写”必须先用 SQL 工具,否则不通过”的硬约束,Prompt 越来越长。第三十次跑:Prompt 已经 1000+ token 了,LLM 还是偶尔选错。
这就是单 Agent 的天花板:工具一多,准确性断崖式下降。
多 Agent 是解法。Spring AI Alibaba 的 Graph 框架提供了 4 种核心模式:顺序、并行、路由、监督。这篇文章讲清楚每种怎么用、什么时候用。
准备:公共 ChatModel12345678910111213141516public class ChatModelFactory { public static ChatModel getChatModel() { DashScop ...
从 Canal 到 Doris:整条数据同步链路的故障恢复实战
一条典型的 AI 后端数据同步链路数据密集型 AI 后端的标准链路长这样:
12345678910111213MySQL(业务主库) │ │ binlog ▼Canal Server(订阅 binlog) │ │ Kafka topic ▼Kafka(消息缓冲) │ │ Consumer ▼Doris / ES(分析 + 搜索)
看起来很标准。但链路越长,能挂的环节越多。生产上我处理过的事故:
Canal 订阅位点丢失,从头重做导致下游重复消费 6 小时
Kafka 集群重启,Consumer Group rebalance 时部分 partition 没被认领
Doris stream load 报 -235 错误(数据格式问题),但 Kafka 消息还在
业务库从主库切到备库,Canal 配置没改导致订阅断了 3 小时
**任何一环出错,最终都是”数据丢了一段时间”或者”数据有重复”**。这篇文章讲清楚这条链路每个环节的故障怎么恢复。
链路一环一环看第 1 环:MySQL binlog风险点:
MySQL 服务重启,binlog 写 ...
ES kNN 性能调优实战:num_candidates、ef_search、混合检索权重怎么调?
问题:为什么我的向量检索慢?你接入了 ES 8.x 的 kNN 检索做 RAG,写了第一个版本:
12345678{ "knn": { "field": "embedding", "query_vector": [0.1, 0.2, ...], "k": 10, "num_candidates": 100 }}
跑通。但生产上拿到百万级文档后,开始抖:
P99 延迟 800ms,业务方反馈”问答卡顿”
单次查询 CPU 飙到 80%
加机器不解决问题(瓶颈是单 shard 的 ANN 搜索时间)
问题不在于 ES 不行,在于你没调参。 ES 的 HNSW 索引有 4-5 个核心参数,每个都直接影响性能和召回率。这篇文章讲清楚每个参数怎么调。
ES kNN 检索的执行流程ES 用的也是 HNSW(图算法)。一次 kNN 查询的过程:
123451. 加载 HNSW 索引(如果没缓存)2. 从顶层稀 ...
Doris Routine Load 的 exactly-once 语义:label 机制到底怎么用?
一个生产事故Kafka 里的订单事件正在被 Doris Routine Load 消费,跑了 3 个月没问题。一天运维重启 Kafka 集群,Routine Load 卡住了。
重启后查状态:
SHOW ALL ROUTINE LOAD\G 显示 Job 状态是 RUNNING
但 data_quality 表里显示过去 10 分钟 0 条数据进入
业务方已经反馈”订单数对不上”
排查发现:Kafka 集群重启时,Routine Load 的 offset 提交丢了。重启后 Doris 重新消费了一批 Kafka 消息,但有些消息已经被前一次消费过——SELECT COUNT(*) FROM orders 比真实多 200 条。
这就是”至少一次(at-least-once)”的代价。Doris Routine Load 的官方文档写”支持 exactly-once”,但你必须正确使用 label 机制。
“exactly-once” 这个词在 Doris 里到底是什么意思?Doris 官方文档里写:
Routine Load 支持 exactly-once 语义,依赖 Kafk ...
Spring AI + MySQL 用 Outbox 模式保证 RAG 数据一致性
一个 RAG 系统常见的”半成品”状态你刚上线一个 RAG 知识库,流程是:
1用户上传文档 → Spring AI 切分 + Embedding → 写入 MySQL 的向量表 → RAG 检索可用
跑通了。但 3 天后你发现一个诡异问题:
用户在管理后台明明看到”文档已上传”
但 RAG 问答时这条文档从来没被检索到
排查发现:MySQL 业务表写了,但向量表 INSERT 失败了——可能是 OOM、可能是事务冲突、可能是 Spring AI 的 batching 异常。结果就是业务数据”已上传”和向量数据”已索引”不一致。
更糟糕的是:这种不一致默默存在,用户问不到,运营看不到,只有最细心的人翻日志才能发现。
这不是 Spring AI 的问题这是分布式数据写入的经典问题。任何”两个存储系统一起写”的场景都躲不开:MySQL + ES、MySQL + 缓存、MySQL + 搜索索引。RAG 只是最新的受害者。
三种”传统”解决方式都有明显缺陷:
方式 1:应用层 try-catch 回滚
123456789transactionTemplate.execute(status ...
Doris 与 ES 同时存在:实时分析用谁、搜索用谁?别让两个 OLAP 打架
一个越来越常见的架构数据密集型 AI 后端项目里,下面的架构正在变多:
12345MySQL(业务主库) │ ├──→ Elasticsearch(搜索 + 向量检索 + 业务聚合) │ └──→ Doris(实时分析 + 报表 + 离线宽表)
问题来了:ES 和 Doris 都能做”聚合查询”,都能做”全文搜索”,都能做”向量检索”。两个一起跑,是不是重复了?能不能砍掉一个?
这是个真实的问题。我自己的踩坑经历是:砍不掉,但必须划清边界。这两个系统在”重叠区域”上看起来都能做,但做了之后的工程成本、运维成本、性能特征完全不同。
各自最擅长什么?Elasticsearch 真正擅长的
多字段全文搜索(中文分词、拼音、纠错、同义词、相关度调优)
多维度过滤聚合(facet、nested aggregation、cross-field query)
向量检索 + 混合搜索(kNN + BM25 一条 query 解决)
时序日志场景(Logstash + Beats 生态成熟)
模糊匹配(fuzzy query、wildcard、regex)
核心优势:搜索领域的工具链成熟度。 ...
Spring AI 2.0 GA 升级清单:从 1.x 迁过来的 5 个必看变化
为什么要升级Spring AI 2.0 GA 在 2026-06-12 发布,距离 1.0 不到一年。但这次的升级不是版本号小跳,而是把 1.x 时代所有”能用但别扭”的地方做了重写。
如果不升级,1.x 还能用,但你会逐渐被以下问题卡住:
工具超过 20 个时 token 爆掉
不同 ChatModel 的 Tool Calling 行为不一致
配置项命名混乱(.options 段、toolNames() 等)
MCP 集成停留在早期规范
项目想升级 Spring Boot 4 时和 Spring AI 1.x 不兼容
反过来,升级的代价是真实的:Spring AI 2.0 硬依赖 Spring Boot 4.0/4.1 + Spring Framework 7.0 + Java 17(推荐 21),整个项目的依赖链都要跟着走。
变化 1:基线重定义,升级是”全家桶”2.0 依赖:
Spring Boot 4.0 / 4.1
Spring Framework 7.0
Jackson 3(不是 Jackson 2)
Java 17 起步,推荐 21
MCP J ...
MySQL / Doris / ES 三角选型:数据密集型 AI 后端怎么决定谁做什么?
问题“我应该把数据放在哪?”
这是任何一个数据密集型 AI 后端项目启动时第一个会撞上的问题。但不是”哪个最好”的问题,而是”应该用哪几个、各自负责什么”的问题。
今天 Java 后端做 AI 应用,可选的”核心数据组件”基本就是这三件套:MySQL、Doris、Elasticsearch。再加一个 MQ 做异步。
但这三个东西看起来都能存数据、都能做查询,凭什么非要全用上?为什么不能只用一个?
重新认识这三件东西在聊选型之前,必须先纠正一个常见误解:这三件东西不是同类。
组件
真正擅长的事
不擅长的事
MySQL
强一致事务、随机点查、行级更新、垂直扩展
大规模 OLAP 聚合、模糊搜索
Doris
大数据量 OLAP 聚合、列存压缩、向量化执行
强事务(只能最终一致)、行级单点更新
Elasticsearch
倒排索引全文搜索、近似向量检索、多维度过滤
强事务、复杂 JOIN、精确聚合统计
它们在 2026 年都开始”补对方的能力”:MySQL 9.2 有了向量搜索,Doris 4.x 有了全文搜索+向量+AI Functions,ES 也有了 PPL 之类 ...
Agent 会先改变代码评审,而不是完全替代编码
Agent 会先改变代码评审,而不是完全替代编码AI 编程工具让代码生产速度大幅提升,但代码审查速度没有同步提升。
这制造了一个新的瓶颈:审查队列变长、大型 PR 被”扫一眼就过”、人类审查者疲劳加剧。Agent 最先切入的,不是取代程序员写代码,而是接管审查流程中结构化、可规模化复制的部分。
审查正在成为瓶颈Anthropic 内部数据显示,在使用 Claude Code Review 之前,只有 16% 的 PR 收到实质性审查意见。这意味着 84% 的 PR 只是被快速浏览后就合并了。
原因很直接:
AI 让单个工程师的代码产出增长了约 200%。
但审查者还是那些人,每天还是那么多小时。
PR 数量增加、单个 PR 复杂度上升、审查者上下文切换成本更高。
结果不是代码质量下降,而是质量保障体系开始跟不上生产节奏。
为什么 Agent 先改变的是审查?代码评审有几个特点,让它特别适合 Agent:
1. 任务高度结构化审查有明确的输入(diff、测试、上下文)和输出(评论、建议、风险标记)。这比”从零写一个新功能”更容易被形式化。
2. 上下文可枚举一次 PR 改动了什么 ...
为什么模块化单体正在回归?
为什么模块化单体正在回归?微服务曾经是一种信仰。
2015 到 2020 年间,几乎所有技术大会都在讲 Netflix、Amazon、Google 的微服务故事。结论是:大公司用了,我们也应该用。于是无数团队把系统拆成十几个、几十个服务,仿佛服务数量本身就是工程成熟度的指标。
2026 年,钟摆正在回摆。不是回到混乱的大泥球,而是回到一种更克制的中间态:模块化单体。
发生了什么?微服务被过度推销了。
Netflix、Amazon 采用微服务,是为了解决数百个工程团队、数亿用户带来的问题。这些问题对于一家 20 人的初创公司来说并不存在。但很多人忽略了这个前提,直接复制了答案。
结果是可预测的:
服务发现、分布式追踪、网络可靠性、数据一致性、部署编排——基础设施工作吞噬了大量本应用于产品的工程能力。
一个原本简单的功能,现在要跨多个服务协调部署。
调试生产问题意味着追踪几十个服务各自的日志和监控。
到了 2023 年前后,一些公司开始公开往回走。Amazon Prime Video 团队发布案例:将微服务整合为单体后,**成本降低 90%**。Shopify 则一直坚持自己的模块化 ...
AI 时代,后端工程师的哪些能力正在贬值?
AI 时代,后端工程师的哪些能力正在贬值?2026 年,后端工程师这个群体正在经历一次静默而剧烈的价值重估。
不是岗位消失,而是市场对”后端工程师”的定义在重写。过去十年里被视为核心竞争力的许多能力,正在快速贬值;而另一些长期被低估的能力,突然变得稀缺。
这不是贩卖焦虑,而是一组正在发生的信号。
一组值得正视的数据
Anthropic 内部数据:生产环境超过 80% 的代码由 Claude 生成,工程师日均代码产出提升约 8 倍。
猎聘 2026 报告:纯编码岗位招聘量暴跌 **52%**,但编程相关岗位总量反增 15%。
GitClear 2026 报告:AI 参与编写的代码,一年内有 47% 被完全重写。
智联招聘 2026 一季度报告:普通后端、前端开发岗位需求同比下降 **52%**。
麦可思《2026 年中国大学生就业报告》:计算机类专业跌出绿牌榜,自动化专业首次跻身绿牌。
这些数据拼在一起,指向一个结论:**市场不再需要”会写代码的人”,市场需要”能用 AI 解决问题的人”**。
这两个身份曾经高度重合,现在正在快速分离。
正在贬值的能力1. 纯语法与 API 记忆过 ...
Doris 4.x 的 AI 化:向量搜索 + AI Functions 意味着什么?
Doris 在做什么Apache Doris 从 4.0 开始,加入了一个新方向:AI 支持。具体包括:
向量搜索:原生支持向量存储和 ANN 检索,类似专用向量数据库的能力。
AI Functions:SQL 中可以直接调用大模型(如 ai_generate() 函数)。
全文搜索增强:和向量搜索结合做混合检索。
这听起来有点像”Doris 想做向量数据库”。但它的实际意图比这更有趣。
为什么一个 OLAP 数据库需要向量搜索?Doris 的核心用户是数据分析师和运营人员。他们的问题是:”上个月销售额最高的品类是哪些?和去年同期比有什么变化?”
但现在的问题是:”为什么这个品类的销量突然下降了?帮我分析原因。”
这个问题的答案不在结构化数据(数字)里,而在非结构化数据里——用户评价、客服对话、社交媒体反馈。传统的 Doris 只能算数字,不能”理解”文本。
Doris 加向量搜索不是为了抢 Milvus 的饭碗,而是为了把”结构化分析”和”非结构化检索”放在同一个引擎里。
具体能做什么?1. “找出和这个问题最相似的历史案例”123456-- 用向量搜索召回与当前问题最相似的历史 ...
Spring AI vs Spring AI Alibaba:Java AI 开发的两个选择
两个框架,一个生态2026 年,Java AI 开发生态最核心的两个框架是 Spring AI 和 Spring AI Alibaba。很多人听到名字以为后者是前者的”阿里版封装”,但实际关系比这复杂。
Spring AI 2.0:2026 年 6 月 12 日发布 GA,基于 Spring Boot 4.1 和 Spring Framework 7.0。官方定位是”连接企业数据和 API 与 AI 模型”——让 LLM 像 JDBC、JMS 那样成为企业系统里一个可插拔的中间件。
Spring AI Alibaba 1.1.2.0:基于 Spring AI 规范构建,但聚焦于多智能体编排(Multi-Agent Orchestration)。内置 Agent 框架、Graph 工作流引擎、MCP 双端支持。
通俗类比:Spring AI 是 Java 的 LangChain(怎么接入 AI),Spring AI Alibaba 是 Java 的 LangGraph(怎么让多个 AI 协同工作)。两者不是竞争关系,是互补关系。
架构层次对比12345678910应用层: ┌───── ...
MQ 在 AI 后端的新角色:从异步解耦到 Agent 事件总线
MQ 的传统角色MQ 在后端架构里一直是”老三样”:
异步解耦:订单创建后,发消息通知库存、物流、通知系统,各系统独立消费。
削峰填谷:秒杀流量来了,MQ 先扛着,后端慢慢消费。
最终一致性:分布式事务的兜底方案——本地事务 + MQ 消息 = 可靠异步通知。
这三个角色在今天仍然重要。但 AI 后端的出现,给了 MQ 一些新的可能性。
Agent 需要一个事件总线看一个场景:用户在 Spring AI 应用里发起一个对话,Agent 需要串联多个操作——搜索 ES、查 MySQL、调用外部 API、生成回答。
传统做法是把这些调用写在 Agent 的逻辑里,串行执行。但如果 Agent 需要等待一个长时间操作(比如跑数据分析、等第三方回调),串行就不行了。
这时候 MQ 可以扮演 Agent 事件总线:
1234用户提问 → Agent 发布"需要搜索文档"事件 → MQ → ES 搜索 Worker 消费 → 返回结果事件 → MQ → Agent 消费结果 → 发布"需要生成回答"事件 → MQ → LLM ...
Spring AI × ES:用 kNN 检索做 RAG,统一搜索 + 问答栈是否成立?
问题一个业务系统通常有两套”检索”:
关键词搜索:用户在搜索框输入”Java 教程”,ES 用 BM25 返回最匹配的文档。这是传统搜索。
语义检索:用户在 AI 对话里问”怎么学 Java”,RAG 用向量相似度从知识库召回相关内容。这是 AI 搜索。
传统做法是两套栈:ES 做关键词搜索,Milvus/Qdrant 做语义搜索。但 ES 从 8.x 开始原生支持 kNN(k-Nearest Neighbors)向量检索。于是就有一个诱人的想法:能不能只用 ES 一套,同时做关键词搜索和 RAG 语义搜索?
ES 的 kNN 做了什么ES 8.0 引入了 dense_vector 字段类型 + knn 查询。8.12 后做了性能优化,支持 HNSW 索引。
123456789101112131415161718192021222324// mapping 定义{ "mappings": { "properties": { "content": { &qu ...
Doris 的数据从哪来:Kafka/RocketMQ 导入的几种姿势与取舍
背景Doris 不是凭空产生数据的。它是个”理解数据”的引擎,数据需要从别处来。
在数据密集型后端架构里,数据来源通常是:
业务数据库(MySQL):用户、订单、商品等结构化数据
日志/埋点:用户行为、系统日志等半结构化数据
外部数据:第三方 API、合作伙伴数据
这些数据到达 Doris 的路径大致是:
1数据源 → 消息队列 → Doris
消息队列是整个数据管道的”中央动脉”。理解不同的接入方式及其取舍,是搭建数据处理链路的基础。
方式一:Routine Load(最常用)Routine Load 是 Doris 从 Kafka 持续消费数据的方式。提交一个例行导入任务后,Doris 会持续从 Kafka 拉取数据,实时写入。
12345678910111213CREATE ROUTINE LOAD example_db.routine_load_job ON user_behaviorCOLUMNS(user_id, event_type, event_time, page_url)PROPERTIES( "desired_concurrent_ ...
ES 与 MySQL 双写一致性:MQ 能解决到什么程度?
这个老问题为什么一直存在?ES 和 MySQL 双写一致性,是一个”二十年前不存在、十年前开始出现、今天几乎人人遇到”的问题。
套路是这样的:用户更新了一条数据,MySQL 写成功了,然后你要把这条数据同步到 ES 让搜索能搜到。如果中间某个环节失败了——MySQL 写成功但 ES 写失败,或者反过来——数据就不一致了。
这个问题一直没被”一劳永逸”地解决,因为它在不同阶段有不同的约束:
十年前:数据量小,可以”更新完 MySQL 再更新 ES”,同步调用,失败重试。
五年前:数据量变大,同步调用扛不住,引入 MQ 异步,但引入了一致性问题。
今天:AI 应用兴起,搜索结果的准确性直接影响用户体验甚至安全(RAG 召回不一致 = 回答错误)。
MQ 在中间做了什么?典型的 MQ 异步同步架构:
1应用 → 写 MySQL 成功 → 发 MQ 消息(包含变更数据) → 消费者 → 写 ES
MQ 解决了什么:
解耦:业务代码不需要关心 ES 是否写成功,只要 MQ 消息发出去了就算”同步任务已提交”。
削峰:高峰期大量写入不会因为 ES 慢而拖垮业务接口。
重试:消费失 ...
MySQL 与 Doris 的真实边界:OLTP/OLAP 的分工逻辑
问题“我们有 MySQL 了,为什么还要 Doris?”
“Doris 号称 HTAP,是不是可以把 MySQL 省了?”
这两个问题本质上是同一个困惑:OLTP 和 OLAP 的边界在哪里,Doris 有没有在抹平这条线?
先理清概念OLTP(在线事务处理)= MySQL 的主场。 特点是:大量小事务、高并发读写、毫秒级响应、强一致性。
OLAP(在线分析处理)= Doris 的主场。 特点是:少量大查询、批量扫描、秒级响应可接受、最终一致性通常够用。
MySQL 做 OLAP 查询(比如”统计过去一年每个品类的日均销量”)慢的原因不是 MySQL 写得不好,而是它用的索引结构(B+ Tree)和存储格式(行存)根本不是为扫描设计的。行存意味着即使你只查两个字段,它也要把整行读出来。
Doris 用的是列存。列存意味着只读查询需要的列,跳过其他所有数据。同时 Doris 的 MPP(大规模并行处理)架构可以把一个查询拆成多份,在多台机器上并行跑,然后汇总。
HTAP 在抹平这条线吗?HTAP(Hybrid Transactional/Analytical ...
Spring AI 接入 MySQL 做 RAG:什么时候够用,什么时候该换专用向量库?
问题搭建一个 RAG(检索增强生成)系统时,第一反应往往是”我得搞个 Milvus 或 Qdrant”。但如果你已经有 MySQL 存业务数据,能不能直接用 MySQL 存向量,省掉一个中间件?
直到最近,这个问题的答案是”生产环境别这么干”。但现在情况变了。
变化:MySQL 9.2 原生向量搜索生产就绪2026 年 MySQL 9.2 发布,HNSW 索引直接集成在 InnoDB 引擎内部,支持 SIMD 硬件加速,性能对标专用向量引擎。
MySQL 8.4 就有 VECTOR 类型,但那更像”能用”的阶段——百万级以内勉强跑,上了生产就开始抖。9.2 版本的关键不在于”支持向量”,而在于向量操作和传统 SQL 操作共享同一套事务、MVCC、备份恢复体系。
这意味着什么?意味着你不需要维护两套数据一致性逻辑。业务数据在 MySQL,向量数据也在 MySQL,一次 JOIN 就能做”找出分类=Java 且语义相似的前 10 个文档”——这在”MySQL + 专用向量库”架构里需要两次查询 + 应用层合并。
Spring AI 怎么接Spring AI 内置了对多种向量存储的 ...
MyBatis ResultMap 吞行问题
MyBatis ResultMap 吞行问题
你写了一对多关联查询,数据库中明明有 10 行数据,MyBatis 返回的列表却只有 3 条。剩下的 7 行去哪了?这就是经典的 ResultMap “吞行”问题。
现象:数据去哪了?假设你有一张订单表 t_order 和一张订单明细表 t_order_item,一个订单可以包含多个商品明细:
123456789101112-- 订单CREATE TABLE t_order ( id BIGINT PRIMARY KEY, order_no VARCHAR(32));-- 订单明细CREATE TABLE t_order_item ( id BIGINT PRIMARY KEY, order_id BIGINT, product_name VARCHAR(64));
你写了一个 SQL 用 JOIN 关联查询:
123456789<select id="getOrders" resultMap="OrderResultMap"> SELECT ...
好文章收集
文字收集原则:同话题文章取最优,同话题多文章必须有多文章的理由
AI彻底爆了!一文吃透AIGC、Agent、MCP的概念和关系
埃隆马斯克 - 放眼未来 无所畏惧
埃隆马斯克 - 放眼未来 无所畏惧
