2.6 버전이상의 Redis에서는 EVAL
,EVALSHA
명령어를 통한 Lua 스트립트를 지원한다.
Lua는 명령형/절차형 프로그래밍 언어다
> EVAL script numkeys [key [key ...]] [arg [arg ...]]
> EVALSHA sha1 numkeys [key [key ...]] [arg [arg ...]]
EVAL
명령의 script
는 실행시킬 Lua 스크립트를 뜻하며, EVALSHA
명령의 sha1
은 스크립트의 SHA1 해시값을 뜻한다.
numkeys
는 이어지는 key의 수를 뜻하며, numkeys
가 0이라면 뒤에 주어지는 값들은 전부 arg라는 뜻이된다.
Lua
Lua는 명령형/절차형 프로그래밍 언어로, 공식 홈페이지에서 관련 정보를 얻을 수 있다.
문법이 단순하고 가볍다는 특징이 있으며, 함수형 프로그래밍도 어느정도 가능하다.
Spring Data Redis에서는 직렬화와 자동으로 스크립트 캐시를 실행하는 고수준의 추상화를 제공한다.
RedisTemplate
의 execute
메서드에서 ScriptExecutor
를 사용해 스크립트를 실행시키며, 기본적으로 템플릿의 직렬화기를 통해 주어진 키와 인수들을 직렬화하고, 스크립트 결과를 역직렬화한다.
스크립트 실행 동작은 1차적으로 EVALSHA
명령을 실행하여 캐시된 스크립트인지 확인하고, 그렇지않다면 EVAL
을 실행하는 식으로 동작한다.
Redis 스크립트 캐시는 이전에 실행한 전적이 있는 스크립트를 저장하는 저장소다.
EVALSHA
명령은 캐시된 스크립트 명령을 실행하는 명령어다.
스크립트의 SHA1 해시 값을 사용하여 스크립트를 실행한다.
@Bean
public RedisScript<Boolean> script() {
ScriptSource scriptSource = new ResourceScriptSource(new ClassPathResource("META-INF/scripts/checkandset.lua"));
return RedisScript.of(scriptSource, Boolean.class);
}
위 예시에서 실행시킬 스크립트는 META-INF/scripts/checkandset.lua
에 작성되어 있다.
이를 바탕으로 RedisScript
객체를 생성시키는 메서드다.
public class Example {
@Autowired
RedisOperations<String, String> redisOperations;
@Autowired
RedisScript<Boolean> script;
public boolean checkAndSet(String expectedValue, String newValue) {
return redisOperations.execute(script, singletonList("key"), asList(expectedValue, newValue));
}
}
이후에 redisOperations.execute
을 통해 스크립트를 실행시키는데, 그 과정에서 key와 value를 전달한다.
여기서 expectedValue는 첫번째 arg 값이되며, newValue는 두번째 arg 값이 된다.
-- checkandset.lua
local current = redis.call('GET', KEYS[1])
if current == ARGV[1]
then redis.call('SET', KEYS[1], ARGV[2])
return true
end
return false
동작시킬 스크립트를 확인해보면,
key
에 저장된 값과 expectedValue
이 동일한지 체크하고 newValue
로 바꾸는 스크립트다.
즉, KEYS[1]
는 singletonList("key")
/ ARGV[1]
는 expectedValue
/ ARGV[2]
는 newValue
와 매칭된다.