ElasticSearch (以下简称es)
ES写数据过程
- 当客户端对一个node发出写入请求
- 这个node可以称为协调节点
- 协调节点会将document路由到实际节点node的primary shard上,
- 当主分片成功处理这个请求,将请求并行发给备份分片,
(primary shard 对应的replica shard ,备份分片可能不止一个,主分片和备份不会在同一台机子上) - 当primary和replica 都写完后,primary节点向协调节点报告成功,协调节点返回结果给客户端
ES路由规则
写入数据和读取数据都是,以下算法实现:
shard_num = hash(_routing) % num_primary_shards
// _routing:一般都是doc_id
// num_primary_shards:主分片数量
- 对数据的doc_id进行hash之后的值
- 在对主要分片数量求余,获得对应编号的主分片
所以 创建索引的时候就确定好主分片的数量,并且永远不会改变这个数量。
如果变了, 那么所有之前路由的值都会无效,文档也再也找不到了。
默认规则存在的缺陷:
假设搜索 “apple” 根据倒排索引获取到对应很多个doc_id,假设数据足够多,doc_id就会均匀分配到不同分片上了
白苹果 黑苹果 蓝苹果 。。。这些数据分布在各个不同分片上
这时候协调节点就要发请求到各个分片节点上进行查询,这种操作会给集群带来负担,增大了网络的开销。
而自定义的Routing模式,将同一个种类的数据放在相同分片上,这是时候查apple就直接去P1分片上查询就行了。
自定义路由
设置路由的两种方式
// 样例1 指定routing为 key1
PUT route_test1/_doc/b?routing=key1
{
"type":"apple"
"data": "red apple"
}
//样例2 指定type字段作为路由
PUT route_test1/_doc/_mapping
{
"order": {
"_routing": {
"required": true,
"path": "type" //指定文档的字段作为路由
}
}
}
# 也可以去查询多个路由
GET route_test/_search?routing=key1,key2
{
"query": {
"match": {
"type": "apple"
}
}
}
另外,指定routing还有个弊端就是容易造成负载不均衡(apple 数据量远大于其他数据)。
所以ES提供了一种机制可以将数据路由到多个shard上面。
只需在创建索引时(也只能在创建时)设置index.routing_partition_size,默认值是1,即只路由到1个shard,可以将其设置为大于1且小于索引shard总数的某个值,就可以路由到多个shard了。
shard_num = (hash(_routing) + hash(_id) % routing_partition_size) % num_primary_shards
ES什么时候写入硬盘
- 内存buffer
- translog日志
- os cache