Elasticsearch
一些运维相关的建议
集群的生命周期管理
-
预上线
- 评估用户的需求及使用场景/数据建模/容量规划/选择合适的部署架构/性能测试
-
上线
- 监控流量 /定期检查潜在问题(防患 于未然,发现错误的使用方式,及时增加机器)
- 对索引进行优化(Index Lifecycle Management) ,检测是否存在不均衡而导致有部分节点过热
- 定期数据备份 /滚动升级
-
下架前监控流量,实现Stage Decommission
部署的建议
- 根据实际场景, 选择合适的部署方式,选择合理的硬件配置
- 搜索类
- 日志/指标
- 部署要考虑,反亲和性(Anti-Affinity)
- 尽量将机器分散在不同的机架。例如,3台Master节点必须分散在不同的机架上
- 善用Shard Filtering进行配置
使用要遵循一定的规范
使用要遵循一定的规范
- 设置 Slowlogs,发现一些性能不好,甚至是错误的使用Pattern
- 例如:错误的将网址映射成keyword, 然后用通配符查询。应该使用Text, 结合URL分词器
- 严禁一切“*” 开头的通配符查询
对重要的数据进行备份
- 集群备份
- https://www. elastic. co/gu ide/en/elas t icsearch/ reference/7.1/modules-snapshots. html
定期更新到新版本
- ES在新版本中会持续对性能作出优化;提供更多的新功能
- Circuit breaker 实现的改进
- 修复一些已知的 bug和安全隐患
ES的版本
-
Elasticsearch的版本格式是: X. Y.Z
- X: Major
- Y: Minor
- z: Patch
-
Elasticsearch可以使用.上一个主版本的索引
- 7.x可以使用6.x / 7.x不支持使用5. x
- 5.x可以使用2.x
Rolling Upgrade v. s Full Cluster Restart
-
Rolling Upgrade
- 没有Downtime .
- https://www. elastic. co/ guide/en/elasticsearch/reference/7.1/rolling-upgrades. html
-
Full Cluster Restart
- 集群在更新期间不可用
- 升级更快
Full Restart的步骤
运维Cheat Sheet: 移动分片
运维Cheat Sheet :从集群中移除-一个节点
- 使用场景:当你想移除一个节点,或者对一个机器进行维护。同时你又不希望导致集群的颜色变
黄或者变红
运维Cheat Sheet :控制Allocation 和Recovery
- 使用场景: 控制Allocation和Recovery 的速率
运维Cheat Sheet : Synced Flush
- 使用场景:需要重启一个节点。
- 通过synced flush, 可以在索引.上放置-一个sync ID。这样可以提供这些分片的Recovery 的时间
运维Cheat Sheet :清空节点上的缓存
- 使用场景:节点上出现了高内存占用。可以执行清除缓存的操作。这个操作会影响集群的性能,
但是会避免你的集群出现0OM的问题
运维Cheat Sheet :控制搜索的队列
- 使用场景: 当搜索的响应时间过长,看到有“reject”指标的增加, 都可以适当增加该数值
运维Cheat Sheet :设置Circuit Breaker
- 使用场景: 设置各类Circuit Breaker。 避免0OM的发生。
运维建议
- 了解用户场景,选择合适部署
- 定期检查,发现潜在问题
- 对重要的数据进行备份
- 保持版本升级
使用Shrink 与Rollover API管理索引
索引管理API
- Open / Close Index: 索引关闭后无法进行读写,但是索引数据不会被删除
- Shrink Index: 可以将索引的主分片数收缩到较小的值
- Split Index: 可以扩大主分片个数
- Rollover Index: 类似Log4J 记录日志的方式,索引尺寸或者时间超过一定值后,创建新的
- Rollup Index: 对数据进行处理后,重新写入,减少数据量
Open / Close Index API
Shrink API
-
ES 5.x后推出的一个新功能,使用场景
- 索引保存的数据量比较小,需要重新设定主分片数
- 索引从Hot 移动到Warm 后,需要降低主分片数
-
会使用和源索引相同的配置创建- - 个新的索引,仅仅降低主分片数
- 源分片数必须是目标分片数的倍数。如果源分片数是素数,目标分片数只能为1
- 如果文件系统支持硬链接,会将Segments 硬连接到目标索引,所以性能好
-
完成后, 可以删除源索引
- 分片必须只读
- 所有的分片必须在同一个节点上
- 集群健康状态为Green
Split API
一个时间序列索引的实际场景
Rollover API
-
当满足一系列的条件,Rollover API支持将一个Alias 指向一个新的索引
- 存活的时间/最大文档数/最大的文件尺寸
-
应用场景
- 当一个索引数据量过大
-
一般需要和Index Lifecycle Management Policies 结合使用
- 只有调用Rollover API 时,才会去做相应的检测。ES并不会自动去监控这些索引
demo API
# 打开关闭索引
DELETE test
#查看索引是否存在
HEAD test
PUT test/_doc/1
{
"key":"value"
}
#关闭索引
POST /test/_close
#索引存在
HEAD test
# 无法查询
POST test/_count
#打开索引
POST /test/_open
POST test/_search
{
"query": {
"match_all": {}
}
}
POST test/_count
# 在一个 hot-warm-cold的集群上进行测试
GET _cat/nodes
GET _cat/nodeattrs
DELETE my_source_index
DELETE my_target_index
PUT my_source_index
{
"settings": {
"number_of_shards": 4,
"number_of_replicas": 0
}
}
PUT my_source_index/_doc/1
{
"key":"value"
}
GET _cat/shards/my_source_index
# 分片数3,会失败
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 3,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
# 报错,因为没有置成 readonly
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 2,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
#将 my_source_index 设置为只读
PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
}
}
# 报错,必须都在一个节点
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 2,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
DELETE my_source_index
## 确保分片都在 hot
PUT my_source_index
{
"settings": {
"number_of_shards": 4,
"number_of_replicas": 0,
"index.routing.allocation.include.box_type":"hot"
}
}
PUT my_source_index/_doc/1
{
"key":"value"
}
GET _cat/shards/my_source_index
#设置为只读
PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
}
}
POST my_source_index/_shrink/my_target_index
{
"settings": {
"index.number_of_replicas": 0,
"index.number_of_shards": 2,
"index.codec": "best_compression"
},
"aliases": {
"my_search_indices": {}
}
}
GET _cat/shards/my_target_index
# My target_index状态为也只读
PUT my_target_index/_doc/1
{
"key":"value"
}
# Split Index
DELETE my_source_index
DELETE my_target_index
PUT my_source_index
{
"settings": {
"number_of_shards": 4,
"number_of_replicas": 0
}
}
PUT my_source_index/_doc/1
{
"key":"value"
}
GET _cat/shards/my_source_index
# 必须是倍数
POST my_source_index/_split/my_target
{
"settings": {
"index.number_of_shards": 10
}
}
# 必须是只读
POST my_source_index/_split/my_target
{
"settings": {
"index.number_of_shards": 8
}
}
#设置为只读
PUT /my_source_index/_settings
{
"settings": {
"index.blocks.write": true
}
}
POST my_source_index/_split/my_target_index
{
"settings": {
"index.number_of_shards": 8,
"index.number_of_replicas":0
}
}
GET _cat/shards/my_target_index
# write block
PUT my_target_index/_doc/1
{
"key":"value"
}
#Rollover API
DELETE nginx-logs*
# 不设定 is_write_true
# 名字符合命名规范
PUT /nginx-logs-000001
{
"aliases": {
"nginx_logs_write": {}
}
}
# 多次写入文档
POST nginx_logs_write/_doc
{
"log":"something"
}
POST /nginx_logs_write/_rollover
{
"conditions": {
"max_age": "1d",
"max_docs": 5,
"max_size": "5gb"
}
}
GET /nginx_logs_write/_count
# 查看 Alias信息
GET /nginx_logs_write
DELETE apache-logs*
# 设置 is_write_index
PUT apache-logs1
{
"aliases": {
"apache_logs": {
"is_write_index":true
}
}
}
POST apache_logs/_count
POST apache_logs/_doc
{
"key":"value"
}
# 需要指定 target 的名字
POST /apache_logs/_rollover/apache-logs8xxxx
{
"conditions": {
"max_age": "1d",
"max_docs": 1,
"max_size": "5gb"
}
}
# 查看 Alias信息
GET /apache_logs