Redis의 고급 기능 소개

王林
풀어 주다: 2021-01-13 10:11:34
앞으로
2081명이 탐색했습니다.

Redis의 고급 기능 소개

원격 사전 서비스인 Redis(Remote Dictionary Server)는 ANSI C 언어로 작성된 오픈소스 로그형 Key-Value 데이터베이스로 네트워크를 지원하고 메모리 기반 및 영속성이 있으며 다국어 API를 제공합니다. .

(동영상 공유 학습: redis 동영상 튜토리얼)

1. redis 게시 및 구독 모드

Redis는 목록과 같은 메시지 대기열 모드를 제공하는 것 외에도 게시/구독 모드를 구현하는 명령 세트도 제공합니다. 예를 들어 웨이보, 공개 계정 등이 모두 이를 통해 구현될 수 있다.

Redis의 고급 기능 소개

1.2 채널 구독

게시자는 구독자가 메시지를 구독할 수 있는 곳으로 메시지를 보내야 합니다. 구독자는 하나 이상의 채널을 구독할 수 있으며 이 채널의 모든 구독자는 이 메시지를 받게 됩니다.

테스트를 위해 두 개의 클라이언트 열기

客户端1 订阅channel1
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1

客户端2 发布一则消息
127.0.0.1:6379> publish channel1 test
(integer) 1

客户端1 订阅消息
127.0.0.1:6379> subscribe channel1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel1"
3) (integer) 1
1) "message"
2) "channel1"
3) "test"
로그인 후 복사

1.2 규칙에 따라 구독

지원되나요? 및 * 자리 표시자. ?는 한 문자를 나타내고, *는 0개 이상의 문자를 나타냅니다.

4개의 redis-cli를 시작합니다. 하나는 메시지 게시자로, 나머지 3개는 구독자로 시작합니다.
구독자 1: 스포츠 관련 구독

psubscribe *sport
로그인 후 복사

구독자 2: 뉴스 관련 구독

psubscribe news*
로그인 후 복사

구독자 3: 날씨 관련 구독

psubscribe new weather*
로그인 후 복사

출판사:

publish news-sport Kobe
publish news-music jaychou
publish news-weather rain
로그인 후 복사

이때 구독자 1은 고베를, 구독자 구독자 2는 모든 정보와 가입자 3은 비를 받게 됩니다. ㅋㅋㅋ

예를 들어 setnx를 사용하여 분산 잠금을 구현할 때 일반적으로 del에서 예외가 발생할 때 잠금이 해제되는 것을 방지하기 위해 키에 만료를 설정합니다. 이 세 가지 작업을 일련의 명령으로 실행하기를 바랍니다.

Redis 트랜잭션에는 두 가지 특징이 있습니다. Redis의 고급 기능 소개

대기열에 들어간 순서대로 실행됩니다.


다른 클라이언트 요청에 영향을 받지 않습니다.

  • Redis 트랜잭션 설계에는 multi(트랜잭션 시작), exec라는 네 가지 명령이 있습니다. (거래 실행), dicard (거래 취소), 감시 (모니터)

    2.2 거래 사용법
  • 이체 시나리오 A와 B는 각각 100위안을 갖고, A는 B에게 10위안을 이체하고, A는 10위안을 빼고, B는 10위안을 더합니다.

    127.0.0.1:6379> set A 100
    OK
    127.0.0.1:6379> set B 100
    OK
    127.0.0.1:6379> multi
    OK
    127.0.0.1:6379> decrby A 10
    QUEUED
    127.0.0.1:6379> incrby B 10
    QUEUED
    127.0.0.1:6379> exec
    1) (integer) 90
    2) (integer) 110
    127.0.0.1:6379> get A
    "90"
    127.0.0.1:6379> get B
    "110"
    로그인 후 복사

    multi 명령을 통해 거래를 시작하세요. 다중 다중 명령은 동일한 효과를 갖습니다. 다중을 사용하여 트랜잭션을 시작한 후 클라이언트는 여러 명령을 서버에 보냅니다. 이러한 명령은 즉시 실행되지 않지만 실행 명령이 대기열에 배치됩니다. 호출 후 대기열에 있는 명령이 실행됩니다.
  • Discard를 사용하여 트랜잭션 대기열을 지울 수 있습니다.
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> set k2 2
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)
로그인 후 복사

트랜잭션 실행시 문제가 발생하면 롤백되나요?

exec 이전에 오류가 발생함(예: 명령어 구문 오류)

127.0.0.1:6379> clear
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name test
QUEUED
127.0.0.1:6379> hset user lisi
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name
(nil)
로그인 후 복사

exec 이후에 오류가 발생함(동일한 키에 대해 다른 데이터 유형의 명령 사용)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 1
QUEUED
127.0.0.1:6379> hset k1 a b
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get k1
"1"
로그인 후 복사

위의 연산을 통해 트랜잭션 오류가 발생했을 때 알 수 있음 exec 이전에 발생하면 모든 작업이 롤백되고, exec 이후 오류가 발생하면 잘못된 명령만 실행되지 않습니다.
트랜잭션에 오류가 있을 때 Redis가 롤백되지 않는 이유는 무엇입니까?
위 작업에서 Redis는 명령어 구문이 잘못된 경우에만 롤백하고 명령어 작업 오류는 개발자에 의해 발생하는 버그라는 것을 알 수 있습니다. 예를 들어 int 유형에 +1한 다음 실수로 +2, 또는 +1합니다. 문자열 유형이면 롤백이 적용되지 않습니다

2.3 watch 명령

Redis 트랜잭션에 대한 CAS 낙관적 잠금 작업을 제공할 수 있습니다. 즉, 여러 스레드가 변수를 업데이트하면 이전 값이 됩니다. 메모리 주소를 비교하고, 동일하면 새 값으로 업데이트됩니다.

watch를 사용하여 하나 이상의 키를 모니터링할 수 있습니다. 트랜잭션을 시작한 후 exec가 실행되기 전에 모니터링되는 키 중 하나 이상이 수정되면 전체 트랜잭션이 취소됩니다.

먼저 클라이언트 1은 watch를 실행하여 사례금을 모니터링하고 거래를 시작하여 100

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incrby money 100
QUEUED
로그인 후 복사

거래가 끝나기 전에 클라이언트 2는 돈을 100감소
127.0.0.1:6379> decrby money 100
(integer) 900
로그인 후 복사

이때 클라이언트 1이 거래를 종료하고, 그리고 돈의 가치는 변하지 않고 감소합니다. 이는 거래 수정이 유효하지 않음을 나타냅니다

127.0.0.1:6379> exec
(nil)
127.0.0.1:6379> get money
"900"
로그인 후 복사

3. Lua 스크립트


Lua 스크립트는 C 언어로 작성된 가벼운 스크립트 언어입니다. 저장 프로시저와 유사합니다. 루아 스크립트를 사용하는 이유는 무엇입니까?

한 번에 여러 명령을 보내 네트워크 오버헤드를 줄이세요. Redis는 스크립트를 전체적으로 실행하여 원자성(트랜잭션을 이런 식으로 대체할 수 있음)과 스크립트 재사용을 보장하므로 여러 클라이언트가 동일한 논리를 더 쉽게 완료할 수 있습니다.

3.1

을 사용하면 다음 명령을 사용하여 lua 스크립트를 호출할 수 있습니다.

eval script numkeys [key1 key2 key3 ....] [arg1 arg2 arg3 ....]
로그인 후 복사

eval은 lua 스크립트를 실행합니다.

script는 lua 스크립트의 내용을 나타냅니다.

numkeys 키 번호

[key1 key2 key3 ....] 键名参数,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。

[arg1 arg2 arg3 ....] 全局变量,可以在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)

来个简单的例子

127.0.0.1:6379> eval "return {KEYS[1],ARGV[1],KEYS[2],ARGV[2]}" 2 key1 key2 val1 val1
1) "key1"
2) "val1"
3) "key2"
4) "val1"
127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 val1 val1
1) "key1"
2) "key2"
3) "val1"
4) "val1"
로그인 후 복사

在lua脚本如何调用redis命令呢?
我们可以使用 redis.call(command, key [param1, param2…])进行操作

commond redis的命令,如set,get等key 被操作的键[param1, param2…]表示给key的参数

127.0.0.1:6379> eval "redis.call('mset',KEYS[1],ARGV[1],KEYS[2],ARGV[2])" 2 name age lisi 18
(nil)
127.0.0.1:6379> mget name age
1) "lisi"
2) "18
로그인 후 복사

以上命令等价于 mset name lisi age 18, key的数量为2,2 后面两个值为key,在之后就是args

直接在redis-cli中写lua脚本不够方便,通常我们会把脚本放在文件中,然后执行这个文件
我们在一个目录下新建一个test.lua的脚本,填写以下内容后执行。

root@VM-0-5-centos src]# mkdir testlua
[root@VM-0-5-centos src]# cd testlua/
[root@VM-0-5-centos testlua]# ll
total 0
[root@VM-0-5-centos testlua]# touch test.lua
[root@VM-0-5-centos testlua]# vim test.lua
redis.call('set',KEYS[1],ARGV[1])
return redis.call('get',KEYS[1])
[root@VM-0-5-centos testlua]# redis-cli --eval test.lua 1 myname , Armin
"Armin"
로그인 후 복사

值得注意的是key和arg之间需要加上空格逗号空格(myname , Armin)

3.2 缓存lua脚本

之所以需要缓存lua脚本,这是因为每次调用的时候都将整个脚本传给redis服务端,会产生较大的网络开销。为了解决这个问题,Redis提供了evalsha命令,让开发人员通过脚本内容的SHA1摘要执行脚本。

那么怎么将生成这个SHA1并将脚本内容加载到缓存呢,这就用到script load命令去计算脚本的SHA1摘要并记录脚本到缓存中,执行evalsha时,redis会根据提供的摘要去脚本缓存找到对应脚本内容,如果找到则执行,否则返回错误提示: “NOSCRIPT No matching script. Please use EVAL”

127.0.0.1:6379> script load "return 'Hey boy'"
"3760855b303510c83f0be2e8acfb0be64113ae6e"
127.0.0.1:6379> evalsha 3760855b303510c83f0be2e8acfb0be64113ae6e 0
"Hey boy"
127.0.0.1:6379> script exists 3760855b303510c83f0be2e8acfb0be64113ae6e //判断是否存在
1) (integer)
로그인 후 복사

Redis还给lua脚本的执行提供了超时时间,默认的超时时间为5s,超过5s之后redis会接受其他命令但是会返回一个"BUSY"的错误
可在redis.conf中修改指定参数

lua-time-limit 5000
로그인 후 복사

Redis提供了个script kill的命令来终止正在运行的脚本

127.0.0.1:6379> set name lisi
(error) BUSY Redis is busy running a script. You can only call SCRIPT KILL or SHUTDOWN NOSAVE.
127.0.0.1:6379> script kill
OK
127.0.0.1:6379> set name lisi
OK
로그인 후 복사

如果数据进行了修改操作,将无法使用script kill终止脚本,因为违反了原子性。此时只能通过shutdown nosave来强行终止redis。
shutdown nosave 和 shutdown 的区别在于 shutdown nosave 不会进行持久化 操作,意味着发生在上一次快照后的数据库修改都会丢失。

相关推荐:redis数据库教程

위 내용은 Redis의 고급 기능 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.im
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿