一、介绍
越来越多的公司使用ELK技术栈做为日志分析平台,ELK是三个工具的简称,即Logstash+ElasticSearch+Kibana,
其中以ElasticSearch(es)为核心(存储数据和查询数据),Logstash收集数据,Kibana进行数据展示,具体流程就是使用Logstash将日志做简单的分析后收集到ElasticSearch中,最后使用Kibana根据不同的业务进行展示(预警)。
ElasticSearch底层使用lucene进行索引,到目前为止ElasticSearch共有3个大版本
ElasticSearch1.x 最初的版本
ElasticSearch2.x
ElasticSearch5.x 提高了性能,并且将elastic所有版本都统一
ElasticSearch6.x
ElasticSearch 是基于 Apache Lucene™ 开发的开源的全文搜索引擎库,2021 年 1 月 15 开始,自 Elastic 7.11 版本开始,Elasticsearch 与 Kibana 代码所遵循的 Apache 2.0 许可会调整为 SSPL 与 Elastic License 双许可。SSPL 是由 MongoDB 制定的源代码许可,目的在于限制云供应商修改 Elasticsearch 源码发布自己的服务版本,而不贡献于社区。查看详细解说。
SSPL 允许用户以自由且不受限制的方式使用并修改代码成果,唯一的要求是:如果将产品以作为一种服务进行交付,那么必须同时公开发布所有关于修改及 SSPL 之下管理层的源代码。
使用注意
使用 Spark 和 Flink 在写 ElasticSearch 的时候,写入的总分区应该 <= ElasticSearch 数据节点 * 3(最大),并且应该优化 ElasticSearch Index 存储和刷新类型。目前写入总上限为 10w/s(去掉副本&不刷新),5w/s(有副本和刷新)。
index.mapping.total_fields.limit 默认是系统设置 1000 个字段,如果是宽表索引应该增加该参数。
index.refresh_interval 刷新时间间隔,-1 代表不刷新,刷新指写入的数据可以查询到。
一定不能使用 swap。
二、本地安装
安装依赖程序
安装JDK
es5+需要jdk8的版本
下载JDK
wget http://download.oracle.com/otn-pub/java/jdk/8u131-b11/d54c1d3a095b4ff2b6607d096fa80163/jdk-8u131-linux-x64.tar.gz?AuthParam=1499007315_3290c5ba69a1db872cf77e9abbd5018e
cd /usr/share && tar xavf jdk-8u131-linux-x64.tar.gz
配置环境变量
sudo vim /etc/profile
#加入以下代码
export JAVA_HOME=/usr/share/jdk1.8.0_131
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
下载
下载elasticSearch-5.4
curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.1.tar.gz
下载elasticSearch其他格式或其他版本<br>ElasticSearch
解压并快速启动
tar xzvf elasticsearch-5.4.1.tar.gz
#创建一个普通用户
user add elastic
sudo passwd elastic #盲打密码
su elastic
chown -R elastic:elastic ./elasticsearch-5.4.1
cd elasticsearch-5.4.1
bin/elasticsearch #按Ctrl+C结束
#浏览器数据,显示json数据
http://127.0.0.1:9200
安装head插件(ElasticSearch可视化)
ES 2.0sudo elasticsearch/bin/plugin install mobz/elasticsearch-head
ES 1.0sudo elasticsearch/bin/plugin -install mobz/elasticsearch-head/1.x
ES 0.xsudo elasticsearch/bin/plugin -install mobz/elasticsearch-head/0.9
open http://localhost:9200/_plugin/head/ES 5.x
git clone git://github.com/mobz/elasticsearch-head.git
cd elasticsearch-head
npm install
npm run start
open http://localhost:9100/
三、集群安装
下载
下载elasticSearch-5.4
curl -L -O https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.4.1.tar.gz
下载elasticSearch其他格式或其他版本 <br>ElasticSearch
修改配置文件
由于作者没有多余的机器进行集群安装(不喜欢虚拟机里面操作),所以通过修改端口的形式来安装启动多个ES
ES有两个端口,一个是9200(rest端口),另一个是9300(内部通讯端口)
node1==>9200,9300(数据节点)
node2==>9400,9500(数据节点)
node3==>9600,9700(辅助选举节点,不存储索引数据)
vim config/elasticsearch.yml
通用配置
# 集群名称 一个网段的多个ES通过集群名称来识别,默认是elasticsearch
cluster.name: my-application
#节点名称 同一集群的节点名称不重复
node.name: node-1
#节点所在机架 可以不配置
#node.attr.rack: r1
#数据存储路径
path.data: /opt/soft/elasticsearch-5.4.0-9200/data
#日志存储路径 默认在安装路径/logs
#path.logs: /path/to/logs
#IP地址 广播地址 绑定端口地址
network.host: 127.0.0.1
#rest端口 一台机器上面唯一
http.port: 9200
#通讯端口
transport.tcp.port: 9300
#初始化节点信息 使用通讯端口,默认是9300
#discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300", "127.0.0.1:9500","127.0.0.1:9700"]
# 最小选举节点数(存在选举节点无需配置)
#discovery.zen.minimum_master_nodes: 2
#指定该节点是否被选举为Master,默认是true
node.master: true
#指定该节点是否存储索引数据
node.data: true
node1
cluster.name: my-application
node.name: node-1
path.data: /opt/soft/elasticsearch-5.4.0-9200/data
network.host: 127.0.0.1
http.port: 9200
transport.tcp.port: 9300
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9500","127.0.0.1:9700"]
node.master: true
node.data: true
node2
cluster.name: my-application
node.name: node-2
path.data: /opt/soft/elasticsearch-5.4.0-9400/data
network.host: 127.0.0.1
http.port: 9400
transport.tcp.port: 9500
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9500","127.0.0.1:9700"]
node.master: true
node.data: true
node3
cluster.name: my-application
node.name: node-3
path.data: /opt/soft/elasticsearch-5.4.0-9600/data
network.host: 127.0.0.1
http.port: 9600
transport.tcp.port: 9700
discovery.zen.ping.unicast.hosts: ["127.0.0.1:9300","127.0.0.1:9500","127.0.0.1:9700"]
node.master: true
node.data: false
打开浏览器输入 http://127.0.0.1:9200/_nodes
四、Docker安装
Docker 环境准备
首先安装Docker 一般Linux发行版本中都支持Docker
# centos
yum install docker
#debian
apt-get install docker
#arch
pac-man install docker
将自己添加到Docker用户组中
#user1 为要添加的用户名 docker为Docker用户组 a为append G为group
sudo usermod -aG docker user1
启动Docker
#新版本服务启动(centos7)
systemctl start docker
#旧版本服务启动(centos6)
service docker start
Docker 基本命令
# 查看Docker进程
docker ps
#查看所有的镜像文件
docker images
# 将远程的Docker镜像pull到本地(比较漫长,视时间和地区大小而定)
docker pull imgName
#前台运行一个容器
docker run -it imgName
#后台运行一个容器
docker run -d imgName
#停止一个容器
docker stop name|uuid
运行Docker-ES local
#获取镜像文件(存在则不会重复获取)
docker pull elasticsearch
#后台运行容器 容器名:elas-local 映射容器端口9200到宿主机9200端口上
docker run -d --name elas-local -p 9200:9200 elasticsearch
#停止容器
docker stop elas-local
运行Docker-ES cluster
#获取镜像文件(存在则不会重复获取)
docker pull elasticsearch
#启动集群模式(使用环境变量传入配置,默认集群名称为:elasticsearch)
docker run -d --name elas-node1 -p 9200:9200 elasticsearch -Etransport.host=127.0.0.1 -Ediscovery.zen.minimum_master_nodes=1
docker run -d --name elas-node2 -p 9400:9200 elasticsearch -Etransport.host=127.0.0.1 -Ediscovery.zen.minimum_master_nodes=1
docker run -d --name elas-node3 -p 9600:9200 elasticsearch -Etransport.host=127.0.0.1 -Ediscovery.zen.minimum_master_nodes=1
#使用配置文件启动
docker run -d -v "$PWD/config":/usr/share/elasticsearch/config elasticsearch
#讲数据文件另存
docker run -d -v "$PWD/esdata":/usr/share/elasticsearch/data elasticsearch
五、实现like搜索(模糊匹配)
六、QA
Q:我的集群最大可以有多少分片?
A:分片的数量和可用堆内存大小成正比,1GB 堆内存在 20-25 个。
Q:index.number_of_shards 设置多少合适?
A:分片的数据应该结合数据大小,需要考虑导未来新增的数据容量,默认是 5,太大和太小都会影响查询性能。每个查询在每个分片中是单线程查询的,并且小分片不利于高速缓存。按照经验设置 30G-50GB 一个分片。
Q:index.store.type 该如何选择?
A:官方文档,如果你的运行环境不是 Windows 并且追求高效率应该使用 niofs,niofs 因为 sun 在 Windows 中实现有错误。mmapfs 会消耗虚拟地址空间,在内存紧张的情况下容易写挂 ElasticSearch,性能不如 niofs。
Q:index.translog 是什么?
A:官方文档,translog 是 ElasticSearch 的事务日志,用于重启断电后的恢复。translog 越短恢复越快,flush 一次表示从内存中刷新导磁盘上。index.translog.durability 表示 translog 到磁盘刷新的类型 async 和 request。async 更快但是有数据丢失的分险,必须确定你容忍丢失 index.translog.sync_interval 的数据。否则应该设置 request。
Q:查询的数量 total=1000,如何显示全部文档?
A:7.x 加上 "track_total_hits": 2147483647 参数,6.x 加上 "adjust_pure_negative": true 参数。
Q:ElasticSearch 内部的文档是只读的,如何实现删除和更新?
A:更新操作其实是根据以前的文档和现在的操作生成一个新的文档,使用乐观锁(_sep_no 、_version)去控制。删除标注其实也是更新操作,查询时如果遇到删除的文档则跳过,在段(segment)合并的时候才会真正删除该文档。
Q:keyword 类型有什么作用?
A:ElasticSearch 字段是支持多类型,默认 string 类型有 text 和 keyword。text 适合存储大的文本,并且可以结合分词器对其相关度打分。keyword 一般用于不太长的文本最大支持的长度为——32766 个 UTF-8 类型的字符,中文应该是 255 个字,超过给定长度不再索引,适合存储姓名,邮箱,电话号码等。
Q:有分片没有被 node 管理,如何操作?
A:有可以大批量分片恢复有一些分片超时并且重试 3 次都失败了,尝试执行“分片重路由”。
Q:我有一个内存是 125G 的机器,如何部署节点?
A:官方文档,由于 JVM 大于 ~32G 内存时不会使用内存压缩技术,为了避免造成浪费,需要查询并设置小于临界值。采用多节点的方式部署,需要设置 cluster.routing.allocation.same_shard.host: true 避免同一个分片都在同一个物理机上面。需要给 Lucene 至少机器一半的内存也就是 64G,剩余的 64G 分别启动两个节点。
$ JAVA_HOME=`/usr/libexec/java_home -v 1.7` java -Xmx32600m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
bool UseCompressedOops := true
$ JAVA_HOME=`/usr/libexec/java_home -v 1.7` java -Xmx32766m -XX:+PrintFlagsFinal 2> /dev/null | grep UseCompressedOops
bool UseCompressedOops = false
Q:如何做冷热数据存储
A:在节点的配置文件中标注是冷/热节点
node.attr.temperature: hot //热节点
node.attr.temperature: cold //冷节点
在创建索引时标注索引到节点的属性
index.routing.allocation.include.{attribute} //表示索引可以分配在包含多个值中其中一个的节点上。
index.routing.allocation.require.{attribute} //表示索引要分配在包含索引指定值的节点上(通常一般设置一个值)。
index.routing.allocation.exclude.{attribute} //表示索引只能分配在不包含所有指定值的节点上。
PUT /xxx
{
"settings": {
"index.routing.allocation.require.hotwarm_type": "hot", # 指定为热数据节点
"number_of_replicas": 0
}
}
# 迁移至冷节点
PUT /xxx/_settings
{
"settings": {
"index.routing.allocation.require.hotwarm_type": "cold" # 指定数据存放到冷数据节点
}
}
Q:有好用的索引运维的工具吗?
A:elastic.co 提供了 elasticsearch-curator,一个 python 写的工具
七、索引(Index)
创建索引
PUT xxx
{
"mappings": {
"properties": {}
},
"settings": {
"index.mapping.total_fields.limit": 100000,
"index.refresh_interval": -1,
"index.number_of_shards": 32,
"index.number_of_replicas": 0,
"index.translog.sync_interval": "30s",
"index.translog.durability": "async",
"index.translog.flush_threshold_size": "1g",
"index.store.type": "niofs",
"index.max_result_window":"2147483647"
}
}
使用脚本搜索
GET xxx/_search
{
"post_filter": {
"script" : {
"script" : "doc['f.value'].values.length > 1"
}
}
}
创建固定内存索引
PUT xxx
{
"settings": {
"index.store.preload": [
"nvd",
"dvd",
"tim",
"doc",
"dim"
],
"index.mapping.total_fields.limit":100000,
"index.refresh_interval": "-1",
"index.number_of_shards": "14",
"index.number_of_replicas": "0",
"index.translog.sync_interval": "10s",
"index.translog.durability": "async",
"index.translog.flush_threshold_size": "1g",
"index.store.type": "niofs",
"index.max_result_window":"2147483647"
}
}
写入前修改索引
PUT xxx/_settings
{
"index.refresh_interval": "-1",
"index.number_of_replicas": 0
}
写入完成后修改索引
PUT xxx/_settings
{
"index.refresh_interval": "5s",
"index.number_of_replicas": 1
}
只删除指定标签
POST xxx/_update_by_query?conflicts=proceed
#&max_docs=100000&refresh=true&requests_per_second=5000
{
"script" : "ctx._source.remove('1')",
"query" : {
"exists": { "field": "1" }
}
}
根据删除查询到的文档
POST xxx/_delete_by_query?conflicts=proceed
#&max_docs=100000&refresh=true&requests_per_second=5000
{
"query": {"exists": {"field": "f"}},
"track_total_hits": 2147483647
}
创建 reindex 任务
POST /_reindex?slices=1&refresh&wait_for_completion=false
{
"source": {
"index": "xxx",
"remote": {
"host": "http://10.0.0.19200",
"socket_timeout": "1m",
"connect_timeout": "60s"
},
"size": 10000
},
"dest": {
"index": "xxxx",
"routing": "=cat"
}
}
查询 reindex 任务
GET _tasks?detailed=true&actions=*reindex
取消所有 reindex 任务
POST _tasks/_cancel?actions=*reindex
八、内存模型
九、路由
分片重路由
POST /_cluster/reroute?retry_failed=true&pretty
十、任务&集群
重启之后设置集群大批量恢复分片
PUT _cluster/settings
{
"persistent" :
{
"cluster.routing.rebalance.enable": "all",
"cluster.routing.allocation.node_concurrent_incoming_recoveries":2,
"cluster.routing.allocation.node_concurrent_outgoing_recoveries":2,
"cluster.routing.allocation.node_initial_primaries_recoveries":4,
"cluster.routing.allocation.same_shard.host":true,
"cluster.routing.allocation.node_concurrent_recoveries": 10,
"indices.recovery.max_bytes_per_sec": "40mb"
}
}
Task 任务查询
GET _cat/tasks
GET _tasks
GET _tasks?actions=indices:*
GET _tasks?actions=indices:data/write/*
GET _tasks?actions=indices:data/write/bulk
GET _tasks?actions=indices:data/write/update/byquery
GET _tasks?actions=indices:data/write/delete/byquery
GET _tasks?actions=indices:admin/flush
GET _tasks?actions=indices:admin/refresh[s]
GET _tasks?actions=indices:admin/forcemerge
清除 JVM cache 数据
POST _cache/clear
刷新至让文档可读
POST /_refresh
POST _flush
POST _flush/synced
节点下线操作(禁止分片迁移)
下线节点
# start
# 步骤1:将节点从集群路由策略中排除
PUT /_cluster/settings?pretty
{"transient":{"cluster.routing.allocation.exclude._name":"10.10.10.11"}}
# 步骤2:等待节点上分片全部被迁移
##检查集群状态,若出现pening_tasks,当pending_tasks的等级>=HIGH时,存在集群无法新建索引的风险
GET /_cluster/health?pretty
GET /_cluster/pending_tasks?pretty
##若集群中出现UNASSIGNED shards,检查原因,查看是否是分配策略导致无法迁移分片
GET /_cluster/allocation/explain?pretty
#步骤3:下线节点
#步骤4:取消节点禁用策略
PUT /_cluster/settings?pretty
{"transient":{"cluster.routing.allocation.exclude._ip": null}}
#end
PUT /_cluster/settings?pretty
{
"transient": {
"cluster.routing.allocation.exclude._name": "es1,es2,es3,es4..."
}
}
评论区