ES中所有数据均衡的存储在集群中各个节点的分片中,会影响ES的性能、安全和稳定性, 所以很有必要了解一下它。
一个索引可以存储超出单个结点硬件限制的大量数据(比如说我的电脑D盘放满了,我也可以在E盘解压一个服务器,让他们集群,可以共享索引库,就可以平均分享一下就可以了.)。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。分片很重要,主要有两方面的原因: 1)允许你水平分割/扩展你的内容容量。 2)允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量。
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
分片还有副本,叫replica shard
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了,这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。
简单来讲就是咱们在ES中所有数据的文件块,也是数据的最小单元块,整个ES集群的核心就是对所有分片的分布、索引、负载、路由等达到惊人的速度
实列场景:
假设 IndexA 有2个分片,我们向 IndexA 中插入10条数据 (10个文档),那么这10条数据会尽可能平均的分为5条存储在第一个分片,剩下的5条会存储在另一个分片中。
和主流关系型数据库的表分区的概念有点类似,如果你比较熟悉关系型数据库的话。
创建 IndexName 索引时候,在 Mapping 中可以如下设置分片 (curl)
PUT indexName
{
"settings": {
"number_of_shards": 5
}
}
注意
索引建立后,分片个数是不可以更改
分片个数是越多越好,还是越少越好了?根据整个索引的数据量来判断。
实列场景:
如果 IndexA 所有数据文件大小是300G,改怎么定制方案了?(可以通过Head插件来查看)
建议:(仅参考)
1、每一个分片数据文件小于30GB
2、每一个索引中的一个分片对应一个节点
3、节点数大于等于分片数
根据建议,至少需要 10 个分片。
结果: 建10个节点 (Node),Mapping 指定分片数为 10,满足每一个节点一个分片,每一个分片数据带下在30G左右。
SN(分片数) = IS(索引大小) / 30
NN(节点数) = SN(分片数) + MNN(主节点数[无数据]) + NNN(负载节点数)
我们可以指定es去具体的分片查询从而进一步的实现es极速查询。
randomizeacross shards
随机选择分片查询数据,es的默认方式
_local
优先在本地节点上的分片查询数据然后再去其他节点上的分片查询,本地节点没有IO问题但有可能造成负载不均问题。数据量是完整的。
_primary
只在主分片中查询不去副本查,一般数据完整。
_primary_first
优先在主分片中查,如果主分片挂了则去副本查,一般数据完整。
_only_node
只在指定id的节点中的分片中查询,数据可能不完整。
_prefer_node
优先在指定你给节点中查询,一般数据完整。
_shards
在指定分片中查询,数据可能不完整。
_only_nodes
可以自定义去指定的多个节点查询,es不提供此方式需要改源码。
/**
* 指定分片 查询
*/
@Test
public void testPreference()
{
SearchResponse searchResponse = transportClient.prepareSearch(index)
.setTypes("add")
//.setPreference("_local")
//.setPreference("_primary")
//.setPreference("_primary_first")
//.setPreference("_only_node:ZYYWXGZCSkSL7QD0bDVxYA")
//.setPreference("_prefer_node:ZYYWXGZCSkSL7QD0bDVxYA")
.setPreference("_shards:0,1,2")
.setQuery(QueryBuilders.matchAllQuery()).setExplain(true).get();
SearchHits hits = searchResponse.getHits();
System.out.println(hits.getTotalHits());
SearchHit[] hits2 = hits.getHits();
for(SearchHit h : hits2)
{
System.out.println(h.getSourceAsString());
}
}
一个index包含3T的数据,每台服务器承载1T的数据,此时我们创建index 的时候设置primaryshard有3个,那么每台服务器就会一个primaryshard, 然后每台服务器都有均匀负载1T的数据.
这就是index分片的基本原理.
ElasticSearch底层基于Lucene开发的,其实底层每个shard就是一个Lucene实例,每个shard都有完整的建立索引和处理请求的能力
就好比说有有六台机器总共七个shard, 肯定就会有一台机器有两个shard, 此时给ElasticSearch集群新增一台机器进来,那么有两个shard的那台机器会自动给一个shard分配给新加入的机器上去.
每个document肯定只存在于某一个primary shard以及其对应的replica shard中,一个document不可能存在于多个primary shard
如果primary shard宕机了,对应replica shard 里面数据依然是存在的,并且还对外处理读请求.
默认有10个shard,5个primary shard,5个replica shard
primary shard数量默认是5 ,replica shard数量默认是1,假如说我primary shard设置为3了,replica shard设置成了1, 那么默认就是3个primary shard 和3个replica shard .
如果我给replica shard设置成了2 ,那么就是每个primaryshard有两个replica shard,结果就是3个primary shard 和 6个replica shard .
否则节点宕机,primary shard和副本都丢失,起不到容错的作用,但是可以和其他primary shard的replica shard放在同一个节点上,
就是可以primaryshard 1和replicashard2放在一个服务器上面, 但是primaryshard1和replicashard1不能放在一个服务器上,
如果primaryshard1和replicashard1放在一台机器上,万一宕机的话,你primaryshard1和replicashard1全部丢失.
所以ElasticSearch官方不允许primary shard不能和自己的replica shard放在同一个节点上
单node环境下,创建一个index,有3个primary shard,3个replica shard,此时集群status是yellow,这个时候,只会将3个primary shard分配到仅有的一个node上去,另外3个replica shard是无法分配的
集群可以正常工作,但是一旦出现节点宕机,数据全部丢失,而且集群不可用,无法承接任何请求
PUT /test_index
{
"settings" : {
"number_of_shards" : 3,
"number_of_replicas" : 1
}
}
如果是一台机器当想,那么这一台机器上就会有3个primary shard,3个replica shard ,此时集群状态为yellow
如果新加入了一台机器的话.ElasticSearch会自动将3个replica shard分配到新的机器上面去.primaryshard的数据会拷贝到对应的replicashard上面去.
然后primaryshard和对应的replicashard上的数据是一模一样的
此时客户端发送读请求的时候,可以去primaryshard1,也可以去primaryshard1对应的replicashard1上去处理.
https://blog.csdn.net/qq_38486203/article/details/80077844
中华石杉的Elasticsearch顶尖高手系列 课程