> 技术文档 > ElasticSearch:不停机更新索引类型

ElasticSearch:不停机更新索引类型

ElasticSearch 详解

基本概念

ElasticSearch 是一个基于 Lucene 的分布式搜索和分析引擎,它提供了近实时的数据索引和搜索能力。以下是其主要特点:

  • 分布式架构:自动将数据分片并分布在多个节点上,支持水平扩展
  • RESTful API:通过简单的 HTTP 接口进行操作,支持 JSON 格式数据
  • 近实时搜索:从索引文档到可搜索只需1秒
  • 多租户:支持多个索引,每个索引可配置不同的设置
  • 文档导向:存储复杂数据结构为 JSON 文档

核心组件

1. 节点与集群

ElasticSearch 采用主从架构:

  • 主节点:负责集群范围内的管理操作
  • 数据节点:存储数据并执行数据相关操作
  • 协调节点:处理客户端请求,路由请求到适当节点

2. 索引与分片

  • 索引(Index):类似数据库中的表,包含一组相关文档
  • 分片(Shard):索引的水平分割单元,每个分片是一个独立的 Lucene 索引
  • 副本(Replica):分片的复制,提供高可用性和读取吞吐量

实际应用示例

文档索引示例

PUT /customer/_doc/1{ \"name\": \"John Doe\", \"age\": 30, \"address\": \"123 Main St\", \"interests\": [\"reading\", \"hiking\"], \"join_date\": \"2023-01-15\"}

搜索查询示例

GET /customer/_search{ \"query\": { \"bool\": { \"must\": [ { \"match\": { \"name\": \"John\" }}, { \"range\": { \"age\": { \"gte\": 25 }}} ] } }, \"sort\": [ { \"join_date\": { \"order\": \"desc\" }} ], \"from\": 0, \"size\": 10}

高级功能

  1. 聚合分析:支持各种数据分析操作,如统计、直方图、日期范围等
  2. 全文检索:提供丰富的查询类型(匹配、短语、模糊、通配符等)
  3. 地理空间搜索:支持地理位置数据的索引和查询
  4. 机器学习:提供异常检测和预测功能

典型应用场景

  1. 企业搜索:文档、产品、客户等内容的快速检索
  2. 日志分析:结合 Logstash 和 Kibana 进行日志集中管理
  3. 电商平台:商品搜索、推荐和个性化展示
  4. 安全分析:检测异常行为和潜在威胁
  5. 指标分析:监控业务和基础设施指标

背景与概念

ElasticSearch 在早期版本中支持使用类型(Type)来对索引中的文档进行分类,类似于关系型数据库中的表。但随着版本演进,类型(Type)的概念已被逐步废弃,在 7.x 版本中完全移除。但在实际生产环境中,我们仍可能遇到需要更新索引类型(Type)结构的需求,同时要保证业务连续性。

不停机更新索引类型的实现方案

1. 别名切换方案

这是最常用的不停机更新方式,具体步骤如下:

  1. 创建新索引:创建一个含有新类型结构的目标索引

    PUT /new_index{ \"mappings\": { \"properties\": { \"field1\": {\"type\": \"text\"}, \"field2\": {\"type\": \"keyword\"} } }}
  2. 数据同步:使用reindex API将数据从旧索引迁移到新索引

    POST _reindex{ \"source\": { \"index\": \"old_index\" }, \"dest\": { \"index\": \"new_index\" }}
  3. 别名切换:给新旧索引设置相同的别名,然后切换

    POST _aliases{ \"actions\": [ {\"remove\": {\"index\": \"old_index\", \"alias\": \"current_index\"}}, {\"add\": {\"index\": \"new_index\", \"alias\": \"current_index\"}} ]}

2. 滚动索引方案

适用于时间序列数据或大型索引:

  1. 创建新索引模板

    PUT _template/new_template{ \"index_patterns\": [\"logs-*\"], \"settings\": {...}, \"mappings\": {...}}
  2. 创建新索引并开始写入

    PUT /logs-2023.01.01
  3. 逐步迁移旧数据:使用reindex分批迁移

  4. 查询时合并结果:使用索引模式或别名查询多个索引

3. 索引重建方案

对于小型索引可以考虑:

  1. 创建临时索引:临时存储新数据
  2. 停止写入:短暂停止写入操作
  3. 重建索引:使用新映射重建主索引
  4. 恢复写入:将临时索引数据合并到主索引

最佳实践

  1. 监控reindex进度

    GET _tasks?detailed=true&actions=*reindex
  2. 优化reindex性能

    POST _reindex{ \"source\": {\"index\": \"old_index\"}, \"dest\": {\"index\": \"new_index\"}, \"size\": 5000, \"script\": { \"source\": \"ctx._source.new_field = \'default_value\'\" }}
  3. 验证数据一致性:比较新旧索引文档数

    GET /old_index/_countGET /new_index/_count
  4. 回滚方案准备:保留旧索引直到确认新索引稳定

ElasticSearch索引类型结构更新注意事项

客户端应用配置

  • 确保所有客户端应用都使用索引别名而非直接引用索引名称
  • 示例:应该配置应用连接products_alias而非直接使用products_v1索引名
  • 好处:这样可以在后台无缝切换索引版本而无需修改应用配置

字段类型变更注意事项

  • 不同类型字段的查询结果可能存在差异,特别是:
    • 字符串类型(text vs keyword)的全文搜索和精确匹配行为不同
    • 数值类型(long vs double)的范围查询精度差异
    • 日期格式变更可能导致已有数据解析失败
  • 建议:在测试环境充分验证查询结果后再上线生产环境

复杂映射变更处理

  • 对于无法通过简单类型转换完成的复杂映射变更:
    1. 编写数据转换脚本预处理数据
    2. 考虑使用Logstash或自定义ETL流程转换数据格式
    3. 测试转换脚本对所有历史数据的处理效果
  • 示例场景:将嵌套文档结构改为父子关系时需要的转换处理

集群资源配置

  • 合理设置分片数量:
    • 单个分片建议保持在10-50GB大小
    • 考虑未来6-12个月的数据增长需求
  • 副本数配置:
    • 生产环境至少1个副本确保高可用
    • 根据查询负载可能需要增加副本数
  • 使用_cat/shardsAPI监控分片分布情况

资源监控与优化

  • Reindex操作前:
    • 检查集群CPU、内存和磁盘IO使用率
    • 考虑在业务低峰期执行reindex操作
    • 可使用wait_for_completion=false参数异步执行
  • 执行过程中:
    • 监控_tasksAPI查看reindex进度
    • 必要时调整scroll_sizerequests_per_second参数控制速度
    • 设置合理的超时时间避免长时间占用资源

通过以上方法,可以在最小化业务影响的前提下完成ElasticSearch索引类型的结构更新,满足业务需求变更和性能优化需求。