Elasticsearch核心知识笔记整理

        本文内容主要从《Elasticsearch源码解析与优化实战》一书中摘录总结成文,可以让我们以最快的速度回顾相关的核心知识点。文章成文以常见的领域模块组织。

集群模块

  1. 底层基于单机模块的Lucene,ES只是将各个节点上的单机Lucene给联合起来组成一个集群。

角色

  1. Master。负责集群管理
  2. 普通数据节点。负责对索引数据进行CRUD操作。
  3. 预处理节点。保存数据之前对其进行转换、富化处理等。
  4. 协调节点。负责请求路由及合并结果返回,即客户端发送请求到任意节点,每个节点都知道任意文档所处的位置,从而可以转发请求到目标节点,再代理目标节点返回结果给客户端。

索引

  1. Lucene的每个索引又由很多分段组成,每个分段都是一个倒排索引。ES每次“refresh”都会生成一个新分段,其中包含若干文档数据。每个分段的内部,文档的不同字段被单独建立了索引 ,每个字段的值由若干词(Term)组成,Term是由原文本内容经过分词器处理和语言处理后的最终结果。
  2. 一个索引Index会拆分成多个分片存储到不同的节点上,每个分片又有多个副本分片存储在其他节点上。类似于kafka中的分区存储方案。

分片

  1. 分片是数据的容器,文档保存在分片内,不会垮分片保存。分片就是保存在节点上的Lucene索引,Lucene本身就是一个完整的搜索引擎,可以执行独立的建立索引和搜索任务。
  2. 主分片负责数据的更新操作,主副分片都可以进行读取操作。分片的目的是为了分割巨大的索引,这样可以提高数据处理并行度。
  3. 集群规模扩大或缩小时,自动迁移分片使数据均匀分布。
  4. 节点扩容或收缩,都会触发自动索引分片及其副本的均衡迁移操作。

元数据

  1. Master节点管理每个索引的主副分片,并将其分布信息广播到集群其他节点,这样客户端随便请求一个节点都能找到目标分片的路由信息而执行查询或数据更新操作。
  2. 主分片推送数据写副分片,如果写失败,则通知Master将其从元数据中的ISA集合中移除。
  3. 元数据分集群层面元数据、索引层面元数据以及分片层面元数据。
  4. 只有具有Master资格的节点和数据节点才可以持久化集群状态。发生变化就会持久化到磁盘。
  5. 元数据选举仅向有Master资格的节点获取,取有最新版本号的即可。因为元数据确认保存时已经按多数原则判断的。
  6. 集群级和索引级元数据恢复都是gateway模块通过版本号选举出来的,分片级元数据是由allocation模块动态计算出来的。
  7. Master负责管理集群状态元数据信息,包含内容路由信息、配置信息等。每次更新后,都会广播到其他普通节点上去缓存。以便提高路由效率。
  8. 集群启动时,每个节点都需要遍历所有其他数据节点上的分片信息,以便缓存到本地进行路由用。但是这种设计方案会导致非常大的网络请求量,为什么不设计为每个节点自己上报给Master,然后由Master广播给集群节点呢???
  9. 元数据变更需要Master下发广播给其他节点,为了保证元数据同步的时序性,使用广播队列机制依次广播不会并行,只有前一个广播任务结束,才会继续下一个任务。为了提高广播事务的原子性,采用弱一致性的二阶段提交模式。即先广播元数据信息,节点接受后暂不应用,给Master反馈结果,当Master收集到过半节点响应成功后,再广播commit事务,集群节点收到后才会应用这个元数据。如果节点没有收到commit(超时)则拒绝应用元数据变更 ,这种情况下就需要后续补偿机制了,节点主动重新获取最新的元数据应用。所以说2PC并不能从根本上保证事务的一致性和原子性,只能大大降低网络异常带来的风险。这种设计zk中也是类似的机制。

选举

  1. 主分片因为自身问题,比如磁盘已满这种可探测到的问题,导致无法继续进行数据更新操作时会主动上报给Master,让Master将其中一个副分片提升为主分片,把自己降级为副分片或移出下线操作。这种主动上报是因为Master无法感知到。但是主分片因为宕机这种异常,Master是可以通过心跳最终感知的,Master就会主动进行故障转移操作了。所以这种异常处理方式是不可或缺的。
  2. 集群需要选举出一个中心节点Master,以便管理元数据和操作集群变更。master也可以向普通节点一样处理数据。可以通过配置指定某些节点才有资格称为master。
  3. master选举采用改进的Bully算法,选举节点编号最大的那个为Master。首先根据参选节点过半得出临时master,然后临时Master还要统计自己的选票数过半才能成为正式Master。这是为了防止网络分区导致双主问题。master并不知道节点数是多少,这是通过配置文件统一硬性设定的值。参选节点和选票数量必须同时过半才能成为最终的Master。
  4. Master选举过程中并不需要考虑其上的元数据信息是否最新,这点和zk有所不同。master选举完后,才会去选举有最新元数据的节点,也需要参与节点数过半,并让其上报给master,然后再广播到其他节点。
  5. 索引分片选主,旧版中由master根据版本号选最新的那个定为主分片。新版中集群元数据已经有了最新主分片的记录,故直接就可以决定。Master使用集群状态的元数据ISA(同步中的副本)管理分片的主副本状态,如果副本同步数据发生异常,Master会从该集合中删除它。该集合也会作为Master选主分片的依据。kafka也采用类似机制。

数据读写模块

数据写

  1. es主副本数据同步借鉴了PacificA算法。PacificA算法里用到了类似ZK中的2PC提交方式。即先主分片预提交本地并发送给副分片也执行预提交,副分片回复ACK给主分片。然后主分片正式提交本地数据并反馈客户端成功,同时发送提交命令给副分片正式提交数据。这里可能不需要像ZK那样副分片过半回复OK,只要一个副分片正常就行,这样就保证了数据不会出现单点故障丢失风险。其他副分片后续可以继续同步完成即可。和ZK一样,每一个数据更新操作都分配有唯一有序递增的序列号,且2PC阶段必须顺序进行,不能后面的操作比前面的操作先行完成。和ZK一样,不管2PC还是3PC,都无法绝对保证数据不丢失和强一致性,只能大大降低不一致性错误的概率。
  2. es主副本数据同步要比PacificA算法简单些,没有2PC阶段,使用最终一致性策略,也有序列号机制保证写入的顺序一致性。即数据写入是先写入主分片,再由主分片节点推送到其他(ISA同步中的副本,需要过半副本分片(包括主分片在内)才行)副分片上去(有些新增的副分片处于恢复阶段,就不用了,使用恢复策略执行同步),这个过程是并行且异步的,此时主分片线程等待副分片回应。副分片写入成功后回复主分片,然后主分片节点会把请求成功(不需要所有副分片都返回成功,也有说需要过半副分片)消息返回给协调节点,再由协调节点回复客户端成功。这是Push模式。很多分布式系统都是使用副本Pull模式,比如redis、mysql。
  3. 创建索引的请求,协调节点会转发给Master操作,成功后Master还会把最新元数据信息广播给所有节点,过半返回PK即可。然后协调节点还可以通过刚刚创建索引元数据信息继续下一步路由操作。
  4. 主分片写数据是先写Lucene文档,成功后再写本地事物日志(Translog),因为写Lucene会有各种检查,比较容易失败。这种设计感觉不合情理,一般都是先写事物日志,再去更新数据文件,如果失败则回滚事物日志即可。这样很好的保证了单机事物的一致性。
  5. 每个节点上的索引分片由很多段构成,每一次新写入操作首先会被记录事物日志,该日志记录了当前操作和数据。写入的索引数据放在内存缓冲区,然后会被定时每隔1秒生成新的段文件,并调用write系统内调用将用户缓冲区数据拷贝到操作系统pageCache中,此时新段文件虽然还没有正式刷入磁盘,但是已经对查询可见了。稍后通过执行定时的flush操作(fsync系统调用)正式写入磁盘。最后清理掉事物日志记录。这个过程和hbase的HFile文件生成机制类似,基于LSM树系统写入数据,对文档的修改、删除操作都是以新追加文件内容实现,而不是直接修改原始文档数据,等后期合并这些小文件来精简数据,搜索时以文档的最后一次更新记录为准即可。
  6. 删除分段只是标记删除,删除整个索引才会物理删除。
  7. 对文档的更新操作使用版本号跟踪,主要是用来实现乐观锁更新。
  8. 对于批量请求,因为每个写操作都可能路由到不同的目标节点,而有些却可以合并到相同的路由。协调节点会根据路由目标分组(按分片分组)及合并请求再转发。
  9. 默认情况下根据文档的_id值哈希后对索引的主分片数取模决定路由,这样可以使得数据比较均匀的分布到每个分片 上去。用户不指定文档ID,则默认生成一个UUID。如果用户指定ID,本身原因可能导致数据发生倾斜,此时也可以通过一个配置(routing_partition_size)避免这种情况。
  10. 协调节点将请求转发给不同的目标分片节点时以分片为单位单独等待处理回应,即便某些目标节点响应异常,最后等所有目标节点都返回响应后,整体做成功响应给客户端。

数据读

  1. 搜索查询过程:客户端发送查询请求给某个协调节点,协调节点因为有全局的文档和索引元数据,故将请求发送给所有需要查询的索引分区所在目标节点(主副分区会简单使用轮换方式作为负载均衡),目标节点各自执行本地的查询将结果返回给协调节点,协调节点然后汇总结果甚至排序分页后再返回给客户端。如果目标节点上的分区故障无法读取,则会重新选择一个分区节点进行请求转发获取结果。这种转发请求的设计和Redis不一样,Redis是返回目标节点的地址给客户端自己去重定向。
  2. GET请求是针对当个文档(数据)而言的,属于精确查找。必须指定三元组_index、_type、_id。这样协调节点可以根据这个信息确定其数据所在分片,然后将请求转发给任意一个副本分片即可。副本分片所属节点最后返回结果给协调节点,最后在返回给客户端。
  3. 准实时读取数据,是根据请求参数“realtime”指定的,旧版本会从translog中读取还未刷入磁盘的写入数据,5.x版本后采用先将translog刷入磁盘后再从Lucene中读取。所以频繁的准实时读取会降低刷磁盘的性能。
  4. Search搜素请求一般是针对所有文档内容的模糊或匹配搜索(也有精确值场景)。所以需要遍历所有分片。协调节点将请求发送给所有分片中的某个副分片分别各自执行本节点的搜索,然后将搜索结果返回协调节点汇总后再返回给客户端。
  5. 对于排序分页搜索,各个分片需要分别返回各自排序后top from*size数量的条数,协调节点汇总后还要排序一次再取其中要展示的分页数据返回给客户端(只有这样才能返回正确的结果)。这个执行的确比较吃力,mycat中也是采用这种做法,效率一般很低。好在一般而言,用户很少去执行翻页查询操作。对于互联网而言,通用的做法就是列表只有上一页和下一页的按钮,连总条数都不展示,也不允许分页跳转。
  6. 分布式搜索的过程中,每个分片在本地执行查询将结果放入一个优先级队列中,因为后面匹配到的结果,可能评分更高,则需要排在前面一些才行。这用普通有序列表是不行的。
  7. 协调节点执行搜索任务转发请求时,是根据分片发送的而不是目标节点。这点似乎可以优化。然后节点上各个分片单独进行查询并返回结果给协调节点。因为这是一个全局模糊搜索,如果是指定的_index另当别论了。相当于在指定的数据库里模糊查某个字段的值。
  8. Search搜索包括Query和Fetch两个阶段。前面说的都是Query阶段,此阶段返回的是文档的ID值(倒排序索引存的)。Fetch阶段就是通过拿到的文档ID重新去分片上精准的获取文档的具体内容,这样最终才能得到用户想要的结果。
  9. GET请求因为是根据文档ID查的,所以使用的是正排序索引,像关系型数据库那样。而Search搜索是对文本的模糊搜索,使用的是倒排序索引。
  10. 每个节点都有一个所有分片共享的cache,缓冲了部分高频查询的文档完整内容。采用LRU算法管理,这样可以尽可能的利用缓冲的优势,如果文档更新了,则从cache中删除即可。这和MySQL中的buffer还不太一样,它是先标记更新缓冲,然后同步到磁盘刷新。

存储模块

磁盘

  1. es有三类数据会持久化存储。分别是state元数据信息、index Lucene生成的索引数据以及translog事务日志。
  2. _index+_type+_id唯一标识一个文档,这里的文档可以理解为对应数据库里某个表的某一条数据。_index相当于对应一个数据库,而_type相当于对应一张表。_id可以系统自动生成,也可以创建时指定,一般对应于某行数据的主键ID。广泛意义上的文档可以是一个网页、一份邮件、一条日志等。
  3. 虽然以上概念和数据库的有对应关系。但是并不是完全相等的。比如es中同一个_index下的不同_type下要求字段不能有冲突,但是数据库里不同的表可以有同名的字段。es中只是删除_type的话,不会真的删除,需要删除_index才行,但数据库里删除表当然是直接物理删除的。es不建议同一个_index下创建多个_type,应该使用不同的_index。且6.x版本中现在只允许一个_type了。未来7.X版本中会废弃掉_type。
  4. 底层数据文件使用JSON格式化存储。
  5. 以索引为单位,建立索引时需充分考虑好主分片数量(副分片可以随意调整),不然后续不好变更。不要持续往一个索引里写数据,这样会导致索引过大影响效率。当索引达到一定数据量时,可以通过新建索引解决分片无法扩充的问题。删除索引数据时以索引为单位可以彻底删除,而以_id为单位删除文档时,并不会真正释放磁盘空间,需要等到系统合并分段时才会物理删除。
  6. Lucene索引都是倒排索引,就是一个以分词为key,文档ID集合为value的Map结构。
  7. 已生成好的索引一般具有不变性,但是如果分词对应的文档增加了怎么办呢?答案是通过新增索引方式,这样查询时会遍历所有的索引及分词,将结果合并后再返回给客户端。
  8. 这种高频的产生新分段文件,会导致文件数据急剧膨胀,也会导致检索效率降低。所以系统会定时的将这些分段合并为一个新的段文件。其中如果被标记删除的则不会合并。生成新段文件后,就会删除旧的段文件。这种设计同样在HBASE、Cassandra中存在。
  9. index中的doc values字段使用列式存储,这在聚合查询时,效率会更加高效。主要用存储非字符串字段值。_source字段存储的是文档原始的JSON格式值,即包含了所有字段的文本存储。另外stored被设计为优化存储某些字段。这些底层存储字段都是可以在创建索引时配置的,都是为了方便提高查询效率而设计的底层存储数据结构,这也意味着es使用了冗余存储设计方式提高查询效率。

内存

  1. 已生成的索引不变性,可以让其缓存到内存中(使用MMAP方式映射),加快查询效率。
  2. 普通节都会缓存集群的元数据,以便提高路由时的效率。
  3. 写入的索引数据先放在内存缓冲区,然后会被定时每隔1秒生成新的段文件,并调用write系统内调用将用户缓冲区数据拷贝到操作系统pageCache中。
  4. 每个节点都有一个所有分片共享的cache,缓冲了部分高频查询的文档完整内容。采用LRU算法管理,这样可以尽可能的利用缓冲的优势,

网络模块

  1. es推荐使用RestFull风格的API,底层使用Netty模块,内部集群节点之间仍然采用socket套接字传输。而不是Java API方式,原因是前者接口兼容性更有优势。加上非QPS场景下应用,效率也不慢。一般的分布式系统都是使用基于TCP套接字的RPC通信。
  2. 每个节点对其他节点的连接多达13个,一般都是某个功能专用的,不能共享。这种设计也有缺点,那就是造成大量网络负担和性能问题。不太可取

容错模块

  1. 为了便于集群迁移或重启,提供数据快照存储方案。快照底层基于Lucene快照,但是ES自己支持增量方式。
  2. 集群健康状态使用绿、黄、红标识。黄表示主分片正常,但是有副分片失去了联系,存在可能的单点故障风险。红表示存在主 分片异常。每个索引都有上述三种状态。

事务

  1. 主分片节点重启需要恢复数据,依赖写数据时的事物日志记录,该日志记录了当前操作和数据。但是创建新的索引分段并写入磁盘的过程可能发生宕机,导致失败。重启后查询事物日志,根据未完成的操作,记录重放日志写入磁盘。这种原理就是广泛应用于数据库事物了。
  2. 副分片要恢复数据,需要分两个走。第一步是给主分片的事务日志加个保留锁(额外记录一份从当前开始的事物日志),让主分片暂停写磁盘,同时生成数据快照发送给副分片进行整体恢复。快照生成完成后,不用等待副分片恢复完成即可进行事物提交写磁盘并清理掉事物日志记录。第二步是将第一步做的额外事物日志发给副分片,以便恢复第一步这个时间段新产生的数据。这个期间也要保证主分片无法写入数据。第二步的操作过程中虽然也会产生新的数据,但是由于这个过程相比于第一步的过程要短暂的多,所以对性能影响不是特别大。第二步操作完成后,放开主分片写入数据,此时主备数据同步也处于正常状态。
  3. 后续版本对于副分片恢复又做了进一步优化,引入全局检查点和本地检查点机制,做增量恢复,而不用每次都全量备份后发送大文件给副分片恢复。全局检查点记录的是主副分片都已经确认同步完成的数据位置。本地检查点则是记录本地分片已经确认写入磁盘的数据位置。这样就可以利用两者之差来做增量恢复。大大提高了效率。
  4. 副分片恢复中的translog经历了多次版本迭代优化。①最早(1.x)是使用保留锁方式,阻塞translog的刷盘操作,但是这样可能会导致阻塞巨大量的数据刷盘。②2.x-5.x是引入translog.view的概念,将translog切分较小的文件,而不是原来的一个文件,也允许正常刷盘提交,但是每个translog文件有一个引用计数,副本分片恢复时加1,恢复完后减1,只有为0时,才可以清理这个translog文件。③从6.x版本开始又移除了translog.view,改为采用对translog文件创建一个快照(副本),这样依然不会阻塞translog的正常提交,恢复过程只跟快照相关了。完美解决了这个问题,实现上也更简单。④从②和③优化开始,translog恢复期间也不需要短暂阻塞主分片的写入提交操作,而是正常同步新操作给副分片。那么这期间的操作时序性上面就存在错乱的问题,比如文档A正常时序操作时先更新值为1,然后更新值为2。但是副分片可能先收到更新值为2的同步请求,后才收到主分片发送的translog重复里的更新值为1的操作。此时就需要通过对比操作的数据版本号来略过这个数据更新了。有了数据的版本号,就不会出现数据最终一致性问题。
  5. 索引的写和别名更新是原子操作,不会出现中间状态。但是批量不是

数据一致性

  1. 默认情况下,主分片写入成功,则就算写入成功,即便副本都写入失败了。所以ES是弱一致性。且主分片写入成功后,数据就可以被读取了。
  2. 分片写入过程中有些异常,比如磁盘已满或损坏会触发上报给Master进行分片迁移操作。如果是网络异常,则不会迁移分片,因为后续网络肯能会恢复,网络问题也无法进行迁移。
  3. 数据落盘失败,但客户端反馈成功:由于flush之前新分段数据还处在操作系统缓冲中,此时write调用返回的是成功状态,新分段的元数据也会被记录到集群中。如果此时断电,则分段数据最终还是没有写入到磁盘而丢失,导致数据不一致性。es通过生成新分段前记录事务日志的方式防止此类问题的发生,等节点重启后,重放该分段写入磁盘即可。事务日志文件一般都是以追加方式写入,所以写入速度很快。这种设计和数据库也差不多。
  4. 客户端写成功返回前,数据已经被读取:由于数据写入操作都是主副分片已经完成后再反馈给客户端成功消息的。所以读写并发时,读操作就可能读到刚刚写入的数据,然后客户端才收到写入成功的应答。理论上来说,这是无法避免的情况,包括数据库这样的系统。
  5. 写入过程可能会很慢:由于为了保证主副分片数据一致性,写成功需要主副分片都写入成功后才算成功(也有说过半),所以个别副分片因为网络问题导致请求缓慢而导致写入性能急剧下降。
  6. 脏读:由于数据写入的过程是先写入主分片。此时数据就已经对外可见了,任何读取操作都可以读取到。默认情况下,主分片写入成功,则就算写入成功,即便副本都写入失败了。通过配置参数“index.write.wait_for_active_shards”设置需要多少个分片写入成功才返回客户端成功,默认值为1,即主分片写入成功即可。
  7. 丢失数据:1、默认配置下,主分片写入成功就算成功。此时可能副本写入都失败了。刚好主分片节点宕机。其中一个副本被提升为主分片。则原来写入主分片的数据就丢失了。2、正常情况下ISA(同步中的副本集合)不为空,Master总是可以使用其中一个副本提升为主副本恢复数据,集群正常运转。但是如果遇到严重的灾难,没有任何ISA副本可用时,集群就处于Red状态,此时就需要手动操作,将某些陈旧的分片副本提升为主副本。这样虽然集群又可以运转了,但是却可能丢失了某些新数据。
  8. 弱一致性:主分片写入成功,数据即可读,但是此时副分片还没有同步到数据,或者同步失败。但客户端返回的是成功。

其他模块

  1. 进程被kill了如何处理?es节点启动时添加了对操作系统kill信号的监听钩子,这样kill进程时可以让应用程序有机会执行一些操作,实现优雅关机,不至于数据瞬间崩溃,等同断电宕机。
  2. 接收处理请求的过程使用管道流水线设计(Pipeline),这种设计非常常见。还允许用户自定义请求处理类,然后注册 到管道中即可。
  3. 系统设计大量使用基于事件触发通知机制实现系统灵活和扩展性,对相关的事件只需实现一个Listener并注册即可。或者使用语言本身的委托特性实现。
  4. 系统设计大量采用线程池,不同类型的任务都使用独立的线程池,哪怕只有一个线程也是如此。这样做或许是保证当前类型的任务有线程可用不被阻塞以及异常隔离。
  5. 系统线程池大致分为CPU密集型和I/O密集型,两种类型的线程数默认设置策略不同。CPU密集型线程数设置为N+1,I/O密集型设置为2N+1。最佳线程数=((线程等待时间+线程CPU时间)/线程CPU时间)XCPU个数。N为CPU个数。
  6. es从6.x版本开始查询路由在选择分片时会利用自适应副本选择(ARS)提升响应速度。本质就是基于健康度的节点选择策略。

优化模块

  1. ES默认的配置,是综合考虑了数据可靠性、搜索实时性、写入速度等因素的。所以针对不同场景下,我们可以做出适当调整。在性能和可靠性方面做出妥协。
  2. 调整translog flush。默认是一个请求就会刷盘一次,这样比较影响效率,但是可靠性却会损失一些,比如断电宕机,translog来不及写入磁盘导致数据丢失。
  3. 调整refresh_interval。默认刷新索引时间为1s,也就是新加的数据一秒后就可以被搜索到。这样会导致频繁的Lucene段创建,如果不需要这么高的实时性则降低配置即可。
  4. 段合并优化。如果是旋转类的硬盘线程数设置为1即可。多了反而可能降低性能。最大合并段设置越小,提高单个段大小也有利于搜索性能。
  5. 调整index_buffer。这是一个块索引CRUD的缓冲区,类似MySQL中的pool_buffer。和上面translog flush是不同的两个概念。这类缓冲区越大那么索引操作效率也会越高,可以固定到某个值。一般是采用LRU算法进行管理。默认为48M。
  6. 使用bulk批量请求。适当增加一次请求的数据量。
  7. 自动生成doc ID。如果写入时指定doc id 则es需要每次去搜索这个id的doc是否存在,以便判断是更新还是新增。所以对数据库表数据做索引时,可以将主键id作为一个普通字段写入,不要作为doc id。
  8. 减少字段数量。将不需要建立索引的字段index属性设置为no。使用不同的分析器进行分词。
  9. 禁用_all字段。6.0之前版本默认开启的,查询结果会去匹配所有字段的值,一般是不需要的。
  10. 对analyzed的字段禁用Norms。一般查询结果不需要对doc进行评分,可以将其禁用。
  11. 合理的文档定义。避免join操作,嵌套算法会使查询慢几倍。父子关系可能慢数百倍。
  12. 字段映射。数值类型标识符映射为keyword。
  13. 避免使用脚本。优先考虑painless和expressions。
  14. 优化日期搜索。不要总是用now,这样没法使用查询缓存。
  15. 为只读索引执行force-merge。只读索引不需要更新,可以将多个段合并为一个段。但是注意不要合并后太大,建议按天、月合并等。
  16. 调节搜索请求中的batched_reduce_size。协调节点预处理结果集。当分片数据返回指定大小数据后协调节点就可以预先处理部分数据,无需等待全部分片返回结果才进行。
  17. 使用近似聚合。对于查询结果准确性要求不高的场景下使用。
  18. 禁用字段索引。默认有所字段都会被索引,禁用其中一些不需要的字段索引如果不需要作为过滤条件的话。
  19. 禁用doc values。如果确定不需要对字段进行排序或聚合或从脚本访问字段值即可禁用。
  20. 不要使用默认的动态字符串映射。默认字符串字段会同时索引为text和keyword。一般id只需作为keyword,其他为text。创建索引时显示指定即可。
  21. 使用较少的分片数量、增大分片的大小。有效提高检索效率,但是也不能太大,会导致较长时间的索引恢复。
  22. 禁用_source字段。这里存储的是文档原始的JSON格式内容,如果不需要就可以禁用。但是会影响某些需要使用该字段的API。比如更新、重新索引。
  23. 减少索引分片数量。使用shrink api操作。
  24. 将ES的最大/最小堆内存设置为一样大小,最大不要超过32G。
  25. 为OS的PageCache保留一半的物理内存。
  26. 生成环境应该关闭OS的Swap功能。
  27. 配置Linux OOM Killer。Linux系统在物理内存不足时,默认会选择一个内存占用大的进程直接杀掉。为了es不被杀掉,在进程启动时设置oom_score_adj参数为一个较小的值,比如-17。Linux的这种机制,会导致我们的进程莫名的挂掉,值得注意。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值