Elasticsearch
接近实时搜索,索引有1秒的延迟
index
存储数据的索引
cluster
代表一个集群,去中心化节点
document
索引的实体
mapping
文档写进索引之前都会先进行分析,如何将输入的文本分割为词条、哪些词条又会被过滤
type
每个文档都有与之对应的类型
shard
索引分片,分片的数量只能在索引创建前指定,并且索引创建后不能更改,默认情况下,Elasticsearch中的每个索引分配5个主分片和1个复制
replicas
分片副本,副本的作用一是提高系统的容错性,提高es的查询效率,es会自动对搜索请求进行负载均衡
river
同步数据到es中
discovery
ES节点自动发现机制,基于p2p的系统,先通过广播寻找存在的节点,然后通过多播协议来进行数据通信,支持点对点的交互
gateway
ES索引的持久化存储方式,es默认是先把索引存放到内存中,当内存满了时再持久化到硬盘
Transport
内部节点或集群与客户端的交互方式,默认内部是使用tcp协议进行交互其它方式可以通过插件方式集成
masternode
元数据的处理,索引操作功能的分配
datanode
负责数据相关操作,比如分片的 CRUD,以及搜索和整合操作,消耗CPU IO 内存
Client node
路由请求的作用,实际上可以看做负载均衡器,如果请求不是很多的业务,这个可以不加
ZenDiscovery
ZenPing
UnicastZenPing
一个节点使用发现机制来发现其他节点的过程
Unicast
传播的路由器
Bully算法
机制
进程向所有编号比它大的进程发送一个election消息
如果无人响应,那么当前进程获胜
如果编号比他大的进程响应,则由响应者接管选举工作,当前进程工作完成
【 任何一个时刻,一个进程只能从编号比他小的进程接受election消息】
任何一个时刻,一个进程只能从编号比他小的进程接受election消息
问题
假死现象,导致系统极度不稳定
算法优化
把所有可以成为master的节点按照nodeid进行排序
然后选出第一个节点,暂且认为它是master节点
对某个节点的投票数达到一定的值(可以成为master节点数n/2+1)
如果当前节点也是选举自己,那么当前节点就是master,否则重新选举
脑裂问题
把候选master节点最小值设置为可以成为master节点数为quornm
一般quornm=(n/2+1)
大于集群节点数量的一半
FaultDetection
MasterFaultDetection
每个节点ping到master,进行错误检测
NodesFaultDetection
node会比较自己的version和另外master的version;如果比别人的小,就会stop掉自己的nodesFD和masterFD,然后rejoin进集群
如果version比别人的大,那么当前node仍然是master,它会向另一个master发出rejoin指令
概要
负责State的下发/维护集群状态/配置的更新
当集群创建好,且选举了master
ClusterState
同步最新状态
数据持久化方式,集群在启动的时候,恢复数据,只恢复索引级,不包括shard级
state,元数据信息
集群层面元信息
MetaData
settings, templates
索引层面元信息
IndexMetaData
numberOfShards,mappings
MappingMetaData
分片层面元信息
ShardStateMetaData
version,indexUUID,primary
index: lucene生成的索引的文件
Translog:产生的事务日志
优化参数配置
index.translog.interval
默认5s。时间过长,会超出下面阈值比较大。
index.translog.flush_threshold_ops
超过多少条日志后需要flush,默认Int的最大值
index.translog.flush_threshold_period
定时flush,默认30m 可动态设置
index.translog.flush_threshold_size
translog 大小超过多少后flush,默认512m
recovery
ES集群可能会有整体重启的情况,比如需要升级硬件、升级操作系统或者升级ES大版本。重启所有结点可能带来的一个问题: 某些结点可能先于其他结点加入集群, 先加入集群的结点可能已经可以选举好master,并立即启动了recovery的过程,由于这个时候整个集群数据还不完整,master会指示一些结点之间相互开始复制数据。 那些晚到的结点,一旦发现本地的数据已经被复制到其他结点,则直接删除掉本地“失效”的数据。 当整个集群恢复完毕后,数据分布不均衡,显然是不均衡的,master会触发rebalance过程,将数据在节点之间挪动。整个过程无谓消耗了大量的网络流量;合理设置recovery相关参数则可以防范这种问题的发生。
参数讲解
gateway.expected_nodes
gateway.expected_master_nodes
gateway.expected_data_nodes
以上三个参数是说集群里一旦有多少个节点就立即开始recovery过程。 不同之处在于,第一个参数指的是master或者data都算在内,而后面两个参数则分指master和data node。在期待的节点数条件满足之前, recovery过程会等待gateway.recover_after_time (默认5分钟) 这么长时间,一旦等待超时,则会根据以下条件判断是否启动:
gateway.recover_after_nodes
gateway.recover_after_master_nodes
gateway.recover_after_data_nodes
实例配置
gateway.expected_data_nodes: 10
gateway.recover_after_time: 5m
gateway.recover_after_data_nodes: 8
那么集群5分钟以内10个data node都加入了,或者5分钟以后8个以上的data node加入了,都会立即启动recovery过程。
核心实现类
实现类
GatewayMetaState
读取恢复数据
GatewayService
生成内容路由信息
GatewayAllocator
执行数据路由
DanglingIndicesState
如果一个新的maste节点启动,并位感知到其他旧节点存储的索引信息,这时候添加旧节点会导入索引数据,避免数据被删除
一个旧的索引可以直接copy它的data目录到一台新机器,然后将新机器加入集群,这时候数据就会导入集群,带replica满足要求后(,就可以把机器移除了DanglingIndicesState
如果一个新的maste节点启动,并位感知到其他旧节点存储的索引信息,这时候添加旧节点会导入索引数据,避免数据被删除
一个旧的索引可以直接copy它的data目录到一台新机器,然后将新机器加入集群,这时候数据就会导入集群,带replica满足要求后(,就可以把机器移除了
主分片恢复
把当前translog做成快照,重放每条记录
调用标准的index来操作创新或更新doc来恢复
再处理recovery过程中新写入的数据
副本分片恢复
对比分段信息,如果syncid相同且doc文档数量相同,就跳过,否则复制整个分段
把当前 translog 做快照,发送所有的 translog operation 到对端节点
RecoverySource
主分片是数据源头
RecoveryTarget
分片数据是目标
副本分片恢复的第一阶段,各节点单独执行分段合并逻辑,合并后的分段基本不会相同,所以拷贝 lucene 分段是最耗时的
解决方案
先执行 synced flush,
syncd flush 并且本身也可能比较慢,因为我们常常为了优化写入速度而加大 translog 刷盘周期,也会延长 translog 恢复阶段时间
只对冷索引有效,对于热索引(5分钟内有更新的索引)没有作用
优化方案
对比序号
global checkpoint
主分片负责维护global checkpoint,
local checkpoint
local checkpoint代表当前分片已写入成功的最新位置,
基于6.0之后的版本
> 关于checkpoint需要仔细琢磨一下.....
触发机制
节点增,删
手工route
副本数量改变
集群重启
类型
创建索引
allocators负责找出所有分片数最少的节点列表,并按分片数量进行升序排序
分片数量最少的节点会被优选选择
ders依次遍历allocators给出的节点, 并判断是否把分片分配到该节点
已有索引
要区分主分片还是副本分片
. 对于主分片, allocators只允许把主分片指定在已经拥有该分片完整数据的节点上
而对于副本分片, allocators则是先判断其他节点上是否已有该分片的数据的拷贝
AllocationDecider
SameShardAllocationDecider
避免主副分片分片到同一个节点
AwarenessAllocationDecider
感知分配器,尽量分散存储shard
ThrottlingAllocationDecider
recovery阶段的限速配置
cluster.routing.allocation.node_concurrent_recoveries
cluster.routing.allocation.node_initial_primaries_recoveries
cluster.routing.allocation.node_concurrent_incoming_recoveries
cluster.routing.allocation.node_concurrent_outgoing_recoveries
ConcurrentRebalanceAllocationDecider
rebalance并发控制
DiskThresholdDecider
根据磁盘空间进行决策分配
RebalanceOnlyWhenActiveAllocationDecider
所有shard都处在active状态下,才可以执行rebalance操作
FilterAllocationDecider
通过接口动态设置的过滤器
index
index.routing.allocation.require
index.routing.allocation.include.
index.routing.allocation.exclude.*
cluster
cluster.routing.allocation.require.*
cluster.routing.allocation.include.*
cluster.routing.allocation.exclude.*
require必须的,include包含,exclude不包含
ReplicaAfterPrimaryActiveAllocationDecider
保证只有在主分片分配完,才能进行副分片分配
ClusterRebalanceAllocationDecider
通过集群中active的shard状态来决定是否可以执行rebalance
allocation
功能
哪个分片应该分配给哪些节点
哪个分片作为主分片,哪个作为副分片
BalancedShardsAllocator
PrimaryShardAllocator
主分片分配
ReplicaShardAllocator
副分片分配
GatewayAllocator
组合使用上面的两个,实现真正分片路由
AllocationService
reroute
真正路由的方法
基础数据结构
IndexRoutingTable
索引路由表
RoutingNode
路由节点信息
RoutingTable
路由表信息
ShardRouting
分片路由信息
路由算法
shard = hash(routing) % number_of_primary_shards
routing,默认就是docid
主分片
先写入Lucene,再写入TransLog
为什么不先写日志?
Lucene的内存写入会有很复杂的逻辑,很容易失败
避免TransLog中有大量无效记录,减少recover的复杂度和提高速度
可靠性
或者是持久性,数据写入系统成功后,数据不会被回滚或丢失
一致性
数据写入成功后,再次查询时必须能保证读取到最新版本的数据,不能读取到旧数据
原子性
一个写入或者更新操作,要么完全成功,要么完全失败,不允许出现中间状态
隔离性
多个写入操作相互不影响
实时性
写入后是否可以立即被查询到
性能
写入性能,吞吐量
Ingest Pipeline
对原始文档做一些处理,比如HTML解析,自定义的处理,具体处理逻辑可以通过插件来实现
Auto Create Index
判断当前Index是否存在,如果不存在,则需要自动创建Index,这里需要和Master交互
Set Routing
设置路由条件
如果Request中指定了路由条件,则直接使用Request中的Routing
否则使用Mapping中配置的,如果Mapping中无配置,则使用默认的_id字段值。
Construct BulkShardRequest
同一个Shard中的请求聚集在一起,构建BulkShardRequest,每个BulkShardRequest对应一个Shard
Send Request To Primary
将每一个BulkShardRequest请求发送给相应Shard的Primary Node
1 Index or Update or Delete
循环执行每个Single Write Request,对于每个Request选择不同的逻辑来处理
2 Translate Update To Index or Delete
Update操作的特有步骤
会通过GetRequest查询到已经存在的同_id Doc
(如果有)的完整字段和值(依赖_source字段),然后和请求中的Doc合并
获取到读到的Doc版本号,记做V1。
3 Parse Doc
这里会解析Doc中各个字段。生成ParsedDocument对象,同时会生成uid Term
4 Update Mapping
有个自动更新Mapping的功能,就在这一步生效
Get Sequence Id and Version
则会从SequenceNumber Service获取一个sequenceID和Version
SequenceID在Shard级别每次递增1,SequenceID在写入Doc成功后,会用来初始化LocalCheckpoint
5 Add Doc To Lucene
索引写入LUCENE,此时索引文件是保存在内存中,对查询不可见
6 Write Translog
写完Lucene的Segment后,会以keyvalue的形式写TransLog,Key是_id,Value是Doc内容
当查询的时候,如果请求是GetDocByID,则可以直接根据_id从TransLog中读取到,满足NoSQL场景下的实时性要去
7 Renew Bulk Request
这里会重新构造Bulk Request,原因是前面已经将UpdateRequest翻译成了Index或Delete请求
不需要再执行Update逻辑,一是保证Replica中逻辑更简单,性能更好,二是保证同一个请求在Primary和Replica中的执行结果一样
8 Flush Translog
这里会根据TransLog的策略,选择不同的执行方式,要么是立即Flush到磁盘,要么是等到以后再Flush
Flush的频率越高,可靠性越高,对写入性能影响越大
9 Send Requests To Replicas
将刚才构造的新的Bulk Request并行发送给多个Replica,然后等待Replica的返回,等待多个Replica成功返回后,Primary Node才会返回用户
具体需要多少Replica Node返回,可以通过配置或者请求参数设置
10 Receive Response From Replicas
Replica中请求都处理完后,且满足最小Replica返回数后,会更新Primary Node的LocalCheckPoint
和Primary Node逻辑基本一致,缺少最后两步
1 ActionModule
RestBulkAction
TransportAction
TransportShardBulkAction
TransportReplicationAction
2 PrimaryOperationTransportHandler
3 ReplicaOperationTransportHandler
类型
支持ES
支持NOSQL数据库
形式
1 Get
通过ID查询特定Doc
查询的时候是先查询内存中的TransLog,如果找到就立即返回
如果没找到再查询磁盘上的TransLog
如果还没有则再去查询磁盘上的Segment
2 Search
通过Query查询匹配Doc
查询的时候是一起查询内存和磁盘上的Segment,最后将结果合并后返回
保证NoSQL场景下的实时性要求。
1 query_and_fetch
第一阶段查询到匹配的DocID
2 query_then_fetch
第二阶段再查询DocID对应的完整文档
3 dfs_query_then_fetch
先收集所有Shard中的TF和DF值,然后将这些值带入请求中
再次执行query_then_fetch,这样算分的时候TF和DF就是准确的
查询的优势是算分更加精准,但是效率会变差
第一阶段的Query Phase请求,则会调用SearchService的executeQueryPhase方法
第二阶段的Fetch Phase请求,则会调用SearchService的executeFetchPhase方法
1 Get Remote Cluster Shard
判断是否需要跨集群访问,如果需要,则获取到要访问的Shard列表。
2 Get Search Shard Iterator
获取当前Cluster中要访问的Shard,勾出要访问完整的shard列表
3 For Every Shard:Perform
遍历每个Shard,对每个Shard执行后面逻辑
4 Send Request To Query Shard
将查询阶段请求发送给相应的Shard
5 Merge Docs
异步等待返回结果,然后对结果合并
维护一个Top N大小的优先级队列,每当收到一个shard的返回,就把结果放入优先级队列做一次排序,直到所有的6 Shard都返回。
分页查询
search_after
返回的总数据量只是和Shard个数以及本次需要的个数有关,和历史已读取的个数无关
深度分页
通过scroll来实现
本质类似于游标
不能逆行查询,往返查询
只能查询下一页
6 Send Request To Fetch Shard
选出Top N个Doc ID后发送Fetch Shard给这些Doc ID所在的Shard,最后会返回Top N的Doc的内容
1 Create Search Context
创建Search Context,之后Search过程中的所有中间状态都会存在Context中
2 Parse Query
解析Query的Source,将结果存入Search Context
3 Get From Cache
判断请求是否允许被Cache,如果允许,则检查Cache中是否已经有结果
4 Add Collectors
收集查询结果,实现排序,自定义结果集过滤和收集等
FilteredCollector
先判断请求中是否有Post Filter,Post Filter用于Search,Agg等结束后再次对结果做Filter,希望Filter不影响Agg结果。如果有Post Filter则创建一个FilteredCollector,加入Collector List中。
PluginInMultiCollector
判断请求中是否制定了自定义的一些Collector,如果有,则加入Collector List。
MinimumScoreCollector
:判断请求中是否制定了最小分数阈值,如果指定了,则创建MinimumScoreCollector加入Collector List中,在后续收集结果时,会过滤掉得分小于最小分数的Doc
EarlyTerminatingCollector
判断请求中是否提前结束Doc的Seek,如果是则创建EarlyTerminatingCollector,加入Collector List中。在后续Seek和收集Doc的过程中,当Seek的Doc数达到Early Terminating后会停止Seek后续倒排链
CancellableCollector
判断请求中是否提前结束Doc的Seek,如果是则创建EarlyTerminatingCollector,加入Collector List中。在后续Seek和收集Doc的过程中,当Seek的Doc数达到Early Terminating后会停止Seek后续倒排链
5 lucene::search
调用Lucene中IndexSearch的search接口,执行真正的搜索逻辑
6 rescore
根据Request中是否包含rescore配置决定是否进行二阶段排序,如果有则执行二阶段算分逻辑,会考虑更多的算分因子
7 suggest::execute()
如果有推荐请求,则在这里执行推荐请求
8 aggregation::execute()
如果含有聚合统计请求,则在这里执行
当Client Node选择出最终Top N的结果后,再对最终的Top N读取Doc内容
ExplainFetchSubPhase
DocValueFieldsFetchSubPhase
ScriptFieldsFetchSubPhase
FetchSourceSubPhase
VersionFetchSubPhase
MatchedQueriesFetchSubPhase
HighlightPhase
ParentFieldSubFetchPhase
【通过插件的形式注册自定义的功能】
AggregationPhase
聚合查询
DfsPhase
三阶段查询
FetchPhase
二阶段查询
QueryPhase
一阶段查询
RescorePhase
二次加分查询
SuggestPhase
推荐查询
1 索引标记删除的标志,并不会立马被删除,而是在索引段合并的时候,才会真正删除标记删除的数据
2 集群角色:主节点,数据节点,预处理节点,协调节点,部落节点
3 bully算法,对节点id进行排序,取id值最大的节点作为master
4 副本分配恢复数据,允许从本地的translog进行回放恢复
5 master节点维护,同步副本列表 in-sync-copies
6 Primay Terms:由主节点分配给每个主分片,每次主分片发生变化的时候,进行递增
7 Sequence Numbers:主分片记录每个写操作的唯一标记
8 Global CK:全局检查点,避免进行全量数据对比,只对比有差异化的数据
9 不建议缓存第一次查询结果,等待翻页命中,而是重新检索一次
10 6.X版本用TslogDeletionPolicy,使用快照替代translog.view
_stats
返回节点或者集群的状态信息
_tasks
返回ES中在执行的任务
_cat/thread pool
返回ES使用的各类线程
线程种类:generic,index,search,get,bulk,snapshot,warmer,refresh,listener,same,management,flush,fetch_shard_started,fetch_shard_store
_nodes
返回节点所有信息
/hot_threads
返回当前节点的热点线程
allocation/explain
节点分片计划
1 加大translog flush间隔
降低iops,writeblock
2 加大index refresh间隔
降低IO
3 调整bulk请求
4 优化磁盘间的任务均匀情况
5 优化节点间的任务分布
6 优化lucene层建立索引的整个过程
7 为文件系统cache预留足够多的内存
1 为文件系统cache预留足够多的内存
3 使用更快的硬件
4 预索引数据
4 优化日期搜索
5 为只读索引执行force-merge
6 预热文件系统cache
7 转换查询表达式
8 调节搜索请求中的batch_reduce_size
协调节点可以在指定分片数据返回,就先进行数据的聚合
9 利用自适应副本提升ES响应速度
ARS算法
节点未完成的搜索请求数,系统中数据节点的数量,响应时间,搜索线程池中队列中等待的任务数量,数据节点上的搜索服务时间等
10 适当的降低副本数量,避免多次跨网络查询
15 配置Linux OOM KIiller
linux 会把进程占用多的内存给kill
设置进程的oom_score_adj的值,越小越不容易被误杀
16 避免热索引分片不均
17 429状态码
由于写入端的并发过大导致的,建议适当降低写入并发
18 了解你的搜索计划
利用profile api分析会命中拿些分片
19 慢日志
慢索引日志
慢搜索日志
Master节点
负责处理集群的管理以及加强状态的整体稳定性
Hot节点
完成集群内所有的索引工作
保存近期的一些频繁被查询的索引
服务器需要强大的SSD存储来支撑
Warm节点
处理大量的而且不经常访问的只读索引而设计的
索引是只读的,Warm节点倾向于挂载大量磁盘(普通磁盘)来替代SSD
Elasticsearch
存储日志数据,查询数据
Logstash
对日志进行采集
Kiban
对索引数据进行可视化图表展示
Filebeat
对日志进行各种条件的过滤