一、Master节点职责
- 处理创建、删除索引请求,索引的创建及删除;
- 决定分片被分配到那个节点;
- 维护及更新cluster status状态。
既然master节点这么重要,生产中考虑设置多个master节点,每个节点只承担master的单一角色。
索引构建完成后,主分片数量是不能再更改,除非reindex,根本的原因是在构建索引的时候,文档分片的路由算法会用到配置的主分片数量,索引一旦建好,路由就已经固定,所以后期不能修改主分片数量。
更新文档删除文档
二、分片的内部原理
Lucene indexES refresh
Transaction Log
ES Flush
merge(合并)
通过上文的介绍,会发现有好多segment产生,ES会定期对这个segment进行merge(合并),删除已经删除的文档(暂存进.del文件中的数据),也可以调用API进行强制合并
POST my_index/_forcemerge
分片为ES最小的工作单元
-
ES的搜索是近实时的(1秒后被搜到)
-
ES如何保证断电数据不丢失
在refresh(默认1秒发生一次) 的时候,index buffer会被清空,会同时写transaction log文件,保证了数据不丢失(1秒以内的可能会丢失) -
删除文档,并不会立即释放空间
因为删除的文件信息会被暂时存放在一个.del文件中
排序,Doc values,Fielddata
ES排序过程Doc values和Fielddata对比
由上图可以看见,doc values默认是开启的,可以通过_mapping设置进行关闭,带来的好处就是可以增加索引速度和减少磁盘占用。关闭之后就不能再打开,除非reindex,这个功能一般用在 很明确不需要做排序和聚合分析的情况
三、ES的分页及遍历
一般使用From ,Size进行分页,背后的逻辑是:从每个分片中取from+size条文档,然后通过coordition node做聚合,最后通过排序取from+size条文档,最后呈现给用户的是size条文档。也就是说,from+size的值越大,占用的内存及计算资源就越多,效率也会越低,这就是分布式系统常见的。ES有个默认限制,限制到10000个文档,如果超过查询就会报错
- 使用search after避免深度分页问题
- 不支持指定页数
- 只能往下翻
看示例代码及注释
//导入测试数据
POST users/_doc
{"name":"user1","age":10}
POST users/_doc
{"name":"user2","age":11}
POST users/_doc
{"name":"user2","age":12}
POST users/_doc
{"name":"user2","age":13}
//查询文档条数
POST users/_count
POST users/_search
{
"size": 1,
"query": {
"match_all": {}
},
"sort": [
{"age": "desc"} , //指定sort,需要保证值的唯一性,一般使用_id来指定sort
{"_id": "asc"}
]
}
//查询出来的结果
"hits" : [
{
"_index" : "users",
"_type" : "_doc",
"_id" : "dJJW4HMBvlP2ZiwLvYAX",
"_score" : null,
"_source" : {
"name" : "user2",
"age" : 13
},
"sort" : [
13,
"dJJW4HMBvlP2ZiwLvYAX"
]
}
]
POST users/_search
{
"size": 1,
"query": {
"match_all": {}
},
"search_after":
[
13,
"dJJW4HMBvlP2ZiwLvYAX" //使用上一步查询出来的结果,作为输入参数,进行查询
],
"sort": [
{"age": "desc"} ,
{"_id": "asc"}
]
}
search after通过排序及From,每次在分片中只取size条文档,然后通过coordication node进行汇聚排序,然后给查询请求返回size条文档,避免了深度排序的问题
四、并发控制(ES采用的是乐观锁)
- 悲观并发控制
- 假定有并发冲突,会对资源加锁,防止冲突,例如数据库行锁
- 乐观并发控制
- 假定冲突时不会发生,不会阻塞正在尝试的操作,如果数据在读写中被修改,更新将会失败,应用程序决定如何处理冲突(使用新的数据或者直接爆出错误)
ES乐观锁控制方法
这里分两种情况
- 内部版本控制
内部版本使用:if_seq_no=1&if_primary_term=1 - 使用外部版本(别的数据库作为主要数据存储)
外部版本使用:version=30000&version_type=external
DELETE products
PUT products
//写入一篇文档
PUT products/_doc/1
{
"title":"iphone",
"count":100
}
//内部版本 使用if_seq_no&if_primary_term的方式来做乐观并发控制
PUT products/_doc/1?if_seq_no=1&if_primary_term=1
{
"title":"iphone",
"count":100
}
//外部版本使用version和version_type的方式来做乐观锁并发控制
PUT products/_doc/1?version=30000&version_type=external
{
"title":"iphone",
"count":100
}
网友评论