针对具有大量聚合的大型群集的ElasticSearch设置

时间:2014-05-29 10:52:19

标签: elasticsearch cluster-computing aggregate scalability

上下文和当前状态

我们正在将我们的集群从Cassandra迁移到完整的ElasticSearch集群。我们的文档索引平均为 ~250-300 docs /秒。在ElasticSearch 1.2.0中,它代表每天〜8Go。

{
 "generic":
    {
      "id": "twi471943355505459200",
      "type": "twitter",
      "title": "RT @YukBerhijabb: The Life is Choice - https://m.facebook.com/story.php?story_fbid=637864496306297&id=100002482564531&refid=17",
      "content": "RT @YukBerhijabb: The Life is Choice - https://m.facebook.com/story.php?story_fbid=637864496306297&id=100002482564531&refid=17",
      "source": "<a href=\"https://twitter.com/download/android\" rel=\"nofollow\">Twitter for  Android</a>",
      "geo": null,
      "link": "http://twitter.com/rosi_sifah/status/471943355505459200",
      "lang": "en",
      "created_at": 1401355038000,
      "author": {
        "username": "rosi_sifah",
        "name": "Rosifah",
        "id": 537798506,
        "avatar": "http://pbs.twimg.com/profile_images/458917673456238592/Im22zoIV_normal.jpeg",
        "link": "http://twitter.com/rosi_sifah"
      }
    },
 "twitter": {
   // a tweet JSON
 }
}

我们的用户在我们的SQL数据库中保存请求,当他们要求他们的仪表板时,我们想要请求我们的ES集群查询(从数据库中检索)并在其上进行一些聚合使用新的ES聚合框架。

每个仪表板都显示一个明确的,用户选择的日期范围,因此我们始终使用

"range": {
 "generic.created_at": {
   "from": 1401000000000,
   "to": 1401029019706
  }
}

以及ES查询。

我们指定了 _routing

"_routing":{
 "required":true,
 "path":"generic.id"
},

_id

"_id": {
  "index": "not_analyzed",
  "store": "false",
  "path": "generic.id"
}

我们在一个索引中存储了 67百万个文档(约40Go)大约5天。我们已经了解了按日分割索引的良好做法。所以现在我们的指数按日分割([index-name] - [YYYY-MM-DD])。

目前每个索引有5个分片和1个副本,我们有一个由3台机器组成的集群,每台机器有8个内核,16个RAM和8个硬盘。我们计划使用另一台机器作为网关(8核,16Go RAM,1To HDD)。

除群集配置外,我们默认保留ES配置。

问题

  1. 对于我们要索引的每个文档,我们明确说明了索引 使用。目前我们使用当天的日期。我们应该使用日期吗? 该文件,以防止热点?因为目前它 表示来自不同日期的文件(在其中指定) created_at)可以存在于当天的相同索引中。
  2. 白天是否有21 600 000份文件足够(或太多)5个分片?
  3. 如果我们希望在不到1秒的时间内处理所有聚合查询,我们应该设置多少副本?
  4. 我们应该改变路线吗?由于我们事先不知道在对集群进行的每个请求的聚合之前将处理哪些文档(因为查询是用户定义的)
  5. 我们应该在这个群集中放置什么样的硬件(多少台机器,什么配置)来支持6个月的文件?
  6. [更新]

    以下是一些查询示例:

    字云

    GET idx-2014-05-01/stream/_search?search_type=count
    {
     "query":{
       "bool": {
         "must": [{
           "query_string" : {
             "query" : "(generic.lang:fr OR generic.lang:en) AND (generic.content:javascript)"
            }},{
            "range": {
              "generic.created_at": {
                "from": 1401000000000,
                "to": 1401029019706
              }
            }}
         ]
       }
     },
      "aggs":{
        "words":{
          "terms":{
            "field": "generic.content",
            "size": 40
          }
        }
      }
    }
    

    直方图

    GET idx-2014-05-01/stream/_search?search_type=count
    {
     "query":{
       "bool": {
         "must": [{
           "query_string" : {
             "query" : "generic.content:apple"
            }},{
            "range": {
              "generic.created_at": {
                "from": 1401000000000,
                "to": 1401029019706
              }
            }}
         ]
       }
     },
      "aggs":{
        "volume":{
          "date_histogram":{
            "field": "generic.created_at",
            "interval":"minute"
          }
        }
      }
    }
    

    必须使用语言

    GET idx-2014-05-01/stream/_search?search_type=count
    {
     "query":{
       "bool": {
         "must": [{
           "query_string" : {
             "query" : "(generic.lang:fr OR generic.lang:en) AND (generic.content:javascript)"
            }},{
            "range": {
              "generic.created_at": {
                "from": 1401000000000,
                "to": 1401029019706
              }
            }}
         ]
       }
     },
      "aggs":{
        "top_source":{
          "terms":{
            "field": "generic.lang"
          }
        }
      }
    }
    

1 个答案:

答案 0 :(得分:16)

让我先说明我的所有答案/评论,并尽可能地尝试自己测试这些场景。虽然Elasticsearch具有很高的可扩展性,但有许多权衡因文档大小和类型,摄取和查询量,硬件和操作系统而受到很大影响。虽然有很多错误的答案,但很少有正确答案。

我将此响应基于几个活动集群,其中包含(当前)约50万个活动文档,以及我们以约4倍的数量执行的一些最近基准测试(每天摄取约8,000个文档)在基准期间)。

1)首先,当你甚至有一个包含5个分片和每个分片1个副本的索引时,你不会创建3个节点的大部分热点。 Elasticsearch会将每个副本从它的主副本分离到不同的节点,并且通常会尝试平衡分片的负载。默认情况下,Elasticsearch将对ID进行哈希处理,以选择要编入索引的分片(然后将其复制到副本)。即使使用路由,如果您有每天创建大量文档的单个ID(这是索引的范围),您也只会遇到热点问题。即使这样,它也不会成为一个问题,除非这些ID产生相当大的总体积百分比,而且它们中只有很少一部分你只能在1或2个分片上聚集。

只有您可以根据您的使用模式确定 - 我建议您对现有数据集进行一些分析以寻找过高的浓度,并分析您可能的查询。

我遇到的一个更大的问题是查询的性质。您没有显示完整的查询,也没有显示完整的架构(我看到&#34; generic.id&#34;引用但未在文档架构中引用,并且您的查询显示在一个时间范围内拉出每个文档 - 是那是对的吗?)。当您的查询受到用于路由的字段的完全匹配的约束时,自定义路由索引非常有用。所以,如果我有一个包含每个人的文档的索引,而我的查询模式只是在一个查询中检索单个用户的文档,那么按用户ID自定义路由对于改进查询非常有用性能并降低整体集群负载。

要考虑的第二件事是摄取与查询的总体平衡。您每天要摄取超过20M的文档 - 您每天执行的查询数量是多少?如果该数字是&lt;&lt;&lt;您可能想要通过自定义路线的需要考虑摄取率。此外,如果查询性能良好或很好,您可能不希望添加额外的复杂性。

最后通过摄取日期与created_at进行索引。我们也在努力解决这个问题,因为我们在收到新文件方面有些滞后。目前我们已经通过摄取日期进行存储,因为它更易于管理,并且一次查询多个索引并不是一个大问题,特别是如果您自动创建别名1周,2周,1一个更大的问题是分发是什么 - 如果你有几周或几个月后出现的文件,你可能想要通过created_at更改为索引,但这需要将这些索引保持在线并打开相当长的一段时间。

我们目前每天使用多个文档索引,基本上是&#34; - &#34;格式。实际上,这目前意味着每天5个索引。这使我们能够更有选择性地将数据移入和移出集群。我们所学到的东西对我们来说并不适合你。

2)以下是关于ES的伟大思考 - 每天创建一个新索引,您可以随着时间的推移调整以增加每个索引的分片数量。虽然您无法为现有索引更改它,但您每天都在创建一个新索引,并且您可以根据实际生产分析做出决策。您当然希望观察数字,并准备增加分片数量,如果您每天摄入量增加。它不是最简单的权衡 - 每个分片都是Lucene实例,可能有多个文件。每个索引的更多分片不是免费的,因为它与时间相乘。鉴于您的用例为6个月,超过1800个分片在3个节点上开放(182天x 5个原色和每天5个副本)。每个碎片的文件倍数可能会打开。我们在节点上发现了一定程度的开销和对资源使用的影响,因为群集中的总碎片数增加到这些范围内。您的里程可能会有所不同,但是当您计划一次保留182个索引(6个月)时,我会小心增加每个索引的分片数量 - 这是一个相当大的乘数。如果您对默认分片计数进行任何更改,我肯定会提前对此进行基准测试。

3)其他任何人都无法提前预测查询性能。它基于整体群集负载,查询复杂性,查询频率,硬件等。它非常适合您的环境。你将不得不对此进行基准测试。就个人而言,如果您已经加载了数据,我会使用ES快照并进行恢复,以便在测试环境中提供这些数据。尝试使用默认的1副本,看看它是如何进行的。添加副本分片非常适合数据冗余,并且可以帮助在整个群集中分散查询,但价格相当陡峭 - 存储量增加50%以及每个额外的副本分片将为其运行的节点带来额外的摄取成本。如果您需要冗余并且可以节省容量,那就太棒了,如果您缺乏足够的查询量来真正利用它,那就太好了。

4)你的问题不完整(以#34结尾;我们从不#34;)所以我无法直接回答 - 但更大的问题是为什么你开始定制路由?当然,它可以带来很好的性能优势,但只有在您可以按照用于路由的字段分割一组文档时,它才有用。如果是这种情况,您的示例数据和部分查询并不完全清楚。我个人在没有任何自定义路由的情况下对其进行测试,然后尝试使用它,看看它是否有重大影响。

5)另一个需要你做一些工作的问题。您需要跟踪(至少)JVM堆使用情况,总体内存和CPU使用率,磁盘使用情况以及磁盘运行时间。我们这样做,阈值设置为在发现问题之前提醒,以便我们可以尽早向集群添加新成员。请记住,当您向群集添加节点时,ES将尝试重新平衡群集。如果丢失节点出现问题(堆耗尽,JVM错误,硬件故障,网络故障等),则仅使用3个具有大型初始文档集的节点运行生产可能会导致问题。 ES将会变黄并在重新洗牌时留在那里很长一段时间。

就个人而言,对于大型文档编号和高摄取,我会先开始添加节点。如果您将节点用于维护,那么如果有更多节点,那么它就不会成为问题。关于您现有的配置,您是如何获得每节点8 TB的硬盘的?考虑到每天摄取8GB的数据,这似乎有点过了6个月的数据。我强烈怀疑,考虑到数据量和索引/分片数量,您需要移动到更多节点,这甚至会进一步降低每个节点的存储需求。

我绝对希望通过在只有1或2个节点的群集上循环通过高容量摄取和正常查询频率的循环来对每个节点的最大文档量进行基准测试,并查看其失败的位置(无论是性能,堆耗尽或其他问题)。然后,我计划将每个节点的文档数量远远低于该数量。

所有这一切都说我会站出来说我怀疑你会对3个16GB节点上的40多亿个文件感到高兴。即使它工作(再次,测试,测试,测试)失去一个节点将是一个非常重要的事件。我个人喜欢较小的节点,但更喜欢它们。

其他想法 - 我们最初基于3个Amazon EC2 m1.xlarge实例(4个内核,15 GB内存)进行基准测试,这些实例在每天80M文档的摄取数天内运行良好,平均文档大小比您看起来要大。最大的问题是索引和分片的数量是开放的(我们每天创建几百个新索引,每天可能还有几千个分片,这就产生了问题)。我们之后添加了几个具有30GB内存和8个内核的新节点,然后添加了另外80M文档来测试它。我们目前的生产方法是保持更适合中等大小的节点而不是几个大节点。

更新:

关于基准测试硬件,如上所述基于3个运行ubuntu 12.04 LTS和ES 1.1.0的Amazon EC2 m1.xlarge虚拟实例进行基准测试。我们每天运行大约80M文档(从我们之前使用的MongoDB数据库中提取数据)。每个实例通过Amazon EBS拥有1 TB的存储空间,提供的IOPS相当于1000 IOPS。我们跑了大约4-5天。我们似乎每天只有80M的cpu受限,并且相信更多的节点会增加我们的摄取率。随着基准运行并且索引和分片的数量增加,我们看到内存压力增加。我们创建了大量索引和分片(每1M文档大约有4到5个索引或每天大约400个索引,每个索引有5个主分片和1个副本分片)。

关于索引别名,我们通过cron条目滚动索引别名创建1周后,2周后等,以便我们的应用程序可以只搜索已知的索引别名并始终在设定的时间范围内运行从今天开始。我们使用索引别名rest api来创建和删除它们:

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/indices-aliases.html