话题 (elasticsearch 2.1) 已与当前话题合并
elasticsearch

elasticsearch

Elastic日报 第403期 (2018-09-23)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 11 次浏览 • 2 小时前 • 来自相关话题

1.将Apache Hive与ElasticSearch一起使用。 http://t.cn/EPzJFKK 2.大数据与分析与数据科学:有什么区别? http://t.cn/EPzxm6P 3.(自备梯子)招聘数据科学家之前需要做的3件事。 http://t.cn/EPz6j4f 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/814 订阅:https://tinyletter.com/elastic-daily
1.将Apache Hive与ElasticSearch一起使用。 http://t.cn/EPzJFKK 2.大数据与分析与数据科学:有什么区别? http://t.cn/EPzxm6P 3.(自备梯子)招聘数据科学家之前需要做的3件事。 http://t.cn/EPz6j4f 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/814 订阅:https://tinyletter.com/elastic-daily

你看懂 Elasticsearch Log 中的 GC 日志了吗?

Elasticsearchrockybean 发表了文章 • 0 个评论 • 15 次浏览 • 13 小时前 • 来自相关话题

如果你关注过 elasticsearch 的日志,可能会看到如下类似的内容:

[2018-06-30T17:57:23,848][WARN ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][228384] overhead, spent [2.2s] collecting in the last [2.3s]

[2018-06-30T17:57:29,020][INFO ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][old][228385][160772] duration [5s], collections [1]/[5.1s], total [5s]/[4.4d], memory [945.4mb]->[958.5mb]/[1007.3mb], all_pools {[young] [87.8mb]->[100.9mb]/[133.1mb]}{[survivor] [0b]->[0b]/[16.6mb]}{[old] [857.6mb]->[857.6mb]/[857.6mb]}

看到其中的[gc]关键词你也猜到了这是与 GC 相关的日志,那么你了解每一部分的含义吗?如果不了解,你可以继续往下看了。

我们先从最简单的看起:

  1. 第一部分是日志发生的时间
  2. 第二部分是日志级别,这里分别是WARNINFO
  3. 第三部分是输出日志的类,我们后面也会讲到这个类
  4. 第四部分是当前 ES 节点名称
  5. 第五部分是 gc 关键词,我们就从这个关键词聊起。

友情提示:对 GC 已经了如指掌的同学,可以直接翻到最后看答案。

1. 什么是 GC?

GC,全称是 Garbage Collection (垃圾收集)或者 Garbage Collector(垃圾收集器)。

在使用 C语言编程的时候,我们要手动的通过 mallocfree来申请和释放数据需要的内存,如果忘记释放内存,就会发生内存泄露的情况,即无用的数据占用了宝贵的内存资源。而Java 语言编程不需要显示的申请和释放内存,因为 JVM 可以自动管理内存,这其中最重要的一部分就是 GC,即 JVM 可以自主地去释放无用数据(垃圾)占用的内存。

我们研究 GC 的主要原因是 GC 的过程会有 Stop The World(STW)的情况发生,即此时用户线程会停止工作,如果 STW 的时间过长,则应用的可用性、实时性等就下降的很厉害。

GC主要解决如下3个问题:

  1. 如何找到垃圾?
  2. 如何回收垃圾?
  3. 何时回收垃圾?

我们一个个来看下。

1.1 如何找到垃圾?

所谓垃圾,指的是不再被使用(引用)的对象。Java 的对象都是在堆(Heap)上创建的,我们这里默认也只讨论堆。那么现在问题就变为如何判定一个对象是否还有被引用,思路主要有如下两种:

  1. 引用计数法,即在对象被引用时加1,去除引用时减1,如果引用值为0,即表明该对象可回收了。
  2. 可达性分析法,即通过遍历已知的存活对象(GC Roots)的引用链来标记出所有存活对象

方法1简单粗暴效率高,但准确度不行,尤其是面对互相引用的垃圾对象时无能为力。

方法2是目前常用的方法,这里有一个关键是 GC Roots,它是判定的源头,感兴趣的同学可以自己去研究下,这里就不展开讲了。

1.2 如何回收垃圾?

垃圾找到了,该怎么回收呢?看起来似乎是个很傻的问题。直接收起来扔掉不就好了?!对应到程序的操作,就是直接将这些对象占用的空间标记为空闲不就好了吗?那我们就来看一下这个基础的回收算法:标记-清除(Mark-Sweep)算法。

1.2.1 标记-清除 算法(Mark Sweep)

该算法很简单,使用通过可达性分析分析方法标记出垃圾,然后直接回收掉垃圾区域。它的一个显著问题是一段时间后,内存会出现大量碎片,导致虽然碎片总和很大,但无法满足一个大对象的内存申请,从而导致 OOM,而过多的内存碎片(需要类似链表的数据结构维护),也会导致标记和清除的操作成本高,效率低下,如下图所示:

1.2.2 复制算法(Copying)

为了解决上面算法的效率问题,有人提出了复制算法。它将可用内存一分为二,每次只用一块,当这一块内存不够用时,便触发 GC,将当前存活对象复制(Copy)到另一块上,以此往复。这种算法高效的原因在于分配内存时只需要将指针后移,不需要维护链表等。但它最大的问题是对内存的浪费,使用率只有 50%。

但这种算法在一种情况下会很高效:Java 对象的存活时间极短。据 IBM 研究,Java 对象高达 98% 是朝生夕死的,这也意味着每次 GC 可以回收大部分的内存,需要复制的数据量也很小,这样它的执行效率就会很高。

1.2.3 标记-整理算法(Mark Compact)

该算法解决了第1中算法的内存碎片问题,它会在回收阶段将所有内存做整理,如下图所示:

但它的问题也在于增加了整理阶段,也就增加了 GC 的时间。

1.2.4 分代收集算法(Generation Collection)

既然大部分 Java 对象是朝生夕死的,那么我们将内存按照 Java 生存时间分为 新生代(Young)老年代(Old),前者存放短命僧,后者存放长寿佛,当然长寿佛也是由短命僧升级上来的。然后针对两者可以采用不同的回收算法,比如对于新生代采用复制算法会比较高效,而对老年代可以采用标记-清除或者标记-整理算法。这种算法也是最常用的。JVM Heap 分代后的划分一般如下所示,新生代一般会分为 Eden、Survivor0、Survivor1区,便于使用复制算法。

将内存分代后的 GC 过程一般类似下图所示:

  1. 对象一般都是先在 Eden区创建
  2. Eden区满,触发 Young GC,此时将 Eden中还存活的对象复制到 S0中,并清空 Eden区后继续为新的对象分配内存
  3. Eden区再次满后,触发又一次的 Young GC,此时会将 EdenS0中存活的对象复制到 S1中,然后清空EdenS0后继续为新的对象分配内存
  4. 每经过一次 Young GC,存活下来的对象都会将自己存活次数加1,当达到一定次数后,会随着一次 Young GC 晋升到 Old
  5. Old区也会在合适的时机进行自己的 GC

1.2.5 常见的垃圾收集器

前面我们讲了众多的垃圾收集算法,那么其具体的实现就是垃圾收集器,也是我们实际使用中会具体用到的。现代的垃圾收集机制基本都是分代收集算法,而 YoungOld区分别有不同的垃圾收集器,简单总结如下图:

从上图我们可以看到 YoungOld区有不同的垃圾收集器,实际使用时会搭配使用,也就是上图中两两连线的收集器是可以搭配使用的。这些垃圾收集器按照运行原理大概可以分为如下几类:

  • Serial GC串行,单线程的收集器,运行 GC 时需要停止所有的用户线程,且只有一个 GC 线程
  • Parallel GC并行,多线程的收集器,是 Serial 的多线程版,运行时也需要停止所有用户线程,但同时运行多个 GC 线程,所以效率高一些
  • Concurrent GC并发,多线程收集器,GC 分多阶段执行,部分阶段允许用户线程与 GC 线程同时运行,这也就是并发的意思,大家要和并行做一个区分。
  • 其他

我们下面简单看一下他们的运行机制。

1.2.5.1 Serial GC

该类 Young区的为 Serial GCOld区的为Serial Old GC。执行大致如下所示:

1.2.5.2 Parallel GC

该类Young 区的有 ParNewParallel ScavengeOld 区的有Parallel Old。其运行机制如下,相比 Serial GC ,其最大特点在于 GC 线程是并行的,效率高很多:

1.2.5.3 Concurrent Mark-Sweep GC

该类目前只是针对 Old 区,最常见就是CMS GC,它的执行分为多个阶段,只有部分阶段需要停止用户进程,这里不详细介绍了,感兴趣可以去找相关文章来看,大体执行如下:

1.2.5.4 其他

目前最新的 GC 有G1GCZGC,其运行机制与上述均不相同,虽然他们也是分代收集算法,但会把 Heap 分成多个 region 来做处理,这里不展开讲,感兴趣的可以参看最后参考资料的内容。

1.2.6 Elasticsearch 的 GC 组合

Elasticsearch 默认的 GC 配置是CMS GC ,其 Young 区ParNewOld 区CMS,大家可以在 config/jvm.options中看到如下的配置:

## GC configuration
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly

1.3 何时进行回收?

现在我们已经知道如何找到和回收垃圾了,那么什么时候回收呢?简单总结如下:

  1. Young 区的GC 都是在 Eden 区满时触发
  2. Serial Old 和 Parallel Old 在 Old 区是在 Young GC 时预测Old 区是否可以为 young 区 promote 到 old 区 的 object 分配空间,如果不可用则触发 Old GC。这个也可以理解为是 Old区满时。
  3. CMS GC 是在 Old 区大小超过一定比例后触发,而不是 Old 区满。这个原因在于 CMS GC 是并发的算法,也就是说在 GC 线程收集垃圾的时候,用户线程也在运行,因此需要预留一些 Heap 空间给用户线程使用,防止由于无法分配空间而导致 Full GC 发生。

2. GC Log 如何阅读?

前面讲了这么多,终于可以回到开篇的问题了,我们直接来看答案

[2018-06-30T17:57:23,848][WARN ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][228384] overhead, spent [2.2s] collecting in the last [2.3s]

[gc][这是第228384次GC 检查] 在最近 2.3 s 内花了 2.2s 用来做垃圾收集,这占比似乎有些过了,请抓紧来关注下。

[2018-06-30T17:57:29,020][INFO ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][old][228385][160772] duration [5s], collections [1]/[5.1s], total [5s]/[4.4d], memory [945.4mb]->[958.5mb]/[1007.3mb], all_pools {[young] [87.8mb]->[100.9mb]/[133.1mb]}{[survivor] [0b]->[0b]/[16.6mb]}{[old] [857.6mb]->[857.6mb]/[857.6mb]}

我们直接来看具体的含义好了,相信有了前面的 GC 基础知识,大家在看这里解释的时候就非常清楚了。

  • [gc][本次是 old GC][这是第228385次 GC 检查][从 JVM 启动至今发生的第 160772次 GC]

  • duration [本次检查到的 GC 总耗时 5 秒,可能是多次的加和],

  • collections [从上次检查至今总共发生1次 GC]/[从上次检查至今已过去 5.1 秒],

  • total [本次检查到的 GC 总耗时为 5 秒]/[从 JVM 启动至今发生的 GC 总耗时为 4.4 天],

  • memory [ GC 前 Heap memory 空间]->[GC 后 Heap memory 空间]/[Heap memory 总空间],

  • all_pools(分代部分的详情) {[young 区][GC 前 Memory ]->[GC后 Memory]/[young区 Memory 总大小] } {[survivor 区][GC 前 Memory ]->[GC后 Memory]/[survivor区 Memory 总大小] }{[old 区][GC 前 Memory ]->[GC后 Memory]/[old区 Memory 总大小] }

3. 看看源码

从日志中我们可以看到输出这些日志的类名叫做JvmGcMonitorService,我们去源码中搜索很快会找到它/Users/rockybean/code/elasticsearch/core/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java,这里就不详细展开讲解源码了,它执行的内容大概如下图所示:

关于打印日志的格式在源码也有,如下所示:

private static final String SLOW_GC_LOG_MESSAGE =
"[gc][{}][{}][{}] duration [{}], collections [{}]/[{}], total [{}]/[{}], memory [{}]->[{}]/[{}], all_pools {}";
private static final String OVERHEAD_LOG_MESSAGE = "[gc][{}] overhead, spent [{}] collecting in the last [{}]";

另外细心的同学会发现输出的日志中 gc 只分了 young 和 old ,原因在于 ES 对 GC Name 做了封装,封装的类为:org.elasticsearch.monitor.jvm.GCNames,相关代码如下:

    public static String getByMemoryPoolName(String poolName, String defaultName) {
        if ("Eden Space".equals(poolName) || "PS Eden Space".equals(poolName) || "Par Eden Space".equals(poolName) || "G1 Eden Space".equals(poolName)) {
            return YOUNG;
        }
        if ("Survivor Space".equals(poolName) || "PS Survivor Space".equals(poolName) || "Par Survivor Space".equals(poolName) || "G1 Survivor Space".equals(poolName)) {
            return SURVIVOR;
        }
        if ("Tenured Gen".equals(poolName) || "PS Old Gen".equals(poolName) || "CMS Old Gen".equals(poolName) || "G1 Old Gen".equals(poolName)) {
            return OLD;
        }
        return defaultName;
    }

    public static String getByGcName(String gcName, String defaultName) {
        if ("Copy".equals(gcName) || "PS Scavenge".equals(gcName) || "ParNew".equals(gcName) || "G1 Young Generation".equals(gcName)) {
            return YOUNG;
        }
        if ("MarkSweepCompact".equals(gcName) || "PS MarkSweep".equals(gcName) || "ConcurrentMarkSweep".equals(gcName) || "G1 Old Generation".equals(gcName)) {
            return OLD;
        }
        return defaultName;
    }

在上面的代码中,你会看到很多我们在上一节中提到的 GC 算法的名称。

至此,源码相关部分也讲解完毕,感兴趣的大家可以自行去查阅。

4. 总结

讲解 GC 的文章已经很多,本文又唠唠叨叨地讲一遍基础知识,是希望对于第一次了解 GC 的同学有所帮助。因为只有了解了这些基础知识,你才不至于被这些 GC 的输出吓懵。希望本文对你理解 ES 的 GC 日志 有所帮助。

5. 参考资料

  1. Java Hotspot G1 GC的一些关键技术(https://mp.weixin.qq.com/s/4ufdCXCwO56WAJnzng_-ow
  2. Understanding Java Garbage Collection(https://www.cubrid.org/blog/understanding-java-garbage-collection
  3. 《深入理解Java虚拟机:JVM高级特性与最佳实践》

6. 相关推荐

如果你想深入的了解 JAVA GC 的知识,可以关注 ElasticTalk 公众号,回复 GC关键词后即可获取作者推荐的电子书等资料。

elasticTalk,qrcode

【求助】添加es的默认mapping模板的一些字段,但是出现报错

Elasticsearchlovefirewall 回复了问题 • 5 人关注 • 6 个回复 • 135 次浏览 • 1 天前 • 来自相关话题

ES移动分片失败

Elasticsearchexceptions 回复了问题 • 2 人关注 • 1 个回复 • 36 次浏览 • 1 天前 • 来自相关话题

请教,elasticsearch 对数字的string是如何分词的?对数字的num类型又是怎么处理和查询的呢?

ElasticsearchelasticStack 回复了问题 • 3 人关注 • 2 个回复 • 41 次浏览 • 1 天前 • 来自相关话题

ElasticSearch --should matchPhraseQuery查询返回数据速度慢问题

Elasticsearchrochy 回复了问题 • 2 人关注 • 3 个回复 • 71 次浏览 • 2 天前 • 来自相关话题

logstash到ES的数据更新问题

Logstashrochy 回复了问题 • 2 人关注 • 1 个回复 • 70 次浏览 • 2 天前 • 来自相关话题

请问大家,ES有没有限制搜索结果数的功能?

Elasticsearchintergret 回复了问题 • 12 人关注 • 11 个回复 • 1344 次浏览 • 2 天前 • 来自相关话题

【求助】filebeat的配置文件问题,能否写成变量

默认分类zqc0512 回复了问题 • 2 人关注 • 3 个回复 • 59 次浏览 • 3 天前 • 来自相关话题

elasticsearch多次查询得分不一致

Elasticsearchlaoyang360 回复了问题 • 4 人关注 • 3 个回复 • 216 次浏览 • 4 天前 • 来自相关话题

es 集群索引 分片分配策略

Elasticsearchyayg2008 回复了问题 • 5 人关注 • 3 个回复 • 94 次浏览 • 4 天前 • 来自相关话题

应使用哪个beats同步mysql数据到es

Beatschienx 回复了问题 • 4 人关注 • 2 个回复 • 298 次浏览 • 5 天前 • 来自相关话题

使用helpers.bulk无法更新index数据

Elasticsearchmedcl 回复了问题 • 5 人关注 • 4 个回复 • 87 次浏览 • 5 天前 • 来自相关话题

"[_na] query malformed, no field after start_object"

ElasticsearchelasticStack 回复了问题 • 2 人关注 • 1 个回复 • 34 次浏览 • 5 天前 • 来自相关话题

【求助】添加es的默认mapping模板的一些字段,但是出现报错

回复

Elasticsearchlovefirewall 回复了问题 • 5 人关注 • 6 个回复 • 135 次浏览 • 1 天前 • 来自相关话题

ES移动分片失败

回复

Elasticsearchexceptions 回复了问题 • 2 人关注 • 1 个回复 • 36 次浏览 • 1 天前 • 来自相关话题

请教,elasticsearch 对数字的string是如何分词的?对数字的num类型又是怎么处理和查询的呢?

回复

ElasticsearchelasticStack 回复了问题 • 3 人关注 • 2 个回复 • 41 次浏览 • 1 天前 • 来自相关话题

ElasticSearch --should matchPhraseQuery查询返回数据速度慢问题

回复

Elasticsearchrochy 回复了问题 • 2 人关注 • 3 个回复 • 71 次浏览 • 2 天前 • 来自相关话题

logstash到ES的数据更新问题

回复

Logstashrochy 回复了问题 • 2 人关注 • 1 个回复 • 70 次浏览 • 2 天前 • 来自相关话题

请问大家,ES有没有限制搜索结果数的功能?

回复

Elasticsearchintergret 回复了问题 • 12 人关注 • 11 个回复 • 1344 次浏览 • 2 天前 • 来自相关话题

【求助】filebeat的配置文件问题,能否写成变量

回复

默认分类zqc0512 回复了问题 • 2 人关注 • 3 个回复 • 59 次浏览 • 3 天前 • 来自相关话题

elasticsearch多次查询得分不一致

回复

Elasticsearchlaoyang360 回复了问题 • 4 人关注 • 3 个回复 • 216 次浏览 • 4 天前 • 来自相关话题

es 集群索引 分片分配策略

回复

Elasticsearchyayg2008 回复了问题 • 5 人关注 • 3 个回复 • 94 次浏览 • 4 天前 • 来自相关话题

应使用哪个beats同步mysql数据到es

回复

Beatschienx 回复了问题 • 4 人关注 • 2 个回复 • 298 次浏览 • 5 天前 • 来自相关话题

使用helpers.bulk无法更新index数据

回复

Elasticsearchmedcl 回复了问题 • 5 人关注 • 4 个回复 • 87 次浏览 • 5 天前 • 来自相关话题

"[_na] query malformed, no field after start_object"

回复

ElasticsearchelasticStack 回复了问题 • 2 人关注 • 1 个回复 • 34 次浏览 • 5 天前 • 来自相关话题

es多个部门使用的集群,是多个小集群好,还是一个大集群好?

回复

Elasticsearchzqc0512 回复了问题 • 3 人关注 • 2 个回复 • 144 次浏览 • 6 天前 • 来自相关话题

关于elasticsearch内存分配策略的问题

回复

Elasticsearchzqc0512 回复了问题 • 4 人关注 • 3 个回复 • 99 次浏览 • 6 天前 • 来自相关话题

Elastic日报 第403期 (2018-09-23)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 11 次浏览 • 2 小时前 • 来自相关话题

1.将Apache Hive与ElasticSearch一起使用。 http://t.cn/EPzJFKK 2.大数据与分析与数据科学:有什么区别? http://t.cn/EPzxm6P 3.(自备梯子)招聘数据科学家之前需要做的3件事。 http://t.cn/EPz6j4f 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/814 订阅:https://tinyletter.com/elastic-daily
1.将Apache Hive与ElasticSearch一起使用。 http://t.cn/EPzJFKK 2.大数据与分析与数据科学:有什么区别? http://t.cn/EPzxm6P 3.(自备梯子)招聘数据科学家之前需要做的3件事。 http://t.cn/EPz6j4f 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/814 订阅:https://tinyletter.com/elastic-daily

你看懂 Elasticsearch Log 中的 GC 日志了吗?

Elasticsearchrockybean 发表了文章 • 0 个评论 • 15 次浏览 • 13 小时前 • 来自相关话题

如果你关注过 elasticsearch 的日志,可能会看到如下类似的内容:

[2018-06-30T17:57:23,848][WARN ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][228384] overhead, spent [2.2s] collecting in the last [2.3s]

[2018-06-30T17:57:29,020][INFO ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][old][228385][160772] duration [5s], collections [1]/[5.1s], total [5s]/[4.4d], memory [945.4mb]->[958.5mb]/[1007.3mb], all_pools {[young] [87.8mb]->[100.9mb]/[133.1mb]}{[survivor] [0b]->[0b]/[16.6mb]}{[old] [857.6mb]->[857.6mb]/[857.6mb]}

看到其中的[gc]关键词你也猜到了这是与 GC 相关的日志,那么你了解每一部分的含义吗?如果不了解,你可以继续往下看了。

我们先从最简单的看起:

  1. 第一部分是日志发生的时间
  2. 第二部分是日志级别,这里分别是WARNINFO
  3. 第三部分是输出日志的类,我们后面也会讲到这个类
  4. 第四部分是当前 ES 节点名称
  5. 第五部分是 gc 关键词,我们就从这个关键词聊起。

友情提示:对 GC 已经了如指掌的同学,可以直接翻到最后看答案。

1. 什么是 GC?

GC,全称是 Garbage Collection (垃圾收集)或者 Garbage Collector(垃圾收集器)。

在使用 C语言编程的时候,我们要手动的通过 mallocfree来申请和释放数据需要的内存,如果忘记释放内存,就会发生内存泄露的情况,即无用的数据占用了宝贵的内存资源。而Java 语言编程不需要显示的申请和释放内存,因为 JVM 可以自动管理内存,这其中最重要的一部分就是 GC,即 JVM 可以自主地去释放无用数据(垃圾)占用的内存。

我们研究 GC 的主要原因是 GC 的过程会有 Stop The World(STW)的情况发生,即此时用户线程会停止工作,如果 STW 的时间过长,则应用的可用性、实时性等就下降的很厉害。

GC主要解决如下3个问题:

  1. 如何找到垃圾?
  2. 如何回收垃圾?
  3. 何时回收垃圾?

我们一个个来看下。

1.1 如何找到垃圾?

所谓垃圾,指的是不再被使用(引用)的对象。Java 的对象都是在堆(Heap)上创建的,我们这里默认也只讨论堆。那么现在问题就变为如何判定一个对象是否还有被引用,思路主要有如下两种:

  1. 引用计数法,即在对象被引用时加1,去除引用时减1,如果引用值为0,即表明该对象可回收了。
  2. 可达性分析法,即通过遍历已知的存活对象(GC Roots)的引用链来标记出所有存活对象

方法1简单粗暴效率高,但准确度不行,尤其是面对互相引用的垃圾对象时无能为力。

方法2是目前常用的方法,这里有一个关键是 GC Roots,它是判定的源头,感兴趣的同学可以自己去研究下,这里就不展开讲了。

1.2 如何回收垃圾?

垃圾找到了,该怎么回收呢?看起来似乎是个很傻的问题。直接收起来扔掉不就好了?!对应到程序的操作,就是直接将这些对象占用的空间标记为空闲不就好了吗?那我们就来看一下这个基础的回收算法:标记-清除(Mark-Sweep)算法。

1.2.1 标记-清除 算法(Mark Sweep)

该算法很简单,使用通过可达性分析分析方法标记出垃圾,然后直接回收掉垃圾区域。它的一个显著问题是一段时间后,内存会出现大量碎片,导致虽然碎片总和很大,但无法满足一个大对象的内存申请,从而导致 OOM,而过多的内存碎片(需要类似链表的数据结构维护),也会导致标记和清除的操作成本高,效率低下,如下图所示:

1.2.2 复制算法(Copying)

为了解决上面算法的效率问题,有人提出了复制算法。它将可用内存一分为二,每次只用一块,当这一块内存不够用时,便触发 GC,将当前存活对象复制(Copy)到另一块上,以此往复。这种算法高效的原因在于分配内存时只需要将指针后移,不需要维护链表等。但它最大的问题是对内存的浪费,使用率只有 50%。

但这种算法在一种情况下会很高效:Java 对象的存活时间极短。据 IBM 研究,Java 对象高达 98% 是朝生夕死的,这也意味着每次 GC 可以回收大部分的内存,需要复制的数据量也很小,这样它的执行效率就会很高。

1.2.3 标记-整理算法(Mark Compact)

该算法解决了第1中算法的内存碎片问题,它会在回收阶段将所有内存做整理,如下图所示:

但它的问题也在于增加了整理阶段,也就增加了 GC 的时间。

1.2.4 分代收集算法(Generation Collection)

既然大部分 Java 对象是朝生夕死的,那么我们将内存按照 Java 生存时间分为 新生代(Young)老年代(Old),前者存放短命僧,后者存放长寿佛,当然长寿佛也是由短命僧升级上来的。然后针对两者可以采用不同的回收算法,比如对于新生代采用复制算法会比较高效,而对老年代可以采用标记-清除或者标记-整理算法。这种算法也是最常用的。JVM Heap 分代后的划分一般如下所示,新生代一般会分为 Eden、Survivor0、Survivor1区,便于使用复制算法。

将内存分代后的 GC 过程一般类似下图所示:

  1. 对象一般都是先在 Eden区创建
  2. Eden区满,触发 Young GC,此时将 Eden中还存活的对象复制到 S0中,并清空 Eden区后继续为新的对象分配内存
  3. Eden区再次满后,触发又一次的 Young GC,此时会将 EdenS0中存活的对象复制到 S1中,然后清空EdenS0后继续为新的对象分配内存
  4. 每经过一次 Young GC,存活下来的对象都会将自己存活次数加1,当达到一定次数后,会随着一次 Young GC 晋升到 Old
  5. Old区也会在合适的时机进行自己的 GC

1.2.5 常见的垃圾收集器

前面我们讲了众多的垃圾收集算法,那么其具体的实现就是垃圾收集器,也是我们实际使用中会具体用到的。现代的垃圾收集机制基本都是分代收集算法,而 YoungOld区分别有不同的垃圾收集器,简单总结如下图:

从上图我们可以看到 YoungOld区有不同的垃圾收集器,实际使用时会搭配使用,也就是上图中两两连线的收集器是可以搭配使用的。这些垃圾收集器按照运行原理大概可以分为如下几类:

  • Serial GC串行,单线程的收集器,运行 GC 时需要停止所有的用户线程,且只有一个 GC 线程
  • Parallel GC并行,多线程的收集器,是 Serial 的多线程版,运行时也需要停止所有用户线程,但同时运行多个 GC 线程,所以效率高一些
  • Concurrent GC并发,多线程收集器,GC 分多阶段执行,部分阶段允许用户线程与 GC 线程同时运行,这也就是并发的意思,大家要和并行做一个区分。
  • 其他

我们下面简单看一下他们的运行机制。

1.2.5.1 Serial GC

该类 Young区的为 Serial GCOld区的为Serial Old GC。执行大致如下所示:

1.2.5.2 Parallel GC

该类Young 区的有 ParNewParallel ScavengeOld 区的有Parallel Old。其运行机制如下,相比 Serial GC ,其最大特点在于 GC 线程是并行的,效率高很多:

1.2.5.3 Concurrent Mark-Sweep GC

该类目前只是针对 Old 区,最常见就是CMS GC,它的执行分为多个阶段,只有部分阶段需要停止用户进程,这里不详细介绍了,感兴趣可以去找相关文章来看,大体执行如下:

1.2.5.4 其他

目前最新的 GC 有G1GCZGC,其运行机制与上述均不相同,虽然他们也是分代收集算法,但会把 Heap 分成多个 region 来做处理,这里不展开讲,感兴趣的可以参看最后参考资料的内容。

1.2.6 Elasticsearch 的 GC 组合

Elasticsearch 默认的 GC 配置是CMS GC ,其 Young 区ParNewOld 区CMS,大家可以在 config/jvm.options中看到如下的配置:

## GC configuration
-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly

1.3 何时进行回收?

现在我们已经知道如何找到和回收垃圾了,那么什么时候回收呢?简单总结如下:

  1. Young 区的GC 都是在 Eden 区满时触发
  2. Serial Old 和 Parallel Old 在 Old 区是在 Young GC 时预测Old 区是否可以为 young 区 promote 到 old 区 的 object 分配空间,如果不可用则触发 Old GC。这个也可以理解为是 Old区满时。
  3. CMS GC 是在 Old 区大小超过一定比例后触发,而不是 Old 区满。这个原因在于 CMS GC 是并发的算法,也就是说在 GC 线程收集垃圾的时候,用户线程也在运行,因此需要预留一些 Heap 空间给用户线程使用,防止由于无法分配空间而导致 Full GC 发生。

2. GC Log 如何阅读?

前面讲了这么多,终于可以回到开篇的问题了,我们直接来看答案

[2018-06-30T17:57:23,848][WARN ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][228384] overhead, spent [2.2s] collecting in the last [2.3s]

[gc][这是第228384次GC 检查] 在最近 2.3 s 内花了 2.2s 用来做垃圾收集,这占比似乎有些过了,请抓紧来关注下。

[2018-06-30T17:57:29,020][INFO ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][old][228385][160772] duration [5s], collections [1]/[5.1s], total [5s]/[4.4d], memory [945.4mb]->[958.5mb]/[1007.3mb], all_pools {[young] [87.8mb]->[100.9mb]/[133.1mb]}{[survivor] [0b]->[0b]/[16.6mb]}{[old] [857.6mb]->[857.6mb]/[857.6mb]}

我们直接来看具体的含义好了,相信有了前面的 GC 基础知识,大家在看这里解释的时候就非常清楚了。

  • [gc][本次是 old GC][这是第228385次 GC 检查][从 JVM 启动至今发生的第 160772次 GC]

  • duration [本次检查到的 GC 总耗时 5 秒,可能是多次的加和],

  • collections [从上次检查至今总共发生1次 GC]/[从上次检查至今已过去 5.1 秒],

  • total [本次检查到的 GC 总耗时为 5 秒]/[从 JVM 启动至今发生的 GC 总耗时为 4.4 天],

  • memory [ GC 前 Heap memory 空间]->[GC 后 Heap memory 空间]/[Heap memory 总空间],

  • all_pools(分代部分的详情) {[young 区][GC 前 Memory ]->[GC后 Memory]/[young区 Memory 总大小] } {[survivor 区][GC 前 Memory ]->[GC后 Memory]/[survivor区 Memory 总大小] }{[old 区][GC 前 Memory ]->[GC后 Memory]/[old区 Memory 总大小] }

3. 看看源码

从日志中我们可以看到输出这些日志的类名叫做JvmGcMonitorService,我们去源码中搜索很快会找到它/Users/rockybean/code/elasticsearch/core/src/main/java/org/elasticsearch/monitor/jvm/JvmGcMonitorService.java,这里就不详细展开讲解源码了,它执行的内容大概如下图所示:

关于打印日志的格式在源码也有,如下所示:

private static final String SLOW_GC_LOG_MESSAGE =
"[gc][{}][{}][{}] duration [{}], collections [{}]/[{}], total [{}]/[{}], memory [{}]->[{}]/[{}], all_pools {}";
private static final String OVERHEAD_LOG_MESSAGE = "[gc][{}] overhead, spent [{}] collecting in the last [{}]";

另外细心的同学会发现输出的日志中 gc 只分了 young 和 old ,原因在于 ES 对 GC Name 做了封装,封装的类为:org.elasticsearch.monitor.jvm.GCNames,相关代码如下:

    public static String getByMemoryPoolName(String poolName, String defaultName) {
        if ("Eden Space".equals(poolName) || "PS Eden Space".equals(poolName) || "Par Eden Space".equals(poolName) || "G1 Eden Space".equals(poolName)) {
            return YOUNG;
        }
        if ("Survivor Space".equals(poolName) || "PS Survivor Space".equals(poolName) || "Par Survivor Space".equals(poolName) || "G1 Survivor Space".equals(poolName)) {
            return SURVIVOR;
        }
        if ("Tenured Gen".equals(poolName) || "PS Old Gen".equals(poolName) || "CMS Old Gen".equals(poolName) || "G1 Old Gen".equals(poolName)) {
            return OLD;
        }
        return defaultName;
    }

    public static String getByGcName(String gcName, String defaultName) {
        if ("Copy".equals(gcName) || "PS Scavenge".equals(gcName) || "ParNew".equals(gcName) || "G1 Young Generation".equals(gcName)) {
            return YOUNG;
        }
        if ("MarkSweepCompact".equals(gcName) || "PS MarkSweep".equals(gcName) || "ConcurrentMarkSweep".equals(gcName) || "G1 Old Generation".equals(gcName)) {
            return OLD;
        }
        return defaultName;
    }

在上面的代码中,你会看到很多我们在上一节中提到的 GC 算法的名称。

至此,源码相关部分也讲解完毕,感兴趣的大家可以自行去查阅。

4. 总结

讲解 GC 的文章已经很多,本文又唠唠叨叨地讲一遍基础知识,是希望对于第一次了解 GC 的同学有所帮助。因为只有了解了这些基础知识,你才不至于被这些 GC 的输出吓懵。希望本文对你理解 ES 的 GC 日志 有所帮助。

5. 参考资料

  1. Java Hotspot G1 GC的一些关键技术(https://mp.weixin.qq.com/s/4ufdCXCwO56WAJnzng_-ow
  2. Understanding Java Garbage Collection(https://www.cubrid.org/blog/understanding-java-garbage-collection
  3. 《深入理解Java虚拟机:JVM高级特性与最佳实践》

6. 相关推荐

如果你想深入的了解 JAVA GC 的知识,可以关注 ElasticTalk 公众号,回复 GC关键词后即可获取作者推荐的电子书等资料。

elasticTalk,qrcode

Elastic日报 第396期 (2018-09-16)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 116 次浏览 • 2018-09-16 08:00 • 来自相关话题

1.(自备梯子)Kibana的第三方地图和平铺服务。 http://t.cn/EvfhXE9 2.Logstash教程:快速入门指南。 http://t.cn/Evf7oTo 3.(自备梯子)苹果想要挽救你的生命。 http://t.cn/Evfzk6z 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/801 订阅:https://tinyletter.com/elastic-daily
1.(自备梯子)Kibana的第三方地图和平铺服务。 http://t.cn/EvfhXE9 2.Logstash教程:快速入门指南。 http://t.cn/Evf7oTo 3.(自备梯子)苹果想要挽救你的生命。 http://t.cn/Evfzk6z 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/801 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第389期 (2018-09-09)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 170 次浏览 • 2018-09-09 11:25 • 来自相关话题

1.ELK Stack完整指南 - 2018年。 http://t.cn/R9RHO6l 2.安全最佳实践:高增长初创企业的经验教训。 http://t.cn/RsoQXK2 3.(自备梯子)再见,面向对象编程。 http://t.cn/Rt4icdt 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/793 订阅:https://tinyletter.com/elastic-daily
1.ELK Stack完整指南 - 2018年。 http://t.cn/R9RHO6l 2.安全最佳实践:高增长初创企业的经验教训。 http://t.cn/RsoQXK2 3.(自备梯子)再见,面向对象编程。 http://t.cn/Rt4icdt 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/793 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第382期 (2018-09-02)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 135 次浏览 • 2018-09-02 08:40 • 来自相关话题

1.如何将Heroku日志导入到Logsene / Managed ELK Stack。 http://t.cn/RFSfTz6 2.5分钟将CoreOS日志导入到ELK。 http://t.cn/RFSxz0S 3.苹果圈:iPhone XS推出9月12日确认,新iPhone SE 2泄漏,苹果公司的恐慌方案。 http://t.cn/RFS9bWj 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 2、Elastic Meetup 9月8日 北京线下交流活动免费报名中 https://elasticsearch.cn/article/759 编辑:至尊宝 归档:https://elasticsearch.cn/article/782 订阅:https://tinyletter.com/elastic-daily 
1.如何将Heroku日志导入到Logsene / Managed ELK Stack。 http://t.cn/RFSfTz6 2.5分钟将CoreOS日志导入到ELK。 http://t.cn/RFSxz0S 3.苹果圈:iPhone XS推出9月12日确认,新iPhone SE 2泄漏,苹果公司的恐慌方案。 http://t.cn/RFS9bWj 活动预告: 1、Elastic 中国开发者大会门票发售中 https://conf.elasticsearch.cn/2018/shenzhen.html 2、Elastic Meetup 9月8日 北京线下交流活动免费报名中 https://elasticsearch.cn/article/759 编辑:至尊宝 归档:https://elasticsearch.cn/article/782 订阅:https://tinyletter.com/elastic-daily 

Curator从入门到实战

ElasticsearchLeon J 发表了文章 • 1 个评论 • 329 次浏览 • 2018-08-30 22:05 • 来自相关话题

Curator 是elasticsearch 官方的一个索引管理工具,可以通过配置文件的方式帮助我们对指定的一批索引进行创建/删除、打开/关闭、快照/恢复等管理操作。

场景

比如,出于读写性能的考虑,我们通常会把基于时间的数据按时间来创建索引。

indices当数据量到达一定量级时,为了节省内存或者磁盘空间,我们往往会根据实际情况选择关闭或者删除一定时间之前的索引。通常我们会写一段脚本调用elasticsearch的api,放到crontab中定期执行。这样虽然可以达到目的,但是脚本多了之后会变得难以维护。

Curator是如何解决这类问题的呢?我们一步一步来:

安装

首先,Curator是基于python实现的,我们可以直接通过pip来安装,这种方式最简单。

pip install elasticsearch-curator

基本配置

接下来,需要为 Curator 配置es连接:

# ~/.curator/curator.yml

client:
  hosts:
    - 127.0.0.1
  port: 9200

logging:
  loglevel: INFO

其中hosts 允许配置多个地址,但是只能属于同一个集群。

这边只列举了最基本的配置,官方文档中包含了更详细的配置。

动作配置

然后需要配置我们需要执行的动作,每个动作会按顺序执行:

# /etc/curator/actions/maintain_log.yml

actions:
  1:
    #创建第二天的索引
    action: create_index
    description: "create new time-based index for log-*"
    options:
      name: '<log-{now/d+1d}>'
  2:
    #删除3天前的索引
    action: delete_indices
    description: "delete outdated indices for log-*"
    filters:
    - filtertype: pattern
      kind: prefix
      value: log
    - filtertype: age
      source: name
      direction: older
      timestring: '%Y.%m.%d'
      unit: days
      unit_count: 3

action 定义了需要执行的动作,curator支持十多种动作,可以在官方文档查看完整的动作列表。

options 定义了执行动作所需的参数,不同动作的参数也不尽相同,具体文档中都有写明。

filters 定义了动作的执行对象,通过设置filter,可以过滤出我们需要操作的索引。同一个action下的filter之间是的关系。比如在上面的定义中,delete_indices下定义了两个filters:

  • 模式匹配:匹配前缀为log的索引
  • “年龄”匹配:根据索引名中“%Y.%m.%d”时间格式,过滤出3天以前的索引

curator支持十多种filter,可以在官方文档查看完整列表。

执行

最后,我们通过curator命令行工具来执行:

curator --config /etc/curator/curator.yml /etc/curator/actions/maintain_log.yml

得到命令行输出:

2018-08-30 12:31:26,829 INFO      Preparing Action ID: 1, "create_index"
2018-08-30 12:31:26,841 INFO      Trying Action ID: 1, "create_index": create new time-based index for log-*
2018-08-30 12:31:26,841 INFO      "<log-{now/d+1d}>" is using Elasticsearch date math.
2018-08-30 12:31:26,841 INFO      Creating index "<log-{now/d+1d}>" with settings: {}
2018-08-30 12:31:27,049 INFO      Action ID: 1, "create_index" completed.
2018-08-30 12:31:27,050 INFO      Preparing Action ID: 2, "delete_indices"
2018-08-30 12:31:27,058 INFO      Trying Action ID: 2, "delete_indices": delete outdated indices for log-*
2018-08-30 12:31:27,119 INFO      Deleting selected indices: ['log-2018.08.24', 'log-2018.08.25', 'log-2018.08.27', 'log-2018.08.26', 'log-2018.08.23']
2018-08-30 12:31:27,119 INFO      ---deleting index log-2018.08.24
2018-08-30 12:31:27,120 INFO      ---deleting index log-2018.08.25
2018-08-30 12:31:27,120 INFO      ---deleting index log-2018.08.27
2018-08-30 12:31:27,120 INFO      ---deleting index log-2018.08.26
2018-08-30 12:31:27,120 INFO      ---deleting index log-2018.08.23
2018-08-30 12:31:27,282 INFO      Action ID: 2, "delete_indices" completed.
2018-08-30 12:31:27,283 INFO      Job completed.

从日志中可以看到,我们已经成功创建了隔天的索引,并删除了28号以前的索引。

定时执行

配置好curator后,还需要配置定时任务

使用crontab -e编辑crontab,

添加一行:

0 23 * * * /usr/local/bin/curator --config /root/.curator/curator.yml /etc/curator/actions/maintain_log.yml >> /var/curator.log 2>&1

crontab配置中的第一段是执行的周期,6个值分别是“分 时 日 月 周”,*表示全部。所以这段配置的含义是在每天23点执行我们的这段脚本。

单个执行

除了定时任务,我们也可以在不依赖action配置文件的情况下用curator执行一些临时的批量操作。curator提供了curator_cli的命令来执行单个action,比如我们想对所有log开头的索引做快照,使用一条命令即可完成:

curator_cli snapshot --repository repo_name --filter_list {"filtertype": "pattern","kind": "prefix", "value": "log"}

是不是特别方便?

执行流程

image-20180830200126973

在命令执行过程中,Curator 会进行以下几步操作:

  1. 从ES拉取所有的索引信息
  2. 根据设置的过滤条件过滤出需要操作的索引
  3. 对过滤后的索引执行指定的动作

复杂需求

实际生产中,会有一些更复杂的需求,简单的action和filter组合并不能满足我们的业务。Curator还提供了python包,方便我们自己写脚本时调用它提供的actions和filters,减少我们的开发工作量。

以上通过一个实际的场景向大家介绍了Curator的使用方式,但是只用到了它一小部分的功能。大家可以通过文中的链接查看官方文档,发掘出更多的使用姿势。希望对大家有所帮助!

elasticTalk,qrcode

​Elastic日报 第375期 (2018-08-26)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 158 次浏览 • 2018-08-26 08:22 • 来自相关话题

1.Kibana高级搜索入门。 http://t.cn/Rk1SYUC 2.(自备梯子)四大NoSQL数据库。 http://t.cn/Rk1anR2 3.(自备梯子)您必须在“按时交付的软件”和“良好软件”之间进行选择。 http://t.cn/Rk1abPX 活动预告: 1、Elastic 中国开发者大会最后一波早鸟票发售进行中 https://conf.elasticsearch.cn/2018/shenzhen.html 2、Elastic Meetup 9月8日 北京线下沙龙正在报名中 https://elasticsearch.cn/article/759 编辑:至尊宝 归档:https://elasticsearch.cn/article/772 订阅:https://tinyletter.com/elastic-daily
1.Kibana高级搜索入门。 http://t.cn/Rk1SYUC 2.(自备梯子)四大NoSQL数据库。 http://t.cn/Rk1anR2 3.(自备梯子)您必须在“按时交付的软件”和“良好软件”之间进行选择。 http://t.cn/Rk1abPX 活动预告: 1、Elastic 中国开发者大会最后一波早鸟票发售进行中 https://conf.elasticsearch.cn/2018/shenzhen.html 2、Elastic Meetup 9月8日 北京线下沙龙正在报名中 https://elasticsearch.cn/article/759 编辑:至尊宝 归档:https://elasticsearch.cn/article/772 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第368期 (2018-08-19)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 161 次浏览 • 2018-08-19 10:09 • 来自相关话题

1.如何使用Nginx作为CentOS 7上的反向代理来保护Kibana。 http://t.cn/RDes1PI 2.如何使用ELK stack管理Nginx日志。 http://t.cn/RkUKe2L 3.(自备梯子)数据科学项目最重要的部分是写博客文章。 http://t.cn/RkU9jJW 活动预告: 1、Elastic Meetup 北京线下沙龙征稿中 https://elasticsearch.cn/article/759 2、Elastic 中国开发者大会预热票今天发售! https://conf.elasticsearch.cn/2018/shenzhen.html  编辑:至尊宝 归档:https://elasticsearch.cn/article/763 订阅:https://tinyletter.com/elastic-daily
1.如何使用Nginx作为CentOS 7上的反向代理来保护Kibana。 http://t.cn/RDes1PI 2.如何使用ELK stack管理Nginx日志。 http://t.cn/RkUKe2L 3.(自备梯子)数据科学项目最重要的部分是写博客文章。 http://t.cn/RkU9jJW 活动预告: 1、Elastic Meetup 北京线下沙龙征稿中 https://elasticsearch.cn/article/759 2、Elastic 中国开发者大会预热票今天发售! https://conf.elasticsearch.cn/2018/shenzhen.html  编辑:至尊宝 归档:https://elasticsearch.cn/article/763 订阅:https://tinyletter.com/elastic-daily

推荐一个同步Mysql数据到Elasticsearch的工具

ElasticsearchMCTW 发表了文章 • 12 个评论 • 681 次浏览 • 2018-08-14 15:47 • 来自相关话题

把Mysql的数据同步到Elasticsearch是个很常见的需求,但在Github里找到的同步工具用起来或多或少都有些别扭。 例如:某记录内容为"aaa|bbb|ccc",将其按|分割成数组同步到es,这样的简单任务都难以实现,再加上配置繁琐,文档语焉不详... 所以我写了个同步工具MysqlsMom:力求用最简单的配置完成复杂的同步任务。目前除了我所在的部门,也有越来越多的互联网公司在生产环境中使用该工具了。 欢迎各位大佬进行试用并提出意见,任何建议、鼓励、批评都受到欢迎。 github: https://github.com/m358807551/mysqlsmom Alt text

简介:同步 Mysql 数据到 elasticsearch 的工具; QQ、微信:358807551

特点

  1. Python 编写;
  2. 支持基于 sql 语句的全量同步,基于 binlog 的增量同步,基于更新字段的增量同步三种同步方式;
  3. 全量更新只占用少量内存;支持通过sql语句同步数据;
  4. 增量更新自动断点续传;
  5. 取自 Mysql 的数据可经过一系列自定义函数的处理后再同步至 Elasticsearch
  6. 能用非常简单的配置完成复杂的同步任务;

环境

  • python2.7;
  • 增量同步需开启 redis
  • 分析 binlog 的增量同步需要 Mysql 开启 binlogbinlog-format=row);

快速开始

全量同步MySql数据到es

  1. clone 项目到本地;

  2. 安装依赖;

    cd mysqlsmom
    pip install -r requirements.txt

    默认支持 elasticsearch-2.4版本,支持其它版本请运行(将5.4换成需要的elasticsearch版本)

    pip install --upgrade elasticsearch==5.4
  3. 编辑 ./config/example_init.py,按注释提示修改配置;

    # coding=utf-8
    
    STREAM = "INIT"
    
    # 修改数据库连接
    CONNECTION = {
       'host': '127.0.0.1',
       'port': 3306,
       'user': 'root',
       'passwd': ''
    }
    
    # 修改elasticsearch节点
    NODES = [{"host": "127.0.0.1", "port": 9200}]
    
    TASKS = [
       {
           "stream": {
               "database": "test_db",  # 在此数据库执行sql语句
               "sql": "select * from person"  # 将该sql语句选中的数据同步到 elasticsearch
           },
           "jobs": [
               {
                   "actions": ["insert", "update"],
                   "pipeline": [
                       {"set_id": {"field": "id"}}  # 默认设置 id字段的值 为elasticsearch中的文档id
                   ],
                   "dest": {
                       "es": {
                           "action": "upsert",
                           "index": "test_index",   # 设置 index
                           "type": "test",          # 设置 type
                           "nodes": NODES
                       }
                   }
               }
           ]
       }
    ]
  4. 运行

    cd mysqlsmom
    python mysqlsmom.py ./config/example_init.py

    等待同步完成即可;

分析 binlog 的增量同步

  1. 确保要增量同步的MySql数据库开启binlog,且开启redis(为了存储最后一次读到的binlog文件名及读到的位置。未来可能支持本地文件存储该信息。)

  2. 下载项目到本地,且安装好依赖后,编辑 ./config/example_init.py,按注释提示修改配置;

    # coding=utf-8
    
    STREAM = "BINLOG"
    SERVER_ID = 99  # 确保每个用于binlog同步的配置文件的SERVER_ID不同;
    SLAVE_UUID = __name__
    
    # 配置开启binlog权限的MySql连接
    BINLOG_CONNECTION = {
       'host': '127.0.0.1',
       'port': 3306,
       'user': 'root',
       'passwd': ''
    }
    
    # 配置es节点
    NODES = [{"host": "127.0.0.1", "port": 9200}]
    
    TASKS = [
       {
           "stream": {
               "database": "test_db",  # [table]所在的数据库
               "table": "person"  # 监控该表的binlog
           },
           "jobs": [
               {
                   "actions": ["insert", "update"],
                   "pipeline": [
                       {"only_fields": {"fields": ["id", "name", "age"]}},  # 只同步这些字段到es,注释掉该行则同步全部字段的值到es
                       {"set_id": {"field": "id"}}  # 设置es中文档_id的值取自 id(或根据需要更改)字段
                   ],
                   "dest": {
                       "es": {
                           "action": "upsert",
                           "index": "test_index",  # 设置 index
                           "type": "test",         # 设置 type
                           "nodes": NODES
                       }
                   }
               }
           ]
       }
    ]
  3. 运行

    cd mysqlsmom
    python mysqlsmom.py ./config/example_binlog.py

    该进程会一直运行,实时同步新增和更改后的数据到elasticsearch;

    注意:第一次运行该进程时不会同步MySql中已存在的数据,从第二次运行开始,将接着上次同步停止时的位置继续同步;

    同步旧数据请看全量同步MySql数据到es

基于更新时间的增量同步

Mysql 表中有类似 update_time 的时间字段,且在每次插入、更新数据后将该字段的值设置为操作时间,则可在不用开启 binlog 的情况下进行增量同步。

  1. 下载项目到本地,且安装好依赖后,编辑 ./config/example_cron.py,按注释提示修改配置;

    # coding=utf-8
    
    STREAM = "CRON"
    
    # 修改数据库连接
    CONNECTION = {
       'host': '127.0.0.1',
       'port': 3306,
       'user': 'root',
       'passwd': ''
    }
    
    # redis存储上次同步时间等信息
    REDIS = {
       "host": "127.0.0.1",
       "port": 6379,
       "db": 0,
       "password": "password",  # 不需要密码则注释或删掉该行
    }
    
    # 一次同步 BULK_SIZE 条数据到elasticsearch,不设置该配置项默认为1
    BULK_SIZE = 1
    
    # 修改elasticsearch节点
    NODES = [{"host": "127.0.0.1", "port": 9200}]
    
    TASKS = [
       {
           "stream": {
               "database": "test_db",  # 在此数据库执行sql语句
               "sql": "select id, name from person where update_time >= ?",  # 将该sql语句选中的数据同步到 elasticsearch
               "seconds": 10,  # 每隔 seconds 秒同步一次,
               "init_time": "2018-08-15 18:05:47"  # 只有第一次同步会加载
           },
           "jobs": [
               {
                   "pipeline": [
                       {"set_id": {"field": "id"}}  # 默认设置 id字段的值 为 es 中的文档id
                   ],
                   "dest": {
                       "es": {
                           "action": "upsert",
                           "index": "test_index",   # 设置 index
                           "type": "test"          # 设置 type
                       }
                   }
               }
           ]
       }
    ]
  2. 运行

    cd mysqlsmom
    python mysqlsmom.py ./config/example_cron.py

组织架构

Alt text

Mysqlsmom 使用实战

Mysqlsmom 的灵活性依赖于:

  • row_handlers.py 中添加自定义函数对取自Mysql的数据进行二次加工。
  • row_filters.py 中添加自定义函数决定是否要同步某一条数据。
  • config/ 目录下的任意配置文件应用上面的函数。

如果不了解 Python 也没关系,上述两个文件中自带的函数足以应付大多数种情况,遇到特殊的同步需求可以在 Github 发起 issue 或通过微信、QQ联系作者。

同步多张表

在一个配置文件中即可完成:

...
TASKS = [
    # 同步表1
    {
        "stream": {
            "database": "数据库名1",
            "table": "表名1"
        },
        "jobs": [...]
    }
    # 同步表2
    {
        "stream": {
            "database": "数据库名2",
            "table": "表名2"
        },
        "jobs": [...]
    }
]

一个 Mysql Connection 对应一个配置文件。

一张表同步到多个索引

分为两种情况。

一种是把相同的数据同步到不同的索引,配置如下:

...
TASKS = [
    {
        "stream": {...},
        "jobs": [
            {
                "actions": [...],
                "pipeline": [...],
                "dest": [
                    # 同步到索引1
                    {
                        "es": {"action": "upsert", "index": "索引1", "type": "类型1", "nodes": NODES},
                    },
                    # 同步到索引2
                    {
                        "es": {"action": "upsert", "index": "索引2", "type": "类型2", "nodes": NODES},
                    }
                ]
            }
        ]
    },
    ...
]

另一种是把同一个表产生的数据经过不同的 pipeline 同步到不同的索引:

...
TASKS = [
    {
        "stream": {...},
        "jobs": [
            {
                "actions": {...},
                "pipeline": [...],  # 对数据经过一系列处理
                "dest": {"es": {"index": "索引1", ...}}  # 同步到索引1
            },
            {
                "actions": {...},
                "pipeline": [...],  # 与上面的pipeline不同
                "dest": {"es": {"index": "索引2", ...}}  # 同步到索引2
            }
        ]
    }
]
  • TASKS 中的每一项对应一张要同步的表。
  • jobs 中的每一项对应对一条记录的一种处理方式。
  • dest 中的每一项对应一个es索引类型。

只同步某些字段

对每条来自 Mysql 的 记录的处理都在 pipeline 中进行处理。

"pipeline": [
    {"only_fields": {"fields": ["id", "name"]}},  # 只同步 id 和 name字段
    {"set_id": {"field": "id"}}  # 然后设置 id 字段为es中文档的_id
]

字段重命名

对于 Mysql 中的字段名和 elasticsearch 中的域名不一致的情况:

"pipeline": [
    # 将name重命名为name1,age 重命名为age1
    {"replace_fields": {"name": ["name1"], "age": ["age1"]}},
    {"set_id": {"field": "id"}}
]

pipeline 会依次执行处理函数,上面的例子等价于:

"pipeline": [
    # 先重命名 name 为 name1
    {"replace_fields": {"name": ["name1"]}},
    # 再重命名 age 为 age1
    {"replace_fields": {"age": ["age1"]}},
    {"set_id": {"field": "id"}}
]

还有一种特殊情形,es 中两个字段存相同的数据,但是分词方式不同。

例如 name_default 的分析器为 defaultname_raw 设置为不分词,需要将 name 的值同时同步到这两个域:

"pipeline": [
    {"replace_fields": {"name": ["name_default", "name_raw"]}},
    {"set_id": {"field": "id"}}
]

当然上述问题有一个更好的解决方案,在 esmappings 中配置 name 字段的 fields 属性即可,这超出了本文档的内容。

切分字符串为数组

有时 Mysql 存储字符串类似:"aaa|bbb|ccc",希望转化成数组: ["aaa", "bbb", "ccc"] 再进行同步

"pipeline": [
    # tags 存储类似"aaa|bbb|ccc"的字符串,将 tags 字段的值按符号 `|` 切分成数组
    {"split": {"field": "tags", "flag": "|"}},
    {"set_id": {"field": "id"}}
] 

同步删除文档

只有 binlog 同步 能实现删除 elasticsearch 中的文档,配置如下:

TASKS = [
    {
        "stream": {
            "database": "test_db",
            "table": "person"
        },
        "jobs": [
            # 插入、更新
            {
                "actions": ["insert", "update"],
                "pipeline": [
                    {"set_id": {"field": "id"}}  # 设置 id 字段的值为 es 中文档 _id
                ],
                "dest": {
                    "es": {
                        "action": "upsert",
                        ...
                    }
                }
            },
            # 重点在这里,配置删除
            {
                "actions": ["delete"],  # 当读取到 binlog 中该表的删除操作时
                "pipeline": [{"set_id": {"field": "id"}}],  # 要删除的文档 _id
                "dest": {
                    "es": {
                        "action": "delete",  # 在 es 中执行删除操作
                        ...  # 与上面的 index 和 type 相同
                    }
                }
            }
        ]
    },
    ...
]

更多示例正在更新

常见问题

为什么我的增量同步不及时?

  1. 连接本地数据库增量同步不及时

    该情况暂未收到过反馈,如能复现请联系作者。

  2. 连接线上数据库发现增量同步不及时

    2.1 推荐使用内网IP连接数据库。连接线上数据库(如开启在阿里、腾讯服务器上的Mysql)时,推荐使用内网IP地址,因为外网IP会受到带宽等限制导致获取binlog数据速度受限,最终可能造成同步延时。

待改进

  1. 据部分用户反馈,全量同步百万级以上的数据性能不佳。

未完待续

文档近期会较频繁更新,任何问题、建议都收到欢迎,请在issues留言,会在24小时内回复;或联系QQ、微信: 358807551;

Elastic日报 第361期 (2018-08-12)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 170 次浏览 • 2018-08-12 09:58 • 来自相关话题

1.(自备梯子)ELK Stack 详细配置。 http://t.cn/RDWHBvW 2.Elasticsearch安全性:身份验证,加密,备份。 http://t.cn/RDWl15I 3.(自备梯子)数据科学中必备的数学知识。 http://t.cn/RDWYsfF 活动预告: Elastic 中国开发者大会预热票发售进行中  https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/752 订阅:https://tinyletter.com/elastic-daily
1.(自备梯子)ELK Stack 详细配置。 http://t.cn/RDWHBvW 2.Elasticsearch安全性:身份验证,加密,备份。 http://t.cn/RDWl15I 3.(自备梯子)数据科学中必备的数学知识。 http://t.cn/RDWYsfF 活动预告: Elastic 中国开发者大会预热票发售进行中  https://conf.elasticsearch.cn/2018/shenzhen.html 编辑:至尊宝 归档:https://elasticsearch.cn/article/752 订阅:https://tinyletter.com/elastic-daily

Elastic日报 第354 (2018-08-05)

Elastic日报至尊宝 发表了文章 • 0 个评论 • 147 次浏览 • 2018-08-05 09:57 • 来自相关话题

1.Kubernetes使用Fluentd和Logz.io记录日志。 http://t.cn/RDPaFVJ 2.Docker使用EFK记录日志。 http://t.cn/RDPNDt3 3.(自备梯子)如何像数据科学家一样思考的12个步骤。 http://t.cn/RDP9e3d 活动预告: Elastic 中国开发者大会 2018 ,开始接受演讲申请和赞助合作 https://conf.elasticsearch.cn/2018/shenzhen.html  编辑:至尊宝 归档:https://elasticsearch.cn/article/744 订阅:https://tinyletter.com/elastic-daily
1.Kubernetes使用Fluentd和Logz.io记录日志。 http://t.cn/RDPaFVJ 2.Docker使用EFK记录日志。 http://t.cn/RDPNDt3 3.(自备梯子)如何像数据科学家一样思考的12个步骤。 http://t.cn/RDP9e3d 活动预告: Elastic 中国开发者大会 2018 ,开始接受演讲申请和赞助合作 https://conf.elasticsearch.cn/2018/shenzhen.html  编辑:至尊宝 归档:https://elasticsearch.cn/article/744 订阅:https://tinyletter.com/elastic-daily

我曲解Elasticsearch了吗?

Elasticsearchandy chen 发表了文章 • 7 个评论 • 324 次浏览 • 2018-07-18 20:05 • 来自相关话题

我曲解了Elasticsearch,我以为是每个节点可以存放不同的数据,哈哈哈😄。既然不是这样,引发了我另一个思考,说是Elasticsearch能处理TB以及PB的数据,这样的话,一台存放PB级数据的机器该是个多“可怕”的配置。每个节点的数据都一样,这是真正意义的分布式吗?我觉得按Elasticsearch的概念只是利用了节点的硬件资源。我真心希望我的理解是错的,这样我将欢欣鼓舞。
我曲解了Elasticsearch,我以为是每个节点可以存放不同的数据,哈哈哈😄。既然不是这样,引发了我另一个思考,说是Elasticsearch能处理TB以及PB的数据,这样的话,一台存放PB级数据的机器该是个多“可怕”的配置。每个节点的数据都一样,这是真正意义的分布式吗?我觉得按Elasticsearch的概念只是利用了节点的硬件资源。我真心希望我的理解是错的,这样我将欢欣鼓舞。

如何解决ES的性能问题

Elasticsearchsterne vencel 发表了文章 • 0 个评论 • 902 次浏览 • 2018-07-10 21:56 • 来自相关话题

Part4:如何解决ES的性能问题 本文是对一篇外文博客的翻译 This post is the final part of a 4-part series on monitoring Elasticsearch performance. Part 1 provides an overview of Elasticsearch and its key performance metrics, Part 2 explains how to collect these metrics, and Part 3describes how to monitor Elasticsearch with Datadog. 这篇文章是监控ES性能系列文章的最后一部分。第1部分概述了ES及其关键性能指标,第2部分解释了如何收集这些指标,第3部分描述了如何使用Datadog监视ES。 Like a car, Elasticsearch was designed to allow its users to get up and running quickly, without having to understand all of its inner workings. However, it’s only a matter of time before you run into engine trouble here or there. This article will walk through five common Elasticsearch challenges, and how to deal with them. 就像汽车一样,用户可以在无需了解其所有内部工作原理的情况下,快速地站起来并运行。然而,在这里或那里遇到引擎故障只是时间问题。本文将介绍五种常见的ES的挑战,以及如何处理它们。 Problem #1: My cluster status is red or yellow. What should I do? 问题#1:我的集群状态是红色或黄色。我应该做什么?
21.png
If you recall from Part 1, cluster status is reported as red if one or more primary shards (and its replicas) is missing, and yellow if one or more replica shards is missing. Normally, this happens when a node drops off the cluster for whatever reason (hardware failure, long garbage collection time, etc.). Once the node recovers, its shards will remain in an initializing state before they transition back to active status. 回顾第1部分,如果丢失一个或多个主分片(及其副本),集群状态将报告为红色;如果丢失一个或多个副本分片,则报告为黄色。通常,这种情况发生在节点出于某些原因(硬件故障、长时间的垃圾收集时间等)退出集群时。一旦节点恢复,它的分片在转换会活跃状态之前将保持初始化状态。 The number of initializing shards typically peaks when a node rejoins the cluster, and then drops back down as the shards transition into an active state, as shown in the graph below. 初始化碎片的数量通常在节点重新加入集群时达到峰值,然后随着分片转换为活跃状态而下降,如下图所示。
22.png
During this initialization period, your cluster state may transition from green to yellow or red until the shards on the recovering node regain active status. In many cases, a brief status change to yellow or red may not require any action on your part. 在此初始化期间,集群状态可能从绿色转变为黄色或红色,直到恢复节点上的分片重新恢复到活跃状态。在很多情况下,一个简短的状态变化为黄色或红色可能不需要你的任何行动。
23.png
However, if you notice that your cluster status is lingering in red or yellow state for an extended period of time, verify that the cluster is recognizing the correct number of Elasticsearch nodes, either by consulting Datadog’s dashboard or by querying the Cluster Health API detailed in Part 2. 但是,如果您注意到您的集群状态在红色或黄色状态中徘徊了很长一段时间,请通过查阅Datadog的仪表板或查询第2部分中详细介绍的集群健康API来验证集群是否识别了正确的ES节点数量。
24.png
If the number of active nodes is lower than expected, it means that at least one of your nodes lost its connection and hasn’t been able to rejoin the cluster. To find out which node(s) left the cluster, check the logs (located by default in the logs folder of your Elasticsearch home directory) for a line similar to the following: 如果活动节点的数量低于预期,则意味着至少有一个节点失去了连接,无法重新加入集群。要找出离开集群的节点,请检查日志(默认位于您的Elasticsearch home目录的logs文件夹中),查找与以下内容类似的行::
[TIMESTAMP] ... Cluster health status changed from [GREEN] to [RED]
Reasons for node failure can vary, ranging from hardware or hypervisor failures, to out-of-memory errors. Check any of the monitoring tools outlined here for unusual changes in performance metrics that may have occurred around the same time the node failed, such as a sudden spike in the current rate of search or indexing requests. Once you have an idea of what may have happened, if it is a temporary failure, you can try to get the disconnected node(s) to recover and rejoin the cluster. If it is a permanent failure, and you are not able to recover the node, you can add new nodes and let Elasticsearch take care of recovering from any available replica shards; replica shards can be promoted to primary shards and redistributed on the new nodes you just added. 节点失败的原因可能不同,从硬件失败,管理程序失败到内存不足的错误。检查监视工具,这些工具可能是在节点失败的同时出现的性能指标的异常变化,比如当前搜索或索引请求的速度突然激增。一旦您知道可能发生了什么,如果是临时故障,您可以尝试让断开连接的节点恢复并重新加入集群。如果是永久性故障,您无法恢复节点,您可以添加新节点,并让Elasticsearch负责从任何可用的副本分片中恢复,副本分片可以提升到主分片,并在刚刚添加的新节点上重新分布。 However, if you lost both the primary and replica copy of a shard, you can try to recover as much of the missing data as possible by using Elasticsearch’s snapshot and restore module. If you’re not already familiar with this module, it can be used to store snapshots of indices over time in a remote repository for backup purposes. 但是,如果您同时丢失了分片的主分片和副本,那么您可以使用ES的快照和恢复模块尽可能多地恢复丢失的数据。如果您还不熟悉这个模块,那么可以使用它在远程存储库中存储索引的快照,以便进行备份。 Problem #2: Help! Data nodes are running out of disk space 问题#2:数据节点空间将要耗尽
25.png
If all of your data nodes are running low on disk space, you will need to add more data nodes to your cluster. You will also need to make sure that your indices have enough primary shards to be able to balance their data across all those nodes. 如果所有数据节点的磁盘空间都很低,那么将需要向集群添加更多的数据节点。你还需要确保您的索引拥有足够的主分片,以便能够跨所有这些节点能够平衡它的数据。 However, if only certain nodes are running out of disk space, this is usually a sign that you initialized an index with too few shards. If an index is composed of a few very large shards, it’s hard for Elasticsearch to distribute these shards across nodes in a balanced manner. 但是,如果只有特定的节点耗尽了磁盘空间,这通常是你用了太多的分片在初始化索引的时候。如果一个索引是由一些非常大的分片组成的,那么用ES很难以一种平衡的方式在节点之间分布这些分片。 Elasticsearch takes available disk space into account when allocating shards to nodes. By default, it will not assign shards to nodes that have over 85 percent disk in use. In Datadog, you can set up a threshold alert to notify you when any individual data node’s disk space usage approaches 80 percent, which should give you enough time to take action. 当master将分片分配给节点时,ES会考虑到节点可用的磁盘空间。默认情况下,它不会将分片分配给使用超过85%磁盘的节点。在Datadog中,您可以设置一个阈值警报,当任何单个数据节点的磁盘空间使用量接近80%时通知您,这应该会给您足够的时间采取行动。 There are two remedies for low disk space. One is to remove outdated data and store it off the cluster. This may not be a viable option for all users, but, if you’re storing time-based data, you can store a snapshot of older indices’ data off-cluster for backup, and update the index settings to turn off replication for those indices. 对于低磁盘空间有两种补救方法。一种是删除过时的数据并将其存储在集群之外。对于所有用户来说,这可能不是一个可行的选择,但是,如果您正在存储基于时间的数据,您可以将旧索引的数据快照存储到集群之外进行备份,并更新索引设置,以关闭对这些索引的复制。 The second approach is the only option for you if you need to continue storing all of your data on the cluster: scaling vertically or horizontally. If you choose to scale vertically, that means upgrading your hardware. However, to avoid having to upgrade again down the line, you should take advantage of the fact that Elasticsearch was designed to scale horizontally. To better accommodate future growth, you may be better off reindexing the data and specifying more primary shards in the newly created index (making sure that you have enough nodes to evenly distribute the shards). 如果需要继续将所有数据存储在集群上,那么第二种方法是惟一的选择:垂直或横向地伸缩集群。如果选择垂直伸缩,就意味着升级硬件。然而,为了避免再次升级,最好使用ES的横向伸缩。为了更好地适应未来的增长,你最好对数据进行索引重建,并在新创建的索引中指定更多的主碎片(确保您有足够的节点来均匀分布碎片)。 Another way to scale horizontally is to roll over the index by creating a new index, and using an alias to join the two indices together under one namespace. Though there is technically no limit to how much data you can store on a single shard, Elasticsearch recommends a soft upper limit of 50 GB per shard, which you can use as a general guideline that signals when it’s time to start a new index. 横向扩展的另一种方法是创建一个新索引,并使用别名滚动改变索引。虽然从技术上讲,您可以在一个分片上存储多少数据没有限制,但Elasticsearch建议在每个碎片上设置一个50 GB的软上限,您可以将其作为一个通用指南,在开始创建新索引时发出信号。 Problem #3: My searches are taking too long to execute 问题#3:我的搜索执行时间太长了 Search performance varies widely according to what type of data is being searched and how each query is structured. Depending on the way your data is organized, you may need to experiment with a few different methods before finding one that will help speed up search performance. We’ll cover two of them here: custom routing and force merging. 根据搜索的数据类型以及每个查询的结构,搜索性能会有很大的不同。根据您的数据的组织方式,您可能需要在找到一个有助于提高搜索性能的方法之前尝试一些不同的方法。我们将介绍其中的两个:自定义路由和强制合并。 Typically, when a node receives a search request, it needs to communicate that request to a copy (either primary or replica) of every shard in the index. Custom routing allows you to store related data on the same shard, so that you only have to search a single shard to satisfy a query. 通常,当一个节点收到一个搜索请求时,它需要将该请求传递给索引中的每个分片的副本(主分片和副本分片)。自定义路由允许你将相关数据存储在同一个shard上,这样您只需要搜索一个分片来满足查询。 For example, you can store all of blogger1’s data on the same shard by specifying a _routing value in the mapping for the blogger type within your index, blog_index. 例如,你可以在索引blog_index中为blogger类型指定一个_routing值,从而将blogger1的所有数据存储在相同的分片上。 First, make sure _routing is required so that you don’t forget to specify a custom routing value whenever you index information of the blogger type. 首先,确保需要_routing,以便在索引blogger类型的信息时不会忘记指定一个定制的路由值。
curl -XPUT "localhost:9200/blog_index" -d '
{
  "mappings": {
    "blogger": {
      "_routing": {
        "required": true 
      }
    }
  }
}'
当您准备索引与blogger1相关的文档时,请指定路由值:
curl -XPUT "localhost:9200/blog_index/blogger/1?routing=blogger1" -d '
{
  "comment": "blogger1 made this cool comment"
}'
Now, in order to search through blogger1’s comments, you will need to remember to specify the routing value in the query like this: 现在,为了搜索blogger1的评论,您需要记住在查询中指定如下的路由值:
curl -XGET "localhost:9200/blog_index/_search?routing=blogger1" -d '
{
  "query": {
    "match": {
      "comment": {
        "query": "cool comment"
      }
    }
  }
}'
In Elasticsearch, every search request has to check every segment of each shard it hits. So once you have reduced the number of shards you’ll have to search, you can also reduce the number of segments per shard by triggering the Force Merge API on one or more of your indices. The Force Merge API (or Optimize API in versions prior to 2.1.0) prompts the segments in the index to continue merging until each shard’s segment count is reduced to max_num_segments (1, by default). It’s worth experimenting with this feature, as long as you account for the computational cost of triggering a high number of merges. 在ES中,每个搜索请求都必须检查它所命中的每个分片的每一段。一旦你可以减少了搜索的分片数量,你也可以通过在一个或多个索引上触发Force Merge API来减少每个分片的段数量。强制合并API(或在2.1.0之前的版本中优化API)提示索引中的段合并,直到每个分片的段计数减少到max_num_segment(默认为1)。考虑一下这个成本和查询的时间成本,值得对该特性进行试验。 When it comes to shards with a large number of segments, the force merge process becomes much more computationally expensive. For instance, force merging an index of 10,000 segments down to 5,000 segments doesn’t take much time, but merging 10,000 segments all the way down to one segment can take hours. The more merging that must occur, the more resources you take away from fulfilling search requests, which may defeat the purpose of calling a force merge in the first place. In any case, it’s usually a good idea to schedule a force merge during non-peak hours, such as overnight, when you don’t expect many search or indexing requests. 当涉及到索引具有大量的段,段合并过程的计算开销就会大得多。例如,强制合并10000个段的索引到5000个段并不需要花费太多时间,但是将10000个段一直合并到一个段需要花费数小时。合并越多,搜索请求越快,这是调用force merge的目的。在任何情况下,通常最好在非高峰时间(比如在一夜之间)安排一个force merge,这样就不会有太多的搜索或索引请求。 Problem #4: How can I speed up my index-heavy workload? 问题#4:怎样才能加快我的索引沉重的工作量? Elasticsearch comes pre-configured with many settings that try to ensure that you retain enough resources for searching and indexing data. However, if your usage of Elasticsearch is heavily skewed towards writes, you may find that it makes sense to tweak certain settings to boost indexing performance, even if it means losing some search performance or data replication. Below, we will explore a number of methods to optimize your use case for indexing, rather than searching, data. ES具有许多预先配置的设置,这些设置试图确保您保留足够的资源用于搜索和索引数据。但是,如果您对ES的使用严重偏向于写操作,可能会发现调整某些设置以提高索引性能是有意义的,即使这意味着丢失一些搜索性能或数据副本。下面,我们将探索一些方法来优化索引而不是优化搜索性能。 Shard allocation: As a high-level strategy, if you are creating an index that you plan to update frequently, make sure you designate enough primary shards so that you can spread the indexing load evenly across all of your nodes. The general recommendation is to allocate one primary shard per node in your cluster, and possibly two or more primary shards per node, but only if you have a lot of CPU and disk bandwidth on those nodes. However, keep in mind that shard overallocation adds overhead and may negatively impact search, since search requests need to hit every shard in the index. On the other hand, if you assign fewer primary shards than the number of nodes, you may create hotspots, as the nodes that contain those shards will need to handle more indexing requests than nodes that don’t contain any of the index’s shards. 分片分配:作为一种高级策略,如果你正在创建频繁更新索引的集群,请确保指定了足够的主分片,这样你就可以将索引负载均匀地分布到所有节点上。一般的建议是为集群中的每个节点分配一个主分片,可能为每个节点分配两个或多个主分片,但前提是这些节点上有大量的CPU和磁盘带宽。但是,请记住,分片过度分配会增加开销,并可能对搜索产生负面影响,因为搜索请求需要命中索引中的每个分片。另一方面,如果你分配的主碎片数量少于节点数量,那么您可能会创建热点(热节点),因为包含这些分片的节点将需要处理更多的索引请求,而不包含索引分片的节点将不做什么操作。 Disable merge throttling: Merge throttling is Elasticsearch’s automatic tendency to throttle indexing requests when it detects that merging is falling behind indexing. It makes sense to update your cluster settings to disable merge throttling (by setting indices.store.throttle.type to “none”) if you want to optimize indexing performance, not search. You can make this change persistent (meaning it will persist after a cluster restart) or transient (resets back to default upon restart), based on your use case. 禁用合并节流:合并节流是ES在检测到合并落后于索引时自动抑制索引请求的趋势。更新集群设置以禁用合并节流是有意义的(设置index .store.throttle.type为none)。这样做可以优化索引性能,而不是搜索。根据你的用例,你可以使这个设置为persist(意味着在集群重新启动之后它将持续)或transient(在重新启动时重新设置为默认)。 Increase the size of the indexing buffer: This setting (indices.memory.index_buffer_size) determines how full the buffer can get before its documents are written to a segment on disk. The default setting limits this value to 10 percent of the total heap in order to reserve more of the heap for serving search requests, which doesn’t help you if you’re using Elasticsearch primarily for indexing. 增加索引缓冲区的大小:此设置(indices.memory.index_buffer_size)确定将文档写到磁盘上的段之前缓冲区的容量。默认设置限制为总堆的10%,以便为服务搜索请求保留更多的堆,如果您主要是在使用Elasticsearch进行索引,这对你是没有帮助。 Index first, replicate later: When you initialize an index, specify zero replica shards in the index settings, and add replicas after you’re done indexing. This will boost indexing performance, but it can be a bit risky if the node holding the only copy of the data crashes before you have a chance to replicate it. *先索引,后复制:初始化索引时,在索引设置中指定0个复制碎片,索引完成后添加副本。这将提高索引性能,但如果拥有数据惟一副本的节点在您有机会复制数据之前崩溃,则可能存在一些风险。 Refresh less frequently: Increase the refresh interval in the Index Settings API. By default, the index refresh process occurs every second, but during heavy indexing periods, reducing the refresh frequency can help alleviate some of the workload. 不经常刷新:增加索引设置API中的刷新间隔。默认情况下,索引refresh过程每秒钟发生一次,但是在索引不断更新的时期,减少刷新频率可以帮助减轻一些工作负载。 Tweak your translog settings: As of version 2.0, Elasticsearch will flush translog data to disk after every request, reducing the risk of data loss in the event of hardware failure. If you want to prioritize indexing performance over potential data loss, you can change index.translog.durability to async in the index settings. With this in place, the index will only commit writes to disk upon every sync_interval, rather than after each request, leaving more of its resources free to serve indexing requests. 调整您的translog设置:在2.0版本中,弹性搜索将在每次请求之后将translog数据刷新到磁盘,从而在硬件故障时降低数据丢失的风险。如果希望将索引性能优先于潜在的数据丢失,可以更改index.translog.durability为async。有了这一点,索引将在sync_interval上提交对磁盘的写操作,而不是在每个请求之后,从而使更多的资源可以用于索引请求。 For more suggestions on boosting indexing performance, check out this guide from Elastic. 有关提高索引性能的更多建议,请参阅《ES》。 Problem #5: What should I do about all these bulk thread pool rejections? 问题#5:对于所有这些大容量线程池拒绝,我应该怎么做?
26.png
Thread pool rejections are typically a sign that you are sending too many requests to your nodes, too quickly. If this is a temporary situation (for instance, you have to index an unusually large amount of data this week, and you anticipate that it will return to normal soon), you can try to slow down the rate of your requests. However, if you want your cluster to be able to sustain the current rate of requests, you will probably need to scale out your cluster by adding more data nodes. In order to utilize the processing power of the increased number of nodes, you should also make sure that your indices contain enough shards to be able to spread the load evenly across all of your nodes. 线程池的拒绝通常表明向节点发送了过多的请求或者请求速度太快。如果这是一个临时的情况(例如,本周必须索引超大量的数据,并且预期它将很快恢复正常),可以尝试降低请求的速度。但是,如果您希望集群能够维持当前的请求速率,您可能需要通过添加更多的数据节点来扩展集群。为了利用增加的节点数量的处理能力,还应该确保索引包含足够的分片,以便能够在所有节点上均匀地分配负载。 Go forth and optimize! 优化 Even more performance tips are available in Elasticsearch’s learning resources and documentation. Since results will vary depending on your particular use case and setup, you can test out different settings and indexing/querying strategies to determine which approaches work best for your clusters. 在ES的学习资源和文档中可以找到更多的性能技巧。由于结果将根据您的特定用例和设置而变化,您可以测试不同的设置和索引/查询策略,以确定哪种方法最适合您的集群。 As you experiment with these and other optimizations, make sure to watch your Elasticsearch dashboards closely to monitor the resulting impact on your clusters’ key Elasticsearch performance metrics. 当您尝试这些优化和其他优化时,请确保密切关注您的ES仪表盘,以监视由此对集群的关键ES性能指标的影响。 With a built-in Elasticsearch dashboard that highlights key cluster metrics, Datadog enables you to effectively monitor Elasticsearch in real-time. If you already have a Datadog account, you can set up the Elasticsearch integrationin minutes. If you don’t yet have a Datadog account, sign up for a free trialtoday. 有了一个内置的ES仪表盘,它突出关键的集群指标,Datadog使您能够实时监控弹性搜索。如果您已经有了一个Datadog帐户,那么您可以在几分钟内设置Elasticsearch集成。如果你还没有一个Datadog帐户,那么今天就注册一个免费试用。 Source Markdown for this post is available on GitHub. Questions, corrections, additions, etc.? Please let us know.

Elastic日报 第323期 (2018-07-05)

Elastic日报sterne vencel 发表了文章 • 0 个评论 • 161 次浏览 • 2018-07-05 09:34 • 来自相关话题

1.使用python操作ES http://t.cn/RBzKP6H 2.使用Beats模块将日志和指标导入ES http://t.cn/RdLtJJp 3.如何在生产环境中重启Elasticsearch集群 http://t.cn/RdL4oxk  活动预告 1. 7月21日上海meetup演讲申请中 https://elasticsearch.cn/m/article/655  编辑:sterne vencel 归档:https://elasticsearch.cn/article/700 订阅:https://tinyletter.com/elastic-daily
1.使用python操作ES http://t.cn/RBzKP6H 2.使用Beats模块将日志和指标导入ES http://t.cn/RdLtJJp 3.如何在生产环境中重启Elasticsearch集群 http://t.cn/RdL4oxk  活动预告 1. 7月21日上海meetup演讲申请中 https://elasticsearch.cn/m/article/655  编辑:sterne vencel 归档:https://elasticsearch.cn/article/700 订阅:https://tinyletter.com/elastic-daily

玩转 Elasticsearch 的 SQL 功能

Elasticsearchmedcl 发表了文章 • 9 个评论 • 3933 次浏览 • 2018-06-27 21:54 • 来自相关话题

最近发布的 Elasticsearch 6.3 包含了大家期待已久的 SQL 特性,今天给大家介绍一下具体的使用方法。

首先看看接口的支持情况

目前支持的 SQL 只能进行数据的查询只读操作,不能进行数据的修改,所以我们的数据插入还是要走之前的常规索引接口。

目前 Elasticsearch 的支持 SQL 命令只有以下几个:

命令 说明
DESC table 用来描述索引的字段属性
SHOW COLUMNS 功能同上,只是别名
SHOW FUNCTIONS 列出支持的函数列表,支持通配符过滤
SHOW TABLES 返回索引列表
SELECT .. FROM table_name WHERE .. GROUP BY .. HAVING .. ORDER BY .. LIMIT .. 用来执行查询的命令

我们分别来看一下各自怎么用,以及有什么效果吧,自己也可以动手试一下,看看。

首先,我们创建一条数据:

POST twitter/doc/
{
  "name":"medcl",
  "twitter":"sql is awesome",
  "date":"2018-07-27",
  "id":123
}

RESTful下调用SQL

在 ES 里面执行 SQL 语句,有三种方式,第一种是 RESTful 方式,第二种是 SQL-CLI 命令行工具,第三种是通过 JDBC 来连接 ES,执行的 SQL 语句其实都一样,我们先以 RESTful 方式来说明用法。

RESTful 的语法如下:

POST /_xpack/sql?format=txt
{
    "query": "SELECT * FROM twitter"
}

因为 SQL 特性是 xpack 的免费功能,所以是在 _xpack 这个路径下面,我们只需要把 SQL 语句传给 query 字段就行了,注意最后面不要加上 ; 结尾,注意是不要!

我们执行上面的语句,查询返回的结果如下:

          date          |      id       |     name      |    twitter    
------------------------+---------------+---------------+---------------
2018-07-27T00:00:00.000Z|123            |medcl          |sql is awesome 

ES 俨然已经变成 SQL 数据库了,我们再看看如何获取所有的索引列表:

POST /_xpack/sql?format=txt
{
    "query": "SHOW tables"
}

返回如下:

              name               |     type      
---------------------------------+---------------
.kibana                          |BASE TABLE     
.monitoring-alerts-6             |BASE TABLE     
.monitoring-es-6-2018.06.21      |BASE TABLE     
.monitoring-es-6-2018.06.26      |BASE TABLE     
.monitoring-es-6-2018.06.27      |BASE TABLE     
.monitoring-kibana-6-2018.06.21  |BASE TABLE     
.monitoring-kibana-6-2018.06.26  |BASE TABLE     
.monitoring-kibana-6-2018.06.27  |BASE TABLE     
.monitoring-logstash-6-2018.06.20|BASE TABLE     
.reporting-2018.06.24            |BASE TABLE     
.triggered_watches               |BASE TABLE     
.watcher-history-7-2018.06.20    |BASE TABLE     
.watcher-history-7-2018.06.21    |BASE TABLE     
.watcher-history-7-2018.06.26    |BASE TABLE     
.watcher-history-7-2018.06.27    |BASE TABLE     
.watches                         |BASE TABLE     
apache_elastic_example           |BASE TABLE     
forum-mysql                      |BASE TABLE     
twitter      

有点多,我们可以按名称过滤,如 twitt 开头的索引,注意通配符只支持 %_,分别表示多个和单个字符(什么,不记得了,回去翻数据库的书去!):

POST /_xpack/sql?format=txt
{
    "query": "SHOW TABLES 'twit%'"
}

POST /_xpack/sql?format=txt
{
    "query": "SHOW TABLES 'twitte_'"
}

上面返回的结果都是:

     name      |     type      
---------------+---------------
twitter        |BASE TABLE     

如果要查看该索引的字段和元数据,如下:

POST /_xpack/sql?format=txt
{
    "query": "DESC twitter"
}

返回:

    column     |     type      
---------------+---------------
date           |TIMESTAMP      
id             |BIGINT         
name           |VARCHAR        
name.keyword   |VARCHAR        
twitter        |VARCHAR        
twitter.keyword|VARCHAR        

都是动态生成的字段,包含了 .keyword 字段。 还能使用下面的命令来查看,主要是兼容 SQL 语法。

POST /_xpack/sql?format=txt
{
    "query": "SHOW COLUMNS IN twitter"
}

另外,如果不记得 ES 支持哪些函数,只需要执行下面的命令,即可得到完整列表:

SHOW FUNCTIONS

返回结果如下,也就是当前6.3版本支持的所有函数,如下:

      name      |     type      
----------------+---------------
AVG             |AGGREGATE      
COUNT           |AGGREGATE      
MAX             |AGGREGATE      
MIN             |AGGREGATE      
SUM             |AGGREGATE      
STDDEV_POP      |AGGREGATE      
VAR_POP         |AGGREGATE      
PERCENTILE      |AGGREGATE      
PERCENTILE_RANK |AGGREGATE      
SUM_OF_SQUARES  |AGGREGATE      
SKEWNESS        |AGGREGATE      
KURTOSIS        |AGGREGATE      
DAY_OF_MONTH    |SCALAR         
DAY             |SCALAR         
DOM             |SCALAR         
DAY_OF_WEEK     |SCALAR         
DOW             |SCALAR         
DAY_OF_YEAR     |SCALAR         
DOY             |SCALAR         
HOUR_OF_DAY     |SCALAR         
HOUR            |SCALAR         
MINUTE_OF_DAY   |SCALAR         
MINUTE_OF_HOUR  |SCALAR         
MINUTE          |SCALAR         
SECOND_OF_MINUTE|SCALAR         
SECOND          |SCALAR         
MONTH_OF_YEAR   |SCALAR         
MONTH           |SCALAR         
YEAR            |SCALAR         
WEEK_OF_YEAR    |SCALAR         
WEEK            |SCALAR         
ABS             |SCALAR         
ACOS            |SCALAR         
ASIN            |SCALAR         
ATAN            |SCALAR         
ATAN2           |SCALAR         
CBRT            |SCALAR         
CEIL            |SCALAR         
CEILING         |SCALAR         
COS             |SCALAR         
COSH            |SCALAR         
COT             |SCALAR         
DEGREES         |SCALAR         
E               |SCALAR         
EXP             |SCALAR         
EXPM1           |SCALAR         
FLOOR           |SCALAR         
LOG             |SCALAR         
LOG10           |SCALAR         
MOD             |SCALAR         
PI              |SCALAR         
POWER           |SCALAR         
RADIANS         |SCALAR         
RANDOM          |SCALAR         
RAND            |SCALAR         
ROUND           |SCALAR         
SIGN            |SCALAR         
SIGNUM          |SCALAR         
SIN             |SCALAR         
SINH            |SCALAR         
SQRT            |SCALAR         
TAN             |SCALAR         
SCORE           |SCORE          

同样支持通配符进行过滤:

POST /_xpack/sql?format=txt
{
    "query": "SHOW FUNCTIONS 'S__'"
}

结果:

     name      |     type      
---------------+---------------
SUM            |AGGREGATE      
SIN            |SCALAR         

那如果要进行模糊搜索呢,Elasticsearch 的搜索能力大家都知道,强!在 SQL 里面,可以用 match 关键字来写,如下:

POST /_xpack/sql?format=txt
{
    "query": "SELECT SCORE(), * FROM twitter WHERE match(twitter, 'sql is') ORDER BY id DESC"
}

最后,还能试试 SELECT 里面的一些其他操作,如过滤,别名,如下:

POST /_xpack/sql?format=txt
{
    "query": "SELECT SCORE() as score,name as myname FROM twitter as mytable where name = 'medcl' OR name ='elastic' limit 5"
}

结果如下:

     score     |    myname     
---------------+---------------
0.2876821      |medcl          

或是分组和函数计算:

POST /_xpack/sql?format=txt
{
    "query": "SELECT name,max(id) as max_id FROM twitter as mytable group by name limit 5"
}

结果如下:

     name      |    max_id     
---------------+---------------
medcl          |123.0          

SQL-CLI下的使用

上面的例子基本上把 SQL 的基本命令都介绍了一遍,很多情况下,用 RESTful 可能不是很方便,那么可以试试用 CLI 命令行工具来执行 SQL 语句,妥妥的 SQL 操作体验。

切换到命令行下,启动 cli 程序即可进入命令行交互提示界面,如下:

➜  elasticsearch-6.3.0 ./bin/elasticsearch-sql-cli

     .sssssss.`                     .sssssss.
  .:sXXXXXXXXXXo`                `ohXXXXXXXXXho.
 .yXXXXXXXXXXXXXXo`            `oXXXXXXXXXXXXXXX-
.XXXXXXXXXXXXXXXXXXo`        `oXXXXXXXXXXXXXXXXXX.
.XXXXXXXXXXXXXXXXXXXXo.    .oXXXXXXXXXXXXXXXXXXXXh
.XXXXXXXXXXXXXXXXXXXXXXo``oXXXXXXXXXXXXXXXXXXXXXXy
`yXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.
 `oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo`
   `oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo`
     `oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo`
       `oXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXo`
         `oXXXXXXXXXXXXXXXXXXXXXXXXXXXXo`
           .XXXXXXXXXXXXXXXXXXXXXXXXXo`
         .oXXXXXXXXXXXXXXXXXXXXXXXXo`
       `oXXXXXXXXXXXXXXXXXXXXXXXXo`   `odo`
     `oXXXXXXXXXXXXXXXXXXXXXXXXo`   `oXXXXXo`
   `oXXXXXXXXXXXXXXXXXXXXXXXXo`   `oXXXXXXXXXo`
 `oXXXXXXXXXXXXXXXXXXXXXXXXo`   `oXXXXXXXXXXXXXo`
`yXXXXXXXXXXXXXXXXXXXXXXXo`    oXXXXXXXXXXXXXXXXX.
.XXXXXXXXXXXXXXXXXXXXXXo`   `oXXXXXXXXXXXXXXXXXXXy
.XXXXXXXXXXXXXXXXXXXXo`     /XXXXXXXXXXXXXXXXXXXXX
.XXXXXXXXXXXXXXXXXXo`        `oXXXXXXXXXXXXXXXXXX-
 -XXXXXXXXXXXXXXXo`            `oXXXXXXXXXXXXXXXo`
  .oXXXXXXXXXXXo`                `oXXXXXXXXXXXo.
    `.sshXXyso`        SQL         `.sshXhss.`

sql> 

当你看到一个硕大的创口贴,表示 SQL 命令行已经准备就绪了,查看一下索引列表,不,数据表的列表:

15301043943573.jpg

各种操作妥妥的,上面已经测试过的命令就不在这里重复了,只是体验不一样罢了。

如果要连接远程的 ES 服务器,只需要启动命令行工具的时候,指定服务器地址,如果有加密,指定 keystone 文件,完整的帮助如下:

➜  elasticsearch-6.3.0 ./bin/elasticsearch-sql-cli --help
Elasticsearch SQL CLI

Non-option arguments:
uri                  

Option                   Description                                           
------                   -----------                                           
-c, --check <Boolean>    Enable initial connection check on startup (default:  
                           true)                                               
-d, --debug              Enable debug logging                                  
-h, --help               show help                                             
-k, --keystore_location  Location of a keystore to use when setting up SSL. If 
                           specified then the CLI will prompt for a keystore   
                           password. If specified when the uri isn't https then
                           an error is thrown.                                 
-s, --silent             show minimal output                                   
-v, --verbose            show verbose output  

JDBC 对接

JDBC 对接的能力,让我们可以与各个 SQL 生态系统打通,利用众多现成的基于 SQL 之上的工具来使用 Elasticsearch,我们以一个工具来举例。

和其他数据库一样,要使用 JDBC,要下载该数据库的 JDBC 的驱动,我们打开: https://www.elastic.co/downloads/jdbc-client

15301048139518.jpg

只有一个 zip 包下载链接,下载即可。

然后,我们这里使用 DbVisualizer 来连接 ES 进行操作,这是一个数据库的操作和分析工具,DbVisualizer 下载地址是:https://www.dbvis.com/

下载安装启动之后的程序主界面如下图:

15301049453527.jpg

我们如果要使用 ES 作为数据源,我们第一件事需要把 ES 的 JDBC 驱动添加到 DbVisualizer 的已知驱动里面。我们打开 DbVisualizer 的菜单【Tools】-> 【Driver Manager】,打开如下设置窗口:

15301054144234.jpg

点击绿色的加号按钮,新增一个名为 Elasticsearch-SQL 的驱动,url format 设置成 jdbc:es:,如下图:

15301054340439.jpg

然后点击上图黄色的文件夹按钮,添加我们刚刚下载好且解压之后的所有 jar 文件,如下:

15301055143574.jpg

添加完成之后,如下图:

15301055446598.jpg

就可以关闭这个 JDBC 驱动的管理窗口了。下面我们来连接到 ES 数据库。

选择主程序左侧的新建连接图标,打开向导,如下:

15301057385898.jpg

选择刚刚加入的 Elasticsearch-SQL 驱动:

15301057824336.jpg

设置连接字符串,此处没有登录信息,如果有可以对应的填上:

15301064989466.jpg

点击 Connect,即可连接到 ES,左侧导航可以展开看到对应的 ES 索引信息:

15301065711818.jpg

同样可以查看相应的库表结果和具体的数据:

15301066251658.jpg

用他自带的工具执行 SQL 也是不在话下:

15301068015599.jpg

同理,各种 ETL 工具和基于 SQL 的 BI 和可视化分析工具都能把 Elasticsearch 当做 SQL 数据库来连接获取数据了。

最后一个小贴士,如果你的索引名称包含横线,如 logstash-201811,只需要做一个用双引号包含,对双引号进行转义即可,如下:

POST /_xpack/sql?format=txt
{
"query":"SELECT COUNT(*) FROM \"logstash-*\""
}

关于 SQL 操作的文档在这里:

https://www.elastic.co/guide/en/elasticsearch/reference/current/sql-jdbc.html

Enjoy!