>  기사  >  데이터 베이스  >  Go 언어의 Lua 스크립트를 통해 Redis를 작동하는 방법

Go 언어의 Lua 스크립트를 통해 Redis를 작동하는 방법

王林
王林앞으로
2023-05-27 19:52:111026검색

머리말

기본 라이브러리 중 하나에서 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")

  • 스크립트가 false를 반환하면 어떻게 될까요? Go는 nil입니다. 스크립트가 true를 반환하면 Go는 int64 유형 1

  • 을 가져옵니다. 스크립트가 {"ok": ...}를 반환하면 Go는 redis 상태 유형(true/false)

    을 가져옵니다.
스크립트가 {"err": ...}를 반환하면 Go에서 err 값을 얻습니다. return redis.error_reply("My Error")를 통해서도 얻을 수 있습니다.

스크립트는 숫자 유형을 반환하며 Go에서 얻은 것은 int64 유형입니다.

스크립트에서 들어오는 KEYS/ARGV의 값을 문자열 유형에서 숫자 유형으로 변환해야 하는 경우 다음을 사용해야 합니다. to_number 함수


🎜🎜If 스크립트가 오랫동안 실행되면 어떻게 되나요? 🎜🎜🎜Lua 스크립트 실행 중에는 다른 작업으로 인한 데이터 오염을 방지하기 위해 이 기간 동안 다른 명령을 실행할 수 없으며, 실행이 완료될 때까지 다른 요청을 계속할 수 없습니다. Lua 스크립트 실행 시간이 lua-time-limit를 초과하면 해당 요청이 SCRIPT KILL(스크립트 종료) 또는 SHUTDOWN NOSAVE(결과를 저장하지 않고 Redis 종료)가 아닌 이상 다른 요청에 Busy 오류가 발생합니다. 🎜🎜더 많은 내용은 다음을 참조하세요. 여기서는 주로 Go 사용 경험을 바탕으로 몇 가지 요약을 제공합니다. https://redis.io/commands/eval🎜🎜키 값을 얻을 때 값에 더 자주 액세스하면 수명 주기가 연장되도록 요구하는 보다 "복잡한" 스크립트입니다. 또한 업데이트 시간을 반드시 비교해야 합니다. 업데이트가 필요하지 않으면 얻은 값을 직접 반환하고 그렇지 않으면 redis.Nil을 반환합니다🎜🎜
// 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제