elasticsearch 容量规划
一. ES的机制原理
ES的基本概念和基本操作介绍完了之后我们可能还有很多疑惑,它们内部是如何运行的?主分片和副本分片是如何同步的?创建索引的流程是什么样的?ES如何将索引数据分配到不同的分片上的?以及这些索引数据是如何存储的?为什么说ES是近实时搜索引擎而文档的 CRUD (创建-读取-更新-删除) 操作是实时的?以及Elasticsearch 是怎样保证更新被持久化在断电时也不丢失数据?还有为什么删除文档不会立刻释放空间?带着这些疑问我们进入接下来的内容。
写索引原理
下图描述了3个节点的集群,共拥有12个分片,其中有4个主分片(S0、S1、S2、S3)和8个副本分片(R0、R1、R2、R3),每个主分片对应两个副本分片,节点1是主节点(Master节点)负责整个集群的状态。
写索引是只能写在主分片上,然后同步到副本分片。这里有四个主分片,一条数据ES是根据什么规则写到特定分片上的呢?这条索引数据为什么被写到S0上而不写到S1或S2上?那条数据为什么又被写到S3上而不写到S0上了?
首先这肯定不会是随机的,否则将来要获取文档的时候我们就不知道从何处寻找了。实际上,这个过程是根据下面这个公式决定的:
shard = hash(routing) % number_of_primary_shards
routing 是一个可变值,默认是文档的 _id ,也可以设置成一个自定义的值。routing 通过 hash 函数生成一个数字,然后这个数字再除以 number_of_primary_shards (主分片的数量)后得到余数 。这个在 0 到 numberofprimary_shards-1 之间的余数,就是我们所寻求的文档所在分片的位置。
这就解释了为什么我们要在创建索引的时候就确定好主分片的数量并且永远不会改变这个数量:因为如果数量变化了,那么所有之前路由的值都会无效,文档也再也找不到了。
由于在ES集群中每个节点通过上面的计算公式都知道集群中的文档的存放位置,所以每个节点都有处理读写请求的能力。在一个写请求被发送到某个节点后,该节点即为前面说过的协调节点,协调节点会根据路由公式计算出需要写到哪个分片上,再将请求转发到该分片的主分片节点上。
假如此时数据通过路由计算公式取余后得到的值是 shard = hash(routing) % 4 = 0,则具体流程如下:
客户端向ES1节点(协调节点)发送写请求,通过路由计算公式得到值为0,则当前数据应被写到主分片S0上。
ES1节点将请求转发到S0主分片所在的节点ES3,ES3接受请求并写入到磁盘。
并发将数据复制到两个副本分片R0上,其中通过乐观并发控制数据的冲突。一旦所有的副本分片都报告成功,则节点ES3将向协调节点报告成功,协调节点向客户端报告成功。
存储原理
上面介绍了在ES内部索引的写处理流程,这个流程是在ES的内存中执行的,数据被分配到特定的分片和副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据。具体的存储路径可在配置文件 …/config/elasticsearch.yml中进行设置,默认存储在安装目录的data文件夹下。建议不要使用默认值,因为若ES进行了升级,则有可能导致数据全部丢失。
path.data: /path/to/data //索引数据
path.logs: /path/to/logs //日志记录
1.分段存储
索引文档以段的形式存储在磁盘上,何为段?索引文件被拆分为多个子文件,则每个子文件叫作段, 每一个段本身都是一个倒排索引,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。在底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。
段被写入到磁盘后会生成一个提交点,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。
段的概念提出主要是因为:在早期全文检索中为整个文档集合建立了一个很大的倒排索引,并将其写入磁盘中。如果索引有更新,就需要重新全量创建一个索引来替换原来的索引。这种方式在数据量很大时效率很低,并且由于创建一次索引的成本很高,所以对数据的更新不能过于频繁,也就不能保证时效性。
索引文件分段存储并且不可修改,那么新增、更新和删除如何处理呢?
新增,新增很好处理,由于数据是新的,所以只需要对当前文档新增一个段就可以了。
删除,由于不可修改,所以对于删除操作,不会把文档从旧的段中移除而是通过新增一个 .del文件,文件中会列出这些被删除文档的段信息。这个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
更新,不能修改旧的段来进行反映文档的更新,其实更新相当于是删除和新增这两个动作组成