elasticsearch part3

集群身份认证与用户鉴权

错误案例
将server.host 设置为0.0.0.0, 公网可以直接访问

免费方案
nginx反向代理

免费的security插件
Search Guard - https://search-guard.com/ 社区免费版
ReadOnly REST - https://github.com/sscarduzio/elasticsearch-readonlyrest-plugin

X-Pack 的 Basic 版
从 ES 6.8 & ES 7.0 开始,Security 纳入 x-pack 的 Basic 版本中,免费使用一些基本的功能
https://www.elastic.co/cn/what-is/elastic-stack-security

身份认证
用户名密码
密钥

xpack 中的认证realms
内置(免费) : 用户名密码存在es中
外置(收费) : ldap

用户鉴权
定义角色 , 分配权限 , 索引, 字段, 集群等

也可以自定义角色

开启并配置x-pack 认证与鉴权
修改配置文件 x-pack.security.enabled = true

案例
开启es x-pack内置鉴权

#启动单节点
bin/elasticsearch -E node.name=node0 -E cluster.name=geektime -E path.data=node0_data -E http.port=9200 -E xpack.security.enabled=true

为指定用户设置密码

Initiating the setup of passwords for reserved users elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.


#运行密码设定的命令,设置ES内置用户及其初始密码。
bin/elasticsearch-setup-passwords interactive

kibana设置 , 声明 elastic连接的权限

# 修改 kibana.yml
elasticsearch.username: "kibana"
elasticsearch.password: "changeme"

#启动。使用用户名,elastic,密码elastic
./bin/kibana

在这里插入图片描述
在es中写入索引

POST orders/_bulk
{"index":{}}
{"product" : "1","price" : 18,"payment" : "master","card" : "9876543210123456","name" : "jack"}
{"index":{}}
{"product" : "2","price" : 99,"payment" : "visa","card" : "1234567890123456","name" : "bob"}

赋予kibana用户该索引的读权限,
在这里插入图片描述
和kibana的读权限
在这里插入图片描述
创建用户, 指定刚创建的角色, 用这个角色登陆后, 仅能进行读操作, 不能写
在这里插入图片描述

集群内部安全通信

只有认证了的es服务才会加入指定的集群 ;
es提供tls 证书的方式来实现, 证书可以3中工作模式, 证书一致 / 证书一致且ip,hostname一致 / 不做认证

创建证书机构 , 使用空密码,默认路径放在bin同级, 路径格式是win的,

bin\elasticsearch-certutil ca

使用证书机构签发证书

bin\elasticsearch-certutil cert --ca elastic-stack-ca.p12

第一个密码是证书机构的, 第二个是文件路径 , 第3个是证书的密码
在这里插入图片描述
按顺序启动以下3个节点 , 前两个节点指定了证书 , 第3个没有指定, 启动报认证相关错, 无法加入指定集群


bin\elasticsearch -E node.name=node0 -E cluster.name=geektime -E path.data=node0_data -E http.port=9200 -E xpack.security.enabled=true -E xpack.security.transport.ssl.enabled=true -E xpack.security.transport.ssl.verification_mode=certificate -E xpack.security.transport.ssl.keystore.path=certs/elastic-certificates.p12 -E xpack.security.transport.ssl.truststore.path=certs/elastic-certificates.p12


bin\elasticsearch -E node.name=node1 -E cluster.name=geektime -E path.data=node1_data -E http.port=9201 -E xpack.security.enabled=true -E xpack.security.transport.ssl.enabled=true -E xpack.security.transport.ssl.verification_mode=certificate -E xpack.security.transport.ssl.keystore.path=certs/elastic-certificates.p12 -E xpack.security.transport.ssl.truststore.path=certs/elastic-certificates.p12

bin\elasticsearch -E node.name=node2 -E cluster.name=geektime -E path.data=node2_data -E http.port=9202 -E xpack.security.enabled=true -E xpack.security.transport.ssl.enabled=true -E xpack.security.transport.ssl.verification_mode=certificate

集群外部安全通信

es集群与 其他组件系统的交互需要有安全保证, kibana , logstash等,
es提供了https的连接方式

ES 启用 https
启动命令

elasticsearch -E node.name=node0 -E cluster.name=geektime -E path.data=node0_data -E http.port=9200 -E xpack.security.enabled=true -E xpack.security.transport.ssl.enabled=true -E xpack.security.transport.ssl.verification_mode=certificate -E xpack.security.transport.ssl.keystore.path=certs/elastic-certificates.p12 -E xpack.security.http.ssl.enabled=true -E xpack.security.http.ssl.keystore.path=certs/elastic-certificates.p12 -E xpack.security.http.ssl.truststore.path=certs/elastic-certificates.p12

启用后, 通过http访问集群失效, 仅支持https

https://localhost:9200/

kibana连接es
kibana对应也要用https方式连接es
需要用openssl 将p12的证书转为pem, 我这转换失败了

# 为kibana生成pem
openssl pkcs12 -in elastic-certificates.p12 -cacerts -nokeys -out elastic-ca.pem

配置文件中指定证书位置和认证模式

elasticsearch.hosts: ["https://localhost:9200"]
elasticsearch.ssl.certificateAuthorities: [ "/Users/yiruan/geektime/kibana-7.1.0/config/certs/elastic-ca.pem" ]
elasticsearch.ssl.verificationMode: certificate

kibana开启https
与es相同 , 生成证书机构
将生成的文件放到kibana的certs路径

bin/elasticsearch-certutil ca --pem

修改配置文件

server.ssl.enabled: true
server.ssl.certificate: config/certs/instance.crt
server.ssl.key: config/certs/instance.key

因为是用的自签发的证书, 无法校验, 会报错

日志审计

常见的集群部署方式

节点单一角色职责

候选节点master eligible : 负责集群状态, 使用低配置cpu,磁盘,ram

datanode数据节点 : 存储数据, 高配cpu,ram,磁盘ssd

ingest数据处理节点: 处理数据, 高配cpu,中配ram, 低配磁盘

dedicate coordinate only node
负责协同处理客户端请求, loadbalance , 高cpu, ram ,低disk

应对大数据量的聚合请求

dedicate master node
从高可用 脑裂问题 出发 , 生产环境配置3台候选主节点, 主节点负责集群状态, 索引维护, 分片管理;

基本部署
3台 master ,
8台datanode, 进行数据水平扩展
4台coordinate node , 吞吐量进行扩展, kibana集群部署在coordinate 服务器上, 对外提供web服务
外侧加lb 负载均衡, 反向代理 ,
针对写请求中需要额外处理数据的 , 使用ingest node , 写lb 对应ingestnode 节点 , 读lb 对应coordinate 节点

异地多活

gtm 全局流量管理
使用gtm保证多活 , 使用多写 或 Cross-cluster replication APIs 保证一致性
阿里云异地多活
在这里插入图片描述

hot & warm 架构与 shard filtering

日志类数据写入后不再改变 , 时间久了也很少被查询, 这种数据(warm)可以放在一些价格低廉的硬件上存储,
经常被查询改变的数据(hot)则应该放到性能较高的设备上;
可以为es的节点打上标签, 对应不同类型的数据, 提供利用率;

标记节点的key-value ,my_node_type可以自定义
启动时确认之前的nodedata文件夹清空 , 脏数据影响演示

# 标记一个 Hot 节点
bin/elasticsearch  -E node.name=hotnode -E cluster.name=geektime -E path.data=hot_data -E node.attr.my_node_type=hot

# 标记一个 warm 节点
bin/elasticsearch  -E node.name=warmnode -E cluster.name=geektime -E path.data=warm_data -E node.attr.my_node_type=warm

# 查看节点
GET /_cat/nodeattrs?v

配置完后 , 添加索引, 指定该索引全部到存储到这个类型的节点
index.routing.allocation可以随时修改, 之后修改成warm 就可以自动将数据挪移至warm节点

# 配置到 Hot节点
PUT log-2022-4-24
{
  "settings":{
    "number_of_shards":2,
    "number_of_replicas":0,
    "index.routing.allocation.require.my_node_type":"hot"
  }
}
#添加
PUT log-2022-4-24/_doc/1
{
  "key":"value"
}

#确认被存储到指定hot节点
GET _cat/shards?v

在这里插入图片描述
更改节点后 , 在确认到了warm节点中

# 配置到 warm 节点
PUT  log-2022-4-24/_settings
{  
  "index.routing.allocation.require.my_node_type":"warm"
}

在这里插入图片描述
rack awareness
将主分片分散到不同的机架上 , 避免出现机架断点宕机丢失数据的情况

rack1中包含两个分片的主分片
在这里插入图片描述
通过自定义变量my_rack_id 标记节点所处的机架

# 标记一个 rack 1
bin/elasticsearch  -E node.name=node1 -E cluster.name=geektime -E path.data=noderack1_data -E node.attr.my_rack_id=rack1

# 标记一个 rack 2
bin/elasticsearch  -E node.name=node2 -E cluster.name=geektime -E path.data=noderack2_data -E node.attr.my_rack_id=rack2

指定集群根据my_rack_id来配置awareness

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes": "my_rack_id"
  }
}

写入索引后 , 查看分片状态 ,

PUT my_index1
{
  "settings":{
    "number_of_shards":2,
    "number_of_replicas":1
  }
}

PUT my_index1/_doc/1
{
  "key":"value"
}


GET _cat/shards?v

r0 和 p1 在一个机架上
在这里插入图片描述

force awareness

强制指定索引要分配到的位置 ,


DELETE my_index1/_doc/1
# 标记一个 rack 1
bin/elasticsearch  -E node.name=node1 -E cluster.name=geektime -E path.data=node1_data -E node.attr.my_rack_id=rack1

# 标记一个 rack 2
bin/elasticsearch  -E node.name=node2 -E cluster.name=geektime -E path.data=node2_data -E node.attr.my_rack_id=rack1

例如force.my_rack_id.values 要分配到rack1,rack2的机架上

PUT _cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.awareness.attributes": "my_rack_id",
    "cluster.routing.allocation.awareness.force.my_rack_id.values": "rack1,rack2"
  }
}

写入索引后 , 因为没有提供rack2的节点 , 数据只存在于rack1 中, 集群状态变为黄色

PUT my_index1/_doc/1
{
  "key":"value"
}
GET _cluster/settings

# 集群黄色
GET _cluster/health

# 副本无法分配
GET _cat/shards?v

GET _cluster/allocation/explain?pretty

shard filtering
为es标记节点的配置 , 通过
node.attr标记节点 ,
index.routing.allocation 指定索引分配到的节点

其他shard filtering配置的有
index.routing.allocation.include.{attribute} include至少包含一个值
index.routing.allocation.require.{attribute} require所有值都要有 , 例如要分配到所有的机架上
index.routing.allocation.exclude.{attribute} exclude, 不包含该值

分片设计管理

一个索引, 单分片无法扩展数据 ;
多分片在节点加入时可以自动扩展;

过多分片会降低集群性能 , 请求会查询所有分片, 集群状态也要维护分片 ;

如何确定分片数
存储上看
日志类 ,单分片不超过50Gb
搜索类 , 单分片不超过20gb

为什么控制分片储存大小
提高update的性能
merge时 , 减少所需的资源
丢失节点后, 具备更快额恢复速度 / 便于分片在集群内 rebalance

副本分片数
副本是分片的拷贝
提系统可用性 , 响应查询 , 防止数据丢失 ;

对性能影响
降低索引速度 , 需要占用和主分片一样的资源
读负载均衡, 提升读qps

调整分片总数设定 避免分配不均衡

es的分片策略大致相同
扩容新的节点没有数据, 导致索引集中在新的节点
热点数据过于集中可能会产生新的问题
total shard per node 指定每个节点上的分片数

index.routing.allocation.total_shards_per_node 索引一个节点最大的分片数

cluster.routing.allocation.total_shards_per_node 集群中每个节点上最大的主分片和副本分片之和
(Dynamic) Maximum number of primary and replica shards allocated to each node. Defaults to -1 (unlimited).

容量规划

一个集群多少节点 一个索引几个分片
节点的高可用

容量规划考虑的因素
机器配置
单条文档的尺寸 / 文档的总数据量 / 索引的总数据量 / 副本分片数
文档是如何写入的
文档的复杂度, 文档文档如何读取

业务性能需求评估
数据吞吐及性能需求
吞吐量 , 每秒写入多少
查询tps
单条查询可接受的最大返回时间

了解你的数据
数据的格式和数据的mapping
实际的查询和聚合长什么样

常见用例

搜索 :固定大小的数据集
搜索的数据增加缓慢

日志: 基于时间序列的数据
使用es存放日志与性能指标, 数据每天不断写入, 增长速度快
结合warm node 做数据的老化处理

硬件配置
数据节点使用ssd

搜索性能要求高的场景使用ssd
按照1:10配置内存和硬盘

日志类和查询低的场景, 使用机械盘
按照1: 50的比例配置内存和硬盘

单节点数据控制在2tb内 , 不超过5tb

jvm配置机器内存的一半, jvm内存配置不建议超过32g;

部署方式
高可用部署3台dedicated 的master 节点

有复杂的查询和聚合, 建议设置coordinate节点;

容量案例1固定大小的数据集

一个案例 : 唱片库

数据特性 :
增长缓慢 , 基数大, 关心聚合和读取性能
数据的重要性和时间范围无关, 关注的是搜索的相关度 ;

估算索引的数据量 , 确定分片的大小
单个分片不超过20G
通过增加副本, 提高查询tps

拆分索引
业务上大量字段基于一个字段进行filter, 该字段又一个有限的枚举值
例如按照订单所在的地区所谓索引名称进行拆分;

如果索引中有大量数据, 将单个索引拆分成多个索引
查询性能可以提高
多个索引进行查询, 查询中指定多个索引

如果业务上大量查询基于一个字段进行filter, 该字段数值并不固定
可以启用routing功能, 按照filter字段的值分不到及群众不同的shard, 避免该shard成为一个热点shard

容量规划案例 2: 基于时间序列的数据

相关类型
日志 / 指标 / 相关events
舆情分析

一些特性
每条数据都有时间戳 , 文档基本不会被更新 ;
用户更过多的会查询近期的数据 ; 对旧数据查询较少
对数据的写入性能要求高

创建基于时间序列的索引
在索引的名字中增加时间信息,
按照 每天 / 每周 / 每月的方式进行划分

带来的好处
更加合理地组织索引, 例如随着时间推移, 便于对索引做的老化处理
利用hot warm architecture
备份和删除以及删除的效率高; (delete by query 执行速度慢 , 也不会立即释放空间 , merge时)

写入时间序列的数据 : 基于date math 的方式
容易使用
时间发生变化 , 需要重新部署代码

如果url中写要进行转义

# POST /<logs-{now/w}/_search 转义
POST /%3Clogs-%7Bnow%2Fw%7D%3E/_search

例如写入日志 , 每晚执行将logs_write指向新的一天索引, 就会把实际的日志索引到最新的一天中

PUT logs_2019-06-27
PUT logs_2019-06-26

POST _aliases
{
  "actions": [
    {
      "add": {
        "index": "logs_2019-06-27",
        "alias": "logs_write"
      }
    },
    {
      "remove": {
        "index": "logs_2019-06-26",
        "alias": "logs_write"
      }
    }
  ]
}

集群扩容

查询量或响应时间上升, 增加 coordinating / ingest node
解决cpu和内存开销的问题

增加数据节点
解决存储的容量问题
避免分片分布不均的问题, 提前监控磁盘空间 , 提前清理数据或增加节点

将不同的类型的数据放在不同的集群中 , 业务数据一个集群 , 日志数据一个集群

私有云管理es

管理单个集群
集群容量不够 , 手工增加节点

节点丢失时 , 手工修复或更换节点

确保rack awareness

集群版本升级 : 数据备份 , 滚动升级
完全手动管理成本高
无法统一管理, 例如整合变更管理

商业版
ece
企业版, 鉴权, 自动备份, 故障恢复
k8s
企业版, 基础班 , yaml 中定义节点数等

构建自己的管理系统
基于虚拟机的编排方式
Puppet Infrastructure (Puppet / Elasticsearch Puppet Module / Foreman)
* puppet是一个运维框架,针对虚拟机,做到想ansible一样批量编排,保持配置一致性
Workflow based Provision & Management

基于k8sde 容器话编排管理方式
基于operator模式 , operator是k8s的一个模块, 方便快速将es部署在k8s上进行管理 ,
https://github.com/operator-framework/operator-sdk

在这里插入图片描述

在这里插入图片描述

公有云上部署es

es在国内跟阿里云 腾讯云合作;
国外选择aws 等,

生产环境常用配置与上线清单

development vs. production mode
从es5后 , 通过http.host / transport.bind_host:参数的值是否为localhost来判断是哪种环境

bootstrap checks
集群在 生产模式启动 会进行bootstraps 检测

jvm
从es6开始, 仅支持64位jvm
配置config / jvm.options设定

避免修改默认配置
将内存xms和xmx设置成一样 , 避免heap resize时引发停顿
xmx设置不要超过物理内存的50%(剩下内存留给lusence), 单节点上最大内存不超过32G(32G下对象压缩技术,不然性能下降)
生产环境, jvm必须使用server模式;
关闭jvm swapping

集群api设定

静态设置和动态设置 静态配置文件尽量简洁,
按照文档设置所有相关系统参数 , elasticsearch.yml配置文件中只写必备参数 , 也可以通过启动命令 -e 设定参数

其他的设置项可通过api进行设定 , 动态设定分transient 和 persistent 两种 , 都会覆盖yaml中的设置
transient重启后会丢失 ;
persistent 重启后不会丢失;

优先级 , transient > persistent > command-line > yml

系统设置
生产模式中需要按照官网的要求对系统进行配置, 不然无法启动
https://www.elastic.co/guide/en/elasticsearch/reference/8.2/system-config.html

在这里插入图片描述

最佳实践: 网络
单个集群不要跨数据中心部署

节点间的hops越少越好

如果有多块网卡 , 将集群通信端口 和 web端口绑定到不同的网卡上 , 设置不同的防火墙rules

按需为 coordinating 和 ingest node 设置负载均衡

最佳实践: 内存

内存 和 磁盘 比例
搜索类 1: 16
日志类 1: 48 ~ 1:96

例如要存储1T 数据, 1个副本, 总量2T , 集群每个节点的内存为31G
如果是搜索类 , 31G16 = 496G, 加上磁盘自身预留空间 , 可用400G , 5个节点就可以满足2T存储需求 ;
如果是日志类 , 31G
50 = 1550G , 2个数据节点就可以了;

最佳实践 : 存储
使用ssd ,避免使用云盘

可以在path.data指定多个磁盘

无需使用raid磁盘阵列进行备份

在warm节点上使用机械磁盘 , 需要关闭 concurrent merges
index.merge.scheduler.max_thread_count: 1

trim ssd 优化ssd
https://www.elastic.co/blog/is-your-elasticsearch-trimmed

最佳实践 : 服务器硬件
使用多个中等配置的物理机 , 不使用一台性能高的物理机 , 单台有单点故障问题,
也不要在一台物理机部署多个节点

集群设置: throttles限流
为 relocation 和recovery 设置限流 , 避免过多任务对集群性能产生影响

recovery : cluster.routing.allocation.node_concurrent_recoveries:2

relocation : cluster.routing.allocation.cluster_concurrent_rebalance: 2

关闭dynamic indexes

关闭动态索引创建功能, 创建索引必须要显示设置mapping

PUT _cluster/setting
{
	"persistent":{
		"action.auto_create_index":false
	}
}

设置白名单模板

#仅支持logstash 和kibana创建的索引
PUT _cluster/setting
{
	"persistent":{
		"action.auto_create_index":"logstash-*,.kibana*"
	}
}

集群安全设定

为es和kibana配置安全功能, 打开x-pack security功能
打开authentication & authorization
实现索引和字段级的安全控制

节点间通信加密

enable https

audit logs

监控es集群

es stats 相关api
node stats : _node/stats
cluster stats : _cluster/stats
index stats : _index_name/stats

GET _nodes/stats

#Cluster Stats:
GET _cluster/stats

task api
查询 task 相关 api
pending cluster tasks api : GET _cluster/pending_tasks
task management api : GET _tasks(可以用来cancel一个task)

#当前执行的任务
GET _cluster/pending_tasks

监控 thread pool

GET _nodes/thread_pool

GET _nodes/hot_threads

GET _nodes/stats/thread_pool

index & query slow log
支持将分片上 , 查询 获取慢的写入日志文件

支持query 和 fetch 阶段分别定义阈值

索引级的动态设置, 可以按需设置 , 或者通过index template 统一设定

slog log 文件通过 log4j2.properties 进行配置

# 设置 Index Slowlogs
# the first 1000 characters of the doc's source will be logged
PUT my_index/_settings
{
  "index.indexing.slowlog":{
    "threshold.index":{
      "warn":"10s",
      "info": "4s",
      "debug":"2s",
      "trace":"0s"
    },
    "level":"trace",
    "source":1000  
  }
}

# 设置查询
DELETE my_index
//"0" logs all queries
PUT my_index/
{
  "settings": {
    "index.search.slowlog.threshold": {
      "query.warn": "10s",
      "query.info": "3s",
      "query.debug": "2s",
      "query.trace": "0s",
      "fetch.warn": "1s",
      "fetch.info": "600ms",
      "fetch.debug": "400ms",
      "fetch.trace": "0s"
    }
  }
}

dash board

开发 es plugin , 通过读取监控api ,导入es

使用metricbeats搜集指标

使用kibana或 graffna 创建dashboard

开发es exporter , 通过 Prometheus 监控 es

集群运维面临的挑战

用户集群数量多 , 业务场景差异大

使用配置不当, 优化不够
如果更高效使用es,了解集群状态

es提供Support Diagnostics Tool,

集群潜在问题
防患
节点负载大, 宕机
副本丢失
集群压力大

提升性能
数据节点复杂不均衡 , / 优化分片 , segment
规范操作的方式 (利用别名 / 避免dynamic mapping 引发过多字段 ,

**案例 **
集群索引的诊断 ,
索引总数
字段过多
分片个数是否合理
单节点分片是否过多
数据节点之间的负载偏差是否过大
冷热数据分配是否正确

公有云
阿里云会对es客户的集群进行监控诊断

多维度构建
日常运维类 ;
候选master数量
单节点shard 数量

在这里插入图片描述

解决集群黄红状态

docker-compose的elk启动问题:maxCountxxx

分片/索引/ 集群健康

案例:
当前集群状态为green , 创建索引时指定1个副本分片 , 指定仅能在hot节点存储, 之后状态变黄, explain原因为该索引的副本和主分片在同一个节点

# 检查集群状态,查看是否有节点丢失,有多少分片无法分配
GET /_cluster/health/

PUT mytest
{
  "settings":{
    "number_of_shards":2,
    "number_of_replicas":1,
    "index.routing.allocation.require.box_type":"hot"
  }
}

# Explain 原因
GET /_cluster/allocation/explain

dangling
集群丢失节点后 , 删除了某索引 , 之后该节点重新加入, 仍包含被删除的索引 , 需要手动删除该索引

集群变红 , 检查是否有节点离线
配置导致的问题 , 需要修复相关的配置
磁盘空间限制 , 分片规则引发的 , 需要调整规则或者增加节点

总结
创建索引后会引起状态变化 , 监控需要延迟避免误报 ;

move 和 reallocate 分片

提高集群写性能

方法
目标 ; 增加吞吐量 ,
客户端 ; 多线程 批量写
通过写性能测试确定最佳文档数量
需要观察是否有http 429返回, 表示es阻塞了 , 业务上有重试 和 动态调整并发写

服务器 ; 单个性能问题 , 需要分解问题解决, 单个节点进行压测, 观察硬件资源 和 es线程,jvm

服务器端优化写入性能的一些手段
降低io操作
使用es生成的文档id , 一些相关的es配置 , 入refresh interval

降低cpu和存储开销
减少不必要分词 / 避免不需要的docvalue / 文档的字段尽量保证相同的顺序 , 可以提高文档的压缩率

尽可能做到写入和分片的负载均衡 实现水平扩展
shardfilter / 写负载

调整bulk线程池和队列

优化写入性能
es的默认设置 , 已经综合考虑了数据可靠性, 搜索的实时性能 , 不要盲目修改
一切优化 , 基于高质量的数据建模

关闭无用的功能
只要聚合不要搜索 ,将index设置成false
不需要算分 , 将norms设置成false
不对字符串使用默认的dynamic mapping , 字段数量过多 , 会对性能产生比较大的影响
index_options控制在创建倒排索引时 , 哪些内容会被添加到倒排索引. 优化这些设置, 一定程度节约cpu
关闭source , 减少io操作 ;
在这里插入图片描述
针对性能的取舍
如果追求极致的写入速度 , 可以牺牲数据可靠性及搜索实时性已换取性能
牺牲可靠性 , 将副本分片设置为0, 写入完后在调整回去
牺牲搜索实时性, 增加refresh interval的时间
牺牲可靠性 : 修改translog的配置

数据写入过程
refresh :
将文档保存在index buffer中, 以refresh_interval为时间间隔 , 定期清空buffer , 生成segment, 借助文件系统缓存的特性 , 先将segment放在文件的系统缓存中 , 并开放查询 , 以提升搜索的实时性;
可调大refresh_interval时间间隔, 增加indices.memory.index_buffer_size 的空间(满了会触发refresh_interval);

translog:
segment没有写入磁盘, 即便发生了宕机, 重启后, 数据也能恢复, 默认配置是每次请求都会落盘
降低写盘频率, 牺牲容灾性 ;
Index.translog.durability :默认是 request,每个请求都落盘。设置成async,
Index.translog.sync_interval 设置为 60s,每分钟执行一次
Index.translog.flush_threshod_size: 默认 512 mb,可以适当调大。当translog 超过该值,会触发flush
flush:
删除旧的translog文件
生成segment并写入磁盘, 更新commit point 并且写入磁盘 , es 自动完成;

分片设定
副本在写入时设为 0,完成后再增加

合理设置主分片数,确保均匀分配在所有数据节点上
Index.routing.allocation.total_share_per_node: 限定每个索引在每个节点上可分配的主分片数
5 个节点的集群。 索引有 5 个主分片,1 个副本,应该如何设置?
(5+5) / 5 = 2
生产环境中要适当调大这个数字,避免有节点下线时,分片无法正常迁移

bulk ,线程池和队列大小
客户端
单个bulk请求体的大小在5- 15M内 ;
写入端bulk请求超时需要足够长, 建议60s
写入端尽量轮询到不同节点上;

服务器端
创建索引属于计算密集型, 线程池数为cpu+1, 队列不要太大 ,占内存

在这里插入图片描述

提升读性能

建模
非关系型建模 , 尽量不用嵌套, 父子对象
使用 Nested 类型的数据。查询速度会慢几倍
使用 Parent / Child 关系。查询速度会慢几百倍

先行计算 , 再存入es ,减少script使用 , 可以用ingest完成

尽量用filter , 减少算分 , filter基于缓存,
在这里插入图片描述
结合profile explain 分析 慢查询 , 严禁用* terms查询

聚合文档消耗内存 ,
聚合查询中加入query ,限定文档数量

避免通配符
在这里插入图片描述

优化分片
避免over sharding , 减少索引分片数量

结合场景 , 控制分片大小

时间序列的索引日志, iot , 做老化压缩处理 , 减少segment数量, force merge

集群压力测试

压力测试的目的
容量规划 / 性能优化 / 版本比较 / 性能问题诊断
系统稳定性 , 考察系统功能极限和隐患

测试目标
读写性能 / 集群容量规划
es参数进行修改 , 评估优化效果
修改mapping和setting , 对建模优化
测试新版本, 对比老版本

测试数据
数据量 / 数据分布

测试脚本
调用es api接口测试 ,
jmeter / gatling 开源

es rally
官网 https://esrally.readthedocs.io/en/stable/tournament.html
es官方开源 , es专用的测试工具

自动创建/配置/运行/ 销毁 es集群 /
支持数据导入

名词 ;
rally 拉力
目标/ tournament
赛道/ track 测试场景
car / 测试方案 , 不同es集群
award / 结果

**安装运行 **

Python 3.4+ 和 pip3 / JDK 8 / git 1.9+
运行 pip3 install esrally
运行 esrally configure

压测流程
Pipeline 指的是压测的一个流程
rally 默认配置了几个流程

自定义
可运行指定的es集群 https://esrally.readthedocs.io/en/latest/car.html

可以指定分布式测试 https://esrally.readthedocs.io/en/latest/recipes.html#recipe-distributed-load- driver

实例:比较不同的版本的性能
esrally race --distribution-version=6.0.0 --track=nyc_taxis --challenge=append-no- conflicts --user-tag="version:6.0.0”

esrally race --distribution-version=7.1.0 --track=nyc_taxis --challenge=append-no- conflicts --user-tag=“version:7.1.0”

esrally list races

esrally compare --baseline=[6.0.0 race] --contender=[7.1.0 race]

段合并优化及注意事项

es分片lucene 的一个index , 文档索引后每隔一段时间会refresh成一个lucene的segment , segment会存在内存中, 会进行合并

merge优化
es和lucene 会进行自动优化

merge操作比较重 , 降低频率 ,

增加refresh的时间间隔 , 增加 index buffer的空间 , 减少文档更新操作

降低分段大小
Index.merge.policy.segments_per_tier,默认为 10, 越小需要越多的合并操作 ;
Index.merge.policy.max_merged_segment, 默认 5 GB, 操作此大小以后,就不再参与后续的 合并操作

force merge
index不再有写入操作的时候 , 设置成force merge
提升查询速度 / 减少内存开销
在这里插入图片描述

缓存 及 使用breaker限制内存使用

ES还有Off-heap内存,由Lucene管理,负责缓存倒排索引(Segment Memory)
es 用来做缓存, 在jvm 堆中 , 分为3部分
node query cache
一个节点的所有分片共用一个 , 只存 filter context的内容 , lru过期;
需要在每个节点上进行配置
Node Level - indices.queries.cache.size: ”10%”
Index Level: index.queries.cache.enabled: true

shard request cache
缓存每个分片上的查询结果
值缓存设置了 size=0 的查询对应的结果 . 不缓存hits ; 缓存agg 和suggestions

cache key ; 整个查询的json , lru过期

配置 ; 数据节点:indices.requests.cache.size: “1%”

fielddata cache
text 类型的排序需要fielddata , 结果缓存在cache中 , 配置Indices.fielddata.cache.size (默认无限制)

管理内存的重要性
es高效运维依赖于内存的合理分配
内存一般分配给jvm , 一半给操作系统 , 缓存索引文件

内存问题 , 引发的问题
full gc 导致的节点丢失

诊断内存

GET _cat/nodes?v 

GET _nodes/stats/indices?pretty 

GET _cat/nodes?v&h=name,queryCacheMemory,queryCacheEvictions,requestCacheMemory,reques tCacheHitCount,request_cache.miss_count 

GET _cat/nodes?h=name,port,segments.memory,segments.index_writer_memory,fielddata.memory_size,query_cache.memory_size,request_cache.memory_size&v     

一些常见内存问题
频繁full gc , 没有写操作 , 查看segments.memory , 如果是空间过大, 将segment 进行合并为1个

fielddata.memory.size 占用过大 ,indices.fielddata.cache.size 设小, 重启节点

复杂的嵌套聚合 , 导致集群full gc , 需要导出dump分析 , 是否有大量bucket对象 ,

circuit breaker
熔断器 , es用来限制内存占用, 保护自身的措施 ,
Parent circuit breaker:设置所有的熔断器可以使用的内存的总量
Fielddata circuit breaker:加载 fielddata 所需要的内存
Request circuit breaker:防止每个请求级数据结构超过一定的内存(例如聚合计算的内存)
In flight circuit breaker:Request中的断路器
Accounting request circuit breaker:请求结束后不能释放的对象所占用的内存

统计熔断情况

GET /_nodes/stats/breaker?

在这里插入图片描述

Tripped 大于 0, 说明有过熔断
Limit size 与 estimated size 约接近,越可能引发熔断

7.0后 ,增加了 indices.breaker.total.use_real_memory 配置项,可以更 加精准的分析内存状况,避免 OOM
https://www.elastic.co/blog/improving-node-resiliency-with-the-real-memory-circuit-breaker

运维建议

集群生命周期管理
容量规划
流量监控 / 索引优化 / 备份

部署建议
搜索 / 日志指标

高可用 / 至少3主节点分散到不同机架

规范
mapping
禁止自动创建索引 / 动态映射

慢查询
严禁模糊搜索, *号,

集群备份
通过快照恢复集群
https://www.elastic.co/guide/en/elasticsearch/reference/7.1/modules-snapshots.html

定期更新版本
bug修复 , 性能提升

full restart & rolling upgrade
rolling upgrade 不需要停机升级

full restart 需要停机升级步骤
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/restart-cluster.html

停止写入 , 备份集群;
disable shard allocation; cluster.routing.allocation.enable, 关闭分片挪移策略, 不然关闭节点时, es会将该节点的分片挪移到其他节点上
执行synced flush
关闭 , 然后更新节点
先运行master节点 , 再运行其他节点
集群变黄后打开shard allocation

cheat sheet 移动分片
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/cluster-reroute.html
将一个节点的分片移动到另外一个节点

使用场景
当一个数据节点上有过多的hot shard , 将hot shard移动到其他节点上均衡资源利用

POST /_cluster/reroute
{
  "commands": [
    {
      "move": {
        "index": "test", 
        "shard": 0,
        "from_node": "node1", 
        "to_node": "node2"
      }
    },
    {
      "allocate_replica": {
        "index": "test", "shard": 1,
        "node": "node3"
      }
    }
  ]
}

cheat sheet 移除节点
移除一个节点 , 不希望集群颜色变红 黄

PUT _cluster/settings
{
  "transient" : {
    "cluster.routing.allocation.exclude._ip" : "10.0.0.1"
  }
}

执行命令后 , 该节点的数据会被移动到其他节点 , 之后可将节点下线

cheat sheet 控制allocation 和 recovery
https://www.elastic.co/guide/en/elasticsearch/reference/7.10/modules-cluster.html

控制并发数
cluster.routing.allocation.cluster_concurrent_rebalance

控制节点上分片恢复的并发数
cluster.routing.allocation.node_concurrent_recoveries

synced flush
重启一个节点用到, https://www.elastic.co/guide/en/elasticsearch/reference/7.10/indices-synced-flush-api.html

帮助es快速恢复

cheat sheet 清空缓存
清空节点缓存 ,防止oom

post _cache/clear

控制搜索队列
threadpool.search.queue_size:

熔断
indices.breaker.total.limit

shrink rollover api

open close ; 关闭索引节省资源, 无法查询 , 可随时打开 , 数据不会真正删除

shrink
重建索引, 仅可更改主分片数 , 比reindex性能好,

分片数仅能是原分片数的倍数, 原分片数大于更改后分片数
分片仅能只读
都在同一个节点上
集群green

操作完成后将新建的索引改为可写

split api
与shrink相反 , 重建索引, 仅可更改主分片数 , 比reindex性能好,

不需要在同一个节点

时间序列索引
一天一个日志索引, 索引有5个分片, 每个分片推荐20G, 某天日志突增, 总数据量100G以上 ,超过了一个索引的推荐容量 , 分片存储了过多的数据, 期望这种情况该天将日志索引分成多个,分散到不同的分片上节点 ; 类似log4j框架切割日志文件

rollover api
满足一系列条件 , rollover api将alias指向一个新的索引
文档数/ 存活时间 / 最大文件尺寸

以下两个案例, 区别在 “is_write_index”:true , true表示别名索引包含旧的索引, 在查询, 统计时会展示所有索引的数据

案例1

创建索引并设置别名 ,

DELETE nginx-logs*

# 不设定 is_write_true
# 原索引名字符合rollover api命名规范 , 必须已-000001 数字结尾
PUT /nginx-logs-000001
{
  "aliases": {
    "nginx_logs_write": {}
  }
}

写入5次文档

# 多次写入文档
POST nginx_logs_write/_doc
{
  "log":"something"
}

执行 rollover , 设定了 该索引的时间超过1天, 最大文档数超过5个, 最大容量超过5g的指标

POST /nginx_logs_write/_rollover
{
  "conditions": {
    "max_age":   "1d",
    "max_docs":  5,
    "max_size":  "5gb"
  }
}

再次写入第6个文档, 执行rollover, 会创建一个nginx-logs-000002索引, 并别名指向该索引

# 查看 Alias信息
GET /nginx_logs_write

获取别名指向2索引的文档数 , 为0个, 原索引nginx-logs-000001为6个文档
再次nginx_logs_write写入文档, nginx_logs_write索引的文档数增加

GET /nginx_logs_write/_count
GET /nginx-logs-000001/_count

案例2


DELETE apache-logs*


# 设置 is_write_index
PUT apache-logs1
{
  "aliases": {
    "apache_logs": {
      "is_write_index":true
    }
  }
}

POST apache_logs/_count

GET apache-logs1/_count
GET apache-logs8xxxx/_count

POST apache_logs/_doc
{
  "key":"value"
}


#  apache-logs1不符合命名规范, 需要指定 target 的名字
POST /apache_logs/_rollover/apache-logs8xxxx
{
  "conditions": {
    "max_age":   "1d",
    "max_docs":  1,
    "max_size":  "5gb"
  }
}


# 查看 Alias信息
GET /apache_logs

索引全生命周期管理及工具

hot / warm / cold / delete

es curator
es官方 , 基于python命令行工具

可配置流程动作管理索引 , 通过名称过滤索引

需要手动执行

index lifecycle management
es 6.6后推出 ,免费

policy 策略
策略中可配置针对四种阶段的阈值 , 文档数量 / 索引时间 / 索引大小 , 满足阈值后就会触发动作,
在这里插入图片描述

案例

# 运行三个节点,分片 将box_type设置成 hot,warm和cold
# 具体参考 github下,docker-hot-warm-cold 下的docker-compose 文件

DELETE *

GET _cat/nodes

# 设置 1秒刷新1次,生产环境10分种刷新一次
PUT _cluster/settings
{
  "persistent": {
    "indices.lifecycle.poll_interval":"1s"
  }
}

创建策略, ilm为 index life cycle缩写, kibana中配置的单位只有天和小时 , 这里用秒来演示
hot策略 ; 5个文档触发rollover, 创建新索引
warm策略; 索引存活10s后 allocate 移动到warm节点
cold策略; 索引存货15s后,allocate 移动到cold节点
delete策略; 索引存活20s后, 删除该索引


# 设置 Policy
PUT /_ilm/policy/log_ilm_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": {
            "max_docs": 5
          }
        }
      },
      "warm": {
        "min_age": "10s",
        "actions": {
          "allocate": {
            "include": {
              "box_type": "warm"
            }
          }
        }
      },
      "cold": {
        "min_age": "15s",
        "actions": {
          "allocate": {
            "include": {
              "box_type": "cold"
            }
          }
        }
      },
      "delete": {
        "min_age": "20s",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

设置模板, 使用该索引周期, 并指定初始存储节点为hot


# 设置索引模版
PUT /_template/log_ilm_template
{
  "index_patterns" : [
      "ilm_index-*"
    ],
    "settings" : {
      "index" : {
        "lifecycle" : {
          "name" : "log_ilm_policy",
          "rollover_alias" : "ilm_alias"
        },
        "routing" : {
          "allocation" : {
            "include" : {
              "box_type" : "hot"
            }
          }
        },
        "number_of_shards" : "1",
        "number_of_replicas" : "0"
      }
    },
    "mappings" : { },
    "aliases" : { }
}

创建索引后 ,副本为0 方便演示 ,cerebro 调整5s刷新, 观察cerebro ,


#创建索引
PUT ilm_index-000001
{
  "settings": {
    "number_of_shards": 1,
    "number_of_replicas": 0,
    "index.lifecycle.name": "log_ilm_policy",
    "index.lifecycle.rollover_alias": "ilm_alias",
    "index.routing.allocation.include.box_type":"hot"
  },
  "aliases": {
    "ilm_alias": {
      "is_write_index": true
    }
  }
}

在这里插入图片描述
之后写入5个文档, 触发hot的rollover , 观察cerebro

# 对 Alias写入文档
POST  ilm_alias/_doc
{
  "dfd":"dfdsf"
}

创建新索引 0002, 并转移到了warm节点 , 集群变黄为正常
在这里插入图片描述

在这里插入图片描述

索引0001转移到了 cold
在这里插入图片描述

索引0001最终被删除,
在这里插入图片描述

继续向索引写入文档, 会重现整个周期迭代的情况

# 对 Alias写入文档
POST  ilm_alias/_doc
{
  "dfd":"dfdsf"
}

在这里插入图片描述

最终只剩0003在hot节点
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值