文章目录
- 1. 查看文档存储分片
- 2. 是怎么分配分片的呢?
- 3. 注意 添加 Routing 后问题
- 4. 案例 :
- 5. 锁概念
- 5.1 悲观锁概念
- 5.2 乐观锁
- 6. 版本控制
- 6.7 之前
- 最新方案(Es6.7 之后)
1. 查看文档存储分片
- ElasticSearch 是一个分布式系统,当我们存储一个文档到 es 上之后,这个文档则会存储到 master 节点上的 某一个分片中
- 例如 新建一个索引
创建一个 lionet 索引
put lionet
ES 创建索引 默认 1个分片 一个 副本
- 可通过 number_of_replicas 修改 副本数
PUT lionet/_settings
{
"number_of_replicas": 2
}
错误
, 索引创建完成后, 不可在动态修改索引的 shards(分片数)t, 索引和分片在创建 Index 时指定分片数量、副本数量
PUT lionet/_settings
{
"index":
{
"number_of_shards" : 2
}
}
5. 创建一个新的 索引有两个分片, 2 个副本,
PUT /my_index
{
"settings": { ... any settings ... },
"mappings": {
"type_one": { ... any mappings ... },
"type_two": { ... any mappings ... },
...
}
}
案例
PUT /bravelionet
{
"settings": {
"number_of_replicas": 1
, "number_of_shards": 2
}
}
查询索引
GET _cat/shards/bravelionet?v
- shard 0 1 代表存在两个分片
- node : node -1 node-2 代表两个分片(master 除外)
创建 10 个 文档查询分布
10个文档分布不同节点不分片上, master节点 1号分片存储2 个文档, node-2为存储 1号分片副本( ES 索引 是 0 至 N-1 编号)
2. 是怎么分配分片的呢?
- ES 中路由是通过哈希算法,将具有相同 hash值的文档放置同一个主分片中,分片计算位置 公式 :
shard=hash(routing) % number_of_primary_shards - routing可以是任意字符串, 如果不一定 routing 默认使用 文档 id 作为 routing值, 通过 hash 算法计算出来一个 数字, 然后将 该 数字 和 分片数量取余, 取余的结果则是存储位置
- 默认的这种 routing 模式, 最大的优势是负载均衡, 这种模式是非常友好的存储到不同的分片中
(当然不是绝对的)
, 但是: 这种默认算法有一个很大的劣势, 就是查询时无法确定文档的位置, 此时他会广播到所有分片上执行查询,另一方便
则是使用默认的路由模式,后期修改分片不方便 - 当然开发者是可以进行自定义 routing值得
PUT index/_doc/id?routing=routing value
POST bravelionet/_doc/20?routing=lionet
{
"title":"倔强的小狮子",
"content":"学习 Elastic Search "
}
3. 注意 添加 Routing 后问题
- 上面文档中提高删除文档时如果添加了 routing 不携带 routing是删除不成功的
- 文档添加了 routing后不只是删除时需要添加 routing, 查询和修改时也是需要进行携带的
- 查询 GET index/_doc/id?routing=routing value
GET bravelionet/_doc/20?routing=1
- 修改 PUT index/_doc/id?routing=routing value
PUT bravelionet/_doc/20?routing=1
{
"title":"小狮子"
}
- 修改时需特别注意 如果在修改 在创建时指定了 routing的 文档时 譬如没 指定 routing 值, 则会进行创建新 文档 (可以理解成 :修改时 ES 会先进行查询, 在进行修改, 如果查询到则直接进行创建操作)
- 删除 DELETE index/_doc/id?routing=routing value
delete bravelionet/_doc/20?routing=1
4. 案例 :
对于用户数据,我们可以将 userid 作为 routing,这样就能保证同一个用户的数据保存在同一个分片中,检索时,同样使用 userid 作为 routing,这样就可以精准的从某一个分片中获取数据
5. 锁概念
5.1 悲观锁概念
在进行操作都非常悲观,认为别人可能会进行进行操作数据, 所以会屏蔽所有可能破坏数据完整性操作,关系型数据库中悲观锁使用的比较多一些 例如 : 行锁,表锁 等
5.2 乐观锁
在进行操作时很乐观,都会认为不会有人破坏本次操作数据的完整性,只有才提交时才会检查数据的完整性,这种锁的方式可以省去锁的开销,有利于提高系统的 QPS
索引在ES中使用 乐观锁( version 版本锁)
6. 版本控制
6.7 之前
- 在 ES 6.7 之前,使用 version + version_type 来进行乐观并发锁的控制,根据上诉文档的案例操作, 发现每次
更改文档时 version 都会进行 +1
, 所以 ES 是通过 version 来确保每次操作的有序完整性 - version 分为内部版本锁和外部版本锁, ES 自己维护的 ES 的版本成为 内部版本锁,当创建一个文档时, ES 会给文档的版本赋值 1, 每当用户修改一次文档, 版本则会 +1
- 以后更新的时候,版本要大于已有的版本号
- vertion_type=external 或者 vertion_type=external_gt 表示以后更新的时候,版本要大于已有的版本号
- vertion_type=external_gte 表示以后更新的时候,版本要大于等于已有的版本号。
最新方案(Es6.7 之后)
- 现在使用 if_seq_no 和 if_primary_term 两个参数来做并发控制
-
seq_no 不属于某一个文档
,它是属于整个索引的(version 则是属于某一个文档的,每个文档的 version 互不影响
)。现在更新文档时,使用 seq_no 来做并发。由于 seq_no 是属于整个 index 的,所以任何文档的修改或者新增,seq_no 都会自增。 - 现在就可以通过 seq_no 和 primary_term 来做乐观并发控制
\