Elaticsearch
LUCENE索引
norm:用来计算得分,根据文档+权重计算得出
doc values:用来存储字段的正排索引,以此来优化分组、排序、聚合等操作。
Elaticsearch索引
一个Elaticsearch索引由多个Luene索引构成,其实就是数据分片,细节由分片和备份机制及其配置决定。
节点分类
数据节点:用来持有数据,提供对这些数据的搜索功能
主节点:作为督促者,监督其他节点工作,一个集群只能与一个主节点
部落节点:可以连接多个集群
分析器
GET http://121.36.53.194:9200/_analyze json
{
"analyzer":"standard",
"text":"Text to analyze"
}
{
"tokens": [
{
"token": "text",
"start_offset": 0,
"end_offset": 4,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "to",
"start_offset": 5,
"end_offset": 7,
"type": "<ALPHANUM>",
"position": 1
},
{
"token": "analyze",
"start_offset": 8,
"end_offset": 15,
"type": "<ALPHANUM>",
"position": 2
}
]
}
token :分解后的词项
start_offset:起始索引
end_offset:结束索引
type:类型
position:所在位置
什么时候发起选举
当候选master节点满足以下条件时发起选举
- 该候选master节点不是master时
- 该候选master节点无法ping到master节点
- 包含当前这个候选master节点在内,超过了最小票数的候选节点都无法连接到master节点
总结:当一个节点发现包括自己在内的多数派的master-eligible节点认为集群没有master时,就可以发起master选举。
选举谁?
先根据节点的clusterStateVersion比较,clusterStateVersion越大,优先级越高。clusterStateVersion相同时,进入compareNodes,其内部按照节点的Id比较(Id为节点第一次启动时随机生成)。
什么时候选举成功
当一个master-eligible node(我们假设为Node_A)发起一次选举时,它会按照上述排序策略选出一个它认为的master。
- 假设Node_A选Node_B当Master:
Node_A会向Node_B发送join请求,那么此时:
(1) 如果Node_B已经成为Master,Node_B就会把Node_A加入到集群中,然后发布最新的cluster_state, 最新的cluster_state就会包含Node_A的信息。相当于一次正常情况的新节点加入。对于Node_A,等新的cluster_state发布到Node_A的时候,Node_A也就完成join了。
(2) 如果Node_B在竞选Master,那么Node_B会把这次join当作一张选票。对于这种情况,Node_A会等待一段时间,看Node_B是否能成为真正的Master,直到超时或者有别的Master选成功。
(3) 如果Node_B认为自己不是Master(现在不是,将来也选不上),那么Node_B会拒绝这次join。对于这种情况,Node_A会开启下一轮选举。
- 假设Node_A选自己当Master:
此时NodeA会等别的node来join,即等待别的node的选票,当收集到超过半数的选票时,认为自己成为master,然后变更cluster_state中的master node为自己,并向集群发布这一消息。
如何保证不脑裂
基本原则是多数派策略。
缺陷:假设Node1给Node2投了一票,但是Node2迟迟未被成功推选为Master,那么Node1的join请求将会被超时返回,那么Node1将会再次尝试join,此时,正好有一个优先级更高的节点Node0加入到了集群,那么Node1将会给Node1再投一票,显然Node1在该过程中投出了两票,这就意味着,存在多个节点都被多数节点投票的故障。
解决方案:
采用raft算法,引入周期的概念,保证了每个节点在每个周期内只能投一次票,如果选出来多个master,那么周期最大的那个将会成为最终的master。因为他是最新的被投出多数票的节点。
心跳机制
Master定期Ping其他节点,检查其是否存活,若不存活,则将其移出集群,Node如果发现连不上Master,那么发起rejoin请求,若达到选举master的条件,则将会重新选举master。
启动流程
- 使用发现模块来发现该集群中其他的节点并连接他们。
- 集群中选举出来一个节点为主节点,该节点负责集群的状态管理以及在集群拓扑发生变化时及时作出反应,分发索引分片至集群的响应节点上去。
- 主节点读取集群状态,检查有哪些索引分片,因决定哪些分片将用作主分片,集群进入黄色状态。
- 主节点决定如何创建分片和副本,当一切顺利进行后,集群进入绿色状态。
故障检测
当集群正常工作时,主节点会监控所有节点,检查他们是否正常工作,如果有任何节点在预期时间内未响应,则认为该节点挂掉了,然后开始处理故障。这意味着要在存活的节点中做重新平衡,选择新的主节点,处理丢失数据等等。
新增文档
当新增文档的请求被发送到一个节点上时,如果该节点没有对应的主分片,那么请求将会被转发到拥有主分片的节点,然后该节点会吧该请求群发至所有副本,等待其完成备份。
- 客户端发出请求,请求某个Node,此时这个Node就是协调节点
- 协调节点进行路由,将请求转发给主分片所在的Node
- 由主分片所在的Node处理请求,然后将副本分片进行同步
- 完成以上流程后,协调节点将会吧结果响应给客户端
查询操作
- 客户端向某个节点发出请求,该协调节点创建一个from+size大小的优先级队列
- 协调节点转发search请求到每一个主分片或者副本分片,每个分片将命中的DocmentId和所有参与排序字段的值添加到协调节点的优先级队列中,由协调节点将所有收集到的数据合并。
- 协调节点发送批量的get请求,获取size个document,最后将所有结果合并,将合并后的集合返回给客户端。
评分
依赖于:权重、查询本身的结构、被依赖的词项数目、词项所在字段等等。
根据评分公式计算得出。
查询改写(系统优化)
例如前缀查询和通配符查询都会被改写,比如查询name以y开头的,那么他会从索引里找到哪些索引是以y开头并且是在字段首字母出现的,然后去查询这些索引指向的文档即可。
过滤和查询的区别
过滤不会影响文档得分,过滤的性能更高,因为过滤这一步骤不会算分
多数情况下应该使用前置过滤
底层实现:FST
路由:hash(id) % 主分片数
分片控制:轮询
逻辑删除:当执行删除后会进行逻辑删除,只有要重建索引或者合并索引时才会真正删除
并发控制:通过version字段来实现乐观锁