Elasticsearch默认的并发控制
在Elasticsearch中默认是使用乐观锁基于_version字段来实现并发控制的,_version字段记录的时候每次更新的版本号,只有拿到最新版本号的client才能更新成功,其他拿到过期数据的client则更新失败。
Elasticsearch悲观锁控制方案
下面介绍一下基于Painless脚本实现的Elasticsearch悲观锁方案。
读锁(s锁):允许多个线程同时持有,用于对共享资源的读取,与写锁互斥。
写锁(x锁):具有排他性,同一时间只能允许一个线程持有,用于对共享资源的写操作。
对document加写锁
在这里专门建立了一个index用于锁的管理,下面展示的是对docment id为1的文档加写锁,如果这时锁是不存在的,直接创建document,并且字段
lock_type=x代表是写锁标志。如果这时锁已经存在,则直接返回noop,无修改就作为上锁失败的标志,使用返回结果里的result=noop作为判断。
POST /my_lock/_update/1
{
"upsert":{
"lock_type": "x",
"read_lock_count":0
},
"script": {
"lang": "painless",
"source": """
ctx.op = 'noop';
return
"""
}
}
对document加读锁
如果锁不存在同样新建document,并且设lock_type=s作为读锁的标志。如果锁存在,则判断锁类型,如果是写锁的话,直接返回noop表示上锁失败。如果是读锁的话则将read_lock_count字段加1,表示此时持有读锁的线程数量。
POST /my_lock/_update/1
{
"upsert":{
"lock_type": "s",
"read_lock_count":1
},
"script": {
"lang": "painless",
"source": """
if(ctx._source.lock_type == params.lock_type){
ctx._source.read_lock_count += 1;
return
}
ctx.op = 'noop';
return
""",
"params": {
"lock_type": "s"
}
}
}
锁的释放
判断锁的类型,如果是读锁并且持有读锁的数量大于1的话就将持有读锁的数量减一,否则直接将这个锁delete掉。
POST /my_lock/_update/1
{
"script": {
"lang": "painless",
"source": """
if(ctx._source.lock_type == "s" && ctx._source.read_lock_count>1){
ctx._source.read_lock_count -= 1;
return
}
ctx.op = 'delete';
return
"""
}
}