Elasticsearch基本介绍
-
ES是什么?
ES是一款基于Apache Lucene的开源分布式搜索引擎
-
应用场景
- 日志记录与分析(接口调用情况)
- 采集和组合公共数据(用户行为、点击事件)
- 全文检索
- 数据可视化(通过Kibana)
-
逻辑与物理设计
首先看一些概念:
-
集群cluster
ES是分布式的,多个节点构成一个集群,并且集群也是可扩展的
-
节点node
每个启动的ES实例就是一个节点,可以随时加入或者脱离集群
-
索引index
名词:一堆字段相似的文档的集合,类比MySQL的一张表
动词:将文档写入某个索引
-
文档document
一条ES的记录,类比MySQL的一行数据
-
分片shard
- 分片是ES所能管理的最小单元
- 一个分片就是一个Lucenne索引
- 一个包含倒排索引的文件目录
- 分片越多(过度分片),搜索有可能越慢
-
分段segment
-
lucene索引再分割的小单元
-
分段不会被修改
-
分段越多,搜索越慢
-
索引新的文档会创建新的分段
-
分段会被持续地合并
-
删除文档的时候不会真的删除(只是设置了标记)
-
-
扩展与容灾
分片:扩展与容灾
首先,一个索引地所有分片会自动均匀地分布在所有节点中。当我们加入一个新节点后,如下图所示,原集群节点中地分片,有部分会迁移到新节点。
注:设置分片数量稍微大于节点数量,有利于横向扩容时,分片蔓延到所有新节点,如图一所示,就是一个index包含四个分片,而es集群中有三个节点,新加入节点后可以蔓延(最理想的状态就是每个节点都有分片)。但是蔓延的过程是有一定消耗的,所以会对集群产生一些抖动的。此外,当主分片和所有副本分片都就绪时,索引地健康状态是绿色
我们在Kibana的monitoring组件上可以看见分片的活跃程度。
接下来我们来分析容灾,如下图所示为在图1的基础上挂掉一个节点的示意图。
- 当挂掉了N个节点时,如果副本分片是N,那么剩下的副本分片将 自动提升为主分片。
- 然后所有的主分片能构成完整的索引,但是副本分片缺失时,此时索引健康状态是黄色。
- 如果挂掉N+1个节点,主分片将缺失,健康状态是红色。
- 我们需要根据实际情况合理的设置副本的数量(副本太多也会影响性能)
- 通常同时挂掉两个节点的概率不高,一般来说一个副本可以满足常规容灾要求。
索引和搜索数据
索引请求如下图所示:
-
具体过程
- 索引文档请求到一个节点
- 文档会被随机到一个主分片上
- 从主分片同步到副本分片
- 返回成功的结果
注:副本分片越多,索引数据越慢,因为要所有副本都完成才算成功
再来看搜索过程,如下图所示:
-
具体过程
- 搜索请求到一个节点
- 节点转发请求到本节点的一个分片和其他节点的另一个分片
- 所有的分片都返回搜索结果到起始节点,但是只要有一个shard搜索到了数据就会立刻返回
- 起始节点返回搜索结果到请求方
注:不同节点的主分片+副本分片的总数越多,请求被分摊的越 多,并发搜索兴能越好。但是如果节点数很少,分片都集中到了少数节点上,搜索速度会变慢,因为增加了开销,实际没有分摊负载。此外,单个搜索没有办法通过分片加速。
分段
-
写入
- 只能写打开的分段(为了避免冲入合并)
- 删除是假的删除,也是往打开的分段里写标志位(这是为了保证随机读写)
- 分段大小超过一定阈值,会触发分段合并
- 小分段合并成大分段,为了查询加速,但合并过程是先创建一个大分段,再把两个小的放进去,再删除这两个小的,但这个过程会耗费大量资源
- 如果希望写入快,就要避免频繁的分段合并
-
读取
- 只能读取关闭的分段(所以ES叫准实时,关闭这个过程也叫做刷新)
- 对一个分片查询,会等它所有的分段返回结果,所以分段过多,查询越慢
- 刷新时,会关闭一批分段,这时候数据才能被查到
- 刷新频率太快会导致分段碎片多
- 刷新频率过慢会导致实时性低
总结一下,我们可以看到,如果我们追求的是写入更快的话,我们就要尽力的避免频繁的分段合并,保留相对多一点的分段;但是如果我们要追求读取性能的话又要考虑减少分段,这也就是鱼和熊掌的问题了,需要我们结合实际业务场景进行分析。
在Kibana中我们可以设置刷新的频率、副本数量等等参数
一些问题
-
那么索引分片不是免费的吗/分片越多越好吗?
-
每个索引和分片都会产生一定的资源开销,尤其是内存资源
-
每个索引,映射和状态的信息都存储在集群中
- 存储在内存中,以便快速访问
- 分片数量过多,会导致集群状态过大
- 这会导致更新变慢,因为所有的更新都是通过单线程来完成的,从而这是在将变更分发到整个集群之前确保一致性的前提
-
分片有一部分数据需要保存在内存中
- 这部分数据也会占据堆内存空间
- 这包括存储分片级别以及段级别信息的数据结构
- 因为只有这样才能确定数据在磁盘上的存储位置
-
那怎么样在单个节点上存储尽可能多的数据呢?
- 管理堆内存使用量
- 尽可能减少开销
- 节点的堆内存空间越多,能处理的数据和分片就越多
- 官方建议:JVM heap每1G不超过20个分片,每个分片大小在20G
-
参考连接