learn-tech/专栏/高并发系统实战课/12引擎分片:Elasticsearch如何实现大数据检索?.md
2024-10-16 11:38:31 +08:00

134 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
12 引擎分片Elasticsearch如何实现大数据检索
你好,我是徐长龙。
上节课我们看到了ELK对日志系统的强大支撑如果没有它的帮助我们自己实现分布式链路跟踪其实是十分困难的。
为什么ELK功能这么强大这需要我们了解ELK中储存、索引等关键技术点的架构实现才能想清楚。相信你学完今天的内容你对大数据分布式的核心实现以及大数据分布式统计服务都会有更深入的理解。
Elasticsearch架构
那么ELK是如何运作的它为什么能够承接如此大的日志量
我们先分析分析ELK的架构长什么样事实上它和OLAP及OLTP的实现区别很大我们一起来看看。Elasticsearch架构如下图
我们对照架构图梳理一下整体的数据流向可以看到我们项目产生的日志会通过Filebeat或Rsyslog收集将日志推送到Kafka内。然后由LogStash消费Kafka内的日志、对日志进行整理并推送到ElasticSearch集群内。
接着,日志会被分词,然后计算出在文档的权重后,放入索引中供查询检索, Elasticsearch会将这些信息推送到不同的分片。每个分片都会有多个副本数据写入时只有大部分副本写入成功了主分片才会对索引进行落地需要你回忆下分布式写一致知识
Elasticsearch集群中服务分多个角色我带你简单了解一下
Master节点负责集群内调度决策集群状态、节点信息、索引映射、分片信息、路由信息Master真正主节点是通过选举诞生的一般一个集群内至少要有三个Master可竞选成员防止主节点损坏回忆下之前Raft知识不过Elasticsearch刚出那会儿还没有Raft标准
Data存储节点用于存储数据及计算分片的主从副本热点节点冷数据节点
Client协调节点协调多个副本数据查询服务聚合各个副本的返回结果返回给客户端
Kibana计算节点作用是实时统计分析、聚合分析统计数据、图形聚合展示。
实际安装生产环境时Elasticsearch最少需要三台服务器三台中有一台会成为Master节点负责调配集群内索引及资源的分配而另外两个节点会用于Data数据存储、数据检索计算当Master出现故障时子节点会选出一个替代故障的Master节点回忆下分布式共识算法中的选举
如果我们的硬件资源充裕我们可以另外增加一台服务器将Kibana计算独立部署这样会获得更好的数据统计分析性能。如果我们的日志写入过慢可以再加一台服务器用于Logstash分词协助加快ELK整体入库的速度。
要知道最近这几年大部分云厂商提供的日志服务都是基于ELK实现的Elasticsearch已经上市可见其市场价值。
Elasticsearch的写存储机制
下图是Elasticsearch的索引存储具体的结构看起来很庞大但是别担心我们只需要关注分片及索引部分即可
我们再持续深挖一下Elasticsearch是如何实现分布式全文检索服务的写存储的。其底层全文检索使用的是Lucene引擎事实上这个引擎是单机嵌入式的并不支持分布式分布式功能是基础分片来实现的。
为了提高写效率常见分布式系统都会先将数据先写在缓存当数据积累到一定程度后再将缓存中的数据顺序刷入磁盘。Lucene也使用了类似的机制将写入的数据保存在Index Buffer中周期性地将这些数据落盘到segment文件。
再来说说存储方面Lucene为了让数据能够更快被查到基本一秒会生成一个segment文件这会导致文件很多、索引很分散。而检索时需要对多个segment进行遍历如果segment数量过多会影响查询效率为此Lucene会定期在后台对多个segment进行合并。
更多索引细节我稍后再给你介绍可以看到Elasticsearch是一个IO频繁的服务将新数据放在SSD上能够提高其工作效率。
但是SSD很昂贵为此Elasticsearch实现了冷热数据分离。我们可以将热数据保存在高性能SSD冷数据放在大容量磁盘中。
同时官方推荐我们按天建立索引当我们的存储数据量达到一定程度时Elasticsearch会把一些不经常读取的索引挪到冷数据区以此提高数据存储的性价比。而且我建议你创建索引时按天创建索引这样查询时。我们可以通过时间范围来降低扫描数据量。
另外Elasticsearch服务为了保证读写性能可扩容Elasticsearch对数据做了分片分片的路由规则默认是通过日志DocId做hash来保证数据分布均衡常见分布式系统都是通过分片来实现读写性能的线性提升。
你可以这样理解单个节点达到性能上限就需要增加Data服务器节点及副本数来降低写压力。但是副本加到一定程度由于写强一致性问题反而会让写性能下降。具体加多少更好呢这需要你用生产日志实测才能确定具体数值。
Elasticsearch的两次查询
前面提到多节点及多分片能够提高系统的写性能但是这会让数据分散在多个Data节点当中Elasticsearch并不知道我们要找的文档到底保存在哪个分片的哪个segment文件中。
所以,为了均衡各个数据节点的性能压力Elasticsearch每次查询都是请求所有索引所在的Data节点查询请求时协调节点会在相同数据分片多个副本中随机选出一个节点发送查询请求从而实现负载均衡。
而收到请求的副本会根据关键词权重对结果先进行一次排序当协调节点拿到所有副本返回的文档ID列表后会再次对结果汇总排序最后才会用 DocId去各个副本Fetch具体的文档数据将结果返回。
可以说Elasticsearch通过这个方式实现了所有分片的大数据集的全文检索但这种方式也同时加大了Elasticsearch对数据查询请求的耗时。下图是协调节点和副本的通讯过程
除了耗时这个方式还有很多缺点比如查询QPS低网络吞吐性能不高协助节点需要每次查询结果做分页分页后如果我们想查询靠后的页面要等每个节点先搜索和排序好该页之前的所有数据才能响应而且翻页跨度越大查询就越慢……
为此ES限制默认返回的结果最多1w条这个限制也提醒了我们不能将Elasticsearch的服务当作数据库去用。
还有一点实践的注意事项这种实现方式也导致了小概率个别日志由于权重太低查不到的问题。为此ES提供了search_type=dfs_query_then_fetch参数来应对特殊情况但是这种方式损耗系统资源严重非必要不建议开启。
除此之外Elasticsearch的查询有query and fetch、dfs query and fetch、dfs query then fetch三种不过它们和这节课主线关联不大有兴趣的话你可以课后自己了解一下。
Elasticsearch的倒排索引
我们再谈谈Elasticsearch的全文检索的倒排索引。
Elasticsearch支持多种查询方式不仅仅是全文检索如数值类使用的是BKD TreeElasticsearch的全文检索查询是通过Lucene实现的索引的实现原理和OLAP的LSM及OLTP的B+Tree完全不同它使用的是倒排索引Inverted Index
一般来说倒排索引常在搜索引擎内做全文检索使用其不同于关系数据库中的B+Tree和B-Tree 。B+Tree和B-Tree 索引是从树根往下按左前缀方式来递减缩小查询范围而倒排索引的过程可以大致分四个步骤分词、取出相关DocId、计算权重并重新排序、展示高相关度的记录。
首先对用户输入的内容做分词找出关键词然后通过多个关键词对应的倒排索引取出所有相关的DocId接下来将多个关键词设计索引ID做交集后再根据关键词在每个文档的出现次数及频率以此计算出每条结果的权重进而给列表排序并实现基于查询匹配度的评分然后就可以根据匹配评分来降序排序列出相关度高的记录。
下面我们简单看一下Lucene具体实现。
如上图Elasticsearch集群的索引保存在Lucene的segment文件中segment文件格式相关信息你可以参考 segment格式其中包括行存、列存、倒排索引。
为了节省空间和提高查询效率Lucene对关键字倒排索引做了大量优化segment主要保存了三种索引
Term Index单词词典索引用于关键词Term快速搜索Term index是基础Trie树改进的FSTFinite State Transducer有限状态传感器占用内存少实现的二级索引。平时这个树会放在内存中用于减少磁盘IO加快Term查找速度检索时会通过FST快速找到Term Dictionary对应的词典文件block。
Term Dictionary单词词典单词词典索引中保存的是单词Term与Posting List的关系而这个单词词典数据会按block在磁盘中排序压缩保存相比B-Tree更节省空间其中保存了单词的前缀后缀可以用于近似词及相似词查询通过这个词典可以找到相关的倒排索引列表位置。
Posting List倒排列表倒排列表记录了关键词Term出现的文档ID以及其所在文档中位置、偏移、词频信息这是我们查找的最终文档列表我们拿到这些就可以拿去排序合并了。
一条日志在入库时,它的具体内容并不会被真实保存在倒排索引中。
在日志入库之前会先进行分词过滤掉无用符号等分隔词找出文档中每个关键词Term在文档中的位置及频率权重然后将这些关键词保存在Term Index以及Term Dictionary内最后将每个关键词对应的文档ID和权重、位置等信息排序合并到Posting List中进行保存。通过上述三个结构就实现了一个优化磁盘IO的倒排索引。
而查询时Elasticsearch会将用户输入的关键字通过分词解析出来在内存中的Term Index单词索引查找到对应Term Dictionary字典的索引所在磁盘的block。接着由Term Dictionary找到对关键词对应的所有相关文档DocId及权重并根据保存的信息和权重算法对查询结果进行排序返回结果。
总结
不得不感叹Elasticsearch通过组合一片片小Lucene的服务就实现了大型分布式数据的全文检索。这无论放到当时还是现在都很不可思议。可以说了Elasticsearch 几乎垄断了所有日志实时分析、监控、存储、查找、统计的市场,其中用到的技术有很多地方可圈可点。
现在市面上新生代开源虽然很多但是论完善性和多样性能够彻底形成平台性支撑的开源仍然很少见。而Elasticsearch本身是一个十分庞大的分布式检索分析系统它对数据的写入和查询做了大量的优化。
我希望你关注的是Elasticsearch用到了大量分布式设计思路和有趣的算法比如分布式共识算法那时还没有Raft、倒排索引、词权重、匹配权重、分词、异步同步、数据一致性检测等。这些行业中的优秀设计值得我们做拓展了解推荐你课后自行探索。
思考题
如果让你实现一个Elasticsearch你觉得需要先解决的核心功能是什么
欢迎你在评论区与我交流讨论,我们下节课见!