Redis Luaスクリプト使用(分散ロック)
19567 ワード
Luaスクリプト
Luaは標準Cで作成され、コードは簡潔で優美で、ほとんどのオペレーティングシステムとプラットフォームでコンパイルし、実行することができます.完全なLua解釈器は200 kにすぎず、現在のすべてのスクリプトエンジンの中でLuaの速度が最も速い.これらはすべてLuaが埋め込みスクリプトとして最適な選択であることを決定します.
RedisでLuaスクリプトを使用するメリット複数のリクエストが1つにまとめる送信され、リクエスト回数 が減少する. redisはluaスクリプトを全体として動作し、redisにおける原子動作 を提供する.クライアントによって送信されたスクリプトはredis中に永続的に存在し、他のクライアントはスクリプト を多重化することができる.高速、移植可能、ソースサイズコンパクト Luaスクリプト使用(spring-boot)
開発環境
Spring-bootプロジェクト、spring-boot-starter-data-redis依存に参加
maven buildにスクリプトファイルに関するresourceを必ず追加し、luaスクリプトをclassesディレクトリにパッケージします.次のようにします.
Luaスクリプトの作成
ディレクトリ構造src/main/java/demo/script/xx.lua
redisのsetnxを使用してkeyをロックする
lock.lua
KEYS,ARGVキーワードの意味:
KEYS[n]は入力パラメータkeyのプライマリ・キーの最初のプライマリ・キー値を表し、0はなしを表し、複数入力可能であり、KEYS[2]が入力した2番目のプライマリ・キー
ARGV[n]は、入力されたパラメータ値を表し、同様に複数の入力が可能である
ロック解除スクリプト
unlock.lua
Luaスクリプト読み出しパッケージ
パッケージされたluaスクリプトをSpringコンテナに追加し、呼び出しが容易になります.
RedisTemplateがluaスクリプトを呼び出す
まとめ
luaスクリプトがredisに現れる原子性は、いくつかの複雑な操作にトランザクション保証を提供します.2つ目は、ネットワークのオーバーヘッドとリクエスト回数を削減します.この二つの点は筆者が最も重要だと思う.
Luaは標準Cで作成され、コードは簡潔で優美で、ほとんどのオペレーティングシステムとプラットフォームでコンパイルし、実行することができます.完全なLua解釈器は200 kにすぎず、現在のすべてのスクリプトエンジンの中でLuaの速度が最も速い.これらはすべてLuaが埋め込みスクリプトとして最適な選択であることを決定します.
RedisでLuaスクリプトを使用するメリット
開発環境
Spring-bootプロジェクト、spring-boot-starter-data-redis依存に参加
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.2.5.RELEASEversion>
<relativePath/>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redisartifactId>
dependency>
dependencies>
maven buildにスクリプトファイルに関するresourceを必ず追加し、luaスクリプトをclassesディレクトリにパッケージします.次のようにします.
<build>
<resources>
<resource>
<directory>${basedir}/src/main/javadirectory>
<includes>
<include>**/*.luainclude>
includes>
resource>
resources>
build>
Luaスクリプトの作成
ディレクトリ構造src/main/java/demo/script/xx.lua
redisのsetnxを使用してkeyをロックする
local expire=tonumber(ARGV[2])
local ret=redis.call('set',KEYS[1],ARGV[1],'NX','PX',expire)
local strret=tostring(ret)
-- , "table: 0x55d040f2edc0", false
redis.call('set','result',strret)
if strret == 'false' then
return false
else
return true
end
lock.lua
KEYS,ARGVキーワードの意味:
KEYS[n]は入力パラメータkeyのプライマリ・キーの最初のプライマリ・キー値を表し、0はなしを表し、複数入力可能であり、KEYS[2]が入力した2番目のプライマリ・キー
ARGV[n]は、入力されたパラメータ値を表し、同様に複数の入力が可能である
ロック解除スクリプト
redis.call('del','result')
if redis.call('get',KEYS[1]) == ARGV[1] then
return redis.call('del',KEYS[1])
else
return 0
end
unlock.lua
Luaスクリプト読み出しパッケージ
パッケージされたluaスクリプトをSpringコンテナに追加し、呼び出しが容易になります.
@Configuration
public class RedisScriptConfig {
@Bean
public RedisScript<Boolean> lockScript(){
RedisScript<Boolean> redisScript=null;
try {
ScriptSource scriptSource=new ResourceScriptSource(new ClassPathResource("demo\\script\\lock.lua"));
redisScript = RedisScript.of(scriptSource.getScriptAsString(), Boolean.class);
} catch (IOException e) {
e.printStackTrace();
}
return redisScript;
}
@Bean
public RedisScript<Long> unlockScript(){
RedisScript<Long> redisScript=null;
try {
ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("demo\\script\\unlock.lua"));
redisScript=RedisScript.of(scriptSource.getScriptAsString(),Long.class);
} catch (IOException e) {
e.printStackTrace();
}
return redisScript;
}
}
RedisTemplateがluaスクリプトを呼び出す
@RestController
public class RedisLuaController {
private final Log logger= LogFactory.getLog(RedisLuaController.class);
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Autowired
RedisScript<Boolean> lockScript;
@Autowired
RedisScript<Long> unlockScript;
@RequestMapping("distrLock/{key}/{uuid}")
public void Lock(@PathVariable String key,@PathVariable String uuid){
try {
Boolean flag = redisTemplate.execute(lockScript, Collections.singletonList(key), uuid, "50000");
logger.info("locked:{}"+flag);
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping("distrUnlock/{key}/{uuid}")
public void unlock(@PathVariable String key,@PathVariable String uuid){
try {
Long unlocked = redisTemplate.execute(unlockScript, Collections.singletonList(key), uuid);
logger.info("unlock status "+unlocked.toString());
} catch (Exception e) {
logger.error(" "+e.getMessage());
}
}
}
まとめ
luaスクリプトがredisに現れる原子性は、いくつかの複雑な操作にトランザクション保証を提供します.2つ目は、ネットワークのオーバーヘッドとリクエスト回数を削減します.この二つの点は筆者が最も重要だと思う.