elasticsearch(es) 和lucene
参考: https://youthlql.gitee.io/javayouth/#/?id=jvm
lucene 是最先进的、功能最强大的搜索库。
elasticsearch 是基于lucene 的高扩展的分布式搜索服务器,支持开箱即用。es隐藏了lucene 的复杂性,提供了简单易用的Java Api 接口,它被用作全文搜索,结构化搜索,分析以及这三个的结合。
es的核心概念:
从写入数据到数据可以查询到有一个小延迟
基于es执行搜索和分析可以达到秒级
Cluster 集群:
这个集群包含多个节点,每个节点属于那个集群都是通过一个配置来决定的,对于中小型应用来说,刚开始一个集群就是一个节点就很正常。
Node 节点:
Node 是集群中的一个节点。节点默认会随机分配一个名称。默认节点会加入一个名称为elasticsearch 的集群。如果直接启动一堆节点,就会自动组成一个elasticsearch 集群,当然一个节点也可以组成集群。
Document 、field:
document(文档)是es中最小的一个数据单元,一个文档可以是一条多种多样的数据,通常用json数据结构来表示。每个文档里面可以有多个field,每个field 就是一个数据字段。
Index:
Index(索引)包含了一堆有相似结构的文档数据,每个index 下的type 都可以存储多条文档(document)。一个索引就代表了一类相似或相同的文档。
type(类型):
每个索引里面都可以有一或多个类型,type 是index 的一个逻辑分类,每个type下的documen 的field 可能不太一样。
shard(分片):
es 可以将一个索引中的数据切分为多个shard,分布在多台服务器上存储。有了shard 就可以横向扩展,存储更多数据。让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个shard 都是一个lucene index。
replica:
shard(分片)分为primary shard 和replica shard 。任何一个服务器随时都有可能宕机,此时shard 就有可能丢失。因此,可以为每一个分片创建多个replica 副本。可以在故障时提供备用服务,保证数据不会丢失。创建多个replica 还可以提升搜索操作的吞吐量和性能。
elasticsearch 分布式架构原理:
es 中存储数据的基本单位是索引,如果要在es 中存储数据,就应该在es 中创建一个索引(oeder_idx),所有的数据都写到索引里面去,一个索引就类似于mysql 里面的一张表。
很多情况下,一个索引里面可能只有一个type,但也会有一个索引index 里面有多个type 的情况。可以认为index 是一个类别的表,具体每个type 代表了mysql 中的一个表,每个类型有一个mapping(映射),索引就代表多个type 同属于一个类型,而映射就是这个类型的表结构定义。
在创建索引的时候可以将索引拆分成多个shard 分片,每个分片存储部分数据,这样的好处:
①、支持横向扩展,比如数据量是3T,3个分片的话每个分片就是1T 数据,如果这是数据量提升到 4T ,要扩展就只需要重新创建一个有4个分片的索引,然后见数据导入即可;
②、提高性能,即使用分布式,数据分布在多个分片中,在多台服务器上操作,都会在多台机器上并行分布执行。就可以提高吞吐量和性能。
shard 的数据会有多个备份,这样就会有一个负责 写入数据然后同步到其他的分片上去。就算有某个机器宕机了还有别的副本在其他机器上,保证了高可用性。
es 集群上有多个节点,es 会自动选取一个节点为master 节点,在这个主分支节点就负责管理工作。要是master节点宕机了会重新选举一个节点为master 节点。就是说如果某个非 master 节点宕机了。那么此节点上的 primary shard 不就没了。master 会让 primary shard 对应的 replica shard(在其他机器上)切换为 primary shard。如果宕机的机器修复了,修复后的节点也不再是 primary shard,而是 replica shard。
es 的写入原理,查询原理:
写入:
①、客户端选择一个node 发送请求,这个node就是协调节点
②、协调节点对document 进行路由,请求转发给对应的node 节点。
③、实际node 上的shard 处理请求,然后将数据同步到replica node 。
④、协调节点发现所有的节点都完成后就返回相应结果给客户端。
读取:
通过doc id 查询,会根据doc id 进行hash 判断在那个shard,在shard上查询
①、客户端发送请求到任意的node,成为coordinator node(协调节点)
②、协调节点对doc id 进行hash 路由,将请求转发到i对应的节点,使用随机轮询算法在primary shard以及所有的replica 中随机选取一个,让读请求负载均衡。
③、接受请求的节点返回文档给协调节点。
④、协调节点返回文档给客户端。
es 的搜索数据过程:
①、客户端发送请求到一个协调节点
②、协调节点将搜索请求转发到所有的分片对应的primary shard 后者replica shard 上。
③、每个分片将自己的搜索结果返回给协调节点,有协调节点进行数据的合并、排序、分页等的操作得到最终结果。
④、由协调节点根据doc id 去各个节点上拉取实际的文档数据,返回给客户端。
删除和修改(更新):
删除操作:commit(提交)时会生成一个 .del 文件,里面将某个doc 标识为deleted 状态,搜索时就知道是否已经被删除。
更新操作:将原来的doc 标识为deleted 状态,然后写入一条数据
倒排索引:
在搜索引擎中,每个文档都有一个对应的文档ID,文档内容被表示为一系列关键词的集合。每个关键词都会记录它在文档中出现的次数和出现的位置。倒排索引就是关键词文档ID 的映射,每个关键词都对应一系列文件,这些文件中都出现了关键词。注意:
- 倒排索引中的所有关键词对应一个或多个文档;
- 倒排索引中的词项根据字典顺序升序排序
查询效率的提高:
filesystem cache:
往es 里面写入数据时,实际上是写入到磁盘文件里;查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache 里面。
数据预热:
es 集群中的每个机器写入的数据超过了文件系统缓存(filesystem cache)一倍时,就可以考虑做数据预热。就是对于访问次数比较多的热数据最好做一个专门的缓存预热子系统。对热数据每隔一段时间就提前访问一下,让数据进入filesystem cache 里。这样下次访问的的时候性能一定会好很多。
冷热分离:
es 可以做类似于msql 的水平拆分,就是将大量的访问少,访问频率低的数据单独写一个索引。将访问频繁的热数据也单独写一个索引。最好的话就是将冷数据写入一个索引中,然后热数据写入另外一个索引中,这样可以确保热数据在预热之后尽量逗留在filesystem cache 里面,不会让冷数据给冲刷掉。
document 模型设计:
MySql 经常有一些复杂的关联查询,但是在es 里应尽量不要使用,一旦使用了复杂的关联查询性能一般都不太好。最好先在Java 系统里完成关联再将关联好的数据写入到es 中去;搜索的时候就不需要利用es 的语法来完成join 之类的一些关联查询了。
documen 模型设计非常重要,使用es 不要再搜索时才去执行各种复杂的操作,不要考虑用es 去完成一些它不好完成的操作;如果真的需要,尽量再document 模型设计写入的时候完成,对于一些太复杂的操作都应该避免,用es 做复杂的操作性能会很差。
分页性能优化:
es 的分页是不那么好的,因为查询必须从每个分片都查出数据,然后根据需求进行排序、筛选等的操作;最后再次进行分页。翻页的时候,翻得越深每个shard 返回的数据就越多,协调节点处理的时间就越长。所以用es 分页时越是翻到后面就越慢。
不允许深度分页:
scroll 分页方式:
为了满足深度分页的场景,es 提供了 scroll 的方式进行分页读取。原理上是对某次查询生成一个游标 scroll_id , 后续的查询就根据这个游标去取数据,直到结果集中返回的 hits 字段为空,表示遍历结束。scroll_id 的生成可以理解为建立了一个临时的历史快照,在此之后的增删改查等操作不会影响到这个快照的结果。所有文档获取完毕之后,需要手动清理掉 scroll_id 。
es 生产集群的部署架构:
es 不同类型的节点:
Master 节点:用于维护索引信息和进群状态。
Data 节点:负责数据存储。
Ingest 节点:数据预处理。
Coordinating 节点:处理用户请求。
ML 节点:机器学习相关功能。
在开发环境中,一个节点可以承担多种角色,但是在生产环境中,建议一个节点负责单一角色,以达到高可用及高性能的额效果,同时根据业务需求和硬件资源来配合分配节点。
节点参数配置:
配置单一角色:默认情况下一个节点会承担多个角色,可以通过配置让一个节点只负责一个角色。
水平扩展结构:当需要更多的磁盘容量和读写能力时,可以增加Data 节点。当系统有大量的复杂查询和聚合分析时,可以增加Coordinating 节点。
读写分离架构:使用 Ingest 节点对数据预处理。
分片设计与管理:
分片分为主分片和副分片,副分片是主分片的拷贝,主要用于备份数据。
分片设计:
主分片:
主分片在索引创建时确定,之后不能修改;
在es 7.0 之后一个索引默认有一个主分片;
一个索引的主分片数不能超过1024;
副分片:
副分片在索引创建之后可以动态修改;
数量默认为1;
建议一个es 集群的分片数(包括主分片和副分片)不超过10w;
如果某个索引只有一个主分片:
优点:查询算分和聚合不精准的问题都可避免。
缺点:集群无法实现水平扩展。
因为索引(不管该索引的数据量达到了多大)只能存储在一个主分片上(一个分片不能跨节点存储/处理);
对于单个主分片的索引来说,即使有再多的数据节点,它也无法利用。
如果某个索引有多个主分片:
优点:集群可以实现水平扩展。
对于拥有多个主分片的索引,该索引的数据可以分布在多个主分片上,不同的主分片可以分布在不同的数据节点中;这样,该索引就可以利用多个节点的读写能力,从而处理更多的数据。
如果当前的数据节点数小于主分片数,当有新的数据节点加入集群后,这些主分片就会自动被分配到新的数据节点上,从而实现水平扩容。
缺点:但是主分片数也不能过多,因为对于分片的管理也需要额外的资源开销。主要会带来以下问题:
每次搜索/聚合数据时需要从多个分片上获取数据,并汇总;除了会带来精准度问题,还会有性能问题。
分片的 Meta 信息由 Master 节点维护管理,过多的分片,会增加 Master 节点的负担。
副本分片是主分片的备份:
优点:
可防止数据丢失,提高系统的可用性;
可以分担主分片的查询压力,提高系统的查询性能。
缺点:
与主分片一样,需要占用系统资源,有多少个副本,就会增加多少倍的存储消耗。
会降低系统的写入速度。
集群容量规划:
考虑机器的软件和硬件的配置;
考虑数据量;
考虑业务需求;