머리말
기본 라이브러리 중 하나에서 Redis와의 통신 비용을 줄이기 위해 일련의 작업을 LUA 스크립트로 캡슐화하고 Redis에서 제공하는 EVAL 명령을 사용하여 작업을 단순화했습니다.
EVAL이 제공할 수 있는 기능:
LUA 스크립트에 여러 작업을 캡슐화할 수 있습니다. Redis 명령어가 여러 개인 경우 캡슐화한 후 모든 매개변수를 Redis에 한 번에 전송하면 결과를 얻을 수 있습니다.
Redis는 Lua 스크립트 실행 중에 다른 명령이 삽입 및 실행되지 않도록 보장하여 데이터베이스 트랜잭션과 같은 원자성을 제공합니다.
Redis는 캐시된 스크립트의 SHA 값에 따라 스크립트를 캐시합니다. Lua 코드를 다시 전송할 필요가 없습니다. 또한 자체 코드에서 Lua 스크립트를 변경하면 Redis는 실행 시 반드시 최신 코드를 사용합니다.
"github.com/go-redis/redis"와 같은 일반 Go 라이브러리를 가져와서 다음 코드를 구현하세요.
Lua 스크립트 생성
// KEYS: key for record // ARGV: fieldName, currentUnixTimestamp, recordTTL // Update expire field of record key to current timestamp, and renew key expiration var updateRecordExpireScript = redis.NewScript(` redis.call("EXPIRE", KEYS[1], ARGV[3]) redis.call("HSET", KEYS[1], ARGV[1], ARGV[2]) return 1 `)
이 변수가 생성되면 Lua 코드가 실행되지 않으며 기존 Redis 연결이 필요하지 않습니다.
Redis에서 제공하는 Lua 스크립트 지원에는 기본적으로 KEYS와 ARGV라는 두 개의 배열이 있습니다. KEYS는 스크립트가 실행될 때 전달되는 여러 키 값을 나타내고 ARGV는 전달되는 여러 매개 변수를 나타냅니다. Lua 코드는 간결해야 하고 읽기 어려워야 하므로 이러한 매개변수에 대한 주석을 작성하는 것이 가장 좋습니다
참고:위 코드는 `가 남아 있는 줄이 비어 있어도 ``를 사용합니다. 입력하면 한 줄로 간주되므로 오류를 보고할 때 잘못된 코드 줄 번호를 읽지 마십시오.
Lua 스크립트 실행
updateRecordExpireScript.Run(c.Client, []string{recordKey(key)}, expireField, time.Now().UTC().UnixNano(), int64(c.opt.RecordTTL/time.Second)).Err()
실행 시 Run은 먼저 EVALSHA를 통해 캐시를 통해 스크립트 실행을 시도합니다. 캐시가 없으면 EVAL을 사용하여 실행하면 전체 Lua 스크립트가 Redis로 전달됩니다.
Lua 스크립트의 한계
Redis는 os 등 추가 패키지 도입을 제공하지 않습니다. redis 패키지만 가능합니다.
Lua 스크립트는 함수에서 실행되며, 모든 변수는 로컬
return을 사용하여 선언해야 합니다. 여러 값이 반환되면 Redis는 첫 번째 값만 제공합니다.
스크립트 유형 제한
스크립트가 nil을 반환하면 Go에서 얻는 것은 err = redis.Nil
입니다(Get이 값을 찾을 수 없는 것과 동일) err = redis.Nil
(与Get找不到值相同)
脚本返回false时,Go中得到的是nil,脚本返回true时,Go中得到的是int64类型的1
脚本返回{"ok": ...}时,Go中得到的是redis的status类型(true/false)
脚本返回{"err": ...}时,Go中得到的是err值,也可以通过return redis.error_reply("My Error")
return redis.error_reply("My Error")
를 통해서도 얻을 수 있습니다. 스크립트는 숫자 유형을 반환하며 Go에서 얻은 것은 int64 유형입니다. 스크립트에서 들어오는 KEYS/ARGV의 값을 문자열 유형에서 숫자 유형으로 변환해야 하는 경우 다음을 사용해야 합니다. to_number 함수
// KEYS: rec:key, key // ARGV: currentUnixTimestamp, hotHit, recordTTL, ttl // When there's a hit, var fetchRecordScript = redis.NewScript(local value = redis.call("GET", KEYS[2]) if(value == nil) then return nil end local hit = redis.call("HINCRBY", KEYS[1], "hit", 1) redis.call("EXPIRE", KEYS[1], ARGV[3]) local minHotHit = tonumber(ARGV[2]) local keyTTL = tonumber(ARGV[4]) if(hit > minHotHit)then keyTTL = keyTTL * 2 end redis.call("EXPIRE", KEYS[2], keyTTL) local expire = tonumber(redis.call("HGET", KEYS[1], "expire")) local unixTime = tonumber(ARGV[1]) if(expire == nil or expire < unixTime) then return nil else return value end) // KEYS: key for record // ARGV: fieldName, currentUnixTimestamp, recordTTL // Update expire field of record key to current timestamp, and renew key expiration var updateRecordExpireScript = redis.NewScript(redis.call("EXPIRE", KEYS[1], ARGV[3]) redis.call("HSET", KEYS[1], ARGV[1], ARGV[2]) return 1)
위 내용은 Go 언어의 Lua 스크립트를 통해 Redis를 작동하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!