深入 Elasticsearch(15):认证、授权与加密
上一篇解决了性能模型和调优思路——定位瓶颈再针对性调整。这一篇进入 ES 的安全层怎样保护集群。 ES 8.x 默认启用安全功能。在此之前安全是 X-Pack 的商业特性。理解安全层的架构——加密、认证、授权、审计——才能正确配置生产集群的访问控制。 本文只抓一个问题:ES 的安全层从外到内有哪几层,各自保护什么。 四层安全从外到内依次拦截请求,每一层解决一个独立的安全问题: 后文逐层展开。 安全特性的历史变化 版本 安全状态 < 6.8 X-Pack 商业功能,需要 Gold/Platinum license 6.8 / 7.1 基础安全免费化(Basic license 即可使用认证、TLS、RBAC) 8.0+ 安全默认启用。首次启动自动生成 CA 证书、TLS 配置、elastic 用户密码 ES 8.x 首次启动时会自动完成:生成自签名 CA 证书和节点证书、启用 transport 和 HTTP 层的 TLS、生成 elastic 超级用户的初始密码、生成 enrollment token 供新节点加入集群。 洋葱模型:四层安全 ...
深入 Elasticsearch(14):搜索延迟、写入吞吐与调优思路
上一篇解决了 segment 和索引的生命周期管理——merge 控制 segment 数量,ILM 管理索引的存储分层。这一篇进入 ES 的性能瓶颈在哪里、调优的思维框架是什么。 性能调优不是背参数表。参数是工具,瓶颈定位才是方法。ES 的性能受搜索延迟和写入吞吐两个维度的独立因素影响,先确定瓶颈在哪个维度的哪个因素上,再针对性调整。 本文只抓一个问题:ES 的性能模型——搜索延迟和写入吞吐分别受什么因素影响,用什么工具定位瓶颈。 搜索延迟的关键因素 1搜索延迟 = f(segment数, query复杂度, shard数, cache命中率, 数据结构选择) 因素 影响机制 观察方式 Segment 数量 每个 segment 独立搜索,结果合并 _segments API Query 复杂度 深层嵌套 bool、wildcard、regexp 代价高 _search?profile=true Shard 数量 scatter-gather 开销随 shard 数线性增长 _cat/shards Filesystem cache Lucene 文件...
深入 Elasticsearch(13):Segment Merge 与 Index Lifecycle Management
上一篇解决了集群协调——master 选举和 cluster state 同步。这一篇进入 segment 随时间增长后怎样管理。 第 02 篇介绍了 segment 是不可变的,写入产生新 segment。随着写入持续,segment 数量会不断增长。segment 太多搜索变慢,删除的文档占据的空间不会自动回收。Segment merge 和 ILM 分别在 Lucene 层和 index 层解决这个存储生命周期问题。 本文抓两个问题:为什么需要 segment merge,以及 ILM 怎样管理索引的生命周期。 Segment Merge 为什么需要 merge 每次 refresh 产生一个新 segment。持续写入的 index 会积累大量小 segment。问题有二: 搜索时需要遍历所有 segment。segment 越多,搜索越慢。 删除文档只是在 .liv 文件中打标记,物理空间不回收。只有 merge 时才真正删除标记文档、回收空间。 123456789101112写入阶段: refresh → seg0(10 docs) refresh → se...
深入 Elasticsearch(12):Master 选举与集群状态同步
上一篇解决了副本机制和故障恢复——primary-replica 的同步模型和 failover 流程。这一篇进入谁来决定 shard 分配、节点角色——集群协调层。 cluster state 是 ES 集群的元数据核心(第 01 篇已经介绍过它的结构)。这一篇聚焦在 cluster state 的写入方——master 节点——是怎样被选举出来的,以及选举机制在 ES 7.x 经历了什么根本性变化。 本文只抓一个问题:ES 的 master 选举算法和脑裂防护机制。 选举机制的演变 ES 7.0 之前使用 Zen Discovery,一种基于 Bully 算法变体的选举机制。这套机制需要手动配置 discovery.zen.minimum_master_nodes,配置不当容易导致脑裂。 ES 7.0 起改用全新的选举机制,基于学术论文中的共识算法思想(接近 Raft 但不是完整 Raft 实现)。新机制自动管理 quorum,不再需要手动配置 minimum_master_nodes。 版本 选举机制 脑裂防护 < 7.0 Zen Discovery ...
深入 Elasticsearch(11):故障恢复与读写模型
上一篇解决了数据怎样分布到 shard 上——路由公式和分片数不可变的约束。这一篇进入 shard 的副本机制和故障恢复。 每个 primary shard 可以有零个或多个 replica shard。Replica 提供两个能力:高可用(primary 故障时 replica 接管)和读扩展(搜索请求可以命中 replica)。理解 primary-replica 的同步模型,才能在一致性和可用性之间做出正确的配置选择。 本文只抓一个问题:primary 和 replica 之间怎样同步数据,primary 故障时怎样恢复。 写入模型 一条文档的写入路径经过 primary shard 再转发到 replica: 12345678910Client → Coordinating Node(路由到 primary shard 所在节点) → Primary Shard: 1. 本地执行写入(buffer + translog) 2. 并行转发给所有 in-sync replica → Replica Shard(s): 3. 本地执行同样的...
深入 Elasticsearch(10):数据分布的核心机制
上一篇解决了聚合分析框架——Bucket、Metric、Pipeline 三层聚合在搜索结果上提供实时分析。这一篇进入数据怎样分布到多个 shard 上。 ES 把一个 index 的数据分成多个 shard,分布到不同的节点上。分片的核心是路由公式——决定一条文档应该落在哪个 shard 上。这个公式看起来简单,但它的分母不可变这一约束影响了 ES 的整个容量规划思路。 本文只抓一个问题:分片路由公式怎样工作,以及分片数不可变的约束从何而来。 路由公式 1shard_num = hash(_routing) % number_of_primary_shards 默认情况下 _routing 等于文档的 _id。这个公式把文档 ID 的哈希值对 primary shard 数取模,得到目标 shard 编号。 5 条文档经过这个公式分配到 3 个 shard 的过程: 哈希函数对同一个 _id 总是产生相同的结果,所以读取时不需要查询元数据——直接算一次就知道文档在哪个 shard 上。 这个公式意味着: 给定相同的 _routing 和相同的 number_of_prim...
深入 Elasticsearch(09):搜索之上的实时分析
上一篇解决了 Query DSL 的查询体系——全文、精确、模糊、地理查询和 bool 组合。这一篇进入在搜索结果之上怎样做实时统计分析。 搜索返回匹配文档的列表。但很多场景不只需要文档列表,还需要统计信息:按类别分组计数、平均价格、日期趋势。ES 的 Aggregation 框架在搜索结果之上提供实时分析能力,不需要把数据导出到 OLAP 系统。 本文只抓一个问题:Aggregation 的三类聚合怎样工作,以及嵌套组合怎样构建复杂分析。 三类聚合 ES 的聚合分为三类,各有不同职责: 1234搜索结果集 → Bucket Aggregation 把文档分到不同的桶里 → Metric Aggregation 在每个桶内计算度量值 → Pipeline Aggregation 在聚合结果上再计算 Bucket 聚合按某种规则把文档分组——类似 SQL 的 GROUP BY。常见的 bucket 聚合: 聚合 分桶规则 类比 SQL terms 按字段值分组 GROUP BY field date_histogram 按时间间隔分组 ...
深入 Elasticsearch(08):从 match 到 bool 的查询体系
上一篇解决了分数怎么算出来的——BM25 的三个因子决定了文档的相关性排序。这一篇进入 Query DSL 的查询类型体系和组合逻辑。 ES 的查询体系不是一个扁平的 API 列表。全文查询、精确查询、模糊查询、地理查询、复合查询分别对应不同的底层数据结构和匹配逻辑。理解这个分类,才能在具体场景中选对查询类型。 本文抓两个问题:ES 的查询类型怎样分类,以及 bool 查询怎样把不同类型的查询组合起来。 查询体系全景 123456789101112131415161718192021222324252627282930313233ES 查询体系├── 全文查询(走 analyzer,参与打分)│ ├── match 分词后多词项匹配│ ├── match_phrase 分词后要求位置相邻│ ├── multi_match 跨多个字段的 match│ └── match_phrase_prefix 短语前缀(输入补全)│├── 精确查询(不走 analyzer,通常用于 filter context)│ ...
深入 Elasticsearch(07):BM25 与打分机制
上一篇解决了搜索的执行流程——Query-Then-Fetch 两阶段在集群中怎样运转。这一篇进入每条结果的分数是怎么算出来的。 ES 的搜索结果按 _score 降序排列。_score 是 BM25 算法算出的相关性分数。理解 BM25,才能理解为什么有些文档排在前面、有些排在后面,也才能有针对性地调整搜索相关性。 本文只抓一个问题:BM25 的三个因子分别衡量什么,以及它们怎样组合成最终分数。 BM25 的直觉 BM25 的名字来自"Best Matching 25"(第 25 号最佳匹配公式)。它取代了 ES 5.x 之前使用的 TF-IDF 模型,成为 Lucene 和 ES 的默认相似度算法。 BM25 的核心思路可以用一句话概括:一个词项越稀有(IDF 高)、在文档中出现越多次(TF 高)、文档越短(字段长度归一化),包含这个词项的文档就越相关。 分数由三个因子相乘构成: 1score(q, d) = IDF(q) × TF_saturation(q, d) × length_norm(d) 三个因子各回答一个独立问题:这个词稀不稀有、在这篇文...
深入 Elasticsearch(06):Query-Then-Fetch 的两阶段流程
上一篇解决了文档怎样变成可搜索的——写入路径经过 buffer、translog、refresh 三步后文档才对搜索可见。这一篇进入一次搜索请求在集群内部怎样执行。 ES 是分布式搜索引擎,一个 index 的数据分布在多个 shard 上。一次搜索需要在所有相关 shard 上执行,然后合并结果。这个过程分成两个阶段:Query 阶段和 Fetch 阶段。 本文只抓一个问题:Query-Then-Fetch 的两阶段搜索是怎么工作的,以及这个设计为什么是必要的。 为什么需要两个阶段 如果 ES 只有一个 shard,搜索很简单:在 shard 上执行查询,取 top-N 结果,返回。但数据分布在多个 shard 上时,直接从每个 shard 取 top-N 的完整文档(包含 _source),再在 coordinating node 合并,会传输大量不需要的数据——大部分文档在全局排序后会被丢弃。 两阶段设计的核心思路:先用轻量数据(docId + score)做全局排序,再只取需要的文档内容。 两阶段之间的关键转折:Query Phase 结束时 coordinating...
