[REDIS] 원자 레디 스 데이터 구조에서 여러 값을 팝?
REDIS원자 레디 스 데이터 구조에서 여러 값을 팝?
(+ 제거를 얻을) 여러 요소를 보여주고의 원자 작업을 수 있도록 해주는 레디 스 데이터 구조, 그것은이 포함되어 있습니까?
이 잘 알려진 SPOP 또는 RPOP가 있지만, 그들은 항상 하나의 값을 반환합니다. 세트 I /리스트로부터 제 N 값을 필요로 할 때 따라서, I 비싸다 명령 N 배를 호출 할 필요가있다. 하자가 설정 / 목록에있는 항목의 수백만을 포함 말한다. 목록에서 1000 오른쪽 대부분의 항목을 반환 돌아가 세트 또는 RPOPM "listName"1,000에서 1,000 임의 항목을 제거 할 SPOPM "에서는 setName"1000 같은이 무엇이든은 있습니까?
나는 SRANDMEMBER 및 LRANGE 같은 명령이 알고 있지만 데이터 구조에서 항목을 제거하지 마십시오. 그들은 개별적으로 삭제할 수 있습니다. 같은 데이터 구조에서 읽기 더 많은 고객이 존재하는 경우, 일부 항목은 읽지 않고 번 일부가 삭제 될 수있는 것보다 읽을 수 있습니다! 따라서, 자성 내 질문에 대해 무엇이다.
이러한 작업에 대한 시간 복잡도가 더 비싼 경우 또한, 나는 괜찮아요. 나는 (하자 1000 말, 앞의 예에서 N)는 N을 발행보다 더 비싼 것입니다 레디 스 서버에 별도의 요청을 의심한다.
또한 별도의 트랜잭션 지원에 대해 알고. 그러나 레디 스의 문서에서이 문장은 세트 (파괴적으로 그것을 읽는)를 수정 병렬 프로세스를 사용에서 저를 낙담 : 시계를 사용하는 경우, EXEC는 체크인 및 세트 메커니즘을 허용, 감시 키가 수정되지 않은 경우에만 명령을 실행합니다.
해결법
-
==============================
1.레디 스 3.2부터 출발 명령 SPOP은 세트로부터 복수의 요소를 검색 [카운트] 인자를 갖는다.
레디 스 3.2부터 출발 명령 SPOP은 세트로부터 복수의 요소를 검색 [카운트] 인자를 갖는다.
http://redis.io/commands/spop#count-argument-extension 참조
-
==============================
2.파이프 라인에 LTRIM과 LRANGE를 사용합니다. 파이프 라인은 하나의 원자 트랜잭션으로 실행됩니다. 당신이 그들 사이에 올 수있는 다른 클라이언트에서 다른 트랜잭션에 대한 기능없이 하나의 트랜잭션으로 LRANGE 및 LTRIM을 실행하고 있기 때문에 시계에 대한 위의 걱정, EXEC 여기에 적용되지 않습니다. 그것을 밖으로보십시오.
파이프 라인에 LTRIM과 LRANGE를 사용합니다. 파이프 라인은 하나의 원자 트랜잭션으로 실행됩니다. 당신이 그들 사이에 올 수있는 다른 클라이언트에서 다른 트랜잭션에 대한 기능없이 하나의 트랜잭션으로 LRANGE 및 LTRIM을 실행하고 있기 때문에 시계에 대한 위의 걱정, EXEC 여기에 적용되지 않습니다. 그것을 밖으로보십시오.
-
==============================
3.루아 대신 lrange 및 LTRIM 내장 명령을 사용하여 목록 모음에 대한 완벽한 예와 엘리의 응답에 확장하려면 :
루아 대신 lrange 및 LTRIM 내장 명령을 사용하여 목록 모음에 대한 완벽한 예와 엘리의 응답에 확장하려면 :
127.0.0.1:6379> lpush a 0 1 2 3 4 5 6 7 8 9 (integer) 10 127.0.0.1:6379> lrange a 0 3 # read 4 items off the top of the stack 1) "9" 2) "8" 3) "7" 4) "6" 127.0.0.1:6379> ltrim a 4 -1 # remove those 4 items OK 127.0.0.1:6379> lrange a 0 999 # remaining items 1) "5" 2) "4" 3) "3" 4) "2" 5) "1" 6) "0"
당신이 작업이 원자 만들고 싶었다 경우 lrange 포장 및 멀티 및 간부 명령에 LTRIM 것이다.
다른 곳에서 언급 한 바와 같이 또한, 당신은 아마 반환 항목 수없는 당신이 질문 항목의 수를 LTRIM한다. 예를 들면 당신이 그랬다면 lrange 0 99 그러나 당신이이 100 LTRIM (50) -1하지 LTRIM 것 50 개 항목을 가지고 -1.
대신 스택의 큐의 의미를 구현 rpush와 lpush 교체하십시오.
-
==============================
4.당신이 루아 스크립트를 원하는 경우,이 빠르고 쉽게해야합니다.
당신이 루아 스크립트를 원하는 경우,이 빠르고 쉽게해야합니다.
local result = redis.call('lrange',KEYS[1],0,ARGV[1]-1) redis.call('ltrim',KEYS[1],ARGV[1],-1) return result
당신은 루프가 없습니다.
최신 정보: 나는 다음과 같은 스크립트 (2.6) srandmember이 작업을 수행하려고 :
local members = redis.call('srandmember', KEYS[1], ARGV[1]) redis.call('srem', KEYS[1], table.concat(table, ' ')) return members
하지만 오류가 발생합니다 :
error: -ERR Error running script (call to f_6188a714abd44c1c65513b9f7531e5312b72ec9b): Write commands not allowed after non deterministic commands
미래의 버전이 허용하지만하지 가정 나도 몰라. 나는 그것이 복제 문제가 될 것이라고 생각합니다.
-
==============================
5.레디 스 4.0 이상을 훨씬 빠르고 루아 스크립트 또는 멀티 / 간부 인 파이프 라인보다 안전 처리와 함께 새로운 기능 및 데이터 유형의 모든 종류의 추가 모듈을 지원합니다.
레디 스 4.0 이상을 훨씬 빠르고 루아 스크립트 또는 멀티 / 간부 인 파이프 라인보다 안전 처리와 함께 새로운 기능 및 데이터 유형의 모든 종류의 추가 모듈을 지원합니다.
레디 스 연구소, 레디 스 뒤 현재 스폰서는 여기 REDEX라는 확장 모듈의 유용한 세트가 있습니다 : https://github.com/RedisLabsModules/redex
rxlists 모듈은 원자 레디 스 목록에서 여러 값을 팝업 할 수 있도록 LMPOP 및 RMPOP 등 여러 목록 작업을 추가합니다. 논리는 여전히 (기본적으로 루프에서 하나의 팝업을하고) O (N)하지만, 당신이해야 할 일은 단지 그 사용자 지정 명령을 전송하면 모듈을 설치합니다. 내가 네트워크 트래픽 500MB의 +를 생성 한 번 문제없이에서 튀어 항목과 수천 수백만 목록에 그것을 사용할 수 있습니다.
-
==============================
6.여기 레디 스-PY와 파이프 라인을 사용하여이를 달성 할 수있는 파이썬 코드 조각입니다 :
여기 레디 스-PY와 파이프 라인을 사용하여이를 달성 할 수있는 파이썬 코드 조각입니다 :
from redis import StrictRedis client = StrictRedis() def get_messages(q_name, prefetch_count=100): pipe = client.pipeline() pipe.lrange(q_name, 0, prefetch_count - 1) # Get msgs (w/o pop) pipe.ltrim(q_name, prefetch_count, -1) # Trim (pop) list to new value messages, trim_success = pipe.execute() return messages
나는 목록 큐가 prefetch_count보다 작은 특히, 심지어 파이프 라인, 난 그냥 팝의 루프 A A를 할 수 있지만, 그 효율적하지 않을 것이라고 생각했다. 난 당신이보고 싶을 경우 전체 RedisQueue 클래스는 여기에 구현했습니다. 희망이 도움이!
-
==============================
7.난 당신이 레디 스에서 LUA 지원 봐야한다 생각합니다. 당신은 레디 스에 LUA 스크립트 및 실행하는 그것을 작성하는 경우, 그것 (레디 스이기 때문에 단일 스레드) 원자 것을 보장한다. 어떤 쿼리가 당신의 LUA 스크립트의 종료 전에 수행되지 않습니다 (예 : 당신은 LUA에 큰 작업을 구현할 수 없습니다 또는 레디 스 느린 얻을 것이다).
난 당신이 레디 스에서 LUA 지원 봐야한다 생각합니다. 당신은 레디 스에 LUA 스크립트 및 실행하는 그것을 작성하는 경우, 그것 (레디 스이기 때문에 단일 스레드) 원자 것을 보장한다. 어떤 쿼리가 당신의 LUA 스크립트의 종료 전에 수행되지 않습니다 (예 : 당신은 LUA에 큰 작업을 구현할 수 없습니다 또는 레디 스 느린 얻을 것이다).
그래서, 당신은 당신의 SPOP 및 RPOP를 추가하려면이 스크립트에서, 당신은 예에 대한 LUA 배열의 각 레디 스 명령의 결과를 추가 할 수 있습니다 다음 레디 스 클라이언트로 배열을 돌려줍니다.
무엇 문서 MULTI에 대해 말하는 것은 낙관적 잠금 감시 값이 수정되지 않습니다 때까지 시계 다 일을하고 수단 다시 시도합니다 있다는 것입니다. 어떤 방식으로 쿼리의 순서를 '세계를 정지'고 먼저 실행 될 : 당신이 지켜 값에 많은 쓰기가 있다면, 그것은 '비관적'이 (POSTGRESQL, MYSQL ... 많은 SQL 데이터베이스 같은) 락킹보다 느린 것 . 비관적 잠금 레디 스에서 구현되지 않습니다,하지만 당신이 원하는 경우에 당신은 그것을 구현할 수 있지만, 복잡하고 어쩌면 당신은 필요하지 않습니다 (: 낙관적 꽤 충분해야이 값에없는 많은 쓰기를).
-
==============================
8.당신은 아마 이런 루아 스크립트 (script.lua)을 시도 할 수 있습니다 :
당신은 아마 이런 루아 스크립트 (script.lua)을 시도 할 수 있습니다 :
local result = {} for i = 0 , ARGV[1] do local val = redis.call('RPOP',KEYS[1]) if val then table.insert(result,val) end end return result
당신은 이런 식으로 호출 할 수 있습니다 :
redis-cli eval "$(cat script.lua)" 1 "listName" 1000
from https://stackoverflow.com/questions/20621775/pop-multiple-values-from-redis-data-structure-atomically by cc-by-sa and MIT license
'REDIS' 카테고리의 다른 글
[REDIS] 해시 내부 저장 목록 레디 스 (0) | 2020.01.22 |
---|---|
[REDIS] Laravel : 레디 스 아니는 연결이 될 수있다 : [TCP를 : //127.0.0.1 : 6379] (0) | 2020.01.22 |
[REDIS] 클러스터를 만들 레디 스-trib.rb를 사용할 때 연결 오류를 얻기? (0) | 2020.01.22 |
[REDIS] 응용 프로그램 캐시 v.s. 두 번째 레벨 캐시를 최대 절전 모드, 어떤을 사용 하는가? [닫은] (0) | 2020.01.21 |
[REDIS] 선택 데이터 타입 레디 스 제안 (0) | 2020.01.21 |