上一篇文章里面讲到了elk的安装,这次来说一下如何进行查询。

进入kibana之后,是没有任何东西可以查的。首先要设置index。

在kibana的management里面,进入index object,在里面创建index。

kibana-create-index

创建完成之后,就可以在Discover里面进行查询了。Discover里面,左侧列出来的就是一些字段以及字段的类型。

Dsicover in kibana

我还是喜欢在Dev tools里面,使用json形式进行查询,如下图所示:

example-query-in-dev-tools

看上面这张图,hits字段里面的total表示命中了4229条记录,但实际返回的只有10个具体的记录,这是因为ES默认返回10条记录。

如果想要更多的记录,或者是某个分片的记录,可以用scroll查询或者是分片查询。

scroll查询 vs 分片查询

scroll查询

scroll查询分成两个部分

  • 初始化scroll查询。
  • 之后的滚动查询
  1. 先来看如何初始化scroll查询,看下面这张示例图:

    init scroll query

    1.1 url格式为yourindexname/_search?scroll=xxm,scroll的取值表示查询游标的过期时间。

    1.2 查询结果里面,会有_scroll_id字段。之后就可以用这个id来进行滚动查询

  2. 再来看如何进行滚动查询。看下面这种示意图:

    scroll query

    2.1 url个格式为_search/scroll,注意前面不要再加上yourindexname

    2.2 查询参数里面只需要传入scroll_idscrollscorll_id就是刚刚初始化的时候拿到的,scroll表示游标的过期时间

    2.3 返回结果里面,也是默认10条记录。如果要取得所有的记录,那么就要不断的滚动查询,知道最后。如果游标过期了,那么返回的结果会报"status": 404之类的错

分片查询

上面说的是滚动查询也叫游标查询。再来说说分片查询。

MySql里面有limit关键字,可以进行分片查询,比如说select * from your_table_name limit 10, 20;表示从表里面的第10条记录开始(包括第十条),获取20条结果。

在ES里面,用from和size也可以进行分片查询,如下所示

GET parsed-nginx-access-log/_search
{
    "query": { "match_all": {}},
    "from": 10,
    "size":  20
}

两者的区别

  • scroll不太适合做实时查询,比较适合做后台批量任务。
  • scroll分为初始化和遍历两部分
  • 分片查询如果是深度分片,会有一系列性能问题。

关于深度分片,这就要说到查询的两个阶段:

查询分成两个阶段,一个是query阶段,一个是fetch阶段。query阶段是确定需要取那些doc,fetch是把这些doc取出来。

例如使用下面这个示例,

GET parsed-nginx-access-log/_search
{
    "query": { "match_all": {}},
    "from": 10,
    "size":  20
}

query阶段

elk query

  • Client 发送一次搜索请求

  • node1 接收到请求,node1 创建一个大小为 from + size 的优先级队列用来存结果,我们管 node1 叫 coordinating node。

  • coordinating node将请求广播到涉及到的 shards

  • 每个 shard 在内部执行搜索请求,每个shared用大小为from + size的队列存储doc_id。每个shared在query阶段只需要返回唯一标记 doc 的 _id 以及用于排序的 _score 即可,这样也可以保证返回的数据量足够小。每个 shard 把暂存在自身优先级队列里的数据返回给 coordinating node

  • coordinating node 拿到各个 shards 返回的结果后对结果进行一次合并,排序后产生一个全局的优先级队列,存到自身的优先级队列里。

在上面的例子中,coordinating node 拿到 (from + size) * 6 条数据,然后合并并排序后选择前面的 from + size 条数据存到优先级队列,以便 fetch 阶段使用。另外,各个分片返回给 coordinating node 的数据用于选出前 from + size 条数据,所以coordinating node 计算好自己的优先级队列后,query 阶段结束,进入 fetch 阶段。

fetch阶段

query阶段知道了要取哪些doc,得到的是这些doc的id。fetch阶段是真正要取这些doc

上图展示了 fetch 过程:

  • coordinating node 发送 GET 请求到相关shards。

  • shard 根据 doc 的 _id 取到数据详情,然后返回给 coordinating node。

  • coordinating node 返回数据给 Client。

注意:

  • coordinating node 的优先级队列里有 from + size 个 _doc _id,但是,在 fetch 阶段,并不需要取回所有数据,在上面的例子中,第0条到第9条数据是不需要取的,只需要取优先级队列里的第10到条到第20条数据即可。

  • 需要取的数据可能在不同分片,也可能在同一分片,coordinating node 使用 multi-get 来避免多次去同一分片取数据,从而提高性能。

  • 深度分页可能会引起一些问题,比如说CPU,内存,IO,网络带宽等。