ES核心概念
- 集群 Cluster
一个集群由多个Node节点组成,共同提供索引与搜索功能 - 节点 Node
一个节点即一个服务器,作为集群Cluster中的一部分存储数据,默认情况下每个Node节点会被加入到名为“elasticsearch”的集群中 - 分片与副本 Shards与Replicas
分片指的是将索引划分为多份,ES7.x+默认一个1个主分片,分片相当于Kafka中分区的概念,每个分片本身也是一个功能完善且独立的索引,这个分片索引可以被存放在集群的任意节点上;分片的作用在于能够水平扩展数据容量,并且基于分片数据的分布式并行操作进而提高性能;
副本指的是分片的备份(副本分片),ES7.x+默认一个副本分片,相当于Kafka中主题分区的副本;副本的作用在于数据的高吞吐及节点的高可用性 - 索引 Index
索引相当于数据表Table,是指一个拥有几分相似特征的文档集合,创建索引时必须指定一个全部小写字母的标识 - 类型 Type
类型即数据表的类型,ES7.x之后的版本类型都是_doc(可省略) - 映射 Mapping
映射相当于数据表的Schema,用来定义一个文档,规定处理数据的方式和规则 - 文档 Document
文档相当于数据表的记录,格式为JSON,是一个可被索引的基本单元 - 字段 Field
字段相当于数据表的列Column
ES数据写入原理(refresh+flush)
ES底层基于Lucene,数据写入时作为一个个Segment数据片段写入到内存,新增数据时采用延迟写入策略,默认索引的refresh时间间隔为1s,默认flush刷盘时间间隔为30min或者translog文件数据量达到刷盘阈值512mb;
Lucene首先将待写入数据写入到内存Segment然后写到translog文件,超过refresh间隔时间会触发Refresh操作,会将内存中的Segment数据刷新到操作系统文件缓存中(此时数据才能被外部访问到),最后当触发flush刷盘时间将操作系统文件缓存的数据写入到Disk磁盘或者当translog文件达到阈值数据大小时将translog数据刷到磁盘。
若对搜索时效性要求不高,可以适度将refresh间隔时间延长至30s,这样能有效减少段刷新次数但会消耗更多的内存。
默认flush刷盘阈值:index.translog.flush_threshold_size:512mb,可以适度加大刷盘阈值大小,这样能存储更多的数据。
分片与副本优化:建议减少副本数量。由于写数据是会同步到副本节点,若副本数较多则影响写数据效率;当批量写数据时也可以先关闭副本复制功能(设置index.number_of_replicas:0)提高效率,批量写完后再恢复副本功能。
ES单机部署
注意:Elasticsearch不能使用root用户启动,必须使用普通用户安装启动!(本次部署使用ES7.6.1版本)
创建用户与设置权限
0. 上传elasticsearch相关安装包并解压
利用tar -zxvf xxx命令解压(略)
1. 创建ES用户
#创建用户组
groupadd elasticsearch
#创建用户
useradd jeffrey
passwd jeffrey (admin)
2. 设置用户权限
usermod -G elasticsearch jeffrey
chown -R jeffrey:elasticsearch /usr/local/elasticsearch-7.6.1
3. 为ES用户添加sudo权限
#编辑
visudo
#将ES用户添加进sudo权限用户列表
jeffrey ALL=(ALL) ALL
修改配置
#切换ES用户
su jeffrey
#进入ES目录
cd /usr/local/elasticsearch-7.6.1
0. 创建es数据目录与日志目录
mkdir -p /usr/local/elasticsearch-7.6.1/data
mkdir -p /usr/local/elasticsearch-7.6.1/log
1. 修改elasticsearch.yml
vi config/elasticsearch.yml
# ======================== Elasticsearch Configuration =========================
#
# NOTE: Elasticsearch comes with reasonable defaults for most settings.
# Before you set out to tweak and tune the configuration, make sure you
# understand what are you trying to accomplish and the consequences.
#
# The primary way of configuring a node is via this file. This template lists
# the most important settings you may want to configure for a production cluster.
#
# Please consult the documentation for further information on configuration options:
# https://www.elastic.co/guide/en/elasticsearch/reference/index.html
#
# ---------------------------------- Cluster -----------------------------------
#
# Use a descriptive name for your cluster:
#
cluster.name: jeffrey-es
#
# ------------------------------------ Node ------------------------------------
#
# Use a descriptive name for the node:
#
node.name: node-1
#
# Add custom attributes to the node:
#
#node.attr.rack: r1
#
# ----------------------------------- Paths ------------------------------------
#
# Path to directory where to store the data (separate multiple locations by comma):
#
path.data: /usr/local/elasticsearch-7.6.1/data
#
# Path to log files:
#
path.logs: /usr/local/elasticsearch-7.6.1/log
#
# ----------------------------------- Memory -----------------------------------
#
# Lock the memory on startup:
#
bootstrap.system_call_filter: false
#
bootstrap.memory_lock: false
#
# Make sure that the heap size is set to about half the memory available
# on the system and that the owner of the process is allowed to use this
# limit.
#
# Elasticsearch performs poorly when the system is swapping the memory.
#
# ---------------------------------- Network -----------------------------------
#
# Set the bind address to a specific IP (IPv4 or IPv6):
#
network.host: 0.0.0.0
#
# Set a custom port for HTTP:
#
http.port: 9200
#
# For more information, consult the network module documentation.
#
# --------------------------------- Discovery ----------------------------------
#
# Pass an initial list of hosts to perform discovery when this node is started:
# The default list of hosts is ["127.0.0.1", "[::1]"]
#
discovery.seed_hosts: ["192.168.126.150"]
#
# Bootstrap the cluster using an initial set of master-eligible nodes:
#
cluster.initial_master_nodes: ["node-1"]
#
# For more information, consult the discovery and cluster formation module documentation.
#
# ---------------------------------- Gateway -----------------------------------
#
# Block initial recovery after a full cluster restart until N nodes are started:
#
#gateway.recover_after_nodes: 3
#
# For more information, consult the gateway module documentation.
#
# ---------------------------------- Various -----------------------------------
#
# Require explicit names when deleting indices:
#
#action.destructive_requires_name: true
#----------------------------------- Http -------------------------------------
http.cors.enabled: true
http.cors.allow-origin: "*"
2. 根据所在机器的内存配置修改jvm.options
适当修改 -Xms 与 -Xmx 大小
启动与验证
#启动es(注意:使用ES专用用户启动)
bin/elasticsearch
启动报错:
1)问题一
原因分析:ES启动时需要打开系统文件创建大量的索引文件,然而当前Linux系统默认最大打开文件数目限制为4096个,最大打开文件数目太小导致启动报错!
解决:修改/etc/security/limits.conf 解除系统默认最大打开文件限制(注意:修改后可能需要重新登录才会生效)
sudo vi /etc/security/limits.conf
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
2)问题二
原因分析:当前系统普通用户的虚拟内存太小导致启动失败!
解决:修改/etc/sysctl.conf,添加内容 vm.max_map_count=262144 保存退出,再执行sysctl -p即可
sudo vi /etc/sysctl.conf
重新启动验证,OK.
后台启动
nohup bin/elasticsearch 2>&1 &
浏览器访问
http://192.168.126.150:9200/
安装可视化界面Kibana
修改kibana解压目录绑定ES用户
#用root用户绑定ES用户权限
chown -R jeffrey:elasticsearch kibana-7.6.1-linux-x86_64
修改kibana.yml配置文件
#切换ES用户
su jeffrey
#进入kibana解压目录,修改config目录下kibana.yml文件
cd …/kibana-7.6.1-linux-x86_64/
vi config/kibana.yml
server.port: 5601
server.host: "192.168.126.150"
elasticsearch.hosts: ["http://192.168.126.150:9200"]
启动kibana
nohup bin/kibana &
kibana启动成功!
登录kibana
http://192.168.126.150:5601/
elasticsearch-head插件
该插件是ES推出的提供方面快捷的查询管理的图形化界面(浏览器插件),安装略.
下载安装IK分词器插件(中文分词插件)
https://github.com/medcl/elasticsearch-analysis-ik/releases (下载对应ES版本的IK分词器插件)
我这里使用的7.6.1版本
https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.6.1/elasticsearch-analysis-ik-7.6.1.zip
解压后放到 ES解压目录下的plugins新建的ik目录下
重启ES。
验证分词效果:
1.单字分词(ES默认分词器)
2.ik分词
-
粗粒度分词
-
细粒度分词
常规操作
新增索引库
PUT /索引名称
查看索引库
GET /索引名称
删除索引库
DELETE /索引名称
新增文档
(注意:ES7.x以上版本的索引类型默认都是_doc)
PUT /索引名称/类型/id
PUT /es_index/_doc/1
{
"userId": 1001,
"name": "jeffrey",
"sex": "man",
"age": 30
}
PUT /es_index/_doc/2
{
"userId": 1002,
"name": "qiutee",
"sex": "woman",
"age": 20
}
PUT /es_index/_doc/3
{
"userId": 1003,
"name": "linda",
"sex": "man",
"age": 26
}
查看文档
GET /索引名称/类型/id
修改文档
PUT /索引名称/类型/id
PUT /es_index/_doc/3
{
"userId": 1003,
"name": "linda",
"sex": "woman",
"age": 26
}
删除文档
DELETE /索引名称/类型/id
说明:PUT与POST都有新增和更新的功能,也有各自的区别
PUT、POST与DELETE关系及区别
1.PUT与DELETE都是幂等操作,多次执行效果一样
2.PUT需要指定id才能执行,而POST不需要但会生成一个随机且唯一的id创建新文档
3.PUT会将JSON数据全部替换掉,而POST只会更新相同字段的值
Restful操作
GET,PUT,POST,DELETE
查看文档数据
查询所有文档
(注意:ES7.x以上版本Restful方式操作数据时可以省略类型_doc)
GET /索引名称/类型/_search
条件查询
GET /索引名称/类型/_search?q=字段名:字段值 (等于)
GET /索引名称/类型/_search?q=字段名:>=字段值 (大于等于)
GET /索引名称/类型/_search?q=字段名:<字段值 (小于)
范围查询
GET /索引名称/类型/_search?q=字段名[开始值 TO 结束值]
多个id批量查询
GET /索引名称/类型/_mget
{
“ids”:[“值1”, “值2”…]
}
分页查询
方式一:from, size
GET /索引名称/类型/_search?from=值1&size=值2
方式二:scroll
适用场景:适用于大数据检索,原理是先对要检索的数据一次性排好序然后分批次取出,排序后的数据会保持一定的时间,后续分页查询会从排序后的数据快照中批次取出的过程。
scroll分页查询,排序后的数据缓存5min,过期后失效抛异常
第一次查询会生成一个_scroll_id,下次查询直接携带这个即可
过滤显示字段
GET /索引名称/类型/_search?_source=字段1,字段2…
排序查询
GET /索引名称/类型/_search?sort=字段:asc/desc
文档批量操作
批量获取文档数据
GET /{索引名称}/_mget
批量更新文档
注意:ES默认批量操作的数据量不超过100m
POST _bulk
DSL查询高级操作
query查询
term精准查询(不使用分词器)
match模糊查询(使用分词器)
multi_match多字段查询
query_string未指定字段查询
范围查询
排序分页输出字段
filter查询
Filter过滤器查询不会计算相关性分值也不会对结果排序,同时查询结果可被缓存,效率更高
agg聚合查询
ES聚合策略terms相当于SQL中的count
注意:size:0表示查询结果不包含原数据信息只包含聚合统计结果
top_hits: 表示对聚合后的结果取出前n条数据
histogram:表示区间统计,以指定区间范围作为一个分组,与之类似的还有个date_histogram基于时间区间统计
文档映射
查看映射
GET /es_index/_mapping
动态映射
文档动态映射是指ES在写入文档时会根据文档字段自动识别出类型的机制
创建动态映射
PUT /es_index/_doc/4
{
"userId": 1004,
"name": "zfy",
"sex": "man",
"age": 26
}
静态映射
文档静态映射是指ES可以实现定义好Mapping映射,包含文档的各字段类型、分词器等
创建静态映射
type:字段类型,index:可被索引,store:可被存储
常用字段类型:
1)string类型,包含keyword与text两种,其中keyword不可分词,可用于过滤、排序与聚合操作,而text可分词,不可用于排序与聚合
2)数值类型,包含long, integer, short, byte, double, float
3)布尔类型,包含boolean
4)日期类型,包含date
普通对象映射
PUT /es_text
{
"mappings": {
"properties": {
"userId": {
"type": "text",
"index": true,
"store": true
},
"name": {
"type": "keyword",
"index": true,
"store": true
},
"age": {
"type": "integer",
"index": true,
"store": true
}
}
}
}
nested内嵌对象映射
# 创建内嵌对象映射索引
PUT /es_user
{
"mappings": {
"properties": {
"name": {
"type": "keyword"
},
"age": {
"type": "short"
},
"address": {
"type": "nested",
"properties": {
"provice": {
"type": "keyword"
},
"city": {
"type": "keyword"
},
"contry": {
"type": "keyword"
}
}
}
}
}
}
# 查询内嵌对象(示例)
POST /es_user/_search
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "address",
"query": {
"bool": {
"must": [
{
"match": {
"address.provice": "天津"
}
},
{
"match": {
"address.city": "天津"
}
}
]
}
}
}
}
]
}
}
}
根据静态映射创建文档
PUT /es_text/_doc/1
{
"userId": "U12345",
"name": "hello",
"age": 40
}
修改已存在的映射
0停机索引映射修改操作:
# 重新建立一个静态索引,将原索引的数据导入到新索引中
POST /_reindex
{
"source": {
"index": "es_text"
},
"dest": {
"index": "es_test"
}
}
# 删除原索引
DELETE /es_text
# 将新索引重命名为原索引名
PUT /es_test/_alias/es_text
文档更新并发控制
- ES7.x之前的老版本更新文档操作使用version乐观锁机制实现更新保证并发安全
PUT /es_text/_doc/1?version=1
{
...
}
- ES7.x之后的新版本更新文档操作使用 if_seq_no=版本号&if_primary_term=文档位置 代替version
POST /es_text/_update/1?if_seq_no=1&if_primary_term=1
{
"doc": {
"userId": "U6666",
"name": "helen",
"age": 24
}
}
数据建模
ES数据建模可以理解为关系型数据库中表结构设计,包含表字段映射、表与表之间的关联关系等。创建索引库时需要根据数据不同业务类型创建不同索引文档,比如一对多关系的业务类型数据放到同一个索引库中可能会导致数据冗余等问题,所以需要将其拆开分别作为两个具有某种join关系的索引文档。
父子关系文档:比如在订单索引库中一个订单数据对应多个订单项(详情)数据,所以这里的订单数据相对于订单项数据而言就作为父文档,而订单项数据就作为子文档。
父子文档与嵌套对象对比:
1)父子文档可独立更新,而嵌套对象文档存储在一起
2)嵌套对象需要额外内存维护对象且需要更新整个文档
父子关系数据建模
# 创建父子索引时指定父子关系映射
PUT /es_order
{
"mappings": {
"properties": {
"order_orderitem_relation": {
"type": "join",
"relations": {
"order": "orderitem"
}
},
"orderId": {
"type": "keyword"
},
"totalAmt": {
"type": "double"
}
}
}
}
# 往索引中插入父文档
PUT /es_order/_doc/order1
{
"order_orderitem_relation": {
"name": "order"
},
"orderId": "O1847",
"totalAmt": 1000.00
}
PUT /es_order/_doc/order2
{
"order_orderitem_relation": {
"name": "order"
},
"orderId": "O2084",
"totalAmt": 2000.00
}
# 往索引中插入子文档
PUT /es_order/_doc/orderitem1?routing=order1
{
"order_orderitem_relation": {
"name": "orderitem",
"parent": "order1"
},
"orderId": "O1847",
"oitemNo": "09031243792",
"amount": 400.00
}
PUT /es_order/_doc/orderitem2?routing=order1
{
"order_orderitem_relation": {
"name": "orderitem",
"parent": "order1"
},
"orderId": "O1847",
"oitemNo": "08309238420",
"amount": 600.00
}
PUT /es_order/_doc/orderitem3?routing=order2
{
"order_orderitem_relation": {
"name": "orderitem",
"parent": "order2"
},
"orderId": "O2084",
"oitemNo": "00283502398",
"amount": 2000.00
}
# 查询所有文档
GET /es_order/_search
# 查询父子文档
# 根据父文档ID查询子文档
POST /es_order/_search
{
"query": {
"parent_id": {
"type": "orderitem",
"id": "order1"
}
}
}
# 根据子文档字段条件查询父文档
POST /es_order/_search
{
"query": {
"has_child": {
"type": "orderitem",
"query": {
"match": {
"oitemNo" : "08309238420"
}
}
}
}
}
# 根据父文档字段条件查询子文档
POST /es_order/_search
{
"query": {
"has_parent": {
"parent_type": "order",
"query": {
"match": {
"orderId" : "O1847"
}
}
}
}
}
# 修改子文档(不会影响父文档)
PUT /es_order/_doc/orderitem3?routing=order2
{
"order_orderitem_relation": {
"name": "orderitem",
"parent": "order2"
},
"amount": 500.00
}
文件系统数据建模
文件系统中关于path路径的检索
# 创建文件系统索引
PUT /es_fs
{
"settings": {
"analysis": {
"analyzer": {
"path_analyzer": {
"tokenizer": "path_hierarchy"
}
}
}
},
"mappings": {
"properties": {
"filename": {
"type": "text"
},
"author": {
"type": "keyword"
},
"path": {
"type": "text",
"analyzer": "path_analyzer",
"fields": {
"key": {
"type": "text",
"analyzer": "standard"
}
}
}
}
}
}
# 往文件系统索引插入文档
# path_hierarchy策略的分词器默认只将path字段分词为/com, /com/itjeffrey, /com/itjeffrey/test
# 而path.key可以将path字段采用standard单字分词
PUT /es_fs/_doc/1
{
"filename": "test.txt",
"author": "jeffrey",
"path": "/com/itjeffrey/test"
}
# 路径查询
GET /es_fs/_search
{
"query": {
"match": {
"path": "/com/itjeffrey"
}
}
}
GET /es_fs/_search
{
"query": {
"match": {
"path.key": "test"
}
}
}
ES template
ES模板类似数据库的存储过程,先提供预处理的模板,然后通过键值对替换模板中变量
示例:
# 创建模板脚本(mustache为搜索预处理的语言)
PUT _scripts/es_script1
{
"script": {
"lang": "mustache",
"source": {
"query": {
"match": {
"name": "{{keyword}}"
}
}
}
}
}
# 通过模板查询
GET /es_index/_search/template
{
"id": "es_script1",
"params": {
"keyword": "jeffrey"
}
}
# 查看模板信息
GET _scripts/es_script1
# 删除模板
DELETE _scripts/es_script1
根据前缀自动补全
通过suggest search实现自动补全功能
示例:
# 创建索引
PUT /es_book
{
"mappings": {
"properties": {
"title": {
"type": "text",
"analyzer": "ik_max_word",
"fields": {
"suggest": {
"type": "completion",
"analyzer": "ik_max_word"
}
}
},
"content": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
# 添加文档
PUT _bulk
{"create": {"_index": "es_book"}}
{"title": "学习ES基础语法","content": "如何学习ES基础语法?主要内容包括ES查询,ES过滤,ES分组,排序,聚合,内嵌等操作..."}
{"create": {"_index": "es_book"}}
{"title": "学习ES进阶架构","content": "如何学习ES进阶架构?主要内容包括ES集群,节点,设计原理,分词原理,倒排索引等..."}
{"create": {"_index": "es_book"}}
{"title": "学习入门ES到放弃","content": "从入门到放弃,从突击到秃法..."}
# 指定prefix前缀自动补全查询文档
GET /es_book/_search
{
"suggest": {
"book_suggest": {
"prefix": "学习ES",
"completion": {
"field": "title.suggest"
}
}
}
}
地理搜索
基于geo_point经纬度地理坐标搜索
# 创建索引
PUT /es_map
{
"mappings": {
"properties": {
"location": {
"type": "geo_point"
},
"address": {
"type": "text",
"analyzer": "ik_max_word"
}
}
}
}
# 插入数据
#注意:lon:表示经度,lat:表示纬度
PUT /es_map/_doc/1
{
"location": {
"lon": -69.32,
"lat": 45.98
},
"address": "测试地点1"
}
PUT /es_map/_doc/2
{
"location": {
"lon": -40.19,
"lat": 60.11
},
"address": "测试地点2"
}
PUT /es_map/_doc/3
{
"location": {
"lon": -108.52,
"lat": -19.69
},
"address": "测试地点3"
}
# 根据指定区域范围查询,建议使用filter过滤位置数据,不会计算score,效率更高
# 矩形范围查询
GET /es_map/_search
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": {
"lon": -180.00,
"lat": 90.00
},
"bottom_right": {
"lon": 180.00,
"lat": -90.00
}
}
}
}
}
# 多边形范围查询
GET /es_map/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"geo_polygon": {
"location": {
"points": [
{
"lat": 40.73,
"lon": -74.1
},
{
"lat": 40.83,
"lon": -75.1
},
{
"lat": 80.83,
"lon": -75.1
}
]
}
}
}
}
}
}
# 圆形范围查询,查询某地点附近的位置(常用单位m-米,km-千米,mi-英里)
GET /es_map/_search
{
"query": {
"bool": {
"must": [
{
"match_all": {}
}
],
"filter": {
"geo_distance": {
"distance": "100km",
"location": {
"lat": 40.73,
"lon": -74.1
}
}
}
}
}
}
# 统计距离某地点范围内的数据(统计算法:aloppy_arc默认算法,arc最高精度,plance最高效率)
GET /es_map/_search
{
"size": 0,
"aggs": {
"analyze_by_locate": {
"geo_distance": {
"distance_type": "arc",
"field": "location",
"origin": {
"lat": 52.376,
"lon": 4.894
},
"unit": "mi",
"ranges": [
{
"to": 100
},
{
"from": 100,
"to": 300
},
{
"from": 300,
"to": 500
}
]
}
}
}
}
Elasticsearch SQL
查询结果格式化
格式化为txt,json,csv等
SQL转为DSL
全文检索
分组查询
ES集群部署
说明:ES集群搭建步骤与上述单机搭建步骤大体相同,唯一不同在于elasticsearch.yml配置有细微区别
#集群名称需要相同
cluster.name: jeffrey-es
#同一集群下节点名称必须唯一
node.name: node-n
#集群hosts与初始节点名称配置:
discovery.seed_hosts: ["IP1", "IP2", "IP3"]
cluster.initial_master_nodes: ["节点1名称", "节点2名称", "节点3名称"]
#其他配置与上述单机ES配置一致!
查看集群节点信息
GET _cat/nodes?v
注意:master项标为*表示主节点,其他都是从节点
GET _cat/health?v
分片
ES7.x之前版本默认5个分片,而7.x之后的版本默认只有一个分片;
新版本可以通过在创建索引映射过程中指定分片数与副本数
"settings": {
"number_of_shards": 3,
"number_of_replicas": 3
}
查看分片信息
GET /_cat/indices?v
延迟分片配置
默认情况下,对于节点瞬断问题,ES集群会等待1min再看该节点是否加入集群,若在这1min内加入集群则该节点会保持原有的分片数据,若超过1min没有加入集群则认为该节点宕机,并将该节点上原有分片数据进行重新分配到其他健康的节点。
另外也可以修改延迟分片时间,尽可能减少重新分配分片时带来的开销。
PUT _all/_settings
{
"settings": {
"index.unassigned.node_left.delayed_timeout": "5m"
}
}
Beats
Beats是一个开源的数据发送器,一般作为一种代理安装在服务器上,可以方便的将数据直接发送到Elasticsearch或者Logstash然后基于Logstash对数据进一步处理后存入Elasticsearch中最后用Kibana可视化。
ES提供了多种Beats实现,使用最多的是基于日志文件的FileBeat。
FileBeat
FileBeat是一个轻量级日志数据采集转发工具,其作为代理安装在服务器上监控指定路径的日志文件并采集数据到ES或Logstash中。
工作原理:
FileBeat启动时会开启一个或多个Input输入,这些Input监控指定日志文件位置,会对每一个文件开启一个Harvester收割器,Harvester读取每个文件的日志并将新的日志发送到libbeat,然后libbeat将数据收集到一起再发送给Output输出。
测试案例
本案例演示FileBeat采集kafka日志数据并输出到ES。
- 在filebeat解压后的目录下新建一个filebeat_log.yml配置文件
# 配置输入Input需要采集的日志目录文件
filebeat.inputs:
- type: log
enabled: true
paths:
- /usr/local/kafka_2.12-2.8.2/logs/server.log.*
# 配置输出到ES
output.elasticsearch:
hosts: ["192.168.126.155:9200"]
- 启动FileBeat
./filebeat -e -c filebeat_log.yml
- 查看ES中filebeat索引数据
Logstash
Logstash是一个开源的数据采集引擎,可以同时动态地将不同数据源(如Log4j,MQ-log,TCP/UDP等)的数据统一采集并按照指定的数据格式处理后转发到其他目的地(如ES等)
FileBeat与Logstash对比
- FileBeat基于golang语言开发轻量级、资源消耗小,而Logstash由JVM运行、资源消耗较大
- FileBeat功能单一、监视并收集数据、速度较快,而Logstash除了收集数据功能外还支持数据过滤功能、速度较慢
一般应用而言,采用FileBeat做日志采集,转发数据到MQ或Redis中然后由Logstash对数据进行过滤处理(数据清洗),最后存储到Elasticsearch中。
另外通过FileBeat与Logstash配合使用进而实现背压机制,即当Logstash处理数据较繁忙时会通知FileBeat放慢采集速度,当Logstash处理数据不繁忙时FileBeat会恢复原来采集速度继续传输。
Logstash过滤器
Logstash集成了很多种插件,其中较常用的包括将非结构化的数据解析为结构化数据的Grok插件。
#查看Logstash插件列表
bin/logstash-plugin list
Grok插件
Grok默认匹配到的数据都是字符串类型,也可以转为int或float类型
Grok模式语法:%{SYNTAX:SEMANTIC},如%{IP:source}
SYNTAX包含:NUMBER-匹配(包含小数)数字;INT-匹配整型;POSINT-匹配正整型;WORD-匹配单词;PATH-匹配路径;IP-匹配IP地址;HTTPDATE-匹配日期;DATA-匹配所有字符等
Debug Grok
Mutate插件
Mutate插件可以对结果字段进行添加、移除等处理
测试案例
1.控制台演示Logstash的输入与输出
本案例仅供演示Logstash基本使用
进入Logstash解压后的目录,运行.
bin/logstash -e ‘input {stdin {} } output {stdout {}}’
2.FileBeat采集日志到Logstash清洗
在FileBeat解压后目录下新建filebeat_logstash.yml配置文件
注意:
multiline.pattern:表示正则表达式,
multiline.negate:默认false,表示匹配pattern的行合并到上一行,为true表示不匹配pattern的行合并到上一行,
multiline.match:after或before,表示合并到上一行的末尾或开头
filebeat.inputs:
- type: log
enabled: true
paths:
- /usr/local/kafka_2.12-2.8.2/logs/server.log.*
multiline.pattern: '^\\d+\\.\\d+\\.\\d+\\.\\d+ '
multiline.negate: true
multiline.match: after
output.logstash:
hosts: ["192.168.126.155:5044"]
在Logstash解压后目录的config目录下新建filebeat_logstash.conf配置文件
# 输入监听5044端口,接收filebeat数据
input{
beats {
port => 5044
}
}
# 输出到控制台
output{
stdout {
codec => rubydebug
}
}
测试Logstash配置是否正确
#进入Logstash解压后目录,运行.
bin/logstash -f config/filebeat_logstash.conf --config.test_and_exit
配置OK.
启动Logstash(–config.reload.automatic表示修改配置文件时自动重新加载)
bin/logstash -f config/filebeat_logstash.conf --config.reload.automatic
再启动FileBeat(当监控的日志文件内容又发生变动时,Harvester会检测到并将数据采集转发到Logstash的5044端口)
./filebeat -e -c filebeat_logstash.yml
FileBeat
Logstash
若输出到Elasticsearch,只需修改filebeat_logstash.conf配置文件即可
output {
elasticsearch {
hosts => ["192.168.126.155:9200"]
}
}
由于Logstash配置的自动刷新功能,随后会自动Reload
之后检测到server.log的数据会自动处理保存到ES中
查看Kibana索引文档
若要过滤数据,则需在filebeat_logstash.conf配置文件中添加filter过滤即可
filter {
grok {
match => {
"message" => "%{DATE:date} %{TIME:time}\] %{WORD:level} \[%{DATA:thread}\]"
}
}
}
若要移除掉生成的某些字段,则需在filebeat_logstash.conf配置文件中添加mutate插件配置即可
filter {
mutate {
enable_metric => "false"
remove_field => ["message", "log", "tags", "input", "agent", "host", "ecs", "@version"]
}
}
若要转换日期格式,则需在filebeat_logstash.conf配置文件中添加date插件配置即可
filter {
date {
match => ["date", "yyyy-MM-dd HH:mm:ss,SSS"]
target => "date"
}
}
若要输出到ES的指定索引库中,则需在filebeat_logstash.conf配置文件中添加index配置即可
output {
elasticsearch {
hosts => ["192.168.126.155:9200"]
index => "kafka_log_%{+YYYY-MM}"
}
}