ELK stack
Lucene:
文档:Document(包含了一个或多个域的容器)
域(field):value(值)组成;对value进行搜索
域(字段):
有很多选项
索引选项、存储选项、域向量使用选项;
索引选项:用于通过倒排索引来控制文本是否可被搜索
Index.ANYLYZED(分析=切词)并单独作为索引项
Index.Not_ANYLYZED(不分析=不切词)并将整个内容作为一个索引项
Index.ANYLYZED_NORMS:类似Index.ANYLYZED,但不存储token(切的词)Norms(加权基准)
Index.Not_ANYLYZED_NORMS:类似Index.Not_ANYLYZED,但不存储值的Norms(加权基准)
Index.NO: 不对此域的值进行索引,因此不能被搜索
存储选项:是否需要存储域的真实值
store.YES: 存储真实值
store.NO: 不存储真实值
域向量选项:用于在搜索期间控制该文档所有的唯一项都能完全从文档中域中检索时使用
· 文档和域的加权操作
加权计算标准:
搜索:
查询Lucene索引时,它返回的是一个有序的scoreDOC对象,查询时,Lucene会为每个文档计算出其score,根据score进行排序
API:
IndexSearcher:搜索索引入口
Query及其子类
QueryParser:查询分析器
TopDocs:保存某一次ScoreDoc中score较高的前十个
ScoreDoc:存储查询结果
Lucene的多样化查询:
IndexSearcher中的search方法
TermQurey: 对索引中的特定项进行搜索;Term是索引中的最小索引片段,每个Term包含了一个域和一个文本值
例: title: This is a Desk.
owner: Tom Blair
description: this is a desk,it's belong to Tom.
title: This is a table.
owner: Clinton
description: this is a desk,it's belong to Clinton.
This (1) (2)
Desk (1)
table (2)
指明哪个域中搜索,那么description中即便有匹配也不去搜索
TermRangeQuery:在索引中的多个特定项中进行搜索,能搜索指定的多个域
NumericRangeQuery: 只做数值范围搜索
PrefixQuery: 前缀搜索,搜索包含以指定字符串开头的项
BooleanQuery: 用于实现组合查询,组合逻辑有(AND,OR,NOT)
PhraseQuery: 词语搜索
wildcaredQurey: 结合通配符查询
FuzzyQuery: 模糊查询
Elasticsearch
ES是一个基于Lucene实现的开源、分布式、Restful的全文本搜索引擎;此外,它还是一个分布式实时文档存储,其中每个文档的每个field均是被索引的数据
且可被搜索;也是一个带实时分析功能的分布式搜索引擎,能够扩展至数以百计的节点,实时处理PB级的数据
基本组件:
(1) 索引(index): 文档的结合,文档容器,具有类似属性的文档的集合。索引名必须使用小写字符
(2) 类型(type): 索引内部的逻辑分区,其意义完全取决于用户需求。一个索引内部可以定义一个或多个类型。一般来说,类型就是拥有相似的域的文档的预定义
(3) 文档(document): 是Lucene索引和搜索的原子单位,它包含了一个或多个域,是域的容器;给予JSON格式表示
每个域的组成部分: 一个名字,一个或多个值;拥有多个值的域通常称为多值域
(4) 映射(mapping): 原始内容存储为文档之前需要事先进行分析,例如切词、过滤掉某些词等;映射用于定义此分析机制该如何实现,除此之外,ES还为
映射提供了诸如将域中的内容排序等功能。
ES的集群组件:
Cluster:ES的集群标识为集群名称(默认Elasticsearch),节点就是靠此名字来决定加入到哪个集群中,一个节点只能属于一个集群
Node:运行了单个ES实例的主机称之为节点。用于存储数据(一个分片或某些分片)、参与集群索引以及搜索操作,节点的标识靠节点名
Shard:将索引切割成为的物理存储组件,但每一个shard都是一个独立且完整的索引;创建索引时,ES默认会将其分割为5个shard,用户也可按需自定义,创建完成后不可修改
shard有两种类型:primary shard:每个索引都会被切割为5个主shard用来存储数据,并且每个主shard都应该有一个副本
replica shard:是primary shard的副本,用于数据冗余和查询时的负载均衡,每个主shard的有多少个副本可自定义,且可动态修改
ES Cluster工作过程:
启动时,通过多播(默认)或单播方式在9300/tcp查找同一集群中的其他节点,并与之建立通信
集群中的所有节点会选举出一个主节点负责管理整个集群状态,以及在集群范围内决定各shard的分布方式。站在用户角度而言,每个节点均可接收并响应用户的各类请求
集群有状态:green,red,yellow(修复状态)
官方站点: www.elastic.co
ES的默认端口:
参与集群的事务:9300/tcp
接收请求:9200/tcp
Restful API:
四类API:
(1) 检查集群、节点、索引等健康与否,以及获取其相应状态
(2) 管理集群、节点、索引及元数据
(3) 执行CRUD(增删查改)操作
(4) 执行高级操作,例如paging,filtering等
ES访问接口: 9200/tcp
curl -X<VERB> '<PROTOCOL>://HOST:PORT/<PATH>?<QUERY_STRING>' -d '<BODY>'
VERB: GET,PUT,DELETE,POST等
PROTOCOL: HTTP,HTTPS
PORT: 9200
QUERY_STRING: 查询参数,例如?pretty表示用易读的json格式输出
BODY: 请求的主体
例:
curl -X GET 'http://192.168.59.100:9200/?pretty'
curl -X GET 'http://192.168.59.100:9200/_cat'
_cat: 查看API
_cluster: 查看集群状态API
Cluster APIs:
health:
curl -X GET 'http://192.168.59.100:9200/_cluster/health?pretty'
state:
curl -X GET 'http://192.168.59.100:9200/_cluster/state/nodes?pretty'
<metric>
节点状态:
curl -X GET 'http://192.168.59.100:9200/_nodes/stats?pretty'
Plugins:
插件扩展ES的功能:
添加自定义映射类型、自定义分析器、本地脚本、自定义节点发现方式
安装:
直接将插件放置于plugins目录中即可(针对ES较低版本)
站点插件:
_site
CRUD操作相关API:
创建文档案例:
curl -H "Content-Type:application/json" -X PUT 'http://192.168.59.100:9200/students/class1/1' -d '
{
"First_name" : "Jin",
"Last_name" : "O",
"gender" : "Male",
"age" : 25,
"courses": "rap"
}'
students: 索引
class1: 类型
1: 文档
获取文档案例:
curl -X GET 'http://192.168.59.100:9200/students/class1/1?pretty'
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_version" : 1,
"found" : true,
"_source" : {
"first_name" : "jin",
"last_name" : "O",
"gender" : "Male",
"age" : 25,
"courses" : "rap"
}
}
更新文档案例:
PUT: 全部覆盖
_update: 只更新部分内容
curl -H "Content-Type:application/json" -X POST 'http://192.168.59.100:9200/students/class1/1?pretty' -d '
{
"doc" : { "age" : 22 }
}'
更新后查看:
curl -X GET 'http://192.168.58.100:9200/students/class1/1?pretty'
{
"_index" : "students",
"_type" : "class1",
"_id" : "1",
"_version" : 2,
"found" : true,
"_source" : {
"first_name" : "jin",
"last_name" : "O",
"gender" : "Male",
"age" : 22,
"courses" : "rap"
}
}
删除文档案例:
curl -X DELETE 'http://192.168.59.100:9200/students/class1/2'
删除索引案例:
curl -X GET 'http://192.168.59.100:9200/_cat/indices?pretty' (查看当前所有索引)
curl -X DELETE 'http://192.168.59.100:9200/students'
查询数据:
Query API
Query DSL: JSON based language for building complex queries
用户实现诸多类型的查询操作,比如, simple term query, phrase, range boolean等
ES的查询操作执行分为两个阶段:
分散阶段:像所查询的索引中的所有shard发起查询过程
合并阶段:将所有shard的返回的结果合并并返回给查询者
查询方式:
向ES发起查询请求的方式有两种:
(1) 通过Restful request API、也成为query string
curl -X GET 'http://192.168.59.100:9200/_search?pretty'
(2) 通过发送REST request body进行
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search?pretty' -d '
{
"query" : { "match_all" : {} }
}'
多索引、所类型查询:
/_search: 所有索引
/INDEX_NAME/_search: 单索引
/INDEX1,INDEX2.../_search: 多索引
/s*,t*/_search: 通配符匹配索引
/students/class1/_search: 单类型搜索
/students/class1,class2.../_search: 多类型搜索
Mapping和Analysis:
ES: 对每一个文档,会取得其所有域的所有值,生成一个名为"_all"的域;执行查询时,如果在query_string中未指定查询的域,则在_all域上执行查询操作
例:
GET /_search?q="Xianglong" #只要是任何一个域中含有此字符串就都会显示,因为在_all域上查询的
GET /_search?q="Xianglong%20Shiba%20Zhang"
GET /_search?q=courses:"Xianglong%20Shiba%20Zhang" #在指定域上做精确搜索
GET /_search?q=courses:"Xianglong"
数据类型: string,numbers,boolean,dates
查看指定类型的mapping示例:
curl -X GET 'http://192.168.59.100:9200/students/_mapping/class1?pretty'
ES中搜索的数据广义上可以被理解为两类:
types: exact
精确值:指未经加工的原始值,在搜索时进行精确匹配
full-text: 用于引用文本中的数据,判断文档在多大程度上匹配查询请求,即文档与用户请求查询的相关度
为了完成full-text搜索,ES必须首先分析文本,并创建出倒排索引,倒排索引中的数据还需要进行"正规化"为标准格式
分词
正规化
即分析
分析需要由分析器进行: analyzer
分析器由三个组件构成:
(1) 字符过滤器
(2) 分词器
(3) 分词过滤器
ES内置分析器:
(1) 标准分析器:默认(Standard analyzer)
(2) 简单分析器:根据字母分,只要不是字母都当做分词(Simple analyzer)
(3) 空白文本分析器:将空白字符当做单词分割(Whitespace analyzer)
(4) 语言分析器(Language analyzer)
分析器不仅在创建索引时用到:在构建查询时也会用到
Query DSL:
request body:
分成两类:
(1) query dsl:执行full-text查询时,基于相关度来评判其匹配结果
查询执行过程复杂,且不会被缓存
(2) filter dsl:执行exact查询时,基于其结果为"yes"或"no"进行评判
速度快,且结果可缓存
查询语句的结构:
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT_2:VALUE2
.....
}
}
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT:VALUE,
....
}
}
}
filter dsl:
term filter: 精确匹配包含指定term(空白分开的词)的文档
{"term" {"name": "Guo"}}
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search' -d '
{
"query": {
"term":{
"name": "Guo"
}
}
}
terms filter: 用于多值精确匹配
{ "terms" : { "name": ["Guo","Rong"] }}
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search?pretty' -d '
{
"query": {
"terms": {
"age": [17,18,25]
}
}
}
range filters: 用于在指定的范围内查找数值或时间
{
"query": {
"range": {
"age": {
"gte": 15, (大于等于15)
"lte": 25 (小于等于25)
}
}
}
}
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search' -d '
{
"query": {
"range": {
"age": {
"gte": 15,
"lte": 25
}
}
}
}'
boolean filter:
基于boolean的逻辑来合并多个filter子句:
must: 其内部的所有子句条件必须同时匹配,即and
{
"query": {
"bool": {
"must": [
{ "match" : { "age" : 25 } },
{ "match" : { "gender": "male" } }
]
}
}
}
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search?pretty' -d '
{
"query": {
"bool": {
"must": [
{ "match" : { "age": 25 } },
{ "match" : { "gender": "male" } }
]
}
}
}'
must_not: 其所有子句必须不匹配,即not
{
"query": {
"bool": {
"must_not" : [
{ "match" : { "age" : 18 } }
]
}
}
}
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search' -d '
{
"query" : {
"bool": {
"must_not" : [
{ "match" : { "age" : 18 } }
]
}
}
}'
should: 至少有一个子句匹配,即or
{
"query": {
"bool": {
"should": [
{ "match" : { "age" = 18 } },
{ "match" : { "age" = 27 } }
]
}
}
}
}
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search?pretty' -d '
{
"query" : {
"bool": {
"should" : [
{ "match" : { "age" : 17 } },
{ "match" : { "age" : 18 } }
]
}
}
}
QUERY DSL:
match_all Query:
用于匹配所有文档,没有指定任何query,默认即为match_all query.
{ "match_all" : {} }
match Query:
在几乎任何域上执行full-text或exact-value查询
如果执行full-text查询:首先对查询时的语句做分析
{ "match" : { "students" : "Guo" } }
如果执行exact-value查询:搜索精确值,此时,建议使用过滤,而非查询
{ "match" : { "name": "Guo" } }
multi_match Query:
用于在多个域上执行相同的查询:
{
"query": {
"multi_match": {
"query": 17,
"fields": ["age","name"]
}
}
}'
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_search' -d '
{
"query": {
"multi_match" : {
"query" : 17,
"fields": [ "age","name" ]
}
}
}'
bool query:
基于boolean的逻辑来合并多个查询子句,与bool filter不同的是,查询子句不是返回"yes" or "no",而是其计算出的匹配度分值,因此"bool query"
会为各子句合并其score
must:
must_not:
should
查询语句语法检查:
GET /INDEX/_validate/query?pretty
{
....
}
查看详细错误信息
GET /INDEX/_validate/query?explain&pretty
{
....
}
例:
curl -H "Content-Type:application/json" -X GET 'http://192.168.59.100:9200/students/_validate/query?pretty' -d '
{
"query": {
"bool": {
"must_not": [
{ "match" : { "age" : 18 } },
{ "match" : { "gender" : "Male" } }
]
}
}
}'
ELK stack的另外两个组件;
L: Logstash(日志收集工具)
K: Kibina
Logstash:
支持多种数据获取机制,通过TCP/UDP协议、文件、syslog、windows EventLogs及标准输入输出等;获取到数据后,支持对数据执行过滤、修改等操作
Jruby语言研发,因此需要运行在JVM虚拟机上
Agent/Server
对于Logstash的Server端来说,功能必须使用插件完成,
(1) 输入插件input plugin(从何处取数据);
(2) 编码插件codec plugin
(3) 过滤插件filter plugin
(4) 输出插件output plugin
配置文件基本框架;
input {
...
}
filter {
...
}
output {
...
}
数据类型:
Arry: [iterm1,iterm2,...]
boolean:[true,false]
bytes:简单数据
codec: 编码器
Hash: key => value
Number: 数值
password: 不会记录下来
PATH: 文件系统路径
String: 字符串
字段引用:["字段名"]
条件判断:
==,!=,>,<,>=,<=,in,not in,and,or,=~,!~,()
Logstash的工作流程: input | filter | output,如无需对数据进行额外处理,filter可省略
Logstash常见插件:
input插件:
file: 从指定文件中读取事件流;不断的将文件的尾部行读取出来(第一次从第一行开始读)
使用Filewatch机制监听文件是否变化;
每一个被监听文件上一次的读取位置保存在.sincedb,从而可以监听到每一个文件上次读取位置在哪里,默认存储在启动logstash用户的家目录
能够自动识别日志的滚动操作;
案例:
~]# vim /app/logstash-6.6.1/config/filesiamble.conf
input {
file {
path => ['/var/log/messages']
type => "system" // 在输入输出时辨别使用哪一种类型的文本信息;可以在filter过滤时指定只过滤哪些数据(比如在filter只过滤system信息)
start_position => "begining" // 从文件的最开始处读还是从结尾(end)处读,默认为end
}
}
output {
stdout{
codec => rubydebug
}
}
~]# logstash -f /app/logstash-6.6.1/config/filesamble.conf --config.test_and_exit //检查配置文件语法是否有问题
~]# logstash -f /app/logstash-6.6.1/config/filesamble.conf
UDP:让Logstash通过UDP协议从网络连接来读取message,其必备配置参数为port(用于指明自己监听的端口),别的主机通过此端口发送数据,host指明本地监听的udp服务地址
collectd: 性能监控程序,可通过自身的network插件将数据发送到特定端口主机
案例:
~]# yum install collectd // 在另一台服务器安装collectd(在epel源中)
~]# vim /etc/collectd.conf // 编辑配置文件监控服务器的哪些性能
Hostname "node2" // 取消主机名注释并写上安装collectd的主机名
LoadPlugin cpu // 取消此行注释,则是监控cpu的性能
LoadPlugin df // 取消此行注释,监控磁盘的性能
.....
<Plugin network> // 添加这四行以便监控
<Server "192.168.59.100" "25826"> // port代表了像哪个端口发数据,IP是Logstash的主机
</Server>
</Plugin>
~]# systemctl start collectd.service
~]# vim $LOGSTASH_HOME/config/udpsamble.conf // 在Logstash安装的服务器上操作
input {
udp {
port => "25826" // 定义哪个端口接收数据
type => "collectd"
codec => collectd {}
}
}
output {
stdout {}
}
~]# logstash -f $LOGSTASH_HOME/config/udpsamble.conf -t
~]# logstash -f $LOGSTASH_HOME/config/udpsamble.conf
Redis插件:
从redis读取数据,支持redis channel和lists两种方式;
filter插件:
用于将event通过output发出之前对其实现某些处理功能;grok
grok:
用于分析并结构化文本数据,目前是logstash中将非结构化日志转化为结构化的可查询数据不二之选
syslog,apache,nginx
192.168.59.1 - - [27/Feb/2019:15:30:52 +0800] "GET /favicon.ico HTTP/1.1" 404 209 "http://192.168.59.100/" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.
36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36"
%ip %user %auth [%datetime] %method %uri %version %status %size %referer %user_agent (符合条件的模式)
ip => 192.168.59.1
user => -
auth => -
daatetime => 27/Feb/2019:15:30:52 +0800
/app/logstash-6.6.1/vendor/bundle/jruby/2.3.0/gems/logstash-patterns-core-4.1.2/patterns/grok-patterns(文件中定义了模式)
语法格式:
%{SYNTAX:SEMANTIC}
SYNTAX: 预定义模式名称,已经定义了存在的名称
SEMANTIC: 匹配到的文本的自定义标识符;
1.1.1.1 GET /index.html 30 0.23
%{IP:clientip} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}
示例:
~]# vim $LOGSTASH_HOME/config/groksamble.conf
input {
stdin {}
}
filter {
grok {
match => {
"message" => "%{IP:clientip} %{WORD:method} %{URIPATHPARAM:request} %{NUMBER:bytes} %{NUMBER:duration}" // 将manager拆分为定义的格式输出
}
}
}
output {
stdout {}
}
~]# logstash -f $LOGSTASH_HOME/config/groksamble.conf -t
~]# logstash -f $LOGSTASH_HOME/config/groksamble.conf
1.1.1.1 GET /index.html 30 0.23 //输入数据查看结果
示例2: 关于Apache的模式应用
~]# vim $LOGSTASH_HOME/config/apachesamble.conf
input {
file {
path => ["/var/log/httpd/access.log"]
type => "apache"
start_position => "begining"
}
}
filter {
grok {
match => {
"message" => %{COMBINEDAPACHELOG}
}
}
}
output {
stdout {
codec => rubydebug
}
}
~]# logstash $LOGSTASH_HOME/config/apachesamble.conf -t
~]# logstash $LOGSTASH_HOME/config/apachesamble.conf
output插件:
stdout {}
elasticsearch {
}
将redis配置为输出插件
~]# yum install epel*
~]# yum install redis
~]# vim /etc/redis.conf
bind 0.0.0.0
~]# systemctl start redis.service
~]# vim $LOGSTASH_HOME/config/apachesamble.conf
input {
file{
path => ["/var/log/access_log"]
type => "apache"
start_position => "begining"
}
}
filter {
grok {
match => {
"message" => "%{COMBINEDAPACHELOG}"
}
}
}
output {
redis {
port => "6379"
host => ["127.0.0.1"]
data_type => "list"
key => "logstash-%{type}"
}
}
~]# logstash $LOGSTASH_HOME/config/apachesamble.conf -t
~]# logstash $LOGSTASH_HOME/config/apachesamble.conf
http://192.168.59.100
~]# redis-cli
~]# LLEN logstash-apache
将redis配置为输入插件
在另一台服务器上操作以展现效果
~]# vim $LOGSTASH_HOME/config/serversample.conf
input {
redis {
port => "6379"
host => ["192.168.59.100"]
data_type => "list"
key => "logstash-apache" // 写redis中的那个列表名称
}
}
output {
stdout {
codec => rubydebug
}
}
~]# logstash -f $LOGSTASH_HOME/config/serversample.conf -t
~]# logstash -f $LOGSTASH_HOME/config/serversample.conf
http://192.168.59.100
Kibana
安装:
从官网下载与ES相同的版本,解压安装
~]# vim /app/kibana-6.5.4-linux-x86_64/config/kibana.yml
server.port: 5601
server.host: 0.0.0.0
elasticsearch.url: "http://192.168.59.100:9200"
~]# cd ../../bin
~]# ./kibana &
http://192.168.59.100:5601