Spring Boot 整合 Elasticsearch 多集群:如何共用一套 DAO?
摘要: 多集群支持不只是创建多个 ElasticsearchClient,还要把 DAO、逻辑索引、查询语义和客户端生命周期连接起来。本文结合 MetaLite
EsClientManager、BaseEntityEsDao与EsHelper,拆解集群路由、SQL 风格 Criteria 翻译、批量部分失败和当前连接配置边界。
企业系统经常同时使用多个 ES 集群:业务搜索、日志检索、审计归档各自隔离。如果每个 DAO 都手写客户端创建和 Query DSL,连接配置、认证和异常处理很快会分叉。
MetaLite 将“选哪个集群”和“查哪个索引”拆成两个路由层。
一、集群路由和索引路由不是一回事
DAO 通过 @Dao(dataSourceGroup="...") 声明集群名称,EsClientManager 根据名称取得客户端。
实体通过 @Table 声明逻辑索引,TableRouter 再把逻辑索引转换为实际索引,例如按月路由到 app-log-202608。
因此一次查询包含两次选择:
dataSourceGroup → Elasticsearch 集群
logicTable + Query → 物理索引表达式
文章 017 已讨论索引路由;本文关注前一层客户端路由和查询翻译。
二、多集群客户端怎样创建和复用
EsProperties 保存集群列表,每项包含名称、节点、用户名和密码。EsClientManager 使用并发 Map 按名称懒创建:
return clientMap.computeIfAbsent(clusterName, name -> createClient(config));
同一 JVM 中,同名集群只复用一个 ElasticsearchClient。应用关闭时遍历 transport,关闭底层 RestClient 并清空 Map。
懒创建减少未使用连接,但也意味着某个集群配置错误可能在第一次业务请求时才暴露。关键集群应增加启动探测或就绪检查。
三、当前节点配置支持到什么程度
节点字符串按逗号拆分,每个节点必须是 ip:port,协议固定为 HTTP。用户名和密码同时非空时启用 Basic Auth。
当前没有暴露这些配置:
- HTTPS 和证书信任;
- 节点 URL 路径;
- 连接、读取和请求超时;
- 连接池参数;
- API Key 等认证方式。
所以“支持多集群”不等于适配所有生产 ES 部署形态。接入托管集群或 TLS 集群前,需要扩展客户端配置。
四、公共 Criteria 如何翻译为 ES 查询
EsHelper 将高频操作符映射到 Bool Query:
- EQ、范围、IN、非空等进入 filter;
- NE、NIN 和 IS_NULL 进入 must_not;
- MATCH、MATCH_PHRASE 进入 must;
- GEO_DISTANCE 构造地理距离查询;
- LIKE 根据通配符位置选择 prefix 或 wildcard。
filter 不参与相关性评分,适合精确筛选;全文检索使用 must,保留评分语义。
这体现了公共 Criteria 的原则:统一查询意图,不伪装成 SQL 和 ES 完全等价。
五、LIKE 翻译为什么特别容易误用
abc% 会被翻译为 prefix,其他带 % 的形式转为 wildcard。它们通常作用于未分词的 keyword 字段。
如果字段是 text,分析器已经改变词项;如果使用前置通配符,查询成本也可能明显上升。
因此同一个 like 调用在 MySQL 和 ES 中只能表达“近似包含意图”,性能和匹配结果仍取决于 mapping。
六、字段选择和排序有哪些差异
公共 Query 的 include/exclude 字段会转换为 _source filter,普通排序转换为 field sort,带 GeoPoint 的排序则使用 geo distance sort。
JDBC 的 GroupBy 当前不会在 BaseEntityEsDao 中得到对应实现。公共对象里存在某个属性,不代表每个存储引擎都消费它。
调用方应按 DAO 实现能力使用 Query,不能只根据公共接口推断全部功能。
七、按条件更新为什么使用 Painless
ES 没有关系数据库式 UPDATE ... SET ... WHERE ...。updateByCriteria 把 Update 字段转换为参数化 Painless 脚本,再调用 update-by-query。
字段值通过 params 传入,避免直接拼值;字段名则进入脚本源。字段最好来自方法引用或受控元数据,不能接受外部任意字符串。
大范围 update-by-query 还会占用集群资源,生产环境需要限制条件范围、超时和冲突策略。
八、批量成功数可能掩盖部分失败
批量新增和批量更新统计 item.error() == null 的条目数并返回。只要部分成功,方法可能返回一个小于输入数量的数字,而不一定抛出整体异常。
调用方如果忽略返回值,就会把部分失败当成成功。
可靠批量链路应检查:
- 成功数是否等于输入数;
- 每个失败项的索引、ID 和原因;
- 是否允许重试,重试会不会重复写入;
- 路由到多个索引时如何汇总结果。
九、JacksonJsonpMapper 与应用 FastJson2 不冲突吗
ES Java Client 的 transport 使用 JacksonJsonpMapper,而 Web MVC 使用 FastJson2。它们位于不同协议边界:一个负责 ES 客户端 JSONP 映射,一个负责应用 HTTP 与框架 JSON 工具。
但同一实体经过两套序列化器时,日期、字段忽略和自定义注解可能表现不同。实体模型必须用集成测试验证,不能假设 FastJson2 全局配置会影响 ES 客户端。
十、多集群能力最终要验证什么
一套可运营的多集群 ORM 至少需要证明:
- DAO 名称能稳定路由到正确集群;
- 逻辑索引与物理索引读写对称;
- Criteria 在目标 mapping 上语义正确;
- 客户端超时、认证和 TLS 满足部署要求;
- 批量部分失败不会被忽略;
- 应用关闭时所有客户端都能释放;
- 单个集群故障不会被误判为全局成功。
MetaLite 已把客户端路由、索引路由和高频查询翻译串成一条统一 DAO 路径。把未覆盖的连接与失败语义明确出来,才能让“多集群”从配置能力变成生产能力。
框架简介
MetaLite 是面向企业生产环境的新一代 Java 微服务技术底座。系列文章重点分享代码背后的设计思路、技术取舍与工程实践。
源码基线
JDK 21、Spring Boot 3.2.9、Spring Cloud 2023.0.1、Spring Cloud Alibaba 2023.0.1.3,具体组件版本以项目 backend-bom 为准。
作者简介
15 年 Spring 体系企业级开发经验,专注于 Java 微服务架构、工程治理与生产实践。
持续更新
MetaLite 系列内容将持续更新,围绕核心设计、源码链路、技术取舍与生产实践展开。欢迎关注作者,及时获取后续内容。
在线演示
演示地址: https://admin.metalite.top/
演示账号: guess
演示密码: admin@2026

400

被折叠的 条评论
为什么被折叠?



