dede网站地图html文件,贵阳网站建设黔搜,专门做图片是网站,做网站的协议#x1f449; 点击关注不迷路 #x1f449; 点击关注不迷路 #x1f449; 点击关注不迷路 文章大纲 Elasticsearch数据更新与删除深度解析#xff1a;2.3.1 避免频繁更新#xff08;Update by Query的代价#xff09;案例背景1. Update by Query的内部机制解析1.1 文档更… 点击关注不迷路 点击关注不迷路 点击关注不迷路 文章大纲 Elasticsearch数据更新与删除深度解析2.3.1 避免频繁更新Update by Query的代价案例背景1. Update by Query的内部机制解析1.1 文档更新底层实现原理1.2 更新操作资源消耗模型 2. 频繁更新引发的性能问题2.1 分段Segment爆炸效应2.2 版本控制开销2.3 真实问题诊断数据 3. 真实场景压力测试数据3.1 测试环境3.2 不同更新频率对比更新频率与性能衰减关系3.3 性能衰减曲线 4. 优化方案与替代策略4.1 数据结构优化4.2 写入模式改造4.3 版本控制优化配置 5. 生产环境故障恢复实践5.1 紧急止血方案5.2 长期治理措施5.3 效果验证 关键结论与最佳实践避坑指南终极解决方案 Elasticsearch数据更新与删除深度解析2.3.1 避免频繁更新Update by Query的代价
案例背景
某物流追踪平台在业务升级后出现集群性能断崖式下降
数据规模每日处理5亿条物流状态更新更新模式使用_update_by_query实时修改运单状态问题表现 写入吞吐量从12万ops/s暴跌至2.3万ops/s查询延迟P99从180ms上升到2100ms磁盘IOPS持续保持98%以上 1. Update by Query的内部机制解析
1.1 文档更新底层实现原理 #mermaid-svg-Lz7Tt7tkZUEtIVq8 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .error-icon{fill:#552222;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .marker.cross{stroke:#333333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .cluster-label text{fill:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .cluster-label span{color:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .label text,#mermaid-svg-Lz7Tt7tkZUEtIVq8 span{fill:#333;color:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node rect,#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node circle,#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node ellipse,#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node polygon,#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node .label{text-align:center;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .node.clickable{cursor:pointer;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .arrowheadPath{fill:#333333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .cluster text{fill:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 .cluster span{color:#333;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Lz7Tt7tkZUEtIVq8 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Update请求 创建新文档 标记旧文档为删除 Refresh操作后可见 Segment Merge时物理删除 关键特性对比不同写操作资源消耗对比
操作类型写入放大系数磁盘IO类型是否触发MergeIndex新建1x顺序写入低概率Update更新3-5x随机读写混合必然触发Delete删除2-3x随机读顺序写中等概率
1.2 更新操作资源消耗模型
单次更新成本公式
总消耗 读操作获取原文 写操作新文档 删除标记 版本更新≈ 2.5 × 文档大小 × 副本数典型资源消耗比例 CPU消耗比新建操作高40-60%磁盘IO比新建操作高300-500%内存压力需要维护版本映射表 2. 频繁更新引发的性能问题
2.1 分段Segment爆炸效应
更新操作对Lucene段的影响
# 查看分段状态
GET /_cat/segments?v# 问题集群输出示例
index shard prirep segment generation docs.count size.mb
logs-2023 0 p _6 1500000 350
logs-2023 0 p _7 800000 180 # 更新产生的分段
logs-2023 0 p _8 750000 170分段异常特征 小分段100MB数量超过50个单个分片分段总数超过100存在大量docs.deleted30%的分段
2.2 版本控制开销
版本号映射表内存消耗
总内存消耗 ≈ 文档数 × 16 bytes × 副本数对于1亿文档的索引
16B × 100,000,000 × 2 3.2GB2.3 真实问题诊断数据
// 节点性能分析
{// io 部分包含了与磁盘输入输出I/O操作相关的性能指标io: {// write_throughput 表示磁盘的写入吞吐量即单位时间内磁盘能够写入的数据量// 这里显示为 450MB/s但注释提示正常值应小于 200MB/s// 较高的写入吞吐量可能意味着系统正在进行大量的数据写入操作可能会对磁盘性能造成较大压力write_throughput: 450MB/s, // 正常值200MB/s// iowait_percent 表示 CPU 等待磁盘 I/O 操作完成的时间占比// 这里的值为 98.7意味着 CPU 大部分时间都在等待磁盘 I/O 操作磁盘 I/O 可能成为系统的性能瓶颈// 高 iowait 可能会导致系统响应变慢影响应用程序的性能iowait_percent: 98.7},// jvm 部分包含了与 Java 虚拟机JVM相关的性能指标jvm: {// old_gc_count 表示老年代垃圾回收Old GC的次数// 注释提示正常情况下老年代垃圾回收次数应小于 5 次/分钟// 这里显示为 35说明老年代垃圾回收过于频繁// 频繁的老年代垃圾回收会导致系统停顿影响应用程序的响应时间和吞吐量old_gc_count: 35, // 正常5次/分钟// buffer_pools 表示 JVM 中的缓冲区池信息buffer_pools: {// direct 表示直接缓冲区池的使用情况// 4.2GB/5GB 表示当前直接缓冲区池已使用 4.2GB 的内存总容量为 5GB// 这反映了堆外内存的使用情况较高的使用比例可能会导致堆外内存压力增大甚至可能引发内存溢出错误direct: 4.2GB/5GB // 堆外内存压力}}
}3. 真实场景压力测试数据
3.1 测试环境
组件配置详情ES集群3节点16C64G NVMe SSD测试数据集1亿条物流数据含15个字段测试模式持续30分钟混合负载更新查询
3.2 不同更新频率对比更新频率与性能衰减关系
更新频率吞吐量ops/s磁盘IOPS段数量/分片GC停顿s/min100次/秒82,00018,000120.8500次/秒47,00053,000383.21000次/秒19,00089,000716.52000次/秒服务不可用100%120Full GC卡死
3.3 性能衰减曲线
Throughput (k ops/s)
100 ┤■■■■■■■■■■■■■■■■■■■■80 ┤■■■■■■■■■■■□□□□□□□□60 ┤■■■■■■■□□□□□□□□□□□□40 ┤■■■□□□□□□□□□□□□□□□□20 ┤□□□□□□□□□□□□□□□□□□□└───────────────────原始负载 更新10% 更新30% 更新50%吞吐量的单位是千操作每秒k ops/s 原始负载对应柱状图高度达到 100 k ops/s 的柱子。这表明在原始负载的情况下系统的吞吐量能够达到 100 千操作每秒此时系统处于一个相对稳定且高效的处理状态。更新 10%柱状图高度约为 80 k ops/s。当负载在原始基础上增加 10% 时系统的吞吐量下降到了 80 千操作每秒。这可能是因为系统开始受到额外负载的影响资源逐渐变得紧张但仍能保持较高的处理能力。更新 50%柱状图高度约为 40 k ops/s。当负载增加到原始负载的 50% 时系统的吞吐量大幅下降到 40 千操作每秒。这显示出系统在高负载下已经难以维持高效的处理能力可能出现了性能瓶颈如 CPU 使用率过高、内存不足、磁盘 I/O 瓶颈等问题。 4. 优化方案与替代策略
4.1 数据结构优化
不可变数据模型设计 在不可变数据模型里一旦数据被写入 Elasticsearch就不会再被修改。若要更新数据不会直接在原数据上操作而是创建一条新的数据记录来替换旧的旧数据仍然保留在系统中。
// 原始结构可修改
{order_no: 20230809123456,status: shipped,update_time: 2023-08-09T12:00:00
}// 优化结构不可变
{order_no: 20230809123456,status_history: [{status: created,time: 2023-08-09T10:00:00},{status: shipped,time: 2023-08-09T12:00:00 }]
}4.2 写入模式改造
事件溯源模式
4.3 版本控制优化配置
# 调整索引配置
# 此操作是对名为 orders 的 Elasticsearch 索引进行配置调整目的是优化索引的性能和功能以适应特定的业务需求。
# PUT 请求用于更新资源这里是更新 orders 索引的设置。PUT /orders/_settings
{index: {# refresh_interval 用于设置索引的刷新间隔。# 索引刷新操作会将内存中的数据刷新到磁盘上使其可以被搜索到。# 这里将刷新间隔设置为 30s即每隔 30 秒进行一次刷新操作。# 降低刷新频率可以减少磁盘 I/O 操作提高索引性能但会增加数据的可见延迟即新写入的数据可能需要更长时间才能被搜索到。refresh_interval: 30s, # 降低刷新频率# number_of_replicas 表示索引的副本数量。# 副本用于提高数据的可用性和可靠性当主分片出现故障时副本分片可以替代主分片继续提供服务。# 这里将副本数量设置为 0意味着在写入数据时关闭副本。# 关闭副本可以减少写入时的同步开销提高写入性能但会降低数据的冗余性和可用性。在数据写入完成后可以根据需要再将副本数量调整回来。number_of_replicas: 0, # 写入时关闭副本# soft_deletes 用于配置软删除功能。# 软删除是指在删除文档时并不立即从磁盘上物理删除文档而是标记为已删除以便后续可以恢复。soft_deletes: {# enabled: true 表示启用软删除功能。# 此功能从 Elasticsearch 7.0 版本开始支持启用后可以在删除文档时保留文档的元数据方便进行数据恢复和审计。enabled: true, # 7.0 启用软删除# retention_leases 用于控制软删除文档的保留策略。retention_leases: {# enabled: true 表示启用保留租约控制。# 保留租约控制可以确保在指定的时间内软删除的文档不会被物理删除以便在需要时可以恢复这些文档。enabled: true # 保留租约控制}}}
}5. 生产环境故障恢复实践
5.1 紧急止血方案
# 第一步限制更新速率# 此步骤的目的是对整个 Elasticsearch 集群的索引存储更新速率进行限制避免因过高的写入速率导致磁盘 I/O 压力过大影响集群的稳定性和性能。# PUT 请求用于更新集群的设置这里更新的是集群的持久化设置持久化设置会在集群重启后依然生效。PUT _cluster/settings
{persistent: {# indices.store.throttle.max_bytes_per_sec 是一个集群级别的设置参数用于限制索引存储时每秒允许的最大字节数。# 这里将其设置为 50mb意味着集群中所有索引在存储数据时每秒写入磁盘的数据量不能超过 50 兆字节。indices.store.throttle.max_bytes_per_sec: 50mb }
}# 第二步关闭副本加快 merge# 此步骤是为了在进行某些操作如强制合并分段时提高操作的速度。因为副本的存在会增加数据同步和处理的开销关闭副本可以减少这些额外的操作。# PUT 请求用于更新索引的设置这里使用 /_all 表示对集群中的所有索引进行设置更新。
PUT /_all/_settings
{# index.number_of_replicas 用于设置索引的副本数量。# 这里将其设置为 0即关闭所有索引的副本。这样在后续的强制合并分段操作中就不需要考虑副本数据的同步问题从而加快合并的速度。# 但需要注意的是关闭副本会降低数据的冗余性和可用性在操作完成后建议根据实际需求恢复副本数量。index.number_of_replicas: 0
}# 第三步强制合并分段# 此步骤的主要目的是对名为 orders 的索引进行分段合并操作以减少索引中的分段数量提高查询性能。# 在 Elasticsearch 中数据是以分段Segment的形式存储的随着数据的不断写入和删除分段数量会逐渐增多这会增加查询的开销。# 通过强制合并分段可以将多个小分段合并成较少的大分段从而提高查询效率。# POST 请求用于触发强制合并操作。# /orders/_forcemerge 表示对 orders 索引执行强制合并操作。#?max_num_segments10 是一个查询参数指定合并后索引中分段的最大数量为 10。POST /orders/_forcemerge?max_num_segments105.2 长期治理措施
三级更新策略
更新类型频率要求实现方式目标延迟实时型1秒应用层直接更新500ms准实时型1-5分钟Kafka批量更新3分钟延迟型30分钟Logstash聚合更新1小时
5.3 效果验证
优化前后核心指标对比
指标优化前优化后改善幅度写入吞吐量19,000/s68,000/s258%段数量/分片71987%磁盘IOPS89,00022,00075%GC停顿时间6.5s/min1.2s/min81% 关键结论与最佳实践
避坑指南 更新频率红线单个分片每秒更新不超过50次 版本数监控定期检查_version字段的统计分布 分段健康度控制每个分片分段数50单个分段100MB 更新模式选择 单字段更新 → 使用Painless脚本多字段更新 → 整文档替换状态变更 → 采用追加模式
终极解决方案
Lambda架构实现