沉淀再出发:ELK使用初探

一、前言

    ELK是Elasticsearch、Logstash、Kibana的简称,这三者是核心套件,但并非全部。

    最近ElasticSearch可以说是非常火的一款开源软件了,自从上市之后,有了更大更远的场景,它最本质的作用就是为公司内部或者一个小的范围之内的系统提供搜索引擎的检索技术,使得检索可以更加的精细化和自动化,相比于其他的软件,es有着更加强大和简易的平台和使用方式,可以快速搭建出我们想要的搜索平台,因此受到了大家广泛的欢迎。Elasticsearch是实时全文搜索和分析引擎,提供搜集、分析、存储数据三大功能;是一套开放REST和JAVA API等结构提供高效搜索功能,可扩展的分布式系统。它构建于Apache Lucene搜索引擎库之上。
    Logstash是一个用来搜集、分析、过滤日志的工具。它支持几乎任何类型的日志,包括系统日志、错误日志和自定义应用程序日志。它可以从许多来源接收日志,这些来源包括 syslog、消息传递(例如 RabbitMQ)和JMX,它能够以多种方式输出数据,包括电子邮件、websockets和Elasticsearch。
    Kibana是一个基于Web的图形界面,用于搜索、分析和可视化存储在 Elasticsearch指标中的日志数据。它利用Elasticsearch的REST接口来检索数据,不仅允许用户创建他们自己的数据的定制仪表板视图,还允许他们以特殊的方式查询和过滤数据。
    由于Logstash服务依赖ES服务,Kibana服务依赖Logstash和ES,所以ELK的服务启动顺序为:ES->Logstash->Kibana。

二、ElasticSearch初步了解

  2.1、简介

     ElasticSearch 的底层是开源的Lucene。Elastic提供了REST API操作接口,是Lucene的扩展。底层依旧是索引,但是可以把大索引切成n片,放到不同的节点,所以就实现了分布式。也就理所当然的是读写负载均衡。此外,他还是一个分布式实时文档存储,其中每个field可被搜索。 ES 可以自动将海量数据分布到多台服务器上去存储和检索海量数据。可以在秒级别在每台服务器上分析数据。Elastic 本质上是一个分布式数据库,允许多台服务器协同工作,每台服务器可以运行多个 Elastic 实例。单个 Elastic 实例称为一个节点(node)。一组节点构成一个集群(cluster)。Elasticsearch是一个近实时(Near Realtime[NRT])的搜索平台。这意味着当你导入一个文档并把它变成可搜索的时间仅会有轻微的延时。
    基本组件:

(1).索引(index):文档容器,类似于关系型数据库中的库。索引名必须是小写字母。
(2).类型(type):类型是索引内部的逻辑分区。其意义完全取决与用户需求,一个索引内部可定义多个类型。类似于关系型数据库中的表结构,字段。
警告,Type在6.0.0版本中已经不赞成使用。 (
3).文档(document):文档是Lucene索引和搜索的原子单位。它包含多个域。基于JSON格式存储。每个域的格式类似于字典。 (4).映射(mapping):原始内容存储为文档之前的分析,映射就是定义此映射过程该如何实现。(例如切词,过滤)

    集群组件:

(1)Cluster:ES的集群标识为集群名称。默认为“elasticsearch”,节点靠此名字决定加入到哪一个集群中。一个节点只能属于一个集群。
(2).Node:运行单个ES实例的主机。节点的标识靠节点名。在一个集群中,你想启动多少节点就可以启动多少节点。此外,如果没有其它节点运行在当前网络中,
只启动一个节点将默认形成一个新的名称为“elasticsearch”单节点集群。 (
3).Shard:将索引切割成为的物理存储组件,但每一个shared都是一个独立且完整的索引,创建索引时,ES默认分割为5个shard。 用户也可以按需自定义,创建完成后不可修改。shard有两种,primary和replica。用于负载均衡。

    ES Cluster启动过程。通过多播(或单播)在9300/tcp查找同一集群中的其他节点,并建立通信。集群中所有节点会选举出一个主节点负责管理整个集群状态。以及在集群范围内决定shared的分布。  

 2.2、安装ElasticSearch

   在使用es之前,我们要先确定已经安装和配置了java环境,之后我们下载ElasticSearch,根据不同的系统下载相应的版本,解压即可。

沉淀再出发:ELK使用初探

       解压之后,我们使用cmd进入其中的bin目录,之后的命令在这个里面启动即可。

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

     这样es服务器已经运行了,我们使用浏览器进行访问 http://127.0.0.1:9200/

  沉淀再出发:ELK使用初探

     至此,es就安装好了,为了方便,我们可以把这个目录放到环境变量之中:

沉淀再出发:ELK使用初探

      同样的我们使用git的curl命令,也可以进行访问:

1 curl localhost:9200

沉淀再出发:ELK使用初探

     下面的命令可以查看当前节点的所有 Index。

curl -X GET 'http://localhost:9200/_cat/indices?v'

沉淀再出发:ELK使用初探

     下面的命令可以列出每个 Index 所包含的 Type。根据规划,Elastic 6.x 版只允许每个 Index 包含一个 Type,7.x 版将会彻底移除 Type。

curl 'localhost:9200/_mapping?pretty=true'

沉淀再出发:ELK使用初探

     作为配置的一部分,在集群之中,我们需要修改es的配置:

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

   2.3、基本概念

     (1)document

document是个文件,里面有很多file。比如
{
    "name":"小红",
    "age":"18"
}
这就一个文件,而name就是个file,age也是

   (2)index

  es里的index概念就像是个数据库,里面存放很多个document

    新建 Index,可以直接向 Elastic 服务器发出 PUT 请求。下面的例子是新建一个名叫weather的 Index。

curl -X PUT 'localhost:9200/weather'

  (3)type

 比如document是存放动物的数据,那么type就是把动物的类型分类,比如猫科,狗科,鸟科等

  (4)shard和replica

    如果有个10T的数据,有5台服务器,每个服务器只能放2T的数据,怎么办?
    分布式解决:那么就是理解10T为index,数据分成5份,每个服务器放2T的数据,而这5台服务器就是shard。
    为了避免服务器宕机就为这5台服务器分别配了台备用服务器,称为replica。这样拿数据就可以在replica拿,也可以在shard拿,
基本上不用担心数据同步问题,因为es是实时性的。

三、安装logstash

  3.1、下载和安装logstash

   我们在官网上下载logstash,然后解压之后进行安装,为了服务的正常运行,建议logstash的版本和es的一致,同样的包括下面将要安装的kibana也是一样。

沉淀再出发:ELK使用初探

   3.2、解压和配置

   将下载好的安装包解压,之后在bin目录下新建配置文件logstash.conf,进行相应的配置

沉淀再出发:ELK使用初探

input { stdin { } }
output {
  elasticsearch { hosts => ["localhost:9200"] }
  stdout { codec => rubydebug }
}

沉淀再出发:ELK使用初探

     然后使用logstash -f logstash.conf启动(注意不用再启动logstash,因为这个命令就是带着配置来启动的):

沉淀再出发:ELK使用初探

    同样的es上面也有提示:

沉淀再出发:ELK使用初探

    此时在logstash的cmd中输入消息,就能被logstash解析并且返回相应格式的结果:

沉淀再出发:ELK使用初探

    同时使用kibana查看日志输出到es的情况:

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

     3.3、logstash本质

    logstash使用管道方式进行日志的搜集处理和输出。在logstash中,包括了三个阶段:输入input --> 处理filter(不是必须的) --> 输出output;每个阶段都由很多的插件配合工作,比如file、elasticsearch、redis等等。每个阶段也可以指定多种方式,比如输出既可以输出到elasticsearch中,也可以指定到stdout在控制台打印。Logstash 每读取一次数据的行为叫做事件

-f:通过这个命令可以指定Logstash的配置文件,根据配置文件配置logstash;
-e:后面跟着字符串,该字符串可以被当做logstash的配置(如果是“” 则默认使用stdin作为输入,stdout作为输出);
-l:日志输出的地址(默认就是stdout直接在控制台中输出);
-t:测试配置文件是否正确,然后退出。

   logstash基本上由三部分组成,input、output以及用户需要才添加的filter,因此标准的配置文件格式如下:

input {...}
filter {...}
output {...}

   在每个部分中,也可以指定多个访问方式,如果在filter中添加了多种处理规则,则按照它的顺序一一处理,但是有一些插件并不是线程安全的。比如在filter中指定了两个一样的的插件,这两个任务并不能保证准确的按顺序执行,因此官方也推荐避免在filter中重复使用插件。

沉淀再出发:ELK使用初探

       此外让我们再看一个例子,将文件作为输入,处理里面的内容,然后输出,注意这里的日志文件最后应该有一个空行,不然因为解析机制可能出错。

    logstash_test.conf:

input {
    file {
        path => "E:/logstash-6.4.2/data/test.log"
        start_position => beginning
    }
}
filter {
    
}
output {
    stdout {}
}

     test.log:

沉淀再出发:ELK使用初探

   file 输入插件默认使用 “\n” 判断日志中每行的边界位置。如果没有“\n”将会导致日志数据无法导入到 Elasticsearch 中。

沉淀再出发:ELK使用初探

      更多的设置可以查看https://www.elastic.co/guide/en/logstash/current/config-examples.html

四、安装kibana

    4.1、下载和安装

    在官网上下载,之后解压、配置、启动即可:

  沉淀再出发:ELK使用初探

 沉淀再出发:ELK使用初探

 沉淀再出发:ELK使用初探

    等服务启动之后,我们访问http://127.0.0.1:5601界面,至此,我们可以灵活地对上面的两个软件进行操作和监控了。

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

五、使用elasticsearch进行增删改查(CRUD)

 5.1、查看es的运行状态是否健康

GET /_cat/health?v

沉淀再出发:ELK使用初探

   或者使用git:

curl -XGET 'localhost:9200/_cat/health?v&pretty'

沉淀再出发:ELK使用初探

    我们可以看到我们的名称为“elasticsearch”的集群正在运行,状态标识为green。无论何时查看集群健康状态,我们会得到green、yellow、red中的任何一个。

    Green - 一切运行正常(集群功能齐全)
    Yellow - 所有数据是可以获取的,但是一些复制品还没有被分配(集群功能齐全)
    Red - 一些数据因为一些原因获取不到(集群部分功能不可用),当一个集群处于red状态时,它会通过可用的分片继续提供搜索服务,但是当有未分配的分片时,需要尽快的修复它。

 5.2、查看正在运行的节点

GET /_cat/nodes?v

沉淀再出发:ELK使用初探

 

curl -XGET 'localhost:9200/_cat/nodes?v&pretty'

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

 5.3、列出所有的索引

GET /_cat/indices?v
curl -XGET  'localhost:9200/_cat/indices?v&pretty'

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

这个返回结果只是一个表头,就是我们的集群中还没有任何索引。

 5.4、创建一个索引  

   现在让我们创建一个索引,名称为“customer”,然后再一次列出所有的索引:

    PUT /customer?pretty
    GET /_cat/indices?v

   Curl命令:

    curl -XPUT    'localhost:9200/customer?pretty&pretty'
    curl -XGET    'localhost:9200/_cat/indices?v&pretty'

   但是我的及其执行之后却显示超时,返回不了正常的结果,到底是什么地方出了问题呢?!查询都能正常运行,说明网络没问题,那么就是程序内部的问题了。

沉淀再出发:ELK使用初探

   但是其实上,我们重启一下es就会发现这个index已经被创建了,原因可能是节点的相应有问题。

沉淀再出发:ELK使用初探

     同样的,我们能看到,节点的状态由正常转变成了黄色,那就是因为这个index没有备份,因为我们只有一个节点,当我们配置了其他的节点,这个状态就会发生改变了。

沉淀再出发:ELK使用初探

    此时,我们再次创建索引就会发现正常显示了,由此可以断定,以前的节点是有问题的,需要重启,在实际工程中遇到问题,我们需要沉着冷静的分析,在发现没有解决办法,网上也找不到的时候,我们可以尝试着缩小问题的范围,定位好问题,然后重新来过试一试

沉淀再出发:ELK使用初探

  5.5、在索引中加入数据并查看

/<Index>/<Type>/<ID> ,pretty是为了让回显过来的数据美观。
1 PUT /customer/doc/2?pretty
2 {
3   "name": "lsx,zyr"
4 }

沉淀再出发:ELK使用初探

curl -XPUT  'localhost:9200/customer/doc/1?pretty&pretty' -H 'Content-Type: application/json' -d '{"name": "John Doe"}'

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

    从上面我们可以看到,一个新的顾客文档已经在customer索引中成功创建。同时这个文档有一个自己的id,这个id就是我们在将文档加入索引时指定的。这里有一个重要的注意点,我们不需要在将一个文档加入一个索引前明确的将这个索引预先创建好。在上面我们创建文档的例子中,如果这个customer索引事先不存在,Elasticsearch会自动创建customer索引。比如:

 curl -XPUT  'localhost:9200/zyr_customer/doc/1994?pretty&pretty' -H 'Content-Type: application/json' -d '{"name": "zyrlsx"}'

 沉淀再出发:ELK使用初探

    由此,我们可以确定上面的put不成功肯定是节点的问题,我们将节点重启一次就好了。

沉淀再出发:ELK使用初探

    我们再次查看索引:

沉淀再出发:ELK使用初探

 

      下面让我们查看插入的数据:

GET /customer/doc/(id)?pretty
沉淀再出发:ELK使用初探
沉淀再出发:ELK使用初探

curl -XGET 'localhost:9200/customer/doc/1?pretty&pretty'

沉淀再出发:ELK使用初探

    found属性表示我们通过请求ID为1发现了一个文档,还有另一个属性_source,_source属性返回我们在上一步中加入索引的完整JSON文档内容。

 5.6、删除一个索引

DELETE /customer?pretty
GET /_cat/indices?v

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

curl -XDELETE 'localhost:9200/zyr_customer?pretty&pretty'
curl -XGET 'localhost:9200/_cat/indices?v&pretty'

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

 5.7、替换和更新索引中的文档

    上面我们已经学习了,增、删、查,那么还有一个命令就是修改了。其实如果我们将id相同的命令,命令不变,参数修改之后再次put进去,那么结果就会被替换了,注意,这里的替换和更新的用法略微有所差异,比如:

    沉淀再出发:ELK使用初探

   沉淀再出发:ELK使用初探

   同时修改之后版本(_version)也会增加。

沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

   这里我们需要注意,如果我们插入文档的时候,不设定id系统会自动分配id,实际Elasticsearch生成的ID(或者是我们明确指定的)将会在API调用成功后返回:

沉淀再出发:ELK使用初探

curl -XPOST 'localhost:9200/zyr_customer/doc?pretty&pretty' -H 'Content-Type: application/json' -d' { "name": "next  123" }'

沉淀再出发:ELK使用初探

    更新文档:

    除了能够新增和替换文档,我们也可以更新文档。注意虽然Elasticsearch在底层并没有真正更新文档,而是当我们更新文档时,Elasticsearch首先去删除旧的文档,然后加入新的文档。

POST /zyr_customer/doc/1994/_update?pretty
{
  "doc": { "name": "朱彦荣,更新文档" }
}

沉淀再出发:ELK使用初探

    使用curl:

curl -XPOST 'localhost:9200/zyr_customer/doc/1994/_update?pretty&pretty' -H 'Content-Type: application/json' -d  '
{
  "doc": { "name" :  "zyr git" }
}
'

 沉淀再出发:ELK使用初探

沉淀再出发:ELK使用初探

  更新操作也可以使用简单的脚本来执行,比如:

POST /zyr_customer/doc/1994/_update?pretty
{
  "script" : "ctx._source.age += 5"
}

 沉淀再出发:ELK使用初探

curl -XPOST 'localhost:9200/zyr_customer/doc/1994/_update?pretty&pretty' -H 'Content-Type: application/json' -d ' { "script" : "ctx._source.age += 5" } '

沉淀再出发:ELK使用初探

    ctx._source指代的是当前需要被更新的source文档。

 沉淀再出发:ELK使用初探

 5.8、删除一个文档

DELETE /zyr_customer/doc/1994?pretty

沉淀再出发:ELK使用初探

curl -XDELETE 'localhost:9200/zyr_customer/doc/1994?pretty&pretty'

沉淀再出发:ELK使用初探

 5.9、批处理     

    除了在单个文档上执行索引,更新和删除操作外,Elasticsearch还提供了批操作的功能,通过使用 _bulk API完成。这个功能非常重要,因为它提供了一种非常高效的机制去通过更少的网络切换尽可能快的执行多个操作。

POST /zyr_customer/doc/_bulk?pretty
{"index":{"_id":"1"}}
{"name": "zyr" }
{"index":{"_id":"2"}}
{"name": "lsx" }

沉淀再出发:ELK使用初探

curl -XPOST 'localhost:9200/zyr_customer/doc/_bulk?pretty&pretty' -H 'Content-Type: application/json' -d ' {"index":{"_id":"3"}} 
{"name": "lsx git" }
{"index":{"_id":"4"}} 
{"name": "zyr git" } 
'

 沉淀再出发:ELK使用初探

    再如下面的案例,更新id为1的文档,删除id为2的文档:

POST /zyr_customer/doc/_bulk?pretty
{"update":{"_id":"1"}}
{"doc": { "name": "批处理更新" } }
{"delete":{"_id":"2"}}

沉淀再出发:ELK使用初探

curl -XPOST 'localhost:9200/zyr_customer/doc/_bulk?pretty&pretty' -H 'Content-Type: application/json' -d ' {"update":{"_id":"3"}} 
{"doc": { "name": "" } } 
{"delete":{"_id":"4"}} 
'

沉淀再出发:ELK使用初探

   至此,我们对es的增删改查有了非常深刻的理解和使用。

六、批量导入数据到elasticsearch中并处理

  6.1、批量导入数据

   首先我们需要有数据,可以从这里拿到数据,然后保存到本地,命名为account.json文件。

   之后,我们需要使用git命令,将目录调整到存放account.json的目录,然后使用下面的命令,创建索引为bank,文档为account的数据:

curl  -H "Content-Type: application/json"   -XPOST  'localhost:9200/bank/account/_bulk?pretty&refresh' --data-binary "@account.json"

    沉淀再出发:ELK使用初探

    这样数据就导入成功了,如下所示,1000条信息。

沉淀再出发:ELK使用初探

   6.2、搜索API

     执行搜索有两种基础的方式,一种是在请求的URL中加入参数来实现,另一种方式是将请求内容放到请求体中。使用请求体可以让JSON数据以一种更加可读和更加富有展现力的方式发送。REST API可以使用_search端点来实现搜索。

    如下的示例将返回bank索引的所有的文档并且按照某一个参数(account_number)从小到大排序:

GET /bank/_search?q=*&sort=account_number:asc&pretty

 沉淀再出发:ELK使用初探

{
  "took": 2716,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 1000,
    "max_score": null,
    "hits": [
      {
        "_index": "bank",
        "_type": "account",
        "_id": "0",
        "_score": null,
        "_source": {
          "account_number": 0,
          "balance": 16623,
          "firstname": "Bradshaw",
          "lastname": "Mckenzie",
          "age": 29,
          "gender": "F",
          "address": "244 Columbus Place",
          "employer": "Euron",
          "email": "bradshawmckenzie@euron.com",
          "city": "Hobucken",
          "state": "CO"
        },
        "sort": [
          0
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "1",
        "_score": null,
        "_source": {
          "account_number": 1,
          "balance": 39225,
          "firstname": "Amber",
          "lastname": "Duke",
          "age": 32,
          "gender": "M",
          "address": "880 Holmes Lane",
          "employer": "Pyrami",
          "email": "amberduke@pyrami.com",
          "city": "Brogan",
          "state": "IL"
        },
        "sort": [
          1
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "2",
        "_score": null,
        "_source": {
          "account_number": 2,
          "balance": 28838,
          "firstname": "Roberta",
          "lastname": "Bender",
          "age": 22,
          "gender": "F",
          "address": "560 Kingsway Place",
          "employer": "Chillium",
          "email": "robertabender@chillium.com",
          "city": "Bennett",
          "state": "LA"
        },
        "sort": [
          2
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "3",
        "_score": null,
        "_source": {
          "account_number": 3,
          "balance": 44947,
          "firstname": "Levine",
          "lastname": "Burks",
          "age": 26,
          "gender": "F",
          "address": "328 Wilson Avenue",
          "employer": "Amtap",
          "email": "levineburks@amtap.com",
          "city": "Cochranville",
          "state": "HI"
        },
        "sort": [
          3
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "4",
        "_score": null,
        "_source": {
          "account_number": 4,
          "balance": 27658,
          "firstname": "Rodriquez",
          "lastname": "Flores",
          "age": 31,
          "gender": "F",
          "address": "986 Wyckoff Avenue",
          "employer": "Tourmania",
          "email": "rodriquezflores@tourmania.com",
          "city": "Eastvale",
          "state": "HI"
        },
        "sort": [
          4
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "5",
        "_score": null,
        "_source": {
          "account_number": 5,
          "balance": 29342,
          "firstname": "Leola",
          "lastname": "Stewart",
          "age": 30,
          "gender": "F",
          "address": "311 Elm Place",
          "employer": "Diginetic",
          "email": "leolastewart@diginetic.com",
          "city": "Fairview",
          "state": "NJ"
        },
        "sort": [
          5
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "6",
        "_score": null,
        "_source": {
          "account_number": 6,
          "balance": 5686,
          "firstname": "Hattie",
          "lastname": "Bond",
          "age": 36,
          "gender": "M",
          "address": "671 Bristol Street",
          "employer": "Netagy",
          "email": "hattiebond@netagy.com",
          "city": "Dante",
          "state": "TN"
        },
        "sort": [
          6
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "7",
        "_score": null,
        "_source": {
          "account_number": 7,
          "balance": 39121,
          "firstname": "Levy",
          "lastname": "Richard",
          "age": 22,
          "gender": "M",
          "address": "820 Logan Street",
          "employer": "Teraprene",
          "email": "levyrichard@teraprene.com",
          "city": "Shrewsbury",
          "state": "MO"
        },
        "sort": [
          7
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "8",
        "_score": null,
        "_source": {
          "account_number": 8,
          "balance": 48868,
          "firstname": "Jan",
          "lastname": "Burns",
          "age": 35,
          "gender": "M",
          "address": "699 Visitation Place",
          "employer": "Glasstep",
          "email": "janburns@glasstep.com",
          "city": "Wakulla",
          "state": "AZ"
        },
        "sort": [
          8
        ]
      },
      {
        "_index": "bank",
        "_type": "account",
        "_id": "9",
        "_score": null,
        "_source": {
          "account_number": 9,
          "balance": 24776,
          "firstname": "Opal",
          "lastname": "Meadows",
          "age": 39,
          "gender": "M",
          "address": "963 Neptune Avenue",
          "employer": "Cedward",
          "email": "opalmeadows@cedward.com",
          "city": "Olney",
          "state": "OH"
        },
        "sort": [
          9
        ]
      }
    ]
  }
}搜索结果
搜索结果

相关文章: