elasticsearch优化总结

 一、 硬件环境选择: 

如果有条件,尽可能使用SSD硬盘, 不错的CPU。ES的厉害之处在于ES本身的分布式架构以及lucene的特性。IO的提升,会极大改进ES的速度和性能。 

二、系统拓朴设计: 

ES集群在架构拓朴时,一般都会采用Hot-Warm的架构模式,即设置3种不同类型的节点:Master节点、Hot 节点和 Warm节点。 

Master节点设置:一般会设置3个专用的maste节点,以提供最好的弹性扩展能力。当然,必须注意discovery.zen.minimum_master_nodes 属性的设置,以防split-brain问题,使用公式设置:N/2+1(N为候选master节点数)。 该节点保持: node.data: false ; 因为master节点不参与查询、索引操作,仅负责对于集群管理,所以在CPU、内存、磁盘配置上,都可以比数据节点低很多。 

Hot节点设置: 索引节点(写节点),同时保持近期频繁使用的索引。 属于IO和CPU密集型操作,建议使用SSD的磁盘类型,保持良好的写性能;节点的数量设置一般是大于等于3个。将节点设置为hot类型: 

node.attr.box_type: hot

针对index, 通过设置index.routing.allocation.require.box_type: hot 可以设置将索引写入hot节点。 

Warm节点设置: 用于不经常访问的read-only索引。由于不经常访问,一般使用普通的磁盘即可。内存、CPU的配置跟Hot节点保持一致即可;节点数量一般也是大于等于3个。 

当索引不再被频繁查询时,可通过index.routing.allocation.require.box_type: warm, 将索引标记为warm, 从而保证索引不写入hot节点,以便将SSD磁盘资源用在刀刃上。一旦设置这个属性,ES会自动将索引合并到warm节点。同时,也可以在elasticsearch.yml中设置 index.codec: best_compression 保证warm 节点的压缩配置 

Coordinating节点:协调节点用于做分布式里的协调,将各分片或节点返回的数据整合后返回。在ES集群中,所有的节点都有可能是协调节点,但是,可以通过设置node.master、node.data 、 node.ingest 都为 false 来设置专门的协调节点。需要较好的CPU和较高的内存。 

三、ES的内存设置: 

由于ES构建基于lucene, 而lucene设计强大之处在于lucene能够很好的利用操作系统内存来缓存索引数据,以提供快速的查询性能。lucene的索引文件segements是存储在单文件中的,并且不可变,对于OS来说,能够很友好地将索引文件保持在cache中,以便快速访问;因此,我们很有必要将一半的物理内存留给lucene ; 另一半的物理内存留给ES(JVM heap )。所以, 在ES内存设置方面,可以遵循以下原则: 

1. 当机器内存小于64G时,遵循通用的原则,50%给ES,50%留给lucene。 

2.  当机器内存大于64G时,遵循以下原则: 

a. 如果主要的使用场景是全文检索, 那么建议给ES Heap分配 4~32G的内存即可;其它内存留给操作系统, 供lucene使用(segments cache), 以提供更快的查询性能。 

b.  如果主要的使用场景是聚合或排序, 并且大多数是numerics, dates, geo_points 以及not_analyzed的字符类型, 建议分配给ES Heap分配 4~32G的内存即可,其它内存留给操作系统,供lucene使用(doc values cache),提供快速的基于文档的聚类、排序性能。 

c.  如果使用场景是聚合或排序,并且都是基于analyzed 字符数据,这时需要更多的 heap size, 建议机器上运行多ES实例,每个实例保持不超过50%的ES heap设置(但不超过32G,堆内存设置32G以下时,JVM使用对象指标压缩技巧节省空间),50%以上留给lucene。 

3. 禁止swap,一旦允许内存与磁盘的交换,会引起致命的性能问题。 通过: 在elasticsearch.yml 中 bootstrap.memory_lock: true, 以保持JVM锁定内存,保证ES的性能。 

4. GC设置原则: 

a. 保持GC的现有设置,默认设置为:Concurrent-Mark and Sweep (CMS),别换成G1GC,因为目前G1还有很多BUG。 

b. 保持线程池的现有设置,目前ES的线程池较1.X有了较多优化设置,保持现状即可;默认线程池大小等于CPU核心数。如果一定要改,按公式((CPU核心数* 3)/ 2)+ 1 设置;不能超过CPU核心数的2倍;但是不建议修改默认配置,否则会对CPU造成硬伤。 

四、 集群分片设置: 

ES一旦创建好索引后,就无法调整分片的设置,而在ES中,一个分片实际上对应一个lucene 索引,而lucene索引的读写会占用很多的系统资源,因此,分片数不能设置过大;所以,在创建索引时,合理配置分片数是非常重要的。一般来说,我们遵循一些原则: 

1. 控制每个分片占用的硬盘容量不超过ES的最大JVM的堆空间设置(一般设置不超过32G,参加上文的JVM设置原则),因此,如果索引的总容量在500G左右,那分片大小在16个左右即可;当然,最好同时考虑原则2。 

2. 考虑一下node数量,一般一个节点有时候就是一台物理机,如果分片数过多,大大超过了节点数,很可能会导致一个节点上存在多个分片,一旦该节点故障,即使保持了1个以上的副本,同样有可能会导致数据丢失,集群无法恢复。所以, 一般都设置分片数不超过节点数的3倍。 

五、 Mapping建模: 

1. 尽量避免使用nested或 parent/child,能不用就不用;nested query慢, parent/child query 更慢,比nested query慢上百倍;因此能在mapping设计阶段搞定的(大宽表设计或采用比较smart的数据结构),就不要用父子关系的mapping。 

2. 如果一定要使用nested fields,保证nested fields字段不能过多,目前ES默认限制是50。参考:index.mapping.nested_fields.limit :50

因为针对1个document, 每一个nested field, 都会生成一个独立的document, 这将使Doc数量剧增,影响查询效率,尤其是JOIN的效率。 

3. 避免使用动态值作字段(key),  动态递增的mapping,会导致集群崩溃;同样,也需要控制字段的数量,业务中不使用的字段,就不要索引。控制索引的字段数量、mapping深度、索引字段的类型,对于ES的性能优化是重中之重。以下是ES关于字段数、mapping深度的一些默认设置: 
index.mapping.nested_objects.limit :10000

index.mapping.total_fields.limit:1000

index.mapping.depth.limit: 20

六、 索引优化设置: 

1.设置refresh_interval 为-1,同时设置number_of_replicas 为0,通过关闭refresh间隔周期,同时不设置副本来提高写性能。 

2. 修改index_buffer_size 的设置,可以设置成百分数,也可设置成具体的大小,大小可根据集群的规模做不同的设置测试。 indices.memory.index_buffer_size:10%(默认)

indices.memory.min_index_buffer_size: 48mb(默认)

indices.memory.max_index_buffer_size

3. 修改translog相关的设置: 

a. 控制数据从内存到硬盘的操作频率,以减少硬盘IO。可将sync_interval的时间设置大一些。
index.translog.sync_interval:5s(默认)。

b. 控制tranlog数据块的大小,达到threshold大小时,才会flush到lucene索引文件。 
index.translog.flush_threshold_size:512mb(默认)

4. _id字段的使用,应尽可能避免自定义_id, 以避免针对ID的版本管理;建议使用ES的默认ID生成策略或使用数字类型ID做为主键。 

5. _all字段及_source字段的使用,应该注意场景和需要,_all字段包含了所有的索引字段,方便做全文检索,如果无此需求,可以禁用;_source存储了原始的document内容,如果没有获取原始文档数据的需求,可通过设置includes、excludes 属性来定义放入_source的字段。 

6. 合理的配置使用index属性,analyzed 和not_analyzed,根据业务需求来控制字段是否分词或不分词。只有 groupby需求的字段,配置时就设置成not_analyzed, 以提高查询或聚类的效率。 

七、 查询优化: 

1. query_string 或 multi_match的查询字段越多, 查询越慢。可以在mapping阶段,利用copy_to属性将多字段的值索引到一个新字段,multi_match时,用新的字段查询。 

2. 日期字段的查询, 尤其是用now 的查询实际上是不存在缓存的,因此, 可以从业务的角度来考虑是否一定要用now, 毕竟利用query cache 是能够大大提高查询效率的。 

3. 查询结果集的大小不能随意设置成大得离谱的值, 如query.setSize不能设置成 Integer.MAX_VALUE, 因为ES内部需要建立一个数据结构来放指定大小的结果集数据。 

4. 尽量避免使用script,万不得已需要使用的话,选择painless & experssions 引擎。一旦使用script查询,一定要注意控制返回,千万不要有死循环(如下错误的例子),因为ES没有脚本运行的超时控制,只要当前的脚本没执行完,该查询会一直阻塞。 

如:
{

    “script_fields”:{

        “test1”:{

            “lang”:“groovy”,

            “script”:“while(true){print 'don’t use script'}”

        }

    }

}


5. 避免层级过深的聚合查询, 层级过深的group by , 会导致内存、CPU消耗,建议在服务层通过程序来组装业务,也可以通过pipeline的方式来优化。 

6. 复用预索引数据方式来提高AGG性能: 

如通过 terms aggregations 替代 range aggregations, 如要根据年龄来分组,分组目标是: 少年(14岁以下) 青年(14-28) 中年(29-50) 老年(51以上), 可以在索引的时候设置一个age_group字段,预先将数据进行分类。从而不用按age来做range aggregations, 通过age_group字段就可以了。 

7. Cache的设置及使用: 

a) QueryCache: ES查询的时候,使用filter查询会使用query cache, 如果业务场景中的过滤查询比较多,建议将querycache设置大一些,以提高查询速度。 

indices.queries.cache.size: 10%(默认),可设置成百分比,也可设置成具体值,如256mb。

当然也可以禁用查询缓存(默认是开启), 通过index.queries.cache.enabled:false设置。 

b) FieldDataCache: 在聚类或排序时,field data cache会使用频繁,因此,设置字段数据缓存的大小,在聚类或排序场景较多的情形下很有必要,可通过indices.fielddata.cache.size:30% 或具体值10GB来设置。但是如果场景或数据变更比较频繁,设置cache并不是好的做法,因为缓存加载的开销也是特别大的。 

c) ShardRequestCache: 查询请求发起后,每个分片会将结果返回给协调节点(Coordinating Node), 由协调节点将结果整合。 
如果有需求,可以设置开启;  通过设置index.requests.cache.enable: true来开启。

不过,shard request cache只缓存hits.total, aggregations, suggestions类型的数据,并不会缓存hits的内容。也可以通过设置indices.requests.cache.size: 1%(默认)来控制缓存空间大小。

亿级规模的ES查询优化实战

  • 能用filter就不用query 
    filter拿到相应的doc后不计算score不用排序 
    query会对符合条件的doc计算score并进行排序 
    filter的查询速度比query快很多

  • 增加相关cache的配置 
    indices.cache.filter.size: 30% 
    indices.fielddata.cache.size: 60% 
    index.cache.field.type: soft 
    indices.breaker.fielddata.limit: 70%

  • 优化方案——总结 
    能用filter就不用query 
    增加冗余字段将部分range aggregation查询变成terms aggregation 
    为常用字段增加配置,将fielddata的loading设成eager,尽量多加载到内存 
    增加集群的缓存资源,把内存尽量多的用起来 
    Global ordinals 
    Index warmer 
    调整aggregation的collect_mode 
    上SSD

elasticsearch一些使用经验以及优化方法

  • Elasticsearch索引速度优化 
    index.refresh_interval :-1 
    index.number_of_shards : X 
    index.number_of_replicas : 0 
    index.translog.sync_interval : 30s 
    index.translog.durability : “async” 
    index.translog.flush_threshold_size: 4g 
    index.translog.flush_threshold_ops: 50000

  • 其它 
    去掉_all字段可节省一半空间 
    开启索引压缩可节省空间,但会有10%-20%的性能损耗 

    不需分词的字符串字段设成not_analyzed

  • ElasticSearch架构概述

    ElasticSearch是现在技术前沿的大数据引擎,常见的组合有ES+Logstash+Kibana作为一套成熟的日志系统,其中Logstash是ETL工具,Kibana是数据分析展示平台。ES让人惊艳的是他强大的搜索相关能力和灾备策略,ES开放了一些接口供开发者研发自己的插件,ES结合中文分词的插件会给ES的搜索和分析起到很大的推动作用。ElasticSearch是使用开源全文检索库ApacheLucene进行索引和搜索的,说架构必须和Lucene的一些东西打交道。

    关于Lucene:

    ApacheLucene将写入索引的所有信息组织成一种倒排索引(Inverted Index)的结构之中,该结构是种将词项映射到文档的数据结构。其工作方式与传统的关系数据库不同,大致来说倒排索引是面向词项而不是面向文档的。且Lucene索引之中还存储了很多其他的信息,如词向量等等,每个Lucene都是由多个段构成的,每个段只会被创建一次但会被查询多次,段一旦创建就不会再被修改。多个段会在段合并的阶段合并在一起,何时合并由Lucene的内在机制决定,段合并后数量会变少,但是相应的段本身会变大。段合并的过程是非常消耗I/O的,且与之同时会有些不再使用的信息被清理掉。在Lucene中,将数据转化为倒排索引,将完整串转化为可用于搜索的词项的过程叫做分析。文本分析由分析器(Analyzer)来执行,分析其由分词器(Tokenizer),过滤器(Filter)和字符映射器(Character Mapper)组成,其各个功能显而易见。除此之外,Lucene有自己的一套完整的查询语言来帮助我们进行搜索和读写。

     [注]ES中的索引指的是查询/寻址时URI中的一个字段如:[host]:[port(9200)]/[index]/[type]/[ID]?[option],而Lucene中的索引更多地和ES中的分片的概念相对应。

    回到ElasticSearch,ES的架构遵循的设计理念有以下几个特征:

    1. 合理的默认配置:只需修改节点中的Yaml配置文件,就可以迅捷配置。这和Spring4中对配置的简化有相似的地方。

    2. 分布式工作模式:ES强大的Zen发现机制不仅支持组广播也支持点单播,且有“知一点即知天下”之妙。

    3. 对等架构:节点之间自动备份分片,且使分片本身和样本之间尽量”远离“,可以避免单点故障。且Master节点和Data节点几乎完全等价。

    4. 易于向集群扩充新节点:大大简化研发或运维将新节点加入集群所需的工作。

    5. 不对索引中的数据结构增加任何限制:ES支持在一个索引之中存在多种数据类型。

    6. 准实时:搜索和版本同步,由于ES是分布式应用,一个重大的挑战就是一致性问题,无论索引还是文档数据,然而事实证明ES表现优秀。

    (一)分片策略

    选择合适的分片数和副本数。ES的分片分为两种,主分片(Primary Shard)和副本(Replicas)。默认情况下,ES会为每个索引创建5个分片,即使是在单机环境下,这种冗余被称作过度分配(Over Allocation),目前看来这么做完全没有必要,仅在散布文档到分片和处理查询的过程中就增加了更多的复杂性,好在ES的优秀性能掩盖了这一点。假设一个索引由一个分片构成,那么当索引的大小超过单个节点的容量的时候,ES不能将索引分割成多份,因此必须在创建索引的时候就指定好需要的分片数量。此时我们所能做的就是创建一个新的索引,并在初始设定之中指定这个索引拥有更多的分片。反之如果过度分配,就增大了Lucene在合并分片查询结果时的复杂度,从而增大了耗时,所以我们得到了以下结论:

    我们应该使用最少的分片!

    主分片,副本和节点最大数之间数量存在以下关系:

    节点数<=主分片数*(副本数+1)

     控制分片分配行为。以上是在创建每个索引的时候需要考虑的优化方法,然而在索引已创建好的前提下,是否就是没有办法从分片的角度提高了性能了呢?当然不是,首先能做的是调整分片分配器的类型,具体是在elasticsearch.yml中设置cluster.routing.allocation.type属性,共有两种分片器even_shard,balanced(默认)。even_shard是尽量保证每个节点都具有相同数量的分片,balanced是基于可控制的权重进行分配,相对于前一个分配器,它更暴漏了一些参数而引入调整分配过程的能力。

    每次ES的分片调整都是在ES上的数据分布发生了变化的时候进行的,最有代表性的就是有新的数据节点加入了集群的时候。当然调整分片的时机并不是由某个阈值触发的,ES内置十一个裁决者来决定是否触发分片调整,这里暂不赘述。另外,这些分配部署策略都是可以在运行时更新的,更多配置分片的属性也请大家自行Google。

    (二)路由优化

    ES中所谓的路由和IP网络不同,是一个类似于Tag的东西。在创建文档的时候,可以通过字段为文档增加一个路由属性的Tag。ES内在机制决定了拥有相同路由属性的文档,一定会被分配到同一个分片上,无论是主分片还是副本。那么,在查询的过程中,一旦指定了感兴趣的路由属性,ES就可以直接到相应的分片所在的机器上进行搜索,而避免了复杂的分布式协同的一些工作,从而提升了ES的性能。于此同时,假设机器1上存有路由属性A的文档,机器2上存有路由属性为B的文档,那么我在查询的时候一旦指定目标路由属性为A,即使机器2故障瘫痪,对机器1构不成很大影响,所以这么做对灾况下的查询也提出了解决方案。所谓的路由,本质上是一个分桶(Bucketing)操作。当然,查询中也可以指定多个路由属性,机制大同小异。

    (三)ES上的GC调优

    ElasticSearch本质上是个Java程序,所以配置JVM垃圾回收器本身也是一个很有意义的工作。我们使用JVM的Xms和Xmx参数来提供指定内存大小,本质上提供的是JVM的堆空间大小,当JVM的堆空间不足的时候就会触发致命的OutOfMemoryException。这意味着要么内存不足,要么出现了内存泄露。处理GC问题,首先要确定问题的源头,一般有两种方案:

    1. 开启ElasticSearch上的GC日志

    2. 使用jstat命令

    3. 生成内存Dump

    关于第一条,在ES的配置文件elasticsearch.yml中有相关的属性可以配置,关于每个属性的用途这里当然说不完。

    第二条,jstat命令可以帮助我们查看JVM堆中各个区的使用情况和GC的耗时情况。

    第三条,最后的办法就是将JVM的堆空间转储到文件中去,实质上是对JVM堆空间的一个快照。

    想了解更多关于JVM本身GC调优方法请参考:http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html

    另外,通过修改ES节点的启动参数,也可以调整GC的方式,但是实质上和上述方法是等同的。

    (四)避免内存交换

    这一点很简单,由于操作系统的虚拟内存页交换机制,会给性能带来障碍,如数据写满内存会写入Linux中的Swap分区。

    可以通过在elasticsearch.yml文件中的bootstrap.mlockall设置为true来实现,但是需要管理员权限,需要修改操作系统的相关配置文件。

    (五)控制索引合并

    上文提到过,ES中的分片和副本本质上都是Lucene索引,而Lucene索引又基于多个索引段构建(至少一个),索引文件中的绝大多数都是只被写一次,读多次,在Lucene内在机制控制下,当满足某种条件的时候多个索引段会被合并到一个更大的索引段,而那些旧的索引段会被抛弃并移除磁盘,这个操作叫做段合并。 

    Lucene要执行段合并的理由很简单充分:索引段粒度越小,查询性能越低且耗费的内存越多。频繁的文档更改操作会导致大量的小索引段,从而导致文件句柄打开过多的问题,如修改系统配置,增大系统允许的最大文件打开数。总的来讲,当索引段由多一个合并为一个的时候,会减少索引段的数量从而提高ES性能。对于研发者来讲,我们所能做的就是选择合适的合并策略,尽管段合并完全是Lucene的任务,但随着Lucene开放更多配置借口,新版本的ES还是提供了三种合并的策略tiered,log_byte_size,log_doc。另外,ES也提供了两种Lucene索引段合并的调度器:concurrent和serial。其中各者具体区别,这里暂不赘述,只是抛砖引玉。

  • ES 手册

    如何提高ES的性能

    不要返回较大的结果集

    ES是设计成一个搜索引擎的,只擅长返回匹配查询较少文档,如果需要返回非常多的文档需要使用Scroll。

    避免稀疏

    因为ES是基于Lucene来索引和存储数据的,所以对稠密的数据更有效。Lucene能够有效的确定文档是通过一个整数的文档id,无论有没有数据都会话费一个字节存储id。稀疏主要影响norms和doc_values,一些可以避免稀疏的推荐:

    避免将不相关的数据放到相同的索引中

    规范的文档结构

    使用相同的字段名来保存同样的数据。

    避免类型

    不用norms和doc_values在稀疏字段

    调整索引速度

    使用bulk请求

    并且每个请求不超过几十M,因为太大会导致内存使用过大

    使用 multiple workers/threads发送数据到ES

    多进程或者线程,如果看到TOO_MANY_REQUESTS (429)EsRejectedExecutionException则说明ES跟不上索引的速度,当集群的I/O或者CPU饱和就得到了工作者的数量。

    增加刷新间隔

    index.refresh_interval默认是1s,可以改成30s以减少合并压力。

    在加载大量数据时候可以暂时不用refresh和repliccas

    index.refresh_interval to -1 and index.number_of_replicas to 0

    禁用swapping

    禁用swapping

    给文件缓存分配内存

    缓存是用来缓存I/O操作的,至少用一般的内存来运行ES文件缓存。

    使用更快的硬件

    • 使用SSD作为存储设备。
    • 使用本地存储,避免使用NFS或者SMB
    • 注意使用虚拟存储,比如亚马逊的EBS

    索引缓冲大小

    indices.memory.index_buffer_size通常是JVM的0.1,确保他足够处理至多512MB的索引。

    调整搜索速度

    给文件系统缓存大内存

    至少给可用内存的一半到文件系统缓存。

    使用更快的硬件

    • 使用SSD作为存储设备。
    • 使用性能更好的CPU,高并发
    • 使用本地存储,避免使用NFS或者SMB
    • 注意使用虚拟存储,比如亚马逊的EBS

    文档建模

    避免链接,嵌套会使查询慢几倍,而亲自关系能使查询慢几百倍,所以如果同样的问题可以通过没有链接的非规范回答就可以提升速度。

    预索引数据

    不明觉厉

    映射

    数值型数据不一定要映射成整形或者长整型

    避免scripts

    如果实在要使用,就用painless和expressions

    强势合并只读索引

    https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-forcemerge.html
    不要强势合并正在写的索引

    准备全局顺序

    准备文件系统缓存

    index.store.preload,如果内存不是很大会使搜索变得缓慢。

    调整磁盘使用

    禁用不需要的功能

    • 不需要过滤时可以禁用索引“index”:false
    • 如果你不需要text字段的score,可以禁用”norms”:false
    • 如果不需要短语查询可以不索引positions"indexe_options":"freqs"

    不用默认的动态字符串匹配

    不要使用_all

    使用best_compression

    使用最小的足够用的数值类型

    byte,short,integer,long
    half_float,float,double

    https://www.elastic.co/guide/en/elasticsearch/reference/master/indices-create-index.html#mappings
    https://www.elastic.co/guide/en/elasticsearch/reference/master/index-modules.html#dynamic-index-settings
    https://www.elastic.co/guide/en/elasticsearch/reference/master/search-request-scroll.html

=======================================================================================

集群结点角色分配

在之前得文章中我们介绍到es集群中得三个角色 master ,data,client

master结点:node.master: true node.data: false

该node服务器只作为一个主节点,但不存储任何索引数据,该node服务器将使用自身空闲得资源,来协调各种创建索引请求或者查询请求,将这些请求合理分发到相关得node服务器上。

data结点:node.master: false node.data: true

该node服务器只作为一个数据节点,只用于存储索引数据。使该node服务器功能 单一,只用于数据存储和数据查询,降低其资源消耗率。

client结点(负载均衡结点):node.master: false node.data: false

该node服务器即不会被选作主节点,也不会存储任何索引数据。该服务器主要用 于查询负载均衡。在查询的时候,通常会涉及到从多个node服务器上查询数据,并请 求分发到多个指定的node服务器,并对各个node服务器返回的结果进行一个汇总处理, 最终返回给客户端。

1:关闭data结点得http功能

    针对ElasticSearch集群中的所有数据节点,不用开启http服务。将其中的配置 参数这样设置:http.enabled: false,同时也不要安装head, bigdesk, marvel等监控 插件,这样保证data节点服务器只需处理创建/更新/删除/查询索引数据等操作。

    http功能可以在非数据节点服务器上开启,上述相关的监控插件也安装到这些服 务器上,用于监控ElasticSearch集群状态等数据信息。这样做一来出于数据安全考虑,二来出于服务性能考虑。

2:一台服务器上最好只部署一个node

    一台物理服务器上可以启动多个Node服务器节点(通过设置不同的启动port),但一台服务器上的CPU,内存,硬盘等资源毕竟有限,从服务器性能考虑,不建议一台服务器上启动多个node节点。

    在大规模局点,比如100个点,可以专门配备3个Master,可使用3台具有内存的刀片即可,即参数配置为node.master: true,node.data: false;可以按比例配备数据汇聚节点,比如10个,即参数配置为node.master: false ,node.data: false;小规模节点,可以不用如此设置,当然如果依然有性能问题,也是一个优化的措施


集群得机器内存设置

    Elasticsearch 默认采用的是Lucene,至于为什么es采用这个,原因可能是因为Lucene是一个成熟的、高性能的、可扩展的、轻量级的,而且功能强大的搜索引擎包。Lucene的核心jar包只有一个文件,而且不依赖任何第三方jar包。更重要的是,它提供的索引数据和检索数据的功能开箱即用。当然,Lucene也提供了多语言支持,具有拼写检查、高亮等功能。当然es使用Lucene作为分词搜索包,势必会造成很大程度上的内存消耗。

1:预留一半内存给Lucene使用

    一个常见的问题是配置堆太大。你有一个64 GB的机器,觉得JVM内存越大越好,想给Elasticsearch所有64 GB的内存。

    当然,内存对于Elasticsearch来说绝对是重要的,用于更多的内存数据提供更快的操作。而且还有一个内存消耗大户-Lucene

    Lucene的设计目的是把底层OS里的数据缓存到内存中。Lucene的段是分别存储到单个文件中的,这些文件都是不会变化的,所以很利于缓存,同时操作系统也会把这些段文件缓存起来,以便更快的访问。

    Lucene的性能取决于和OS的交互,如果你把所有的内存都分配给Elasticsearch,不留一点给Lucene,那你的全文检索性能会很差的。

    最后标准的建议是把50%的内存给elasticsearch,剩下的50%也不会没有用处的,Lucene会很快吞噬剩下的这部分内存。

2:32GB限制

    在java中,所有的对象都分配在堆上,然后有一个指针引用它。指向这些对象的指针大小通常是CPU的字长的大小,不是32bit就是64bit,这取决于你的处理器,指针指向了你的值的精确位置。

    对于32位系统,你的内存最大可使用4G。对于64系统可以使用更大的内存。但是64位的指针意味着更大的浪费,因为你的指针本身大了。浪费内存不算,更糟糕的是,更大的指针在主内存和缓存器(例如LLC, L1等)之间移动数据的时候,会占用更多的带宽。

    java 使用一个叫内存指针压缩的技术来解决这个问题。它的指针不再表示对象在内存中的精确位置,而是表示偏移量。这意味着32位的指针可以引用40亿个对象,而不是40亿个字节。最终,也就是说堆内存长到32G的物理内存,也可以用32bit的指针表示。

    一旦你越过那个神奇的30-32G的边界,指针就会切回普通对象的指针,每个对象的指针都变长了,就会使用更多的CPU内存带宽,也就是说你实际上失去了更多的内存。事实上当内存到达40-50GB的时候,有效内存才相当于使用内存对象指针压缩技术时候的32G内存。

    这段描述的意思就是说:即便你有足够的内存,也尽量不要超过32G,因为它浪费了内存,降低了CPU的性能,还要让GC应对大内存。

3:机器内存大于64GB

    你可以考虑一台机器上创建两个或者更多ES节点,而不要部署一个使用32+GB内存的节点。仍然要 坚持50%原则,假设 你有个机器有128G内存,你可以创建两个node,使用32G内存。也就是说64G内存给ES的堆内存,剩下的64G给Lucene。
    如果你选择第二种,你需要配置

cluster.routing.allocation.same_shard.host:true

这会防止同一个shard的主副本存在同一个物理机上(因为如果存在一个机器上,副本的高可用性就没有了)

4:ES集群的heap参数优化

    所谓的heap即数据缓存的内存大小,ES集群中消耗内存的有以下几个:

1):segment Memory

    Lucene 把每次生成的倒排索引,叫做一个段(segment)。然后另外使用一个 commit 文件,记录索引内所有的 segment。而生成 segment 的数据来源,则是内存中的 buffer。由于词典的size会很大,全部装载到heap里不现实,因此Lucene为词典做了一层前缀索引(Term Index),这个索引在Lucene4.0以后采用的数据结构是FST (Finite State Transducer)。这种数据结构占用空间很小,Lucene打开索引的时候将其全量装载到内存中,加快磁盘上词典查询速度的同时减少随机磁盘访问次数。所以ES的data node存储数据并非只是耗费磁盘空间的,为了加速数据的访问,每个segment都有会一些索引数据驻留在heap里。因此segment越多,瓜分掉的heap也越多,并且这部分heap是无法被GC掉的! 理解这点对于监控和管理集群容量很重要,当一个node的segment memory占用过多的时候,就需要考虑删除、归档数据,或者扩容了。

2):Filter Cache

    Filter cache是用来缓存使用过的filter的结果集的,需要注意的是这个缓存也是常驻heap,无法GC的。默认的10% heap size设置工作得够好了,如果实际使用中heap没什么压力的情况下,才考虑加大这个设置。

3):Field Data cache

    对搜索结果做排序或者聚合操作,需要将倒排索引里的数据进行解析,然后进行一次倒排。在有大量排序、数据聚合的应用场景,可以说field data cache是性能和稳定性的杀手。这个过程非常耗费时间,因此ES2.0以前的版本主要依赖这个cache缓存已经计算过的数据,提升性能。但是由于heap空间有限,当遇到用户对海量数据做计算的时候,就很容易导致heap吃紧,集群频繁GC,根本无法完成计算过程。ES2.0以后,正式默认启用Doc Values特性(1.x需要手动更改mapping开启),将field data在indexing time构建在磁盘上,经过一系列优化,可以达到比之前采用field data cache机制更好的性能。因此需要限制对field data cache的使用,最好是完全不用,可以极大释放heap压力。这里需要注意的是,排序、聚合字段必须为not analyzed。设想如果有一个字段是analyzed过的,排序的实际对象其实是词典,在数据量很大情况下这种情况非常致命。

4):Bulk Queue

    Bulk Queue是做什么用的?当所有的bulk thread都在忙,无法响应新的bulk request的时候,将request在内存里排列起来,然后慢慢清掉。一般来说,Bulk queue不会消耗很多的heap,但是见过一些用户为了提高bulk的速度,客户端设置了很大的并发量,并且将bulk Queue设置到不可思议的大,比如好几千。这在应对短暂的请求爆发的时候有用,但是如果集群本身索引速度一直跟不上,设置的好几千的queue都满了会是什么状况呢? 取决于一个bulk的数据量大小,乘上queue的大小,heap很有可能就不够用,内存溢出了。一般来说官方默认的thread pool设置已经能很好的工作了,建议不要随意去“调优”相关的设置,很多时候都是适得其反的效果。

5):Indexing Buffer

    Indexing Buffer是用来缓存新数据,当其满了或者refresh/flush interval到了,就会以segment file的形式写入到磁盘。这个参数的默认值是10% heap size。根据经验,这个默认值也能够很好的工作,应对很大的索引吞吐量。但有些用户认为这个buffer越大吞吐量越高,因此见过有用户将其设置为40%的。到了极端的情况,写入速度很高的时候,40%都被占用,导致OOM。

6):Cluster State Buffer

    ES被设计成每个Node都可以响应用户的api请求,因此每个Node的内存里都包含有一份集群状态的拷贝。这个Cluster state包含诸如集群有多少个Node,多少个index,每个index的mapping是什么?有少shard,每个shard的分配情况等等(ES有各类stats api获取这类数据)。在一个规模很大的集群,这个状态信息可能会非常大的,耗用的内存空间就不可忽视了。并且在ES2.0之前的版本,state的更新是由Master Node做完以后全量散播到其他结点的。频繁的状态更新都有可能给heap带来压力。在超大规模集群的情况下,可以考虑分集群并通过tribe node连接做到对用户api的透明,这样可以保证每个集群里的state信息不会膨胀得过大。

7):超大搜索聚合结果集的fetch

    ES是分布式搜索引擎,搜索和聚合计算除了在各个data node并行计算以外,还需要将结果返回给汇总节点进行汇总和排序后再返回。无论是搜索,还是聚合,如果返回结果的size设置过大,都会给heap造成很大的压力,特别是数据汇聚节点。

5:优化建议:

一般分配主机1/4-1/2的内存
编辑:elasticsearch/bin/ elasticsearch
加上(10g换成你自己设置的内存数):

ES_MIN_MEM=10g
ES_MAX_MEM=10g
ES_HEAP_NEWSIZE=1g


集群的硬盘和CPU设置

1:硬盘选型:

    硬盘对集群非常重要,特别是建索引多的情况。磁盘是一个服务器最慢的系统,对于写比较重的集群,磁盘很容易成为集群的瓶颈。如果可以承担的器SSD盘,最好使用SSD盘。如果使用SSD,最好调整I/O调度算法。RAID0是加快速度的不错方法。

2:自动调整存储带宽

    在2.0.0之前,elasticsearch会限制合并速度(merges),默认为20MB/sec。但是这个速率经常是显得太小,导致合并速度落后于索引速度,进而限制了索引速度。

    现在Elasticsearch2.0.0之后,使用了自动调整合并IO速度方式:如果合并落于索引速度,合并IO速度会逐渐增大,并且随着合并的持续进行会减小。在索引吞吐量小的时候,即使突然来了一个大的合并任务,这种情况也不会吞噬整个节点可用的IO,极小化的降低对正在进行的查询和索引的影响。
但是对索引请求大的情况下,允许的合并速度会自动调整到跟上索引的速度。有了2.0.0这个特性,意味着我们不需要管任何的限制值了,只要用默认的就好了。

3:多个path.data 路径

    如果磁盘空间和IO性能是Elasticsearch的瓶颈的话,使用多个IO设备(通过设置多个path.data路径)存储shards,能够增加总的存储空间和提升IO性能。

    在Elasticsearch2.0之前的版本,也是配置多个path.data路径,但是其相当于RAID 0,每个shards的数据会分布在所有的磁盘上。当一个节点上有一块盘坏了的情况下,该节点上所有的shards都会损坏了。需要恢复该节点上的所有shards。

    在2.0.0版本,把这个实现改成了:每个shards所有的数据只会在一块磁盘上面。这样即使一个节点的一块磁盘损坏了,也只是损失了该磁盘上的shards,其它磁盘上的shards安然无事。只需要恢复该块盘上的shards即可。

    升级到2.0.0版本时,旧版本一个shard分布到所有磁盘上的数据,会拷贝到一块盘上。

    对应这个改变,在设计shards时,如果一个节点有10块磁盘,共3个节点,则shards至少30个,才能分布在30块盘上(即最大限度使用磁盘空间)。


集群的分片和副本配置

分片(Shard)

一个索引会分成多个分片存储,分片数量在索引建立后不可更改
分片数是与检索速度非常相关的的指标,如果分片数过少或过多都会导致检索比较慢。分片数过多会导致检索时打开比较多的文件别外也会导致多台服务器之间通讯。而分片数过少会导致单个分片索引过大,所以检索速度慢。基于索引分片数=数据总量/单分片数的计算公式,在确定分片数之前需要进行单服务单索引单分片的测试,目前我们测试的结果单个分片的内容为10G。

副本(replicas)

每个索引的数据备份数量。
ElasticSearch在创建索引数据时,最好指定相关的shards数量和replicas, 否则会使用服务器中的默认配置参数shards=5,replicas=1。

因为这两个属性的设置直接影响集群中索引和搜索操作的执行。假设你有足够的机器来持有碎片和副本,那么可以按如下规则设置这两个值:

  • 1) 拥有更多的碎片可以提升索引执行能力,并允许通过机器分发一个大型的索引;
  • 2) 拥有更多的副本能够提升搜索执行能力以及集群能力。

对于一个索引来说,number_of_shards只能设置一次,而number_of_replicas可以使用索引更新设置API在任何时候被增加或者减少。

这两个配置参数在配置文件的配置如下:

index.number_of_shards: 5
number_of_replicas: 1

Elastic官方文档建议:一个Node中一个索引最好不要多于三个shards.配置total_shards_per_node参数,限制每个index每个节点最多分配多少个发片.


集群的优化总结

1:java jdk版本尽量高一点,否则容易出现bug
2:es集群结点规划好,master,client,data node 分开,关闭data node 的http功能
3:合理利用内存
4:根据机器数,磁盘数,索引大小等硬件环境,根据测试结果,设置最优的分片数和备份数,单个分片最好不超过10GB,定期删除不用的索引,做好冷数据的迁移。
5:保守配置内存限制参数,尽量使用doc value存储以减少内存消耗,查询时限制size、from参数。
6:结合实际场景,做好集群监控

======================================================

一. 索引性能(Index Performance)

 


 

首先要考虑的是,索引性能是否有必要做优化?

索引速度提高与否?主要是看瓶颈在什么地方,若是 Read DB(产生DOC)的速度比较慢,那瓶颈不在 ElasticSearch 时,优化就没那么大的动力。实际上 Elasticsearch 的索引速度还是非常快的。

我们有一次遇到 Elasticsearch 升级后索引速度很慢,查下来是新版 IK 分词的问题,修改分词插件后得到解决。

如果需要优化,应该如何优化?

SSD 是经济压力能承受情况下的不二选择。减少碎片也可以提高索引速度,每天进行优化还是很有必要的。在初次索引的时候,把 replica 设置为 0,也能提高索引速度。

bulk 是不是一定需要呢?

若是 Elasticsearch 普通索引已经导致高企的 LA,IO 压力已经见顶,这时候 bulk 也无法提供帮助,SSD 应该是很好的选择。

在 create doc 速度能跟上的时候,bulk 是可以提高速度的。

记得 threadpool.index.queue_size ++,不然会出现索引时队列不够用的情况。

indices.memory.index_buffer_size:10% 这个参数可以进行适当调整。

调整如下参数也可以提高索引速度:index.translog.flush_threshold_ops:50000 和 refresh_interval。

二. 查询性能(Query Perofrmance)


王道是什么?routing,routing,还是 routing。

我们为了提高查询速度,减少慢查询,结合自己的业务实践,使用多个集群,每个集群使用不同的 routing。比如,用户是一个routing维度。

在实践中,这个routing 非常重要。

我们碰到一种情况,想把此维度的查询(即用户查询)引到非用户routing 的集群,结果集群完全顶不住!

在大型的本地分类网站中,城市、类目也是一个不错的维度。我们使用这种维度进行各种搭配。然后在前端分析查询,把各个不同查询分别引入合适的集群。这样做以后,每个集群只需要很少的机器,而且保持很小的 CPU Usage 和 LA。从而查询速度够快,慢查询几乎消灭。

分合?

分别(索引和routing)查询和合并(索引和routing)查询,即此分合的意思。

索引越来越大,单个 shard 也很巨大,查询速度也越来越慢。这时候,是选择分索引还是更多的shards?

在实践过程中,更多的 shards 会带来额外的索引压力,即 IO 压力。

我们选择了分索引。比如按照每个大分类一个索引,或者主要的大城市一个索引。然后将他们进行合并查询。如:http://cluster1:9200/shanghai,beijing/_search?routing=fang,自动将查询中城市属性且值为上海或北京的查询,且是房类目的,引入集群 cluster1,并且routing等于fang。

http://cluster1:9200/other/_search?routing=jinan,linyi。小城市的索引,我们使用城市做 routing,如本例中同时查询济南和临沂城市。

http://cluster1:9200/_all/_search,全部城市查询。

再如: http://cluster2:9200/fang,che/_search?routing=shanghai_qiche,shanghai_zufang,beijing_qiche,beijing_zufang。查询上海和北京在小分类汽车、整租的信息,那我们进行如上合并查询。并将其引入集群 cluster2。

使用更多的 shards?

除了有 IO 压力,而且不能进行全部城市或全部类目查询,因为完全顶不住。

Elastic 官方文档建议:一个 Node 最好不要多于三个 shards。

若是 "more shards”,除了增加更多的机器,是没办法做到这一点的。

分索引,虽然一个 Node 总的shards 还是挺多的,但是一个索引可以保持3个以内的shards。

我们使用分索引时,全量查询是可以顶住的,虽然压力有点儿高。

索引越来越大,资源使用也越来越多。若是要进行更细的集群分配,大索引使用的资源成倍增加。

有什么办法能减小索引?显然,创建 doc 时,把不需要的 field 去掉是一个办法;但是,这需要对业务非常熟悉。

有啥立竿见影的办法?

根据我们信息的特点,内容(field:description)占了索引的一大半,那我们就不把 description 索引进 ES,doc 小了一倍,集群也小了一倍,所用的资源(Memory, HD or SSD, Host, snapshot存储,还有时间)大大节省,查询速度自然也更快。

那要查 description 怎么办?

上面的实例中,我们可以把查询引入不同集群,自然我们也可以把 description 查询引入一个非实时(也可以实时)集群,这主要是我们业务特点决定的,因为description查询所占比例非常小,使得我们可以这样做。

被哪些查询搞过?第一位是 Range 查询,这货的性能真不敢恭维。在最热的查询中,若是有这货,肯定是非常痛苦的,网页变慢,查询速度变慢,集群 LA 高企,严重的时候会导致集群 shard 自动下线。所以,建议在最热的查询中避免使用 Range 查询。

Facet 查询,在后续版本这个被 aggregations 替代,我们大多数时候让它在后端进行运算。

三. 其他

1)线程池

线程池我们默认使用 fixed,使用 cached 有可能控制不好。主要是比较大的分片 relocation时,会导致分片自动下线,集群可能处于危险状态。在集群高压时,若是 cached ,分片也可能自动下线。自 1.4 版本后,我们就一直 fixed,至于新版是否还存在这个问题,就没再试验了。

两个原因:一是 routing王道带来的改善,使得集群一直低压运行;二是使用fixed 后,已经极少遇到自动下线shard了。

我们前面说过,user 是一个非常好的维度。这个维度很重要,routing 效果非常明显。其他维度,需要根据业务特点,进行组合。

所以我们的集群一直是低压运行,就很少再去关注新版本的 使用 cached 配置问题。

hreadpool.search.queue_size 这个配置是很重要的,一般默认是够用了,可以尝试提高。

2)优化

每天优化是有好处的,可以大大改善查询性能。max_num_segments 建议配置为1。虽然优化时间会变长,但是在高峰期前能完成的话,会对查询性能有很大好处。

3) JVM GC的选择:选择 G1还是 CMS?

应该大多数人还是选择了 CMS,我们使用的经验是 G1 和 CMS 比较接近;但和 CMS 相比,还是有一点距离,至少在我们使用经验中是如此。

JVM 32G 现象?

128G内存的机器配置一个 JVM,然后是巨大的 heapsize (如64G)?

还是配多个 JVM instance,较小的 heapsize(如32G)?

我的建议是后者。实际使用中,后者也能帮助我们节省不少资源,并提供不错的性能。具体请参阅 “Don’t Cross 32 GB!" (https://www.elastic.co/guide/en/elasticsearch/guide/current/heap-sizing.html#compressed_oops)

跨 32G 时,有一个现象,使用更多的内存,比如 40G,效果还不如31G!

这篇文档值得大家仔细阅读。

JVM 还有一个配置 bootstrap.mlockall: true,比较重要。这是让 JVM 启动的时候就 锁定 heap 内存。

有没有用过 较小的 heapsize,加上SSD?我听说有人使用过,效果还不错,当然,我们自己还没试过。

Q&A


Q1:您建议生产环境JVM采用什么样的参数设置?FULL GC频率和时间如何?

CMS 标准配置。

ES_HEAP_NEWSIZE=?G

JAVA_OPTS="$JAVA_OPTS -XX:+UseCondCardMark"

JAVA_OPTS="$JAVA_OPTS -XX:CMSWaitDuration=250"

JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC"

JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC"

JAVA_OPTS="$JAVA_OPTS -XX:CMSInitiatingOccupancyFraction=75"

JAVA_OPTS="$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly"

Full GC 很少去care 它了。我们使用 Elasticsearch 在JVM上花的时间很少。

Q2:生产环境服务器如何配置性价比较高?单机CPU核数、主频?内存容量?磁盘容量?

内存大一些,CPU 多核是必要的,JVM 和 Elasticsearch 会充分使用内存和多核的。 关于内存容量的问题,很多是 JVM Tunning 的问题。 磁盘容量没啥要求。

Q3: 分组统计(Facet 查询或 aggregations )大多数时候让它在后端进行运算,怎么实现?应用如果需要实时进行统计而且并发量较大,如何优化?

因为我们是网站系统,所以对于 Facet 请求,引导到后端慢慢计算,前端初始的时候可能没数据,但是此后就会有了。

如果是精确要求的话,那就只能从 提高 facet 查询性能去下手,比如 routing、filter、cache、更多的内存...

Q4:存进Elasticsearch的数据,timestamp是UTC时间,Elasticsearch集群会在UTC 0点,也就是北京时间早上8点自动执行优化?如何改参数设置这个时间?

我们没有使用Elasticsearch的自动优化设置。自己控制优化时间。

Q5:我的Java程序,log4j2 Flume appender,然后机器上的Flume agent ,直接Elasticsearch 的sink avro到 es节点上,多少个agent 连在单个Elasticsearch节点比较合适 ?

ElasticSearch本身是一个分布式计算集群,所以,请求平均分配到每个 node 即可。

Q6:我代码里直接用 Java API 生成Flume appender 格式,Flume agent 里interceptor去拆分几个字段,这样是不是太累了?比较推荐的做法是不是还是各业务点自己控制字段,调用Elasticsearch API 生成索引内容?

业务点自己控制生成的文档吧?如果需要产生不同routing,并且分了索引,这些其实是业务相关的。routing和不同索引,都是根据业务情况哪些查询比较集中而进行处理的。

Q7:您见过或管理过的生产环境的Elasticsearch数据量多大?

我们使用 Elasticsearch 进行某些业务处理,数据量过亿。

Q8:SSD性能提升多少?

SSD 对索引帮助非常大,效果当当的,提高几十倍应该是没问题。不过,我们没有试过完全使用SSD顶查询,而是使用内存,内存性价比还是不错的。

Q9:我们现在有256个shard,用uid做routing,所有查询都是走routing。每个shard有30多G,每次扩容很慢,有什么建议?

可以考虑使用分合查询吗? 或者使用更多的维度? 256个 shard 确实比较难以控制。但是如果是分索引和查询,比more shards(256) 效果应该会好不少。

Q10:Elasticsearch排序等聚合类的操作需要用到fielddata,查询时很慢。新版本中doc values聚合查询操作性能提升很大,你们有没有用过?

Facet 查询需要更大的内存,更多的 CPU 资源。可以考虑routing、filter、cache等多种方式提高性能。

Aggs 将来是要替换 Facet,建议尽快替换原来的facet API。

Q11:Elasticsearch配置bootstrap.mlockall,我们在使用中发现会导致启动很慢,因为Elasticsearch要获取到足够的内存才开始启动。

启动慢是可以接受的,启动慢的原因也许是内存没有有效释放过,比如文件 cached了。 内存充足的情况下,启动速度还是蛮快的,可以接受。 JVM 和 Lucene 都需要内存,一般是JVM 50%, 剩下的50% 文件cached 为Lucene 使用。

Q12:优化是一个开销比较大的操作,每天优化的时候是否会导致查询不可用?如何优化这块?

优化是开销很大的。不会导致查询不可用。优化是值得的,大量的碎片会导致查询性能大大降低。 如果非常 care 查询,可以考虑多个集群。在优化时,查询 skip 这个集群就可以。

Q13:Elasticsearch适合做到10亿级数据查询,每天千万级的数据实时写入或更新吗?

10亿是可以做到的,如果文档轻量,10亿所占的资源还不是很多。

ELK 使用 Elasticsearch ,进行日志处理每天千万是小case吧?

不过我们除了使用 ELK 进行日志处理,还进行业务处理,10亿级快速查询是可以做到,不过,需要做一些工作,比如索引和shards的分分合合

Q14:Elasticsearch相比Solr有什么优势吗?

我们当年使用 Solr 的时候,Elasticsearch 刚出来。他们都是基于 Lucene的。 Elasticsearch 相对于 solr ,省事是一个优点。而且现在 Elasticsearch 相关的应用软件也越来越多。Solr 和 Lucene 集成度很高,更新版本是和Lucene一起的,这是个优点。

Q15:分词用的什么组件?Elasticsearch自带的吗?

我们使用 IK 分词,不过其他分词也不错。IK分词更新还是很及时的。而且它可以远程更新词典。

Q16: reindex有没有好的方法?

reindex 这个和 Lucene 有关,它的 update 就是 delete+ add。

Q17:以上面的两个例子为例 : 是存储多份同样的数据么?

是两个集群。第一个集群使用大城市分索引,不过,还有大部分小城市合并一个索引。大城市还是用类目进行routing,小城市合并的索引就使用城市进行routing 。

第二个集群,大类分得索引,比如fang、che,房屋和车辆和其他类目在一个集群上,他们使用 city+二级类目做routing。

Q18:集群部署有没有使用 Docker ? 我们使用的时候 ,同一个服务器 节点之间的互相发现没有问题 ,但是跨机器的时候需要强制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解决集群互相发现问题。

我们使用puppet进行部署。暂没使用 Docker。 强制指定network.publish_host 和discovery.zen.ping.unicast.hosts 才能解决集群,跨IP段的时候是有这个需要。

Q19:您建议采用什么样的数据总线架构来保证业务数据按routing写入多个Elasticsearch集群,怎么保证多集群Elasticsearch中的数据与数据库中数据的一致性?

我们以前使用 php在web代码中进行索引和分析 query,然后引导到不同集群。 现在我们开发了一套go rest系统——4sea,使用 redis + elastic 以综合提高性能。

索引时,更新db的同时,提交一个文档 ID 通知4sea 进行更新,然后根据配置更新到不同集群。

数据提交到查询时,就是分析 query 并引导到不同集群。

这套 4sea 系统,有机会的可以考虑开源,不算很复杂的。

Q20: 能介绍一下Elasticsearch的集群rebanlance、段合并相关的原理和经验吗?

“段”合并?,我们是根据业务特点,产生几个不一样的集群,主要还是 routing 不一样。

shards 比较平均很重要的,所以选择routing 维度是难点,选择城市的话,大城市所在分片会非常大,此时可以考虑 分索引,几个大城市几个索引,然后小城市合并一个索引。

如果 shards 大小分布平均的话,就不关心如何 allocation 了。

Q21:关于集群rebalance,其实就是cluster.routing.allocation配置下的那些rebalance相关的设置,比如allow_rebalance/cluster_concurrent_rebalance/node_initial_primaries_recoveries,推荐怎么配置?

分片多的情况下,这个才是需要的吧。

分片比较少时,allow_rebalance disable,然后手动也可以接受的。

分片多,一般情况会自动平衡。我们对主从不太关心。只是如果一台机器多个 JVM instance (多个 Elasticsearch node)的话,我们写了个脚本来避免同一shard 在一台机器上。

cluster_concurrent_rebalance 在恢复的时候根据情况修改。正常情况下,再改成默认就好了。

node_initial_primaries_recoveries,在保证集群低压的情况下,不怎么care。

kopf 上面有好多这种配置,你可以多试试。

Q22:合并查询是异步请求还是同步请求?做缓存吗?

合并查询是 Elasticsearch 自带 API。

Q23:用httpurlconnection请求的时候,会发现返回请求很耗时,一般怎么处理?

尽可能减少慢查询吧?我们很多工作就是想办法如何减少慢查询,routing和分分合合,就是这个目的。

Q24:生产环境单个节点存储多少G数据?

有大的,有小的。小的也几十G了。不过根据我们自己的业务特点,某些集群就去掉了全文索引。唯一的全文索引,使用基本的routing(比较平衡的routing,比如user。城市的话,就做不到平衡了,因为大城市数据很多),然后做了 快照,反正是增量快照,1小时甚至更短时间都可以考虑!!!去掉全文索引的其他业务集群,就小多了。

 

你可能感兴趣的:(elasticsearch)