七嘴八舌Elasticsearch索引
2021-10-23 18:09:09 27 举报
说说分布式搜索引擎的索引
作者其他创作
大纲/内容
PART-1(M)
“我们聊了很多“较上层”的东西,而且还有很多没有说。。。但是实际上,我觉得再放慢点,先了解下es的真正底层Lucene是什么!”
“其实大部分稍微高端一点的玩家都或多或少接触过elasticsearch。”
shard-2(M)
cluster
首先我们先看几个关于分布式系统的问题!
127.0.0.2
分段-segment
index_person
PART-2(M)
127.0.0.1
当我这么问你:我们都知道es的数据被存储在“index(索引)”里面,而且你或许也知道es本身是基于Lucene实现的,那么es的索引和Lucene的索引是一个东西吗?如果不是,有什么区别呢? 我觉得大部分人可能都不能很完整的说出来,我也一样!主要是我也只是停留在使用层次,可能稍微用的多一些而已,里面的各种查询、聚合、分析都有用,但是涉及原理的东西却是不是很了解。所以今天,放下身段好好地学习记录一下!
假设我们不指定文档的ID,那么es会生成一个随机id给这条记录,然后就是关键的一步:确定这条文档要写的分片!这里有一个公式:最终落地分片 = hash(文档id) % 总的主分片数。shard = hash(document_id) % (num_of_primary_shards)根据文档id-hash后对总主分片数取模就可以知道要放哪里了。这里又两个结果:1. 确定是shard-1,那么直接将数据缓存存储就行了;2. 确定是shard-2,那么问题来了,127.0.0.1只有shard1的主分片,副本节点只是复制是不能写的。那是不是要让客户端重新发请求到127.0.0.2呢?“ 为什么我这里这么问呢?如果大家熟系redis集群就明白了,如果你客户端查询某个缓存不在指定节点的时候,服务器会返回一个move,告诉请你移步指定节点。i style=\
index_person -> [ { \"_id\
Lucene
field
field value
elasticsearch
PART-1(R)
es:
PART-2(R)
所以,lucene中的segment就是我们索引的最小逻辑单元。实际存储在磁盘上的文件肯定不是 segment.txt 或者 segment.doc 这种,也不是xxx.segment 这种,而是多种小文件组成。这些文件本身包含一些数据结构,我们把这些实际的物理存储文件的组合叫做segment。了解了这个以后,我们就可以继续扩充我们的的索引的结构图,如下:
分区-partition
document
首先,我们要达成一个共识就是:分布式系统跟单体系统来比,多了这么多好处,难道就没有一个缺点?不可能,所有命运赠送的礼物早已在暗中被标好了价格!分布式系统的复杂性不是单体系统可以比的!那么像ES这种分布式存储系统,如果保证高可用呢? 高可用的维度太多,我们单单说分布式存储的话总结就一句话:我的数据你怎么保证不会丢? 其实大部分分布式存储保证数据高可用的方法就是副本!这里我举几个我平时打交道的产品:Kafka(消息副本),集群redis中的主从(从副本),hdfs(数据副本)等等,只要是分布式数据系统,必然离不开副本这个玩意儿 。。。所以ES也是一样的,你索引的数据不会只存储一份,一定是用副本冗余来保证可用性!
PART-3(R)
shard-2(R)
从上面我们对分布式系统的分析来说,index_person这个索引的数据肯定是分开存储的,part-1和part-2的数据是分别存储在两台机器上面且存储的数据不一样(127.0.0.1 和 127.0.0.2)但是这里是没有副本的,我们还需要高可用啊!所以做了下面这个升级 ...
kafka:
问题一:分布式系统的分布式体现在哪里呢?
主题-topic
anything
PART-3(M)
物理文件(倒排索引,正向索引等)
index_personpart-2
这里假设请求到了127.0.0.1
term
segment-3
现在,我们已经知道了Lucene本来已经有了这些概念,es也是建立在Lucene基础之上的。那么在es出现之前,我们索引一条上面这种记录在Lucene之中的时候,到底是如何存储的呢?Lucene中还有一个es中没有的概念叫:segment!
PUT {\"user\":\"a\
说出来,你可能不信!如果你对kafka有了解的话,可以发现两者的结构是“几乎完全一样”的。。。 可见很多分布式系统的设计都是相似的。。。
如右图,我们将每个PART都存储两份:1. 一份main主数据2. 一份replica复制数据127.0.0.1 上存储了part1的主数据和part2的副本数据;127.0.0.2 上存储了part2的主数据和part1的副本数据;这么做的好处就是如果127.0.0.1机器down了,127.0.0.2可以顶上去,而且拥有全量数据,你查询的时候我可以正常返回你需要的,不会出现丢数据的情况!
segment-1
问题二:分布式系统如何保证高可用呢?
water
系统有很多,但分布式系统的一个很重要的区别在于“分布式”!当我们说像ES这样的分布式存储引擎的时候,“分布式”主要体现在数据可以分开存储! 我们对比经典的数据库mysql,一条insert命令传到mysql之后,数据最后是落地到磁盘的聚集索引里面吧,但还不是放到mysql服务器的具体一台机器上。 然而像一些分布式存储引擎,数据并不是放到一台机器上的,而是分开存储在各个地方,这些地方都有一个特点,那就是上面也跑着一个服务,所以这里又引出了一个“分布式”很重要的特点:可拓展!所以,当你需要的时候就可以加一台机器到整个集群里面,这样当新的索引请求过来了,数据可以落地到新的伙伴节点上,这个体现出我们所说的“分布式”!
shard-1(M)
segment-2
index_personpart-1
当有一个存储的请求过来,肯定是随便选一个节点请求的,那么收到请求的节点会说什么呢
shard-1(R)
那我们想想,这样就够了吗?看上去数据也分开存储了,也有副本了,好像一切都没什么问题了!不要被我吓到了哈,确实够了(滑稽)其实做到这里已经满足了基本的分布式的特性,且整个es也可以提供基本的服务了!但是,现在有一个很重要的问题,作为一个设计者,其实已经做了很多,但是作为开发者,我们必须考虑另外一个问题:index_person的数据被分成了part-1和part-2两部分,那么是怎么分的呢?我查询的时候又需要怎么查询呢?我们不能只有笔杆子啊,还要有枪杆子!在开始之前,需要先规范化我们的叫法,我们前面一直叫part。其实在es里面,我们把这个part叫做shard(分片),不管是part还是分片都是一个东西,李姐万岁!
这个图自己画有点麻烦,就借用官方图了:过程是这样的:1:请求到node-1(127.0.0.1)然后对文档进行hash发现实际上要写到P0。2:那么就将请求转发到Node-3(127.0.0.3),因为P0的主节点在3号节点上。3:当Node-3写成功后,因为副本机制,所以需要同步写副本(127.0.0.1,127.0.0.2)这个时候再次请求转发两个副本节点4:待大家都写完了,那么这条数据就算真实的完成索引!
index name
127.0.0.3
一条新的index_person文档被索引的过程是什么样的呢?
分片-shard
索引-index
- Index:索引,由很多的Document组成。- Document:由很多的Field组成,是Index和Search的最小单位。- Field:由很多的Term组成,包括Field Name和Field Value。- Term:由很多的字节组成。一般将Text类型的Field Value分词之后的每个最小单元叫做Term。可以看到,我们熟知的索引/文档/字段/单词 其实都是Lucene的概念,并不是es创造出来的!
物理文件(索引,消息日志等)
field name
0 条评论
下一页