Elasticsearch杂记
分片
-
主分片,用以解决数据水平扩展的问题。通过主分片,可以将数据分布到集群内的所有节点之上。
- 一个分片是一个运行的Lucene的实例
- 主分片数在索引创建时指定,后续不允许修改,除非Reindex
-
副本,用以解决数据高可用的问题。分片是主分片的拷贝
- 副本分片数,可以动态调整
- 增加副本数,还可以在一定程度上提高服务的可用性(读取的吞吐)
如何设计分片数
-
当分片数 > 节点数时
- 一旦集群中有新的数据节点加入,分片就可以自动进行分配
- 分片在重新分配时,系统不会有downtime
-
多分片的好处:一个索引如果分布在不同节点,多个节点可以并行执行
- 查询可以并行执行
- 数据写入可以分散到多个机器
分片过所带来的副作用
-
Shard是ElasticSearch实现集群水平扩展的最小单位
-
过多设置分片数会带来一些潜在的问题
-
每个分片是一个Lucene的索引,会使用机器的资源。过多的分片会导致额外的性能开销
- Lucene Indices / File descriptors / RAM / CPU
- 每次搜索的请求,需要从每个分片上获取数据
- 分片的Meta信息由Master节点维护。过多,会增加管理的负担。经验值,控制分片总数在10W以内
-
分片的设定
-
对于生产环境中分片的设定,需要提前做好容量规划
-
分片数设置过小
- 导致后续无法增加节点实现水平扩展
- 单个分片的数据量太大,导致重新分配耗时
-
分片数设置过大,7.0开始,默认主分片设置成1,解决了over-sharding的问题
- 影响搜索结果的相关性打分,影响统计结果的准确性
- 单个节点上过多的分片,会导致资源浪费,同时也会影响性能
-
如何确定主分片数
-
从存储的物理角度看
- 日志类应用,单个分片不要大于50GB
- 搜索类应用,单个分片不要超过20GB
-
为什么要控制分片存储大小
- 提高Update的性能
- Merge时,减少所需的资源
- 丢失节点后,具备更快的恢复速度 / 便于分片在集群内Rebalancing
如何确定副本分片数
-
副本是主分片的拷贝
- 提高系统可用性:相应查询请求,防止数据丢失
- 需要占用和主分片一样的资源
-
对性能的影响
-
副本会降低数据的索引速度:有几份副本就会有几倍的CPU资源消耗在索引上
-
会减缓对主分片的查询压力,但是会消耗同样的内存资源
- 如果机器资源充分,提高副本数,可以提高整体的查询QPS
-
倒排索引不可变性
-
倒排索引采用Immutable Design,一旦生成,不可更改
-
不可变性,带来了的好处如下:
- 无需考虑并发写文件的问题,避免了锁机制带来的性能问题
- 一旦读入内核的文件系统缓存,便留在那里。只要文件系统存有足够的空间,大部分请求就会直接请求内存,不会命中磁盘,提升了很大的性能
- 缓存容易生成和维护/数据可以被压缩
-
不可变性,带来了的挑战:如果需要让一个新的文档可以被搜索,需要重建整个索引。
刷新的本质:写入数据由内存 buffer 写入到内存段中,以保证搜索可见
将文档插入 Elasticsearch 时,它们会被写入缓冲区中,然后在刷新时定期从该缓冲区刷新到段中。刷新频率由 refresh_interval 参数控制,默认每1秒发生一次。也就是说,新插入的文档在刷新到段(内存中)之前,是不能被搜索到的。
关于是否需要实时刷新
- 如果新插入的数据需要近乎实时的搜索功能,则需要频繁刷新
- 如果对最新数据的检索没有实时性要求,则应增加刷新间隔,以提高数据写入的效率,从而应释放资源辅助提高查询性能
关于刷新频率对查询性能的影响
- 由于每刷新一次都会生成一个Lucene段,刷新频率越小就意味着同样时间间隔,生成的段越多
- 每个段都要消耗句柄和内存
- 每次查询请求都需要轮询每个段,轮询完毕后再对结果进行合并
- 也就意味着:refresh_interval越小,产生的段越多,搜索反而会越慢;反过来说,加大refresh_interval,会相对提升索引性能
什么是段
- 一个集群包含1个或多个节点
- 一个节点包含1个或多个索引
- 一个索引:类似MySQL中的数据库
- 每个索引都是一个Lucene索引实例,可以将其视作一个独立的搜索引擎,它能够对Elasticsearch集群中的数据子集进行索引并处理相关查询
- 每个分片包含多个segment(段),每一个segment都是一个倒排索引
在查询的时候,会把所有的segment查询结果汇总归并为最终的分片查询结果返回
为什么段是不可变的?
- 在lucene中,为了实现高索引速度,故使用了segment分段架构存储
- 一批写入数据保存在一个段中,其中每个段是磁盘中的单个文件
- 由于两次写入之间的文件操作非常繁重,因此将一个段设为不可变的,以便所有后续写入都转到New段
什么是段合并?
由于自动刷新流程每秒会创建一个新的段(由动态配置参数:refresh_interval决定),这样会导致短时间内的段数量暴增。
而段数据太多会带来较大的麻烦
- 消耗资源:每一个段都会消耗文件句柄、内存和CPU运行周期
- 搜索变慢:每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢
Elasticsearch通过在后台进行段合并来解决这个问题:小的段被合并到大的段,然后这些大的段再被合并到更大的段。
段合并做了什么?
段合并的时候会将那些旧的已删除文档从文件系统中消除,
被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中,
启动段合并不需要你做任何事,进行索引和搜索时会自动进行。
为什么要进行段合并?
- 索引段的个数越多,搜索性能越低并且消耗更多的内存
- 索引段是不可变的,你不能物理上从中删除信息
可以物理上删除document,但只是做了删除标记,物理上并没有删除
- 当段合并的时候,这些被标记位删除的文档并没有被拷贝至新的索引段中,这样减少了最终的索引段中的document数目。
段合并的好处是什么?
- 减少索引段的数量并提高检索速度
- 减少索引的容量(文档数)
原因:段合并会移除被标记为已删除的那些文档
段合并可能带来的问题
- 磁盘IO操作的代价
- 速度慢的系统中,段合并会显著影响性能
重建索引
使用场景
-
一般在以下几种情况时,我们需要重建索引
- 索引的Mappings发生变更:字段类型更改,分词器及字典更新
- 索引的Settings发生变更:索引的主分片数发生改变
- 集群内,集群间需要做数据迁移
-
Elasticsearch的内置提供的API
- Update By Query:在现有索引重建
- Reindex:在其他索引上重建索引
性能优化
https://elastic.blog.csdn.net/article/details/97695931
分片大小
- 如果分片给索引的分片太多,则Lucene分段会很小,从而导致开销增加。当同时进行多个查询,许多小分片也会降低查询吞吐量
- 分片太大会导致搜索性能下降和故障恢复时间更长
数据动态持续写入场景
Index Sorting
注意:索引排序机制是6.X版本才有的特性
在Elasticsearch中创建索引时,可以配置每个分片中的分段的排序方式。默认情况下,Lucene不会应用任何排序。index.sort.*定义应使用哪些字段对每个Segment内的文档进行排序
面试题
一旦创建索引后,为什么无法更改索引的主分片数量?
如果我们要更改分片的数量,那么对于文档,运行路由公式的结果将发生变化。
假设:设置有 5 个分片时文档已存储在分片 A 上,因为那是当时路由公式的结果。
后面我们将主分片更改为7个,如果再尝试通过ID查找文档,则路由公式的结果可能会有所不同。
现在,即使文档实际上存储在Shard A上,该公式也可能会路由到ShardB。这意味着永远不会找到该文档。
以此可以得出:主分片创建后不能更改的结论。