1、悲观锁
对于一个共享数据,某个线程访问到这个数据的时候,会认为这个数据随时有可能会被其他线程访问而造成数据不安全的情况,因此线程在每次访问的时候都会对数据加一把锁。这样其他线程如果在加锁期间想访问当前数据就只能等待,也就是阻塞线程了。
2、乐观锁
乐观锁的并不是真的加了一把锁。乐观锁机制表示线程在每次操作数据的时候,都乐观的认为不会有其他线程来会来操作当前数据,因此不加锁。但是乐观锁在每次更新数据的时候都会通过比对版本号来检查当前数据是不是被其他线程修改过。如果没有,则正常修改数据并且更新数据版本号,否则,仅更新自身版本号。
3、如何选择
•首先,悲观锁和乐观锁没有孰优孰劣,他们各自有各自的适用场景。•当并发写入数量较少的情况,乐观锁因为并没有真正的去上锁,从而避免频繁的上锁、释放锁而带来的性能开销,从而提升了吞吐性能•当并发写入量较大的时候,线程之间竞争激烈,就会导致线程频繁的尝试,每次尝试都要进行版本号比对,尝试失败还要更新自身携带的版本号,这样反复尝试积累的性能损耗可能已经超过了使用直接加锁然后将线程挂起而带来的损耗,此时使用悲观锁更加合适。
4、乐观锁并发控制
Elasticsearch 是分布式的。创建、更新或删除文档时,必须将文档的新版本复制到集群中的其他节点。ES 也是异步并行的,所以这些复制请求是并行发送的,并且可能不按顺序执行到每个节点。ES需要一种并发策略来保证数据的安全性,而这种策略就是 乐观锁并发控制策略。
为了保证旧文档不会被新文档覆盖,对文档执行的每个操作都由协调该更改的主分片分配一个序列号(_seq_no
)。每个操作都会操作序列号递增,因此可以保证较新的操作具有更高的序列号。然后,ES 可以使用操作序列号来确保更新的文档版本永远不会被分配了较小序列号的版本覆盖。
4.1 版本号:_version
基本原理
每个索引文档都有一个版本号。默认情况下,使用从 1 开始的内部版本控制,每次更新都会增加,包括删除。版本号可以设置为外部值(例如,如果在数据库中维护)。要启用此功能,version_type
应设置为 external
。提供的值必须是大于或等于 0 且小于 9.2e+18 左右的数字长整型值。
使用外部版本类型时,系统会检查传递给索引请求的版本号是否大于当前存储文档的版本。如果为真,文档将被索引并使用新的版本号。如果提供的值小于或等于存储文档的版本号,则会发生版本冲突,索引操作将失败。
作用范围
_version 的有效范围为当前文档
版本类型
•external
或者 external_gt
:仅当给定版本严格高于存储文档的版本或不存在现有文档时才索引文档。给定版本将用作新版本,并将与新文档一起存储。提供的版本必须是非负长整数。•external_gte
仅当给定版本等于或高于存储文档的版本时才索引文档。如果没有现有文档,则操作也会成功。给定版本将用作新版本,并将与新文档一起存储。提供的版本必须是非负长整数。external_gte
需要谨慎使用,否则可能会丢失数据。
4.2 使用 if_seq_no
和 if_primary_term
进行版本控制
if_seq_no 和 if_primary_term 是用来并发控制,和 _version
不同,_version
属于当前文档,而 _seq_no
属于整个index。
_seq_no
和 _primary_term
•_seq_no:索引级别的版本号,索引中所有文档共享一个 _seq_no
。•_primary_term:_primary_term是一个整数,每当Primary Shard发生重新分配时,比如节点重启,Primary选举或重新分配等,_primary_term会递增1。主要作用是用来恢复数据时处理当多个文档的_seq_no 一样时的冲突,避免 Primary Shard 上的数据写入被覆盖。
if_seq_no
和 if_primary_term
if_seq_no 和 if_primary_term 是具体在控制并发的时候使用的参数,其中 if_seq_no
代表版本号。
长按加关注
学习唠嗑两不误

觉得内容还不错的话,给我点个“在看”呗






