ELasticSearch路由
在ELasticSearch 里面,路由功能算是一个高级用法,大多数时候我们用的都是系统默认的路由功能,一个es索引可以分成shard和每个shard又可以有多个replia,那么添加进去的数据,在如何分布在各个shard上面的,而查询的时候文档是如何路由的。
默认情况下,索引数据的分片规则,是下面的公式:
shard = hash(_routing) % num_primary_shards
routing 是用来进行hash计算的路由值,默认是使用文档id值。我们可以在索引文档时通过routing参数指定别的路由值,number_of_primary_shards:创建索引时指定的主分片数
ES默认是基于hash的分片,保证在每个shard上数据量都近似平均,这样就不会出现负载不均衡的情况,然后在检索的时候,ES默认会搜索所有的shard上的数据,然后在master节点上面汇聚处理后,返回最终结果。
有时候,会有另外一种情况,比如说存储一年的数据,如果按照hash去索引,那就是分布非常的均匀,这样的话无论查询什么数据都会去所有的shard上面查询,如果数据量比较大,那么响应速度就比较慢,但这时,我们通过调查发现,一年12个月的数据本身分布并不均匀,有几个月的数据偏多,有几个月的数据偏少,理想情况下,数据偏少的月,查询性能应该更快,但如果是基于hash分片,那么我们并不能实现这种需求,因为hash分片,查询时候必须命中所有的shard之后,查询的结果才是准的,这样一来每次查询都要扫描所有的shard,比如我已经知道数据本身就是1月份的,那其实最好情况下,只查询1月份的数据就行,而不需要把一年的数据都扫描一遍,导致最终结果就是慢的更慢,快的也慢所以我们要针对性的做优化。
那么如何优化,其实思路也比较明确了,那就是按照月份分区,每一个月份的数据都存放在指定的分区中,如果mysql那就是每一个月份一张表,然后查询的时候,直接查询对应月份的数据即可,在es和solr中原理也大致如此,唯一不同的地方在以es 和 solr都比较方便的支持了路由字段的设置而如果数据库,则需要自己通过中间件的方式来搞定,比如说mycat等。
使用路由
es中使用路由字段,看一个官网给的一个例子
1 | #指定了一个用户的属性作为路由进行分区,然后查询的时候也必须指定路由。 |
注意,只要在索引的时候加入了路由字段,那么在以后的get、delete、update中都必须指定使用路由字段,否则会出现问题。
路由字段,也是可以被查询的:
1 | GET my_index/_search |
也可以指定多个路由字段:
1 | GET my_index/_search?routing=user1,user2 |
如果指定了多个用户属性,那么只会查询关联了这两个route属性的shard
如果加入路由字段之后,其他的操作都必须指定字段,为了避免在使用时忘了添加路由字段,导致同类型数据会分布在多个shard上面,这就违反了路由的原则,所以我们可以在mapping中设置路由字段是必需字段,否则会提示错误:
1 | PUT my_index2 |
缺失字段会抛出异常:routing_missing_exception
还需要注意的是如果使用了路由字段,那么_id字段只能由用户来保证唯一性,因为同一个id的数据,如果路由字段不一样,他是可以被存在到多个shard中的,而默认情况下是不会出现这种情况的。
集群
集群组成
首先启动的一定是主节点,主节点存储的是集群的元数据信息;
Node2节点启动之前会配置集群的名称Cluster-name:ess,然后配置可以作为主节点的ip地址信息discovery.zen.ping.unicast.hosts: [“10.0.1.11”,“10.0.1.12”],配置自己的ip地址networ.host: 10.0.1.12;
Node2启动的过程中会去找到主节点Node1告诉Node1我要加入到集群里面了,主节点Node1接收到请求以后看Node2是否满足加入集群的条件,如果满足就把node2的ip地址加入的元信息里面,然后广播给集群中的其他节点有新节点加入,并把最新的元信息发送给其他的节点去更新;
集群中的所有节点的元信息都是和主节点一致的,因为一旦有新的节点加入进来,主节点会通知其他的节点同步元信息。
集群有节点出现故障,如主节点挂了,会重新选择主节点。
集群中创建索引的流程
- 1、首先请求转发到master节点;
- 2、选择节点 的分片、副本、记录元信息;
- 3、通知给参与存放索引分片、副本的节点从节点创建分片、副本;
- 4、参与的节点向主节点反馈结果;
- 5、等待时间到了,master向一个节点反馈信息,节点响应请求;
- 6、主节点将元信息广播给所有的从节点。
在集群中索引文档
索引文档的步骤:
- 1、node2计算文档的路由值得到文档存放的分片(假定路由选定的是分片0)。
- 2、将文档转发给分片0(P0)的主分片节点 node1。
- 3、node1索引文档,同步给副本(R0)节点node3索引文档。
- 4、node1向node2反馈结果
- 5、node2作出响应
文档是如何路由的
shard = hash(_routing) % num_primary_shards
1 | number_of_primary_shards:创建索引时候指定的主分片数参数值 |
在集群中进行搜索流程
搜索的步骤:如要搜索 索引 s0
- 1、node2解析查询。
- 2、node2将查询发给索引s0的分片/副本(R1,R2,R0)节点
- 3、各节点执行查询,将结果发给Node2
- 4、Node2合并结果,作出响应。
Master节点的工作任务
- 存储集群的元信息,如集群名称、集群中的节点
- 转发创建索引和索引文档的请求
- 和其他的节点进行通信,告诉其他节点有新的节点加入等