Cloudflare Queues로 구현하는 더블 버퍼링

Double Buffering with Cloudflare Queues

bellone.com ▲ 57 댓글 8 b_llc

요약

큐 두 개를 한 시간씩 번갈아 쓰면 텔레메트리를 시간별 파일로 묶어 저장 비용을 낮출 수 있습니다.

bellone.com에 실린 짧은 기술 글입니다. 글쓴이는 Cloudflare의 Workers, Queues, Workflows, R2로 텔레메트리(앱이나 기기가 보내는 이벤트 기록) 수집 파이프라인을 운영하며, 요금 구조를 최대한 활용하는 방법으로 이 패턴을 소개했습니다.

왜 중요한가

  • 이벤트를 한 시간에 파일 하나로 모아 쓰면 R2 쓰기 요금이 사실상 사라집니다.
  • 글을 올린 이용자에 따르면 쓰기는 한 달 약 720회로, 무료 제공량 100만 회에 한참 못 미칩니다.
  • 불규칙하게 들어오는 이벤트가 시간별로 나뉜 압축 파일이 되므로 후속 분석에 쓰기도 쉬워집니다.

핵심 내용

  • 프로듀서는 이벤트 시각의 UTC 시(時)가 짝수면 짝수 큐로, 홀수면 홀수 큐로 메시지를 보냅니다.
  • 소비 작업은 매시 30분에 실행되고, 한 시간 전 시각의 홀짝으로 지금 쓰이지 않는 큐를 골라 비웁니다.
  • 꺼낸 묶음은 gzip으로 압축해 R2의 /연/월/일/시/dataset.json.gz 경로에 저장합니다.
  • UTC를 쓰는 이유는 일광 절약 시간(서머타임) 처리를 피하기 위해서입니다.

HN 반응

  • 일부 이용자는 크론이 늦거나 소비 작업이 실패하면 이벤트가 엉뚱한 시간 묶음에 섞인다며, 정상 동작만 가정한 설계라고 지적했습니다.
  • 시간 계산이 어긋날 걱정은 크지 않다는 평가도 있었지만, 코드를 줄이자는 제안에서 인덱스 버그가 나와 바로 지적받기도 했습니다.

댓글

8개 표시 · 전체 8개
  1. 8organicbits HN

    영리한 정상 경로(happy path) 해법이긴 한데, 문제 상황에 대한 방어력은 그다지 높지 않다고 생각합니다. 클라우드 크론이 제때 실행되지 않거나 컨슈머가 실패하면 큐가 제시간에 비워지지 않습니다. 그러면 이벤트가 엉뚱한 시간대 묶음에 들어가게 됩니다.

    배치를 어떻게 만드는지는 보이지 않습니다만, 배치 크기, 메시지 소비 확인(acknowledge) 등 신경 쓸 복잡한 문제가 많습니다. 시간당 dataset.json.gz 파일 하나만 남기는 방식을 보면 안전하게 처리되고 있지 않다는 느낌이 듭니다. 데이터가 유실되지 않도록 꼼꼼히 다시 확인해 보시길 권합니다.

    압축에 관해 한 가지 팁을 드리면, json/jsonl 데이터에는 zstd 압축을 써 봤는데 매우 만족스러웠습니다.

  2. vivzkestrel HN
  3. b_llc HN

    클라우드플레어 쓰기 비용을 0으로 만들면서 엣지에서 텔레메트리를 배치 처리하려고 제가 쓰는 스테이트리스(stateless) 패턴입니다.

  4. fwlr HN

    멋진 패턴이에요. 비판하는 사람들은 “프로그래머들이 시간에 대해 믿는 거짓들”을 들먹이겠지만, 클라우드 서비스라서 이게 깨질 정도로 시간이 이상해지면 훨씬 더 중요한 것들이 먼저 깨질 테니 괜찮습니다.

    그래도 코드는 못생겼네요.

      // env
      QUEUES = [EVEN_QUEUE, ODD_QUEUE]
    
    // producers
      env.QUEUES[hour % 2].send …
    
    // consumer
      env.QUEUES[1 + hour % 2]
    
  5. danhite HN

    env.QUEUES[1 + hour % 2]

    // js는 *, /, %가 +, -보다 우선순위가 높아서 인덱스가 1 또는 2가 됩니다

    그럼 보기에 간결하길 원하셨던 것 같으니 이런 식으로 하면 어떨까요? ...

    env.QUEUES[hour % 2 ^ 1]

    // 원하는 대로 js 인덱스가 0 또는 1이 됩니다

    그나저나 AI 코드 어시스턴트를 자주 쓰시는 분들께 여쭙니다. 이런 늙은 해커에게 알려 주실 수 있을까요? 그쪽 코드 리뷰 도구라면 이런 버그를 잡아냈을까요?

  6. fwlr HN

    아, 평문으로 프로그래밍하는 일의 위험이네요.

    AI 코드 어시스턴트가 이런 코드를 썼을지, 아니면 잡아냈을지는 저도 모릅니다. 아이러니하게도 “평문으로 프로그래밍하는 일의 위험”이 제가 AI 어시스턴트를 쓰지 않는 이유 중 하나거든요.

    간결함 때문에 제가 당했으니 그냥 간결함을 포기하고 이렇게 가야겠어요.

      // over the range 0..23, +1 gives the same result%2 as -1, and also handles edge case of 0
      const lastHour = new Date().getUTCHours() + 1
      …
      env.QUEUES[lastHour % 2]
    

    근본적으로 제가 마음에 안 들었던 건, 불리언을 뒤집으려고 시간 영역에서 산술 연산을 한다는 점이었던 것 같습니다.

  7. raffraffraff HN

    여기서 가격이 어떻게 되는 건지 설명해 주실 수 있나요?

  8. b_llc HN

    Cloudflare R2는 쓰기(100만 건당 $4.50), 읽기(100만 건당 $0.36), 저장 용량(월 GB당 $0.015)에 요금이 부과됩니다. 무료 구간은 월 쓰기 100만 건, 읽기 1,000만 건, 저장 10GB입니다. 업로드를 시간 단위로 묶으면 한 달에 쓰기가 약 720건뿐이라서 쓰기 비용이 완전히 사라지고, 저장 용량만 비용으로 남습니다.

Hacker News에서 보기 ↗