Hangfire에서 RabbitMQ로: 데이터베이스 폴링(Polling) 제거하기

Hangfire는 소규모 팀에 매우 좋습니다. NuGet 패키지를 추가하고 데이터베이스를 지정하기만 하면 됩니다. 그러면 작업 실행기(job runner)와 대시보드를 무료로 얻을 수 있습니다. 단일 서비스라면 이보다 더 나은 선택을 찾기 어렵습니다.

저는 SavePosty에서 이메일, 웹훅, 콘텐츠 가져오기를 처리하기 위해 Hangfire를 사용했습니다. 모든 작업은 동일한 방식으로 작동했습니다. 모든 작업이 새로운 작업이 있는지 확인하기 위해 몇 초마다 Postgres 데이터베이스를 폴링했습니다.

결국 저는 모든 것을 RabbitMQ로 옮겼습니다. 왜 그렇게 했는지, 그리고 무엇을 잃었는지 공유하겠습니다.

옮긴 이유:

  • 폴링 부하는 작업량이 아닌 시간에 따라 증가합니다. 모든 Hangfire 작업은 타이머에 따라 데이터베이스에 접근합니다. 작업이 없더라도 데이터베이스는 계속 바쁩니다. 이 비용은 작업 수와 폴링 빈도에 따라 증가합니다.
  • 모델이 너무 많았습니다. 앱의 한 부분은 이미 RabbitMQ를 사용하고 있었고, 나머지는 Hangfire를 사용하고 있었습니다. 이는 백그라운드 작업을 관리하는 방식이 두 가지라는 의미였습니다. RabbitMQ로 옮기면서 모든 것을 통합했습니다.
  • 지연 시간(Latency). 브로커는 작업이 도착하는 즉시 전달합니다. Hangfire는 다음 폴링을 기다려야 합니다.

트레이드오프(Trade-offs):

Hangfire는 설정이 쉽습니다. 기존 SQL 테이블을 사용하며, 훌륭한 내장 대시보드를 제공합니다.

RabbitMQ는 브로커를 관리해야 합니다. 데이터베이스 CPU 대신 RAM과 네트워크를 사용합니다. 확장성은 더 좋아지지만, 운영 오버헤드가 늘어납니다.

안전하게 마이그레이션하는 방법:

비즈니스 로직은 정확히 동일하게 유지했습니다. 입구 역할을 하는 얇은(thin) 컨슈머(consumer)를 구축했습니다. 컨슈머가 메시지를 받으면 기존 작업 클래스에 전달하는 방식입니다.

저는 두 가지에 집중했습니다:

  • 재시도 일관성(Retry parity). 메시지를 잃지 않도록 RabbitMQ 컨슈머의 재시도 설정을 Hangfire와 동일하게 맞췄습니다.
  • 스키마 안전성. 배포 중에 데이터베이스가 깨지지 않도록 기존 컬럼을 nullable 상태로 유지했습니다.

잃은 것:

가장 큰 단점은 가시성입니다. Hangfire를 사용하면 실패한 작업을 클릭하여 정확히 어떤 일이 일어났는지 볼 수 있습니다. RabbitMQ는 Dead Letter Queue에 메시지가 얼마나 있는지 보여주지만, 작업별로 제공되는 것과 같은 쉬운 뷰를 제공하지는 않습니다. 이제 저는 대시보드 대신 구조화된 로그(structured logs)에 의존합니다.

조언:

다음의 경우 Hangfire를 계속 사용하세요:

  • 단일 서비스를 운영하는 경우.
  • 소규모 팀인 경우.
  • 디버깅을 위한 쉬운 대시보드가 필요한 경우.

다음의 경우 RabbitMQ로 옮기세요:

  • 여러 서비스를 운영하는 경우.
  • 폴링으로 인한 데이터베이스 부하가 높은 경우.
  • pub/sub 패턴을 사용하고 싶은 경우.

결정은 단일 작업이 아니라 시스템에 달려 있습니다.

Source: https://dev.to/gabrielleroux/from-hangfire-to-rabbitmq-killing-database-polling-in-a-net-app-4og4

Optional learning community: https://t.me/GyaanSetuAi