본문 바로가기

빅데이터/Kafka

레디슈 큐(queue), 레디스 스트림(streams), 레디스 펍섭(pub/sub) 그리고 카프카와 비교

레디스란?

레디스는 오픈소스 인 메모리 데이터 구조 저장소로서 데이터베이스, 캐시, 메시지 브로커로 역할을 수행한다. 레디스는 String, hash, lists, sets, sorted sets, bitmaps, streams등을 지원한다.

레디스 큐란?

레디스 큐는 레디스의 자료구조 중 List를 이용하여 Queue를 구현한 것이다. 큐는 FIFO(First In First Out)구조로 먼저 들어온 데이터가 먼저 처리되는 것이다. LIST자료구조의 LPUSH, RPOP(또는 RPUSH, LPOP)을 사용하여 구현할 수 있다. 이외에도 BLPOP을 사용하여 블락킹(blocking) pop을 수행할 수 있다. 지정한 시간만큼 기다리고 값이 들어오면 LPOP을 수행하는 것이다.

$ lpush my-queue value1
1
$ lpush my-queue value2
2
$ rpop my-queue
1
$ rpop my-queue
2

레디스 스트림?

레디스 5.0부터 새로 도입된 데이터 타입. 컨슈머 그룹이 처음 도입되는데, 카프카의 컨슈머 그룹과 매우 유사하다. 데이터는 메시지 키, 메시지 값, 필드의 묶음으로 이루어져 있다.

$ XADD key ID field value [field2 value2 ...]
// 데이터 추가시 수행하는 명령어
// key : 메시지 키
// ID : <millisecondsTime>-<sequenceNumber>로 이루어진 데이터. 설정하지 않으면 자동으로 들어간다.
// value + field : 값 이름과 값 정보를 함께 담은 데이터 
$ XADD sensor-1234 * temperature 98.7
1538319053569-0
$ XADD sensor-1234 1538319053569-1 temperature 98.8
1538319053569-1

데이터 조회하기

$ XLEN sensor-1234   //데이터 길이(개수)조회
(integer) 2
$ XRANGE sensor-1234 - +  //데이터 조회 
1) 1) 1538319053569-0
    2) 1) "temperature"
        2) "98.7"
2) 1) 1538319053569-1
    2) 1) "temperature"
        2) "98.8"

데이터 읽기

$ XREAD count 1 STREAMS sensor-1234 1538322045065-0
1) 1) "sensor-1234"
    2) 1) 1) 1538322045065-1
        2) 1) "temperature"
            2) "98.8"
            
// count : 읽어올 데이터 개수, 설정하지 않으면 모든 데이터 읽어옴
// ID : 지정한 ID의 다음 데이터를 읽어옴. 처음부터 읽으려면 0으로 지정
// Block : 새데이터가 들어올때 까지 기다림. LIST의 BLPOP과 비슷
$ XREAD block 5000 STREAMS sensor-1234 $

데이터 읽기(컨슈머  그룹)

컨슈머 그룹을 사용하면 컨슈머가 제대로 데이터를 처리했는지 확인(ack)할 수 있다. 만약 데이터 처리가 제대로 되지 않았다면 다른 컨슈머가 데이터 처리를 할 수 있도록 처리할 수 있다.

// 컨슈머 그룹 생성
$ XGROUP CREATE sensor-1234 ConsumerGroup $

// 데이터 넣기
$ XADD sensor-1234 * temperature 100
$ XADD sensor-1234 * temperature 101
$ XADD sensor-1234 * temperature 102
$ XADD sensor-1234 * temperature 103
$ XADD sensor-1234 * temperature 104
$ XADD sensor-1234 * temperature 105

// 컨슈머 그룹으로 데이터 읽기
$ XREADGROUP GROUP ConsumerGroup Consumer-A count 1 STREAMS sensor-1234 >
1) 1) "sensor-1234"
    2) 1) 1) 1538568726521-0
        2) 1) "temperature"
            2) "100"
$ XREADGROUP GROUP ConsumerGroup Consumer-A COUNT 1 STREAMS sensor-1234 >
1) 1) "sensor-1234"
    2) 1) 1) 1538568728545-0
        2) 1) "temperature"
            2) "101"
            
// 처리여부확인
$ XPENDING sensor-1234 ConsumerGroup
1) (integer) 2
2) 1538568726521-0
3) 1538568728545-0
4) 1) 1) "Consumer-A"
    2) "2"
    
    
// 처리완료(카프카 컨슈머의 커밋과 유사)
$ XACK sensor-1234 ConsumerGroup 1538568726521-0
(integer) 1

레디스 펍섭?

레디스 펍섭은 레디스 큐, 스트림과 다르게 모든 구독자(subscriber)에게 메시지를 던지는 시스템이다. 즉, 카프카에서 사용하는 토픽처럼 데이터를 저장하는게 아니기 때문에 구독자가 없으면 데이터는 사라진다. publish 명령어로 데이터를 보내고 subscribe 명령으로 데이터를 받는다. 전달하고 받는 큐의 이름은 채널(channel)이라고 부른다. 레디스의 구독자는 카프카 컨슈머의 polling방식이 아니라 push 방식이다.

$ publish my-channel01 "a"
(Integer) 1                        //메시지를 받는 구독자 수
$ publish my-channel02 "a"
(Integer) 1
$ publish my-channel02 "a"
(Integer) 1
$ subscribe my-channel01 my-channel02    //publish가 보낸 채널의 메시지를 받는다.
Reading messages...
1) "a"
2) "b"
3) "c"

레디스 스트림즈 vs 카프카

이까지 살펴보면 스트림즈가 카프카의 동작과 매우 유사한 것을 확인할 수 있다. 그렇다면 레디스 스트림즈와 카프카 무엇을 쓰면 좋을까? 어떤점이 가장 다를까? 

 

- 레디스 스트림즈는 최대 길이(메시지 개수)를 지정할 수 있다. 카프카는 byte 또는 ms로 크기를 지정한다.

- 레디스 스트림즈는 Hash 처럼 데이터를 저장하고 사용한다. 카프카는 직렬화가능한 모든 형태로 지정할 수 있다.

- 레디스 스트림즈는 파티션 개념이 없다. 카프카는 파티션 개념을 사용한다.

 

가장 다른점은 레디스의 컨슈머 그룹은 파티션의 존재 유무라고 볼 수 있다. 스트림처리에 있어 1개의 큐에 여러 컨슈머가 붙어서 데이터를 동시처리하는 것이다. 이런 방식은 데이터 처리 순서를 보장할 수 없다. 

 

참고한 링크

redis streams vs kafka : mattwestcott.co.uk/blog/redis-streams-vs-kafka
redis : redis.io/
redisgate : redisgate.kr/

반응형