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}
高级功能
- 聚合分析:支持各种数据分析操作,如统计、直方图、日期范围等
- 全文检索:提供丰富的查询类型(匹配、短语、模糊、通配符等)
- 地理空间搜索:支持地理位置数据的索引和查询
- 机器学习:提供异常检测和预测功能
典型应用场景
- 企业搜索:文档、产品、客户等内容的快速检索
- 日志分析:结合 Logstash 和 Kibana 进行日志集中管理
- 电商平台:商品搜索、推荐和个性化展示
- 安全分析:检测异常行为和潜在威胁
- 指标分析:监控业务和基础设施指标
背景与概念
ElasticSearch 在早期版本中支持使用类型(Type)来对索引中的文档进行分类,类似于关系型数据库中的表。但随着版本演进,类型(Type)的概念已被逐步废弃,在 7.x 版本中完全移除。但在实际生产环境中,我们仍可能遇到需要更新索引类型(Type)结构的需求,同时要保证业务连续性。
不停机更新索引类型的实现方案
1. 别名切换方案
这是最常用的不停机更新方式,具体步骤如下:
-
创建新索引:创建一个含有新类型结构的目标索引
PUT /new_index{ \"mappings\": { \"properties\": { \"field1\": {\"type\": \"text\"}, \"field2\": {\"type\": \"keyword\"} } }}
-
数据同步:使用reindex API将数据从旧索引迁移到新索引
POST _reindex{ \"source\": { \"index\": \"old_index\" }, \"dest\": { \"index\": \"new_index\" }}
-
别名切换:给新旧索引设置相同的别名,然后切换
POST _aliases{ \"actions\": [ {\"remove\": {\"index\": \"old_index\", \"alias\": \"current_index\"}}, {\"add\": {\"index\": \"new_index\", \"alias\": \"current_index\"}} ]}
2. 滚动索引方案
适用于时间序列数据或大型索引:
-
创建新索引模板
PUT _template/new_template{ \"index_patterns\": [\"logs-*\"], \"settings\": {...}, \"mappings\": {...}}
-
创建新索引并开始写入
PUT /logs-2023.01.01
-
逐步迁移旧数据:使用reindex分批迁移
-
查询时合并结果:使用索引模式或别名查询多个索引
3. 索引重建方案
对于小型索引可以考虑:
- 创建临时索引:临时存储新数据
- 停止写入:短暂停止写入操作
- 重建索引:使用新映射重建主索引
- 恢复写入:将临时索引数据合并到主索引
最佳实践
-
监控reindex进度:
GET _tasks?detailed=true&actions=*reindex
-
优化reindex性能:
POST _reindex{ \"source\": {\"index\": \"old_index\"}, \"dest\": {\"index\": \"new_index\"}, \"size\": 5000, \"script\": { \"source\": \"ctx._source.new_field = \'default_value\'\" }}
-
验证数据一致性:比较新旧索引文档数
GET /old_index/_countGET /new_index/_count
-
回滚方案准备:保留旧索引直到确认新索引稳定
ElasticSearch索引类型结构更新注意事项
客户端应用配置
- 确保所有客户端应用都使用索引别名而非直接引用索引名称
- 示例:应该配置应用连接
products_alias
而非直接使用products_v1
索引名 - 好处:这样可以在后台无缝切换索引版本而无需修改应用配置
字段类型变更注意事项
- 不同类型字段的查询结果可能存在差异,特别是:
- 字符串类型(text vs keyword)的全文搜索和精确匹配行为不同
- 数值类型(long vs double)的范围查询精度差异
- 日期格式变更可能导致已有数据解析失败
- 建议:在测试环境充分验证查询结果后再上线生产环境
复杂映射变更处理
- 对于无法通过简单类型转换完成的复杂映射变更:
- 编写数据转换脚本预处理数据
- 考虑使用Logstash或自定义ETL流程转换数据格式
- 测试转换脚本对所有历史数据的处理效果
- 示例场景:将嵌套文档结构改为父子关系时需要的转换处理
集群资源配置
- 合理设置分片数量:
- 单个分片建议保持在10-50GB大小
- 考虑未来6-12个月的数据增长需求
- 副本数配置:
- 生产环境至少1个副本确保高可用
- 根据查询负载可能需要增加副本数
- 使用
_cat/shards
API监控分片分布情况
资源监控与优化
- Reindex操作前:
- 检查集群CPU、内存和磁盘IO使用率
- 考虑在业务低峰期执行reindex操作
- 可使用
wait_for_completion=false
参数异步执行
- 执行过程中:
- 监控
_tasks
API查看reindex进度 - 必要时调整
scroll_size
和requests_per_second
参数控制速度 - 设置合理的超时时间避免长时间占用资源
- 监控
通过以上方法,可以在最小化业务影响的前提下完成ElasticSearch索引类型的结构更新,满足业务需求变更和性能优化需求。