当前位置: 首页 > 科技观察

ElasticSearch的基本概念和集群的分布式底层实现

时间:2023-03-13 07:48:28 科技观察

深度分页导致的机器性能问题机器资源使用:集群系统中的深度分页要理解为什么深度分页有问题,让我们想象一下在一个有5个主分片的索引中搜索.当我们请求第一页结果(结果1到10)时,每个分片生成其前10个结果并将它们返回给请求节点,请求节点对所有50个结果进行排序以选择前10个结果。现在假设我们请求第1000页-结果10001到10010。两者的工作方式相同,除了每个分片必须产生前10010个结果。然后请求节点对这50050个结果进行排序,丢弃50040!您可以看到,在分布式系统中,对结果进行排序所花费的资源和时间随着页面分页的深度呈指数级增长。这就是为什么网络搜索引擎中没有一条语句可以返回超过1000个结果的原因。要看懂上面的文字,就需要了解ElasticSearch集群的底层原理和集群中的查询。本文试图通过总结ElasticSearch的基本概念和底层原理来加深自己的理解。同时希望对用户有所帮助,避免不必要的踩踏。坑。基本概念索引(index)“索引”一词在ElasticSearch语境中有多种含义:索引(名词):相对于传统的关系数据库领域,索引相当于SQL中的数据库。索引由其名称(必须全部为小写字符)标识,文档的创建、搜索、更新和删除均参照该名称。索引(动词):索引文档就是将文档存储在索引(名词)中,以便可以检索和查询。这与SQL语句中的INSERT关键字非常相似,只是如果文档已经存在,则新文档将替换旧文档。倒排索引:关系型数据库通过在指定的列上增加一个“索引”,例如B树(B-tree)索引,来提高数据检索速度。ElasticSearch和Lucene出于相同的目的使用一种称为“倒排索引”的结构。例如文档和词条的关系如下:图1:文档和词条的关系字段值解析后存入倒排索引,倒排索引存储分词(Term)和文档(Doc),倒排索引的简化版如下:图2:倒排索引类型(Type)类型是索引内部的逻辑分区(category/partition),但其含义完全取决于用户需求。因此,可以在一个索引中定义一种或多种类型。通常,类型是为共享相同字段的文档预定义的。类比传统的关系数据库领域,一个类型就相当于一张“表”。文档(Document)文档类似于一行完整的数据。在ElasticSearch中,文档是基于JSON格式表示的。文档是索引和搜索的原子单位,是一个包含一个或多个字段(Field)的容器。每个文档可以存储一组不同的域,但同一类型(Type)下的文档至少应该有一定程度的相似性。节点(Node)一个运行的ElasticSearch实例称为节点,集群由一个或多个具有相同cluster.name配置的节点组成,它们分担数据和负载的压力。ES集群中有三种不同类型的节点:Master节点:负责管理集群内的所有变更,比如增删索引,或者增删节点等,Master节点不需要参与操作例如文档级更改和搜索。可以通过属性node.master进行设置。数据节点:存储数据及其对应的倒排索引。默认情况下,每个节点都是一个数据节点(包括主节点),可以通过node.data属性进行设置。Coordinator节点:如果node.master和node.data属性都为false,则该节点称为协调节点,用于响应客户请求,均衡各节点负载。分片(Shard)一个索引中的数据存储在多个分片中,相当于水平分表。分片是Lucene的一个实例,它本身就是一个完整的搜索引擎。我们的文档存储并索引到分片中,但应用程序直接与索引交互,而不是与分片交互。分片可以是主分片或副本分片。索引中的任何文档都属于一个主分片,因此主分片的数量决定了索引可以存储的最大数据量。副本分片只是主分片的副本。副本分片作为冗余备份,防止硬件故障时的数据丢失,并为查询、返回文档等读操作提供服务。集群分布式底层实现以上我们对ElasticSearch的基本概念有了初步的了解,接下来我们深入这些内部细节,帮助大家更好的理解数据在分布式系统中是如何存储和查询的。ES其实是使用sharding来实现分发的。分片是数据的容器,文档存储在分片中,分片分配给集群中的每个节点。当你的集群扩容或缩容时,ES会自动在各个节点间迁移分片,让数据依然均匀分布在集群中。主分片的数量在创建索引的时候就已经确定了,但是副本分片的数量可以随时修改。默认情况下,一个索引将有5个主分片和任意数量的副本。主分片和副本分片的状态决定了集群的健康状况。每个节点上只会保存主分片或其对应的副本分片,同一节点上不会存在相同的副本分片。如果集群中只有一个节点,则不会分配副本分片。此时集群健康状态为黄色,存在数据丢失风险。分布式文档CRUD索引新文档(Create)当用户向节点提交索引新文档的请求时,该节点将计算新文档应该添加到哪个分片。每个节点存储每个分片存储在哪个节点上的信息,因此协调节点将请求发送到相应的节点。注意,这个请求会发送到主分片,当主分片完成索引后,这个请求会并行发送到它的所有副本分片,以确保每个分片都拥有最新的数据。每次写入一个新的文件,都会先写入内存,这个操作会写入一个translog文件(transactionlog)。此时,如果进行搜索操作,则无法对新文档进行索引。图3:新文档写入内存,操作写入translogES每1秒执行一次刷新操作(refresh)(这个时间可以修改)。这时,在这1秒内写入内存的新文件将被写入一个文件系统缓存(filesystemcache),并构成一个段(segment)。此时可以搜索到该段中的文件,但还没有写入硬盘,也就是说,如果此时发生断电,这些文件可能会丢失。图4:刷新完成后,内存被清空,新文件写入文件系统缓存中,不断写入新文件,不断重复这个过程。每秒都会产生一个新的段,translog文件会越来越大。图5:translog每30分钟持续添加新的文档记录或者translog文件变得非常大,然后进行一次fsync操作。此时会将文件系统缓存中的所有段写入磁盘,并删除translog(之后会生成新的translog)。图6:执行fsync后,segment写入磁盘,内存和translog清空。从上面的过程可以看出,在两次fsync操作之间,存储在内存和文件系统缓存中的文件是不安全的。一旦停电,这些文件就会丢失。所以ES引入translog来记录两次fsync之间的所有操作,以便机器故障恢复或重启,ES根据translog进行恢复。当然translog本身也是一个文件,存在于内存中,掉电就会丢失。因此,ES会每隔5秒或一次写请求完成后,将translog写入磁盘。可以认为,对文档的操作一旦写入磁盘,就是安全的、可恢复的。因此,只有当当前操作记录写入磁盘后,ES才会将操作成功的结果返回给发送操作请求的客户端。另外,由于每秒钟都会产生一个新的段,因此很快就会有大量的段。对于一个分片的查询请求,会依次查询分片中的所有段,这样会降低查找效率。因此,ES会自动开始合并段的工作,将一些大小相似的段合并成一个新的大段。合并的过程实际上创建了一个新的段,当新的段写入磁盘时,所有被合并的旧段都被清除了。图7:合并段图8:合并完成后删除旧段,可以搜索到新段更新(Update)和删除(Delete)文档ES的索引不能修改,所以更新和删除操作不直接在原始索引工具上。磁盘上的每个段都会维护一个del文件来记录删除的文件。每当用户发出删除请求时,文档并没有真正被删除,索引也没有改变,只是在del文件中将文档标记为已删除。因此,删除的文档仍然可以被检索到,只是在返回检索结果时被过滤掉了。每次启动段合并作业时,标记为删除的文档实际上都会被删除。更新文档会先搜索原始文档,获取文档的版本号。然后将修改后的文档写入内存,就像写入新文档一样。同时,旧版本文档被标记为删除。同样,可以搜索到文档,但最终被过滤掉了。读操作(Read):查询过程查询过程大致分为两个阶段:查询(query)和检索(fetch)。该节点的工作是向所有相关分片广播查询请求,并将它们的响应聚合到一个全局排序的结果集中返回给客户端。在查询阶段,当节点收到搜索请求时,该节点成为协调节点。查询过程分布式搜索图9:查询过程分布式搜索第一步是向索引中每个节点的分片副本广播一个请求。查询请求可以由主分片或副本分片处理,协调节点将轮询后续请求中的所有分片副本以分担负载。每个分片都会在本地建立一个优先级队列。如果客户端请求返回一个size从结果排序中的数字开始的结果集,则每个节点需要生成一个sizefrom+size的结果集,所以优先级队列的size也是from+size。Sharding只会返回一个轻量级的结果给协调节点,包含结果集中每个文档的ID和排序所需的信息。协调节点会聚合所有分片的结果,进行全局排序,得到最终的查询排序结果。至此查询阶段结束。在检索阶段,查询过程得到一个排序结果,它标记了哪些文档符合搜索要求。这个时候,还是需要去获取这些文件,并返回给客户的。协调节点将确定实际需要返回的文档,并向包含该文档的分片发送get请求;分片获取文档并将其返回给协调节点;协调节点返回结果给客户端作者:张勇http://tech.dianwoda.com/