elasticsearnch深入分片

深入分片

一. 使文本可以被搜索

想要让文本中的每个单词都可以被搜索,这意味这数据库需要存多个值
支持一个字段多个值的最佳数据结构是倒排索引
文档加入了倒排索引
每一个JSON文档中被索引的字段都有它自己的倒排索引
倒排索引存储了比包含了一个特定term的文档列表多地多的信息。它可能存储包含每个term的文档数量,一个term出现在指定文档中的频次,每个文档中term的顺序,每个文档的长度,所有文档的平均长度,等等。这些统计信息让Elasticsearch知道哪些term更重要,哪些文档更重要,也就是相关性。
为了实现倒排索引预期的功能,它必须要知道集合中所有的文档
在全文检索的早些时候,会为整个文档集合建立一个大索引,并且写入磁盘。只有新的索引准备好了,它就会替代旧的索引,最近的修改才可以被检索。

写入磁盘的倒排索引是不可变的

  • 不需要锁。如果从来不需要更新一个索引,就不必担心多个程序同时尝试修改。
  • 一旦索引被读入文件系统的缓存(译者:在内存),它就一直在那儿,因为不会改变。只要文件系统缓存有足够的空间,大部分的读会直接访问内存而不是磁盘。这有助于性能提升。
  • 在索引的声明周期内,所有的其他缓存都可用。它们不需要在每次数据变化了都重建,因为数据不会变。
  • 写入单个大的倒排索引,可以压缩数据,较少磁盘IO和需要缓存索引的内存大小。

缺点:
这不仅严重限制了一个索引所能装下的数据,还有一个索引可以被更新的频次

二. 动态索引

使用多个索引,在保持不可变好处的同时更新倒排索引
不是重写整个倒排索引,而是增加额外的索引反映最近的变化
每个倒排索引都可以按顺序查询,从最老的开始,最后把结果聚合。
Lucene索引是Elasticsearch中的分片,Elasticsearch中的索引是分片的集合
一个段(segment)是有完整功能的倒排索引,但是现在Lucene中的索引指的是段的集合+提交点

一个per-segment search如下工作:

  1. 新的文档首先写入内存区的索引缓存。
  2. 不时,这些buffer被提交:
    • 一个新的段——额外的倒排索引——写入磁盘。
    • 新的提交点写入磁盘,包括新段的名称。
    • 磁盘是fsync’ed(文件同步)——所有写操作等待文件系统缓存同步到磁盘,确保它们可以被物理写入。
  3. 新段被打开,它包含的文档可以被检索
  4. 内存的缓存被清除,等待接受新的文档。
    当一个请求被接受,所有段依次查询。所有段上的Term统计信息被聚合,确保每个term和文档的相关性被正确计算。通过这种方式,新的文档以较小的代价加入索引。


删除和更新
段是不可变的,所以文档既不能从旧的段中移除,旧的段也不能更新以反映文档最新的版本。相反,每一个提交点包括一个.del文件,包含了段上已经被删除的文档。
当一个文档被删除,它实际上只是在.del文件中被标记为删除,依然可以匹配查询,但是最终返回之前会被从结果中删除。
文档的更新操作是类似的:当一个文档被更新,旧版本的文档被标记为删除,新版本的文档在新的段中索引。也许该文档的不同版本都会匹配一个查询,但是更老版本会从结果中删除。
在合并段这节,我们会展示删除的文件是如何从文件系统中清除的。

三. 近实时搜索

近实时搜索
因为per-segment search机制,索引和搜索一个文档之间是有延迟的
利用内存缓存,一个文件被缓存,它也可以被打开和读取
Lucene允许新段写入打开,好让它们包括的文档可搜索,而不用执行一次全量提交。这是比提交更轻量的过程,可以经常操作,而不会影响性能。
写入buf

缓存但是没提价

refeash API
这种写入打开一个新段的轻量级过程,叫做refresh
默认每个分片每秒自动刷新一次
用户可能会找不到文档,可以利用手动刷新

POST /_refresh           // refresh所有索引
POST /blogs/_refresh     //只refresh 索引blogs

刷新比提交更轻量,但是会影响性能,生产环境不要使用,测试时用
配置refresh_interval,减少刷新频率

PUT /my_logs
{
  "settings": {
    "refresh_interval": "30s" //每30s refresh一次my_logs
  }
}

refresh_interval可以在存在的索引上动态更新,创建大索引是可以先关闭,需要时打开

PUT /my_logs/_settings
{ "refresh_interval": -1 }   //禁用所有自动refresh

PUT /my_logs/_settings
{ "refresh_interval": "1s" } //每秒自动refresh

四. 持久化变更

关闭了磁盘的fsync功能,使用全提交,写到提交点,这会列出所有的已知的段;
ES增加了事务日志,记录每次操作;
有了事务日志,过程现在如下:
1.当一个文档被索引,它被加入到内存缓存,同时加到事务日志

2.refresh使得分片的进入如下图描述的状态。每秒分片都进行refeash

  • 内存缓冲区的文档写入到段中,但没有fsync。
  • 段被打开,使得新的文档可以搜索。
  • 缓存被清除

经过一次refresh,缓存被清除,但事务日志没有

3.随着更多的文档加入到缓存区,写入日志,这个过程会继续
事务日志会记录增长的文档

4.不时地,比如日志很大了,新的日志会创建,会进行一次全提交:

  • 内存缓存区的所有文档会写入到新段中。
  • 清除缓存
  • 一个提交点写入硬盘
  • 文件系统缓存通过fsync操作flush到硬盘
  • 事务日志被清除

事务日志记录了没有flush到硬盘的所有操作。当故障重启后,ES会用最近一次提交点从硬盘恢复所有已知的段,并且从日志里恢复所有的操作。
事务日志还用来提供实时的CRUD操作。当你尝试用ID进行CRUD时,它在检索相关段内的文档前会首先检查日志最新的改动。这意味着ES可以实时地获取文档的最新版本。

五. 合并段

每个段消费文件句柄,内存,cpu资源;每次搜索请求都需要依次检查每个段。段越多,查询越慢
1。索引过程中,refresh会创建新的段,并打开它
2.合并过程会在后台选择一些小的段合并成大的段,这个过程不会中断索引和搜索

两个提交的段和一个未提交的段合并为了一个更大的段

3.下图描述了合并后的操作:

  • 新的段flush到了硬盘。
  • 新的提交点写入新的段,排除旧的段。
  • 新的段打开供搜索。
  • 旧的段被删除。

段合并完后,旧的段被删除

合并大的段会消耗很多IO和CPU,如果不检查会影响到搜素性能。默认情况下,ES会限制合并过程,这样搜索就可以有足够的资源进行。

optimize API
强制合并api,它强制分片合并段以达到指定max_num_segments参数,这是为了减少段的数量(通常为1)达到提高搜索性能的目的。
不要在动态索引(正在活跃更新)使用optimize API,系统已经做得很好
记录日志,这中情况下日志是按照每天,周,月存入索引
旧的索引一般是只可读的,它们是不可能修改的

POST /logstash-2014-10/_optimize?max_num_segments=1 //把索引中的每个分片都合并成一个段
posted @ 2016-09-28 15:02  zhangshihai1232  阅读(176)  评论(0)    收藏  举报