elasticsearch学习笔记(三十六)——Elasticsearch 内核原理 倒排索引组成结构以及索引不可变原因对于倒排索引是非常适合用来进行搜索的它的结构1包含这个关键词的document list2包含这个关键词的所有document的数量IDFinverse document frequency3这个关键词在每个document中出现的次数TFterm frequency4这个关键词在这个document中的次序5每个document的长度length norm6包含这个关键词的所有document的平均长度其实本质上主要是为了计算相关度分数_score boost * idf * tf 此时boost 2.2, idf 0.18232156, tf 0.5116279 idf log(1 (N - n 0.5) / (n 0.5)) 此时n 2 (n, number of documents containing term), N 2(N, total number of documents with field) tf freq / (freq k1 * (1 - b b * dl / avgdl)) 此时freq 1(freq, occurrences of term within document), k1 1.2(k1, term saturation parameter), b 0.75(b, length normalization parameter), d1 4 (dl, length of field), avgdl 5.5(avgdl, average length of field)倒排索引的不可变好处1不需要锁提升了并发能力避免锁的问题2数据不变一直保存在OS cache中只要cache内存足够3filter cache一直驻留在内存4可以压缩节省cpu和io开销这个对应的就是primary shard的数量不变不能修改field的属性将date改成text倒排索引不可变的坏处1每次都需要重新构建整个索引document写入原理1数据写入buffer2commit point3buffer中的数据写入新的index segment4等待在OS cache中的index segment被fsync强制刷到磁盘上5新的index segment被打开供search使用6buffer被清空下面做几点说明1、在Elasticsearch中底层用的是lucenelucene底层的index是分为多个segment的每个segment都会存放部分数据。2、如果是删除操作每次commit的时候就会生成一个.del文件标明哪个index segment的哪个document被删除了。3、如果是更新操作实际上是将的doc标记为deleted然后将新的document写入新的index segment中。下次search过来的时候也许会匹配到一个document的多个版本但是之前的版本已经被标记为deleted了所以只会返回最新版本的doc4、如果搜索请求过来在index segment中匹配到了id1的doc此时会发现在.del文件中已经被标识为deleted了这种数据就会被过滤掉不会作为搜索结果返回。图示如下写入流程近实时NRT现有的流程的问题每次都必须等待fsync将segment刷入磁盘才能将segment打开供search使用这样的话从一个document写入到它可以被搜索可能会超过1分钟这也就不是近实时的搜索了。主要的瓶颈在于fsync从磁盘IO写数据进磁盘是很耗时的。ES写入流程的改进1数据写入buffer2每个一定时间buffer中的数据被写入segment文件但是先写入OS cache3只要segment写入OS cache那就直接打开供search使用不立即执行commit数据写入OS cache并被打开供搜索的过程叫做refresh默认是每隔一秒refresh一次也就是说每隔一秒就会将buffer中的数据写入OS cache中写入一个新的index segment file。所以ES是近实时的数据写入到可以被搜索默认是1秒。一般不用修改让ES自己搞定就好了要修改的话通过refresh_interval参数即可格式PUT /{index} { settings: { refresh_interval: 1s } }图示如下写入流程的实现 durability可靠存储最终流程1数据写入buffer缓存和translog日志文件 2每隔一秒buffer中的数据被写入新的segment file并进入os cache此时segment被打开并供search使用 3buffer被清空 4重复1~3新的segment不断添加buffer不断被清空而translog中的数据不断累加 5当translog长度达到一定程度的时候commit操作发生 5.1buffer中的所有数据写入一个新的segment并写入os cache打开供使用 5.2buffer被清空 5.3一个commit point被写入磁盘标明了所有的index segment 5.4filesystem cache中的所有index segment file缓存数据被fsync强制刷到磁盘上 5.5现有的translog被清空创建一个新的translogtranslog对Lucene的更改仅在Lucene提交期间持久保存到磁盘这是一项相对昂贵的操作因此无法在每次索引或删除操作后执行。如果进程退出或硬件发生故障Lucene将在一次提交之后和另一次提交之前发生的更改将从索引中删除。因为Lucene提交对于每个单独的更改都执行起来太昂贵所以每个分片副本还有一个事务日志称为与之关联的translog。所有索引和删除操作在由内部Lucene索引处理之后但在确认之前写入translog。在发生崩溃的情况下最新的已确认但尚未包含在上一个Lucene提交中的事务可以在分片恢复时从translog中恢复。Elasticsearch flush是执行Lucene提交并启动新的translog的过程。在后台自动执行刷新以确保translog不会变得太大这将使得在恢复期间重放其操作需要相当长的时间。手动执行刷新的能力也通过API公开尽管很少需要。translog设置translog中的数据仅在fsync编辑和提交translog时持久保存到磁盘 。如果发生硬件故障自上次translog提交以来写入的任何数据都将丢失。默认情况下fsync如果index.translog.durability设置为async或request 在每个索引删除 更新或 批量请求结束时设置为默认则Elasticsearch会每隔5秒提交一次translog 。更确切地说如果设置为request则fsync在主数据库和每个已分配的副本服务器上成功编辑和提交translog之后Elasticsearch将仅向客户端报告索引删除更新或批量请求的成功 。以下可动态更新的每索引设置控制translog的行为index.translog.sync_interval fsync无论写入操作 如何translog都经常被写入磁盘并提交。默认为5s。小于的值100ms是不允许的。 index.translog.durability 是否fsync在每个索引删除更新或批量请求之后提交translog。此设置接受以下参数 request 默认fsync并在每个请求后提交。如果发生硬件故障所有已确认的写入都已提交到磁盘。 async fsync并在每个背景中提交sync_interval。如果发生硬件故障将丢弃自上次自动提交以来的所有已确认写入。 index.translog.flush_threshold_size translog存储尚未安全保存在Lucene中的所有操作即不是Lucene提交点的一部分。尽管这些操作可用于 读取但如果要关闭并且必须恢复则需要重新编制索引。此设置控制这些操作的最大总大小以防止恢复时间 过长。达到最大大小后将发生刷新生成新的Lucene提交点。默认为512mb。 index.translog.retention.size 要保留的translog文件的总大小。保留更多的translog文件会增加在恢复副本时执行基于同步操作的机会。如 果translog文件不足副本恢复将回退到基于文件的同步。默认为512mb index.translog.retention.age 保留translog文件的最长持续时间。默认为12h。图示如下数据恢复假设os cache中囤积了一些数据但是此时不巧宕机了os cache中的数据全部丢失那么我们怎么进行数据恢复呢我们知道写doc的时候也会写入translog那么translog就存储了上一次flush直到现在最近的数据变更记录。机器被重启之后disk上的数据并没有丢失此时就会将translog文件中的变更记录进行回收重新执行之前的各种操作在buffer中执行在重新刷一个一个的segment到os cache中等待下一次commit发生即可。海量磁盘文件的合并每秒一个segment file会导致文件过多而且每次search都要搜索所有的segment很耗时。所以在Elasticsearch内部会默认在后台执行segment merge操作(forcemerge)在merge的时候被标记为deleted的document也会被彻底物理删除掉。每次merge的操作流程1选择一些有相似大小的segmentmerge成一个大的segment2将新的segment flush到磁盘上去3写一个新的commit point包括了新的segment,并且排除旧的那些segment4将新的segment打开供搜索5将旧的segment删除