Skip to main content Link Menu Expand (external link) Document Search Copy Copied

created at 2025-04-25

Table of contents

  1. Notation
  2. How can I gracefully re-consume for my unconsumed event in PEL?
  3. 어떤 파드가 어떤 이벤트를 처리할것인가?
    1. 이벤트 별 처리( event-A -> pod-1, event-B -> pod-2 )
    2. 특정 노드가 이벤트 처리( if(10:12:00 000000 KST < now <= 10:15:00 000000 KST) event-A,B,C,… -> pod-1 )

Notation

  • PEL (Pending Entry List): Redis Stream에서 이벤트를 소비(XREADGROUP)했지만 아직 ACK되지 않은 상태의 이벤트 목록.
  • Rebalancing: 특정 파드 또는 컨슈머가 중단되었을 때, 해당 컨슈머가 담당하던 이벤트 또는 파티션을 다른 컨슈머에게 할당하는 과정.

    redis stream 은 일단 단일 파티션이며 해당 파티션 listening 하는 consumer group 중 누군가 죽으면 두 가지를 신경써줘야함.

    1. 해당 컨슈머가 읽다가 죽었을 경우 PEL 에 남아있는 이벤트를 누군가가 대신 처리해주어야함.
    2. 파티션을 재할당시켜주는것. redis XREADGROUP 쓰면 재할당 굳이 해줄 필요없이 자동가능. redis 에서 XREADGROUP 컨슈머 그룹 별 offset 저장/관리해주기때문. 컨슈머 +/- 에 상관없이 누락되는 이벤트는 없음.

How can I gracefully re-consume for my unconsumed event in PEL?

  • stream-key 는 postfix/prefix 로 version 추가. 그래서 특정 토픽 처리 방식이 변경되었을 때 consumer 들의 처리방식의 일관성을 유지하도록.
  • consuming 이후 redis stream 으로 ACK 안날리면 이벤트는 PEL(pending entry list) 에 머무름. 이 때 consumer serving 횟수, idle time(서빙 이후 경과 시간)도 볼 수 있음. PEL 에서 idle time 이 일정시간이상이면 이벤트 소비 실패 처리로 판단. 이후 XCLAIM, XAUTOCLAIM 으로 consume.

일단 처리 실패한 이벤트가 무엇인지 정의가 필요함. PEL에 존재하면서, idleTime이 일정 기준(x ms) 이상 지난 이벤트를 실패로 간주. 실패횟수도 일정이상 초과하면 더 이상 재처리의 의미가 없다고 판단하고 그 빈도를 낮추기 위해 별도의 DLQ(Dead Letter Queue) 로 이동시킴.

어떤 파드가 어떤 이벤트를 처리할것인가?

이벤트 별 처리( event-A -> pod-1, event-B -> pod-2 )

  • x초 간격 pod 들은 alive redis set 에 자신의 고유키를 등록함. TTL y초
  • pod 는 현재 live 한 node 들의 list 를 알고 있음. XPENDING event ID 가져와서 처리안된상태 확인하고, 내 키를 alive 에 다시 push 하고, min(hash(msgId + pod-1-key), hash(msgId + pod-2-key), ...) 가 제일 작은 애가 해당 이벤트 처리하는거임. 물론 이 때 pod 들의 실행시점은 동기화되어있지 않아 alive 리스트는 변동가능이므로 여러 파드가 동시에 이벤트를 읽을려고 할 수 있음. 동시 처리제어가 필요한데 consume 이전에 lock 걸고 끝나면 ACK 전송 후 lock 해제하면 PEL 내 소비중인 msg 재접근를 차단가능 및 동시접근 제어가능. 이벤트 소비가 (lock -> consume -> business logic -> ack -> unlock) 이 시퀀스로 진행되기때문에 해당 이벤트는 중복소비가 불가능.

요약하면 PEL 내 이벤트의 중복소비를 제어하는 방식은 아래와 같이 구현함.

  1. 이벤트 소비 끝나면 ack 로 PEL 에서 제거.
  2. 이벤트 소비 전/후 lock/unlock.
  3. 이벤트 소비 하기 전 msgId lock waitTime=0 시도 후 누군가 점유하고있으면(다른 pod 가 해당 msg 처리중이면) 다른 msg 로 skip.

롤백이 필요하면 소비 실패 시 롤백 진행필요.

이벤트 consume 했는데 ack 못날리고 죽으면? 이벤트 처리기록 저장 없이 죽으면? 로직에 따라 롤백필요! 내부 호출은 TX 로 묶으면 간단하게 롤백 가능. 하지만 외부 호출 중간에 껴있는 경우는 롤백요청을 직접 한번 날려야함. 예로 페이코 포인트 사용 했는데 롤백되버리면 중복 페이코 포인트사용 호출을 제어할 수 있어야 함.

  • 이벤트 처리할 때 lock 획득 후 처리할 수 있도록. ex) pod-a 가 처리중이고 아직 자신의 alive 를 등록못했는데 pod-b 에서 자신이 처리진행할 수 있음. 동시 이벤트 처리 제어 해야함.

특정 노드가 이벤트 처리( if(10:12:00 000000 KST < now <= 10:15:00 000000 KST) event-A,B,C,… -> pod-1 )

  • pod-a -> leader key 존재 확인 -> pod-b -> leader key 존재 확인 -> pod-a SETNX leader “{nodeId}” + TTL 선점 시도. 1 반환 시 내가 리더니까 이벤트 청크들 소비 시작. 0 반환받으면 나는 leader 가 아님. next.
  • leader key 가 존재하면 내부 nodeId 확인 후 나와 동일하다면 나는 리더파드이며 PEXPIRE 로 주기적으로 leader key 의 TTL 늘림.