catelog
集群身份认证与用户鉴权
错误案例
将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存储需求 ;
如果是日志类 , 31G50 = 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,了解集群状态
集群潜在问题
防患
节点负载大, 宕机
副本丢失
集群压力大
提升性能
数据节点复杂不均衡 , / 优化分片 , 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节点