主要知识点
- 悲观锁的简要说明
- 全局锁实验
- 全局锁的优缺点及适用场景
一、悲观锁的简要说明
悲观锁不象悲观锁那样基于version进行并发控制,而是直接加锁,加锁后只有加锁的线程可以使用该index(或type),其他线程不同同时使用,只有当这个线程解锁之后,其他线程才能恢复使用,本节合文件系统建模的这个案例,把悲观锁的并发控制,3种锁粒度,都给大家仔细讲解一下。其中最粗的一个粒度就是全局锁,也就是直接锁整个index。现假设/workspace/projects/helloworld目录下有一个名为README.txt的文件。如果有多个线程要并发地修改/workspace/projects/helloworld下的README.txt的文件名。此时如果不加锁,纯并发的话,先执行的修改操作被后执行的修改操作给覆盖了。
乐观锁的做法是先获得版本号(get current version),然后带着这个current version去执行修改,如果一旦发现数据已经被别人给修改了,version号跟之前自己获取的已经不一样了, 就必须重新获取新的version号再次尝试修改。直到一致为止。
悲观锁的做是在修改之前就直接就尝试给这条数据加个锁,如果加锁不成功就等待。继续加锁,如果加锁成功,此时就只有这一个线程能执行的操作,其他线程不能执行操作。
第一种锁:全局锁,直接锁掉整个fs index
二、全局锁实验
1、加锁
PUT /fs/lock/global/_create
{}
- fs: 你要上锁的那个index
- lock: 就是你指定的一个对这个index上全局锁的一个type。也就是说加锁也是创建一个type,只不过这个type的作用就是用来加锁。
- global: 就是你上的全局锁对应的这个doc的id。global就是lock的id。
- _create:强制必须是创建操作,也就是说必须是本线程新建锁,如果其他线程已创建锁,那么创建失败,则会报错。
{
"_index": "fs",
"_type": "lock",
"_id": "global",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
另外一个线程同时尝试上锁就会报错,但是我在第二个线程上执行修改更新操作会成功,不知为会么?
这里只有当第二个线程上同样的锁(id相同)才会报错,也就是说第二个线程也执行如下语句才会报错,
PUT /fs/lock/global/_create
{}
如果第二个线程执行这样的语句,就不会报错,
PUT /fs/lock/fuck/_create
{}
然后可以执行各种操作。。。
POST /fs/file/1/_update
{
"doc": {
"name": "README1.txt"
}
}
2、解锁
解锁其实就是删除对应id的doc
DELETE /fs/lock/global
三、全局锁的优缺点及适用场景
优点:操作非常简单,非常容易使用,成本低
缺点:直接就把整个index给上锁了,这个时候对index中所有的doc的操作,都会被block住,导致整个系统的并发能力很低。通过和自已的实验,实际不会block住其他线程,
适用场景:上锁解锁的操作不是频繁,然后每次上锁之后,执行的操作的耗时不会太长,用这种方式,方便