从零吃透 Elasticsearch + 分布式基础:倒排索引、DSL、Seata 分布式事务、Redis 分布式锁全记录
这周是我学习 Java 后端的一个分水岭。前六周学完了 Spring Boot、MySQL、Redis、微服务、消息队列感觉自己已经能写业务代码了。但这一周学完 ES 和分布式基础之后我才意识到真正的后端开发远不止 CRUD 那么简单。一、Elasticsearch为什么 MySQL LIKE 不够用1.1 从模糊查询说起之前做项目有个搜索框要查书名。我想当然地写了SELECT * FROM book WHERE title LIKE %Java%。数据量小的时候跑得挺欢等数据上了十万接口直接超时——全表扫描索引用不上。后来才知道MySQL 的 B 树索引是为精确查找和范围扫描设计的。你想查内容里包含哪些词B 树根本帮不上忙。这时候就该 Elasticsearch 出场了。1.2 倒排索引ES 的核心武器ES 用的是倒排索引。打个比方你有一本书传统做法是第 1 页写了什么、第 2 页写了什么正排倒排索引反过来是Java 这个词出现在第 1、5、10 页虚拟机出现在第 3、7 页词 → 页码列表。查询的时候把搜索词分词“Java 虚拟机分成Java和虚拟机”直接查倒排索引表拿到包含这些词的文档 ID根本不用扫全表。这就是为什么 ES 能在毫秒级返回结果。1.3 text 和 keyword两种字段类型ES 里字段类型分两种text写入时分词存的是一个个词条用于全文搜索用 match 查它keyword不分词整个值作为一个整体用于精确匹配、排序、聚合用 term 查它新手第一大坑用 term 去查 text 字段。text 字段写入时词条会被转成小写“Java存成了java”而 term 不分词拿大写Java原样去查当然查不到。正确做法是精确匹配走 keyword 子字段{term: {title.keyword: 完整书名}}。二、DSL 查询ES 里的 SQLES 的查询语言叫 DSLDomain Specific Language本质就是一段 JSON。查询的统一入口是GET /索引名/_searchbody 里放查询条件。2.1 match 和 term全文搜索 vs 精确匹配match查询词会被分词任意词条命中即匹配并按命中程度计算 _score相关性得分用于全文搜索term查询词不分词整体精确匹配用于状态、ID、枚举等精确过滤口诀搜内容用 match筛条件用 term。2.2 bool 查询四个子句各管一摊真实业务从来不只有一个条件。“价格 30-80、书名含 Java、排除某分类、最好还讲并发”——这种组合条件用 bool 查询子句含义参与算分吗must必须满足相当于 AND✅ 参与filter必须满足相当于 AND❌ 不参与should满足了加分不满足也行相当于 OR✅ 参与must_not必须不满足相当于 NOT❌ 不参与must 和 filter 的区别是面试高频中的高频两者都要求条件必须满足但 must 会计算 _scorefilter 不算分。不算分为什么反而是优点因为过滤结果可以被 ES 缓存而且省掉了算分开销——所以所有不需要按相关度排序的条件状态、时间范围、价格区间、分类一律放 filter性能更好。2.3 深分页问题用 from size 分页时ES 是分布式的数据散在多个分片上。你要第 100 页from990, size10ES 得让每个分片都把前 1000 条发给协调节点合并排序再从中挑出你要的 10 条——越往后翻白搬运的数据越多。所以生产上一般限制翻页深度更深的需求用search_after。三、Spring Boot 集成 ES三步走3.1 依赖和配置引入spring-boot-starter-data-elasticsearchyml 里配置 ES 地址spring:elasticsearch:uris:http://localhost:92003.2 实体类映射用Document注解把 Java 类映射到 ES 索引Field定义字段类型和分词器Document(indexNamebooks)publicclassBookDocument{IdprivateStringid;Field(typeFieldType.Text,analyzerik_max_word)privateStringtitle;Field(typeFieldType.Keyword)privateStringcategory;// ...}3.3 NativeQuery 三步流程复杂查询bool 组合、排序、高亮用ElasticsearchOperationsNativeQuery// 第一步构建 QueryNativeQueryqueryNativeQuery.builder().withQuery(q-q.bool(b-b.must(m-m.match(mq-mq.field(title).query(keyword))).filter(f-f.range(r-r.field(price).gte(JsonData.of(30)).lte(JsonData.of(80)))))).withPageable(PageRequest.of(page-1,size)).withSort(s-s.field(f-f.field(price).order(SortOrder.Asc))).withHighlightQuery(newHighlightQuery(newHighlight(List.of(newHighlightField(title))),BookDocument.class)).build();// 第二步执行查询SearchHitsBookDocumenthitsesOperations.search(query,BookDocument.class);// 第三步处理结果含高亮for(SearchHitBookDocumenthit:hits.getSearchHits()){BookDocumentbookhit.getContent();MapString,ListStringhighlightFieldshit.getHighlightFields();if(highlightFields.containsKey(title)){book.setTitle(String.join(,highlightFields.get(title)));}}记住这个流程NativeQuery.builder() 链式拼条件 → search 执行 → 遍历 SearchHit 处理高亮。3.4 数据同步MySQL 和 ES 怎么保持一致MySQL 是主存储增删改、事务都靠它ES 是搜索副本。两份数据怎么同步同步双写业务代码写完 MySQL 顺手写 ES简单但有失败不一致的风险监听 binlog用 Canal 等工具监听 MySQL 变更日志异步同步到 ES业务解耦、一致性更好大厂常用四、分布式事务CAP、BASE 和四种方案4.1 问题从哪来单体应用里一个Transactional就能保证多个操作要么全成功、要么全回滚。但微服务里订单在 order-service订单库库存在 inventory-service库存库Transactional只能管住自己这一个数据库——订单插进去了远程调用扣库存失败了订单怎么办跨服务记账怎么保证不出错就是分布式事务要解决的问题。4.2 CAP 定理三者最多满足两个CAP 定理说一个分布式系统一致性C、可用性A、分区容错性P三者最多只能同时满足两个。关键推论P 是没得选的。分布式系统里机器之间靠网络通信而网络故障是必然会发生的你不可能不允许网络分区。所以实际的选择是在 C 和 A 之间二选一CP保一致宁可拒绝服务也不能给错数据。ZooKeeper选主期间短暂不可用、银行转账AP保可用先给你响应数据之后再对齐。Eureka、Nacos、电商商品详情页选型原则资金、库存这类给错数据会出大事的场景保 C搜索、推荐、详情页这类给旧数据也无所谓的场景保 A。4.3 BASE 理论AP 的具体落地选了 AP等于承认数据可以暂时不一致。BASE 理论给出了答案Basically Available基本可用出问题时系统不整体挂掉但允许降级Soft State软状态允许数据存在中间状态不要求实时同步Eventually Consistent最终一致性不要求实时一致但最终所有数据会对齐一句话总结BASE 牺牲强一致性换取系统的高可用。4.4 四种分布式事务方案方案一致性性能业务侵入适用场景2PC两阶段提交强一致差同步阻塞低传统数据库 XA现在少用TCC强一致较高高要写三个接口资金、核心短链路Seata AT最终一致接近强中低一个注解一般业务最常用MQ 最终一致最终一致高中允许延迟的异步场景Seata AT 模式是我最想说的。它的卖点是对业务几乎零侵入——加一个注解搞定。工作原理分两阶段一阶段每个分支事务直接执行本地提交同时 Seata 自动拦截 SQL把修改前后的数据快照记到undo_log表里beforeImage 和 afterImage二阶段如果所有分支都成功 → 全局提交undo_log 异步删掉如果任何分支失败 → 全局回滚按 undo_log 里的 beforeImage 生成反向 SQL 补偿回去为什么一阶段直接提交还能保证一致因为 Seata 有全局锁被全局事务占用的行记录其他全局事务不能改防止了脏写。代码里就一个注解GlobalTransactional(rollbackForException.class)publicvoidcreateOrder(LonguserId,LongproductId,Integercount){orderMapper.insert(newOrder(userId,productId,count));inventoryFeign.deduct(productId,count);// 远程扣库存accountFeign.debit(userId,count*100);// 远程扣余额}任何一步抛异常TC 会驱动所有分支按 undo_log 回滚。五、分布式锁Redis 的三个坑和 Redisson5.1 为什么需要分布式锁单机场景synchronized锁住一个 JVM 内的共享资源就够了。但微服务部署了多个实例3 个 Pod 各自扣库存synchronized只能锁住自己这个 JVM3 个实例之间互相看不到——库存只剩 1 件3 个 Pod 同时判断还有货各自扣一次结果超卖了。你需要一把跨仓库的公共钥匙——谁拿到这把公共钥匙谁才能进仓库操作这就是分布式锁。5.2 Redis 实现分布式锁的三个坑基础实现SET key value NX EX secondsNX 表示不存在才设置保证互斥EX 表示过期时间防止死锁。必须原子操作不能用 SETNX EXPIRE 两步。坑 1不可重入。同一个线程再次获取锁会失败——自己把自己锁死了。解决用 Hash 结构记录持有者和重入次数。坑 2过期时间不好设。设短了业务没执行完锁就过期别人拿到锁设长了持有者宕机别人要等很久。解决看门狗自动续期——默认给锁 30 秒过期每 10 秒检查一次持有者还活着就续期到 30 秒。坑 3主从切换锁丢失。Redis 主节点刚加锁、还没同步到从节点就挂了从节点升级为主——别人可以拿到锁互斥性被破坏。解决RedLock 算法向 N 个独立 Redis 节点都加锁过半成功才算成功但争议大生产环境强一致场景用 ZooKeeper 更可靠。5.3 Redisson把三个坑全填了Redisson 是 Redis 官方推荐的 Java 客户端封装了分布式锁的所有坑RLocklockredisson.getLock(lock:stock:1);try{lock.lock();// 默认30s过期看门狗自动续期// 业务逻辑}finally{lock.unlock();}生产环境直接用 Redisson不用自己手写。六、分布式 ID雪花算法6.1 方案对比UUID128 位无序太长不适合做主键B 树插入性能差数据库自增简单但有瓶颈单点、性能差Snowflake 雪花算法趋势递增、不依赖中心、高性能6.2 雪花算法 64 位分配1 位符号位永远 0 41 位时间戳毫秒级可用 69 年 10 位机器 ID最多 1024 台 12 位序列号每毫秒 4096 个趋势递增时间戳在高位整体递增B 树插入友好不依赖中心每台机器根据 workerId 独立生成不需要协调高性能本地计算不依赖网络时钟回拨问题服务器时间被 NTP 同步回退导致生成的 ID 重复。解决方案等待时钟追上、或报错拒绝、或用美团 Leaf 等开源方案处理。七、项目实战设备管理平台这周学的东西在设备管理平台里都用到了ES 搜索设备搜索接口用 ESbool 查询组合关键词全文搜 状态过滤 时间范围过滤 高亮飘红数据同步设备主数据存 MySQL通过 Canal 监听 binlog 异步同步到 ES分布式锁设备绑定/解绑时用 Redisson 锁住 deviceId防止并发重复绑定分布式事务设备绑定要同时更新用户服务和设备服务用 Seata AT 保证强一致分布式 ID设备数据上报量巨大用雪花算法生成趋势递增的 report_id面试讲项目时可以说“强一致的场景我们用 Seata AT允许延迟的场景用 MQ 最终一致性选型依据是业务对一致性的容忍度”——这一句话就能体现你不是背八股而是真的做过取舍。八、本周感悟这周学完我最大的感触是后端开发远不止 CRUD。之前觉得会写 Spring Boot、会连数据库、会调接口就够了。但这周学完 ES 和分布式基础之后我才意识到真正的后端开发要考虑性能ES 倒排索引、要考虑一致性分布式事务、要考虑并发分布式锁、要考虑扩展性分布式 ID。每一个技术选型背后都是对业务场景的权衡。CAP 定理告诉你为什么做不到完美BASE 理论告诉你实践中怎么妥协四种分布式事务方案告诉你不同场景怎么选。这周的内容面试必问尤其是 CAP、Seata AT、Redis 分布式锁的三个坑、雪花算法。我把它们整理成博客也算给自己做个总结。下一周要学 Kafka 和 Flink搜广推方向的核心技术。继续加油。参考资料Elasticsearch 官方文档Spring Data Elasticsearch 参考文档Seata 官方文档Redisson 官方文档作者王俊翰原文链接一周从零吃透 Elasticsearch 分布式基础转载请注明出处

相关新闻

Windows访问局域网Linux主机:SSH、SFTP与远程桌面全攻略

Windows访问局域网Linux主机:SSH、SFTP与远程桌面全攻略

1. 项目概述与核心需求解析 最近在帮几个刚入行的朋友配置开发环境,发现一个挺普遍的需求:他们主力办公用的是Windows系统的笔记本或台式机,但项目代码、数据库或者一些服务又跑在局域网里另一台Linux主机上。每次想操作Linux主机&#xff0c…

2026/10/12 16:11:35 阅读更多 →
SMT产线良率波动?锡膏选型五大误区与实战避坑指南

SMT产线良率波动?锡膏选型五大误区与实战避坑指南

引言:锡膏——SMT焊接工艺的“血液” 在SMT(表面贴装技术)产线上,良率一旦出现波动,工程师十有八九会首先将目光投向锡膏和印刷工艺。锡膏,这看似不起眼的灰色膏体,实则是整个回流焊接工艺的“血…

2026/10/6 7:02:54 阅读更多 →
游戏道歉公告怎么写:步骤、指标与复盘重点

游戏道歉公告怎么写:步骤、指标与复盘重点

玩家不满意的往往不是游戏出了问题,而是运营方不知道如何回应。回到游戏道歉公告怎么写,关键在于先判断事件类型和玩家情绪焦点,再依次完成事实认定、责任说明、处理动作、补偿或整改、后续沟通与复盘。对游戏社区运营来说,道歉公…

2026/10/12 12:55:19 阅读更多 →

最新新闻

STM32+华为云IoT+Qt:智能家居全栈开发实战

STM32+华为云IoT+Qt:智能家居全栈开发实战

1. 项目缘起与整体架构拆解智能家居这个词已经被说烂了,但真正自己动手从零搭一套完整系统的人并不多。大部分人要么停留在用现成模组点个灯的阶段,要么卡在设备上云这一步就放弃了。我当初做这个项目的出发点很简单:家里有几台老式空调和加湿…

2026/10/15 16:28:41 阅读更多 →
储能EMS社招面试全攻略:核心考点与避坑指南

储能EMS社招面试全攻略:核心考点与避坑指南

1. 储能EMS社招面试到底在考什么储能EMS,全称Energy Management System,直译过来就是能量管理系统。放在储能行业里,它是一套负责调度、监控、优化储能电站充放电策略的软件系统。社招面试和校招面试最大的区别在于:校招可以容忍你…

2026/10/15 16:28:41 阅读更多 →
Oppia 测试模块映射体系全解析:core/tests/test-modules-mappings 如何驱动 GitHub CI 精准测试

Oppia 测试模块映射体系全解析:core/tests/test-modules-mappings 如何驱动 GitHub CI 精准测试

教育后端前端 【免费下载链接】oppia A free, online learning platform to make quality education accessible for all. 项目地址: https://gitcode.com/gh_mirrors/op/oppia 点击查看 免费下载 在 Oppia 的 CI 流程中,每一次 Pull Request 并不会盲目…

2026/10/15 16:28:41 阅读更多 →
编译原理基础:从语言定义到文法分类与语法分析

编译原理基础:从语言定义到文法分类与语法分析

1. 项目概述语言的定义是整个编译原理的起点,也是最容易被初学者一带而过的部分。很多人学编译原理一上来就啃词法分析、语法分析,结果看到自动机、文法推导就懵了,根子就在于没有真正理解“语言”到底是个什么东西。哈工大这套课程把语言的定…

2026/10/15 16:28:41 阅读更多 →
Qt低功耗蓝牙开发实战:从GATT通信到MTU协商与Notify订阅

Qt低功耗蓝牙开发实战:从GATT通信到MTU协商与Notify订阅

简介:本资源是一套基于Qt框架的低功耗蓝牙(BLE)特征值读写测试例程,面向嵌入式开发、物联网应用及跨平台桌面端BLE通信初学者与进阶开发者,解决BLE设备调试中服务发现、GATT特征交互、异步读写响应等核心实践难点。压缩…

2026/10/15 16:28:41 阅读更多 →
AP-0316语音处理模组实战:回声消除与波束成形调试指南

AP-0316语音处理模组实战:回声消除与波束成形调试指南

1. 这块模组到底解决了什么问题语音交互这件事,看起来简单,做起来处处是坑。你对着设备喊一句话,设备听到的可能是:你自己的声音、隔壁房间的电视声、空调出风口的呼呼声、桌面共振的低频嗡嗡声,以及电路本身产生的底噪…

2026/10/15 16:27:40 阅读更多 →

日新闻

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

Docker Compose 容器化部署 ChirpStack LoRaWAN 网络服务器实战

1. 为什么选择容器化方式部署 LoRa 网络服务LoRa 物联网项目落地时,网络服务器是整个链路的核心枢纽。它负责接收网关上报的数据包、完成去重与解密、再把有效载荷分发给上层应用。早期大家习惯把网络服务器直接装在物理机上,依赖一堆系统库和特定版本的…

2026/10/15 0:00:46 阅读更多 →
共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

共享LLM服务下的跨模型自动扩缩容:Kubernetes实战与避坑指南

1. 共享推理服务里,扩缩容到底难在哪做过大模型推理服务部署的人,大概都经历过这样的场景:一个团队共用一套推理集群,A 业务跑的是 7B 的小模型,B 业务跑的是 72B 的大模型,C 业务白天流量高、晚上几乎归零…

2026/10/15 0:00:46 阅读更多 →
Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

Systemd 启动阶段根文件系统只读之谜:fstab 与 remount-fs 服务深度解析

1. 引子:一次内核恐慌引发的追查先从一个真实场景说起。某次我给一台老旧的嵌入式设备折腾系统裁减,为了把启动时间压进两秒以内,我手贱地把一串自认为“没用”的 systemd 服务给 disable 了,其中就包括systemd-remount-fs.servic…

2026/10/15 0:00:46 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/15 16:18:54 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/14 16:30:29 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 0:14:36 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 22:45:47 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 9:49:14 阅读更多 →