域名建设好了怎么在建设网站创意设计图片素材
news/
2025/10/8 16:30:24/
文章来源:
域名建设好了怎么在建设网站,创意设计图片素材,平面设计论坛,邗江区城乡建设局网站目录 一、Elasticsearch是什么#xff1f;
二、为什么要使用ElasticSearch
2.1 关系型数据库有什么问题#xff1f;
2.2 ElasticSearch有什么优势#xff1f;
2.3 ES使用场景
三、ElasticSearch概念、原理与实现
3.1 搜索引擎原理
3.2 Lucene 倒排索引核心原理
倒排…目录 一、Elasticsearch是什么
二、为什么要使用ElasticSearch
2.1 关系型数据库有什么问题
2.2 ElasticSearch有什么优势
2.3 ES使用场景
三、ElasticSearch概念、原理与实现
3.1 搜索引擎原理
3.2 Lucene 倒排索引核心原理
倒排索引
四、Elasticsearch 整体架构
4.1 集群节点角色
4.2 数据副本
4.3 水平扩容
4.4 故障转移
4.5 路由机制
4.6 新建、更新、删除文档
4.6.1 写数据底层原理
4.6.2 索引的不变性
4.6.3 动态索引创建过程
4.6.4 分步查看数据持久化过程
4.6.5 更新/删除数据底层原理
4.7 查询文档
4.8 更新文档
4.9 分布式检索
五、ElasticSearch实际使用过程中会有什么问题
5.1 分片的设定
5.2 ES数据近实时问题
5.3 深分页问题
六、ES性能优化
七、ElasticSearch运维 一、Elasticsearch是什么
Elasticsearch简称ES是一个分布式、可扩展、实时的搜索与数据分析引擎。ES不仅仅只是全文搜索还支持结构化搜索、数据分析、复杂的语言处理、地理位置和对象间关联关系等。
ES的底层依赖LuceneLucene可以说是当下最先进、高性能、全功能的搜索引擎库。但是Lucene仅仅只是一个库。为了充分发挥其功能你需要使用Java并将Lucene直接集成到应用程序中。更糟糕的是您可能需要获得信息检索学位才能了解其工作原理因为Lucene非常复杂。
鉴于Lucene如此强大却难以上手的特点诞生了ES。ES也是使用Java编写的它的内部使用Lucene做索引与搜索它的目的是隐藏Lucene的复杂性取而代之的提供一套简单一致的RESTful API。
ES具有如下特点 一个分布式的实时文档存储引擎每个字段都可以被索引与搜索 一个分布式实时分析搜索引擎支持各种查询和聚合操作 能胜任上百个服务节点的扩展并可以支持PB级别的结构化或者非结构化数据 二、为什么要使用ElasticSearch
2.1 关系型数据库有什么问题
传统的关系数据库提供事务保证具有不错的性能高可靠性久经历史考验而且使用简单功能强大同时也积累了大量的成功案例。
后来随着访问量的上升几乎大部分使用 MySQL 架构的网站在数据库上都开始出现了性能问题web 程序不再仅仅专注在功能上同时也在追求性能。
读写分离 由于数据库的写入压力增加读写集中在一个数据库上让数据库不堪重负大部分网站开始使用主从复制技术来达到读写分离以提高读写性能和读库的可扩展性。Mysql 的 master-slave 模式成为这个时候的网站标配了。
分表分库 开始流行使用分表分库来缓解写压力和数据增长的扩展问题。这个时候分表分库成了一个热门技术也是业界讨论的热门技术问题。
MySQL 的扩展性瓶颈 大数据量高并发环境下的 MySQL 应用开发越来越复杂也越来越具有技术挑战性。分表分库的规则把握都是需要经验的。虽然有像淘宝这样技术实力强大的公司开发了透明的中间件层来屏蔽开发者的复杂性但是避免不了整个架构的复杂性。分库分表的子库到一定阶段又面临扩展问题。还有就是需求的变更可能又需要一种新的分库方式。
关系数据库很强大但是它并不能很好的应付所有的应用场景。MySQL 的扩展性差需要复杂的技术来实现大数据下 IO 压力大表结构更改困难正是当前使用 MySQL 的开发人员面临的问题。
2.2 ElasticSearch有什么优势
非关系型、搜索引擎、近实时搜索与分析、高可用、天然分布式、横向可扩展
2.3 ES使用场景 搜索引擎 电商网站的商品搜索、站内搜索、模糊查询、全文检索服务 非关系型数据库 业务宽表数据库字段太多查询太慢索引没有办法再做优化 数据库做统计查询 大数据近实时分析引擎 日志分析
三、ElasticSearch概念、原理与实现
3.1 搜索引擎原理
一次完整的搜索从用户输入要查询的关键词开始比如想查找 Lucene 的相关学习资料我们都会在 Google 或百度等搜索引擎中输入关键词比如输入“Lucene 全文检索框架”之后系统根据用户输入的关键词返回相关信息。一次检索大致可分为四步
第一步查询分析 正常情况下用户输入正确的查询比如搜索“里约奥运会”这个关键词用户输入正确完成一次搜索但是搜索通常都是全开放的任何的用户输入都是有可能的很大一部分还是非常口语化和个性化的有时候还会存在拼写错误用户不小心把“淘宝”打成“涛宝”这时候需要用自然语言处理技术来做拼写纠错等处理以正确理解用户需求。
第二步分词技术 这一步利用自然语言处理技术将用户输入的查询语句进行分词如标准分词会把“lucene全文检索框架”分成 lucene | 全 | 文检索框架 IK分词会分成 lucene全文检索框架,还有简单分词等多种分词方法。
第三步关键词检索 提交关键词后在倒排索引库中进行匹配倒排索引就是关键词和文档之间的对应关系就像给文档贴上标签。比如在文档集中含有 lucene 关键词的有文档1 、文档 6、文档9含有 全文检索 关键词的有文档1 、文档6 那么做与运算同时含有 lucene 和 全文检索 的文档就是文档1和文档6在实际的搜索中会有更复杂的文档匹配模型。
第四步搜索排序 对多个相关文档进行相关度计算、排序返回给用户检索结果。 3.2 Lucene 倒排索引核心原理
Lucene 是一个成熟的权威检索库具有高性能、可伸缩的特点并且开源、免费。在其基础上开发的分布式搜索引擎便是 Elasticsearch。 Elasticsearch 的搜索原理简单过程是索引系统通过扫描文章中的每一个词对其创建索引指明在文章中出现的次数和位置当用户查询时索引系统就会根据事先的索引进行查找并将查找的结果反馈给用户的检索方式。
倒排索引
倒排索引是整个 ES 的核心正常的搜索以一本书为例应该是由 “目录 - 章节 - 页码 - 内容” 这样的查找顺序这样是正排索引的思想。 但是设想一下我在一本书中快速查找 “elasticsearch” 这个关键字所在的页面该怎么办 倒排索引的思路是通过单词到文档ID的关系对应。 倒排索引包含两个部分 单词词典Term Dictionary记录所有文档的单词记录单词到倒排列表的关联关系单词词典一般比较大通过 B 树或哈希拉链法实现以满足高性能的插入与查询 倒排表Posting List记录了单词对应的文档结合由倒排索引组成。 文档ID 词频 TF - 该单词在文档中分词的位置。用于语句搜索 位置Position- 单词在文档中分词的位置用于语句搜索 偏移Offset- 记录单词的开始结束位置实现高亮显示。
如何理解倒排索引呢假如现有三份数据文档文档的内容如下分别是 Java is the best programming language. PHP is the best programming language. Javascript is the best programming language.
为了创建倒排索引我们通过分词器将每个文档的内容域拆分成单独的词我们称它为词条或 Term创建一个包含所有不重复词条的排序列表然后列出每个词条出现在哪个文档。
结果如下所示
Term Doc_1 Doc_2 Doc_3
-------------------------------------
Java | X | |
is | X | X | X
the | X | X | X
best | X | X | X
programming | x | X | X
language | X | X | X
PHP | | X |
Javascript | | | X
-------------------------------------
这种结构由文档中所有不重复词的列表构成对于其中每个词都有一个文档列表与之关联。
这种由属性值来确定记录的位置的结构就是倒排索引。带有倒排索引的文件我们称为倒排文件。
我们将上面的内容转换为图的形式来说明倒排索引的结构信息如下图所示 其中主要有如下几个核心术语需要理解 词条Term索引里面最小的存储和查询单元对于英文来说是一个单词对于中文来说一般指分词后的一个词。 词典Term Dictionary或字典是词条 Term 的集合。搜索引擎的通常索引单位是单词单词词典是由文档集合中出现过的所有单词构成的字符串集合单词词典内每条索引项记载单词本身的一些信息以及指向“倒排列表”的指针。 倒排表Post list一个文档通常由多个词组成倒排表记录的是某个词在哪些文档里出现过以及出现的位置。
每条记录称为一个倒排项Posting。倒排表记录的不单是文档编号还存储了词频等信息。 倒排文件Inverted File所有单词的倒排列表往往顺序地存储在磁盘的某个文件里这个文件被称之为倒排文件倒排文件是存储倒排索引的物理文件。
像 B 树一样可以在页里实现二分查找。 Lucene 的倒排索引增加了最左边的一层「字典树」term index它不存储所有的单词只存储单词前缀通过字典树找到单词所在的块也就是单词的大概位置再在块里二分查找找到对应的单词再找到单词对应的文档列表。
Lucene 的实现会要更加复杂针对不同的数据结构采用不同的字典索引使用了FST模型、BKDTree等结构。
真实的倒排记录也并非一个链表而是采用了SkipList、BitSet等结构 四、Elasticsearch 整体架构 Document文档指一行数据 Index索引是多个document的集合和sql数据库的表对应 Shard分片当有大量的文档时由于内存的限制、磁盘处理能力不足、无法足够快的响应客户端的请求等一个节点可能不够。这种情况下数据可以分为较小的分片。每个分片放到不同的服务器上。 当你查询的索引分布在多个分片上时ES会把查询发送给每个相关的分片并将结果组合在一起而应用程序并不知道分片的存在。即这个过程对用户来说是透明的 Replia副本为提高查询吞吐量或实现高可用性可以使用分片副本。 副本是一个分片的精确复制每个分片可以有零个或多个副本。ES中可以有许多相同的分片其中之一被选择更改索引操作这种特殊的分片称为主分片。 当主分片丢失时如该分片所在的数据不可用时集群将副本提升为新的主分片。 Node节点形成集群的每个服务器称为节点一个节点可以包含多个shard Cluster集群ES可以作为一个独立的单个搜索服务器。不过为了处理大型数据集实现容错和高可用性ES可以运行在许多互相合作的服务器上。这些服务器的集合称为集群。 4.1 集群节点角色 ES集群的服务器主要分为以下三种角色
1master节点负责保存和更新集群的一些元数据信息之后同步到所有节点所以每个节点都需要保存全量的元数据信息 集群的配置信息 集群的节点信息 模板template设置 索引以及对应的设置、mapping、分词器和别名 索引关联到的分片以及分配到的节点
主节点负责创建索引、删除索引、跟踪哪些节点是群集的一部分并决定哪些分片分配给相关的节点、追踪集群中节点的状态等稳定的主节点对集群的健康是非常重要的。
2data节点负责数据存储和查询
数据节点负责数据的存储和相关的操作例如对数据进行增、删、改、查和聚合等操作所以数据节点Data 节点对机器配置要求比较高对 CPU、内存和 I/O 的消耗很大。
3coordinator节点协调节点 路由索引请求 聚合搜索结果集 分发批量索引请求
4候选主节点
可以被选举为主节点Master 节点集群中只有候选主节点才有选举权和被选举权其他节点不参与选举的工作。
master选举选举策略 1. 如果集群中存在master认可该master加入集群
2. 如果集群中不存在master从具有master资格的节点中选id最小的节点作为master选举时机
如果你使用 Master 候选节点作为单播列表你只要列出三个就可以了。这个配置在 elasticsearch.yml 文件中
discovery.zen.ping.unicast.hosts: [host1, host2:port]
每个节点既可以是候选主节点也可以是数据节点通过在配置文件 ../config/elasticsearch.yml 中设置即可默认都为 true。
node.master: true //是否候选主节点
node.data: true //是否数据节点
3. 集群启动后台启动线程去ping集群中的节点按照上述策略从具有master资格的节点中选举出master 4. 现有的master离开集群后台一直有一个线程定时ping master节点超过一定次数没有ping成功之后重新进行master的选举避免脑裂 脑裂问题是采用master-slave模式的分布式集群普遍需要关注的问题脑裂一旦出现会导致集群的状态出现不一致导致数据错误甚至丢失。 5. ES避免脑裂的策略过半原则可以在ES的集群配置中添加一下配置避免脑裂的发生
4.2 数据副本 ES通过副本分片的方式保证集群数据的高可用同时增加集群并发处理查询请求的能力相应的在数据写入阶段会增大集群的写入压力。
数据写入的过程中首先被路由到主分片写入成功之后将数据发送到副本分片为了保证数据不丢失最好保证至少一个副本分片写入成功以后才返回客户端成功。
4.3 水平扩容 Node 1 和 Node 2 上各有一个分片被迁移到了新的 Node 3 节点现在每个节点上都拥有2个分片而不是之前的3个。 这表示每个节点的硬件资源CPU, RAM, I/O将被更少的分片所共享每个分片的性能将会得到提升。
分片是一个功能完整的搜索引擎它拥有使用一个节点上的所有资源的能力。 我们这个拥有6个分片3个主分片和3个副本分片的索引可以最大扩容到6个节点每个节点上存在一个分片并且每个分片拥有所在节点的全部资源。
但是如果我们想要扩容超过6个节点怎么办呢
主分片的数目在索引创建时就已经确定了下来。实际上这个数目定义了这个索引能够 存储 的最大数据量。实际大小取决于你的数据、硬件和使用场景。 但是读操作——搜索和返回数据——可以同时被主分片 或 副本分片所处理所以当你拥有越多的副本分片时也将拥有越高的吞吐量。
在运行中的集群上是可以动态调整副本分片数目的我们可以按需伸缩集群。让我们把副本数从默认的 1 增加到 2 4.4 故障转移
如果我们关闭第一个节点这时集群的状态为 我们关闭的节点是一个主节点。而集群必须拥有一个主节点来保证正常工作所以发生的第一件事情就是选举一个新的主节点 Node 2 。
在我们关闭 Node 1 的同时也失去了主分片 1 和 2 并且在缺失主分片的时候索引也不能正常工作。 如果此时来检查集群的状况我们看到的状态将会为 red 不是所有主分片都在正常工作。
幸运的是在其它节点上存在着这两个主分片的完整副本 所以新的主节点立即将这些分片在 Node 2 和 Node 3 上对应的副本分片提升为主分片。
4.5 路由机制
当索引一个文档的时候文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢当我们创建文档时它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢
首先这肯定不会是随机的否则将来要获取文档的时候我们就不知道从何处寻找了。实际上这个过程是根据下面这个公式决定的
shard hash(routing) % number_of_primary_shards
routing 是一个可变值默认是文档的 _id 也可以设置成一个自定义的值。 routing 通过 hash 函数生成一个数字然后这个数字再除以 number_of_primary_shards 主分片的数量后得到 余数 。这个分布在 0 到 number_of_primary_shards-1 之间的余数就是我们所寻求的文档所在分片的位置。
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量 并且永远不会改变这个数量因为如果数量变化了那么所有之前路由的值都会无效文档也再也找不到了。
4.6 新建、更新、删除文档 客户端选择一个 node 发送请求过去这个 node 就是 coordinating node 协调节点。 coordinating node 对 document 进行路由将请求转发给对应的 node有 primary shard。 实际的 node 上的 primary shard 处理请求然后将数据同步到 replica node 。 coordinating node 如果发现 primary node 和所有 replica node 都搞定之后就返回响应结果给客户端。 4.6.1 写数据底层原理
write - refresh - flush - merge 4.6.2 索引的不变性
由于倒排索引的结构特性在索引建立完成后对其进行修改将会非常复杂。再加上几层索引嵌套更让索引的更新变成了几乎不可能的动作。 所以索性设计成不可改变的倒排索引被写入磁盘后是不可改变的它永远不会修改。不变性有重要的价值 1. 不需要锁。如果你从来不更新索引你就不需要担心多进程同时修改数据的问题。 2. 一旦索引被读入内核的文件系统缓存便会留在哪里由于其不变性。只要文件系统缓存中还有足够的空间那么大部分读请求会直接请求内存而不会命中磁盘。这提供了很大的性能提升。 3. 其它缓存(像filter缓存)在索引的生命周期内始终有效。它们不需要在每次数据改变时被重建因为数据不会变化。
4. 写入单个大的倒排索引允许数据压缩减少磁盘 I/O 和 需要被缓存到内存的索引的使用量。
当然一个不变的索引也有不好的地方。主要事实是它是不可变的你不能修改它。如果你需要让一个新的文档 可被搜索你需要重建整个索引。这要么对一个索引所能包含的数据量造成了很大的限制要么对索引可被更新的频率造成了很大的限制。
怎样在保留不变性的前提下实现倒排索引的更新答案是: 用更多的索引。
通过增加新的补充索引来反映新近的修改而不是直接重写整个倒排索引。每一个倒排索引都会被轮流查询到—从最早的开始—查询完后再对结果进行合并。
4.6.3 动态索引创建过程 writeroute协调节点默认使用文档ID进行计算也支持通过 routing为路由提供合适的分片。 shard hash(document_id) % (num_of_primary_shards) refresh当分片所在的节点接收到来自协调节点Coordinating Node的请求后将请求写入到 Memory Buffer然后定时默认是每隔1s写入到 Filesystem Cache这个从 Memery Buffer 到 Filesystem Cache 的过程叫做 refresh。 flush假设当 Memory Buffer 和 Filesystem Cache 的数据丢失时ES 通过 translog 的机制来保证数据的不丢失。其实现机制是接收到请求后同时也会写入到 translog 中当 Filesystem Cache 中的数据写入到磁盘中时才会清除掉这个过程叫做 flush。在 flush 过程中内存中的缓冲将被清除内容被写入一个新的 SegmentSegment 的 fsync 将创建一个新的提交点 Commit Point并将内容刷新到磁盘旧的translog将被删除并开始一个新的translogflush 触发的时机是定时触发默认30分钟或者 translog 变得太大默认512M时。 merge由于自动刷新流程每秒会创建一个新的 Segment 这样会导致短时间内的 Segment 数量暴增。每一个 Segment 都会消耗文件句柄、内存和cpu运行周期。更重要的是每个搜索请求都必须轮流检查每个Segment 所以 Segment 越多搜索也就越慢。小的 Segment 被合并到 大的 Segment然后这些大的Segment 再合并到更大的 Segment。
# 一个 Segment 的内部
$ tree xgChCUdvTZ2G0dyJjGcp6A
xgChCUdvTZ2G0dyJjGcp6A
├── 0
│ ├── _state
│ │ ├── retention-leases-42.st
│ │ └── state-3.st
│ ├── index
│ │ ├── _1e.fdm
│ │ ├── _1e.fdt
│ │ ├── _1e.fdx
│ │ ├── _1e.fnm
│ │ ├── _1e.kdd
│ │ ├── _1e.kdi
│ │ ├── _1e.kdm
│ │ ├── _1e.si
│ │ ├── _1e_1.fnm
│ │ ├── _1e_1_Lucene90_0.dvd
│ │ ├── _1e_1_Lucene90_0.dvm
│ │ ├── _1e_Lucene90_0.doc
│ │ ├── _1e_Lucene90_0.dvd
│ │ ├── _1e_Lucene90_0.dvm
│ │ ├── _1e_Lucene90_0.tim
│ │ ├── _1e_Lucene90_0.tip
│ │ ├── _1e_Lucene90_0.tmd
│ │ ├── _1f.cfe
│ │ ├── _1f.cfs
│ │ ├── _1f.si
│ │ ├── segments_e
│ │ └── write.lock
│ └── translog
│ ├── translog-16.tlog
│ └── translog.ckp
└── _state└── state-8.st
4.6.4 分步查看数据持久化过程
write - refresh - flush - merge write 过程 一个新文档过来会存储在 in-memory buffer 内存缓冲区中顺便会记录 TranslogElasticsearch 通过事务日志在每一次对 Elasticsearch 进行操作时记录操作。
这个时候数据还没有到 segment搜不到新文档。数据只有被 refresh 后才可以被搜索到。 refresh 过程 refresh 默认1s可通过 index.refresh_interval 设置。refresh 流程大致如下 in-memory buffer 中的文档写入到新的 segment 中但 segment 是存储在文件系统的缓存中。此时文档已经可以被搜索到。 最后清空 in-memory buffer。注意Translog 没有被清空为了将 segment 写到磁盘中。 文档经过 refresh 后segment 暂时写到文件系统缓存。这样避免了性能 IO 操作又可以使文档搜索到 refresh 每秒执行一次性能损耗较大一般建议稍微延长这个 refresh 时间间隔比如 5s。这样做到准实时就可以了。 flush 过程
每隔一段时间如果 translog 变得越来越大索引会被刷新flush一个新的 translog 被创建并且一个全量提交被执行 上个过程 segment 在文件系统缓存中会有意外故障文档丢失那么为了保证文档不会丢失需要将文档从文件缓存写入磁盘的过程就是 flush写入磁盘后清空 translog具体过程如下 所有的内存缓冲区的文档被写入一个新的 Segment。 缓冲区被清空。 一个 Commit Point 被写入硬盘。 文件系统缓存通过 fsync 被刷新flush。 老的 translog 被删除。 merge 过程
由于自动刷新流程每秒会创建一个新的 Segment 这样会导致短时间内的 Segment 数量暴增。而 Segment 数目太多会带来较大的麻烦。 每一个 Segment 都会消耗文件句柄、内存和cpu运行周期。更重要的是每个搜索请求都必须轮流检查每个Segment 所以 Segment 越多搜索也就越慢。
Elasticsearch 通过在后台进行 Merge Segment 来解决这个问题小的 Segment 被合并到 大的 Segment然后这些大的Segment 再合并到更大的 Segment。
当索引的时候 refresh 操作会创建新的 Segment 并将Segment 打开供搜索使用合并进程选择一小部分大小相似的段并且在后台将他们合并到更大的段中。这并不会中断索引和搜索。 合并大的段需要消耗大量的I/O和CPU资源如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制所以搜索仍然 有足够的资源很好地执行。 4.6.5 更新/删除数据底层原理
如果是删除操作commit 的时候会生成一个 .del 文件里面将某个 doc 标识为 deleted 状态那么搜索的时候根据 .del 文件就知道这个 doc 是否被删除了。
如果是更新操作就是将原来的 doc 标识为 deleted 状态然后新写入一条数据。
buffer 每 refresh 一次就会产生一个 segment file 所以默认情况下是 1 秒钟一个 segment file 这样下来 segment file 会越来越多此时会定期执行 merge。每次 merge 的时候会将多个 segment file 合并成一个同时这里会将标识为 deleted 的 doc 给物理删除掉然后将新的 segment file 写入磁盘这里会写一个 commit point 标识所有新的 segment file 然后打开 segment file 供搜索使用同时删除旧的 segment file 。 4.7 查询文档
可以从主分片或者从其它任意副本分片检索文档 可以通过 doc id 来查询会根据 doc id 进行 hash判断出来当时把 doc id 分配到了哪个 shard 上面去从那个 shard 去查询。
shard hash(document_id) % (num_of_primary_shards) 客户端发送请求到任意一个 node成为 coordinate node 。 coordinate node 对 doc id 进行哈希路由将请求转发到对应的 node此时会使用 round-robin 随机轮询算法在 primary shard 以及其所有 replica 中随机选择一个让读请求负载均衡。 接收请求的 node 返回 document 给 coordinate node 。 coordinate node 返回 document 给客户端。
4.8 更新文档 以下是部分更新一个文档的步骤 客户端向 Node 1 发送更新请求。 它将请求转发到主分片所在的 Node 3 。 Node 3 从主分片检索文档修改 _source 字段中的 JSON 并且尝试重新索引主分片的文档。 如果文档已经被另一个进程修改它会重试步骤 3 超过 retry_on_conflict 次后放弃。 如果 Node 3 成功地更新文档它将新版本的文档并行转发到 Node 1 和 Node 2 上的副本分片重新建立索引。 一旦所有副本分片都返回成功 Node 3 向协调节点也返回成功协调节点向客户端返回成功。
4.9 分布式检索
所有的搜索系统一般都是两阶查询第一阶段查询到匹配的 DocID第二阶段再查询 DocID 对应的完整文档。 在初始查询阶段时查询会广播到索引中每一个分片拷贝主分片或者副本分片每个分片在本地执行搜索并构建一个匹配文档大小为 from size 的优先队列。搜索时会查询 Filesystem Cache 但有部分数据还在 Memory Buffer,所以搜索是近实时的。 每个分片返回各自优先队列中所有文档 ID 和排序值给协调结点。 协调节点辨别出哪些些文档需要被取回并向相关的分片提交多个 GET 请求每个分片加载并丰富文档所有文档取回后协调结点返回结果给客户端。
查询阶段
在初始查询阶段时查询会广播到索引中每一个分片拷贝主分片或者副本分片。 每个分片在本地执行搜索并构建一个匹配文档的优先队列。 查询阶段包含以下三个步骤: 客户端发送一个 search 请求到 Node 3 Node 3 会创建一个大小为 from size 的空优先队列。 Node 3 将查询请求转发到索引的每个主分片或副本分片中。每个分片在本地执行查询并添加结果到大小为 from size 的本地有序优先队列中。 每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点也就是 Node 3 它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
当一个搜索请求被发送到某个节点时这个节点就变成了协调节点。 这个节点的任务是广播查询请求到所有相关分片并将它们的响应整合成全局排序后的结果集合这个结果集合会返回给客户端。
协调节点将这些分片级的结果合并到自己的有序优先队列里它代表了全局排序结果集合。至此查询过程结束。
取回阶段
查询阶段标识哪些文档满足搜索请求但是我们仍然需要取回这些文档这是取回阶段的任务。 分布式阶段由以下步骤构成 协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。 每个分片加载并 丰富 文档如果有需要的话接着返回文档给协调节点。 一旦所有的文档都被取回了协调节点返回结果给客户端。
协调节点首先决定哪些文档确实需要被取回。例如如果我们的查询指定了 { from: 90, size: 10 } 最初的90个结果会被丢弃只有从第91个开始的10个结果需要被取回。这些文档可能来自和最初搜索请求有关的一个、多个甚至全部分片。
深分页 每个分片必须先创建一个 from size 长度的队列协调节点需要根据 number_of_shards * (from size) 排序文档来找到被包含在 size 里的文档。 取决于你的文档的大小分片的数量和你使用的硬件给 10,000 到 50,000 的结果文档深分页 1,000 到 5,000 页是完全可行的。但是使用足够大的 from 值排序过程可能会变得非常沉重使用大量的CPU、内存和带宽。
五、ElasticSearch实际使用过程中会有什么问题
5.1 分片的设定
分片数过小数据写入形成瓶颈无法水平拓展
分片数过多每个分片都是一个lucene的索引分片过多将会占用过多资源
如何计算分片数
需要注意分片数量最好设置为节点数的整数倍保证每一个主机的负载是差不多一样的特别的如果是一个主机部署多个实例的情况更要注意这一点否则可能遇到其他主机负载正常就某个主机负载特别高的情况。
一般我们根据每天的数据量来计算分片保持每个分片的大小在 50G 以下比较合理。如果还不能满足要求那么可能需要在索引层面通过拆分更多的索引或者通过别名 按小时 创建索引的方式来实现了。
5.2 ES数据近实时问题
ES数据写入之后要经过一个refresh操作之后才能够创建索引进行查询。但是get查询很特殊数据实时可查。
ES5.0之前translog可以提供实时的CRUDget查询会首先检查translog中有没有最新的修改然后再尝试去segment中对id进行查找。5.0之后为了减少translog设计的负责性以便于再其他更重要的方面对translog进行优化所以取消了translog的实时查询功能。
get查询的实时性通过每次get查询的时候如果发现该id还在内存中没有创建索引那么首先会触发refresh操作来让id可查。
5.3 深分页问题
解决方案1服务端缓存 Scan and scroll API
为了返回某一页记录其实我们抛弃了其他的大部分已经排好序的结果。那么简单点就是把这个结果缓存起来下次就可以用上了。根据这个思路ES提供了Scroll API。它概念上有点像传统数据库的游标(cursor)。
scroll调用本质上是实时创建了一个快照(snapshot)然后保持这个快照一个指定的时间这样下次请求的时候就不需要重新排序了。从这个方面上来说scroll就是一个服务端的缓存。既然是缓存就会有下面两个问题 一致性问题。ES的快照就是产生时刻的样子了在过期之前的所有修改它都视而不见。 服务端开销。ES这里会为每一个scroll操作保留一个查询上下文(Search context)。ES默认会合并多个小的索引段(segment)成大的索引段来提供索引速度在这个时候小的索引段就会被删除。但是在scroll的时候如果ES发现有索引段正处于使用中那么就不会对它们进行合并。这意味着需要更多的文件描述符以及比较慢的索引速度。
其实这里还有第三个问题但是它不是缓存的问题而是因为ES采用的游标机制导致的。就是你只能顺序的扫描不能随意的跳页。而且还要求客户每次请求都要带上”游标”。
解决方案2Search After
Scroll API相对于fromsize方式当然是性能好很多但是也有如下问题 Search context开销不小。 是一个临时快照并不是实时的分页结果。
针对这些问题ES 5.0 开始推出了Search After机制可以提供了更实时的游标(live cursor)。它的思想是利用上一页的分页结果来提高下一页的分页请求。
六、ES性能优化
存储设备
磁盘在现代服务器上通常都是瓶颈。Elasticsearch 重度使用磁盘你的磁盘能处理的吞吐量越大你的节点就越稳定。
这里有一些优化磁盘 I/O 的技巧 使用 SSD。就像其他地方提过的 他们比机械磁盘优秀多了。 使用 RAID 0。条带化 RAID 会提高磁盘 I/O代价显然就是当一块硬盘故障时整个就故障了。不要使用镜像或者奇偶校验 RAID 因为副本已经提供了这个功能。 另外使用多块硬盘并允许 Elasticsearch 通过多个 path.data 目录配置把数据条带化分配到它们上面。 不要使用远程挂载的存储比如 NFS 或者 SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰的。 如果你用的是 EC2当心 EBS。即便是基于 SSD 的 EBS通常也比本地实例的存储要慢。
内部索引优化 Elasticsearch 为了能快速找到某个 Term先将所有的 Term 排个序然后根据二分法查找 Term时间复杂度为 logN就像通过字典查找一样这就是 Term Dictionary。
现在再看起来似乎和传统数据库通过 B-Tree 的方式类似。但是如果 Term 太多Term Dictionary 也会很大放内存不现实于是有了 Term Index。
就像字典里的索引页一样A 开头的有哪些 Term分别在哪页可以理解 Term Index是一棵树。
这棵树不会包含所有的 Term它包含的是 Term 的一些前缀。通过 Term Index 可以快速地定位到 Term Dictionary 的某个 Offset然后从这个位置再往后顺序查找。
在内存中用 FST 方式压缩 Term IndexFST 以字节的方式存储所有的 Term这种压缩方式可以有效的缩减存储空间使得 Term Index 足以放进内存但这种方式也会导致查找时需要更多的 CPU 资源。
对于存储在磁盘上的倒排表同样也采用了压缩技术减少存储所占用的空间。
调整配置参数
调整配置参数建议如下 给每个文档指定有序的具有压缩良好的序列模式 ID避免随机的 UUID-4 这样的 ID这样的 ID 压缩比很低会明显拖慢 Lucene。 对于那些不需要聚合和排序的索引字段禁用 Doc values。Doc Values 是有序的基于 documentfield value 的映射列表。 不需要做模糊检索的字段使用 Keyword 类型代替 Text 类型这样可以避免在建立索引前对这些文本进行分词。 如果你的搜索结果不需要近实时的准确度考虑把每个索引的 index.refresh_interval 改到 30s 。
如果你是在做大批量导入导入期间你可以通过设置这个值为 -1 关掉刷新还可以通过设置 index.number_of_replicas: 0 关闭副本。别忘记在完工的时候重新开启它。 避免深度分页查询建议使用 Scroll 进行分页查询。普通分页查询时会创建一个 fromsize 的空优先队列每个分片会返回 fromsize 条数据默认只包含文档 ID 和得分 Score 给协调节点。
如果有 N 个分片则协调节点再对fromsize×n 条数据进行二次排序然后选择需要被取回的文档。当 from 很大时排序过程会变得很沉重占用 CPU 资源严重。 减少映射字段只提供需要检索聚合或排序的字段。其他字段可存在其他存储设备上例如 Hbase在 ES 中得到结果后再去 Hbase 查询这些字段。 创建索引和查询时指定路由 Routing 值这样可以精确到具体的分片查询提升查询效率。路由的选择需要注意数据的分布均衡。
JVM 调优
JVM 调优建议如下 确保堆内存最小值 Xms 与最大值 Xmx 的大小是相同的防止程序在运行时改变堆内存大小。
Elasticsearch 默认安装后设置的堆内存是 1GB。可通过 ../config/jvm.option 文件进行配置但是最好不要超过物理内存的50%和超过 32GB。 GC 默认采用 CMS 的方式并发但是有 STW 的问题可以考虑使用 G1 收集器。 ES 非常依赖文件系统缓存Filesystem Cache快速搜索。一般来说应该至少确保物理上有一半的可用内存分配到文件系统缓存。
七、ElasticSearch运维 磁盘打满
删除不用的索引
获取磁盘空间情况
GET /_cat/allocation?v
查看索引占用情况
GET _cat/indices?v
查看索引占用情况按索引排序
GET _cat/indices?vsindex:asc
删除索引
DELETE onebyone-bizmember-k8s-logs-2023.05.30-171317 节点挂掉
参考
理解ElasticSearch工作原理
看完这篇还不会 Elasticsearch我跪搓衣板
elasticsearch 原理及入门
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/931706.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!