웹 푸시 알림의 내부 작동 원리
새로운 메시지, 주문 업데이트 또는 결제 알림을 받게 됩니다.
단순해 보입니다. 백엔드에서 메시지를 보내면 사용자가 받는 방식이죠.
하지만 실제로는 복잡한 과정이 얽혀 있습니다. 백엔드는 브라우저와 직접 통신하지 않습니다. 대신 푸시 서비스(Push Service)를 사용합니다.
Google Chrome은 Firebase Cloud Messaging을 사용하고, Firefox는 Mozilla Push Service를 사용합니다.
워크플로우는 다음과 같습니다:
Backend → Push Service → Browser → Service Worker → User
다음은 React와 Golang을 사용하여 이 시스템을 구축하는 방법입니다.
구성 요소
- 프론트엔드 (React): 권한을 요청하고 Service Worker를 등록합니다.
- Service Worker: 브라우저에서 실행되는 백그라운드 스크립트입니다. 웹사이트가 닫혀 있을 때도 이벤트를 처리합니다.
- 백엔드 (Golang): 구독 정보를 저장하고 암호화된 메시지를 전송합니다.
- 푸시 서비스 (Push Service): 브라우저로 메시지를 전달하는 중개자 역할을 합니다.
구독 흐름
메시지를 보내려면 구독(subscription)이 필요합니다.
- 사용자가 권한을 허용합니다.
- 브라우저가 엔드포인트(endpoint)와 보안 키를 포함하는 구독 객체를 생성합니다.
- React 앱이 이 객체를 Golang 백엔드로 전송합니다.
- 백엔드가 이를 데이터베이스에 저장합니다.
서버를 식별하려면 VAPID 키를 사용해야 합니다. 프론트엔드에는 공개 키(public key)를, 백엔드에는 개인 키(private key)를 사용하세요. 개인 키는 절대 공유해서는 안 됩니다.
구현 방법
React에서는 푸시 이벤트를 수신하기 위해 Service Worker를 등록합니다. 이 워커는 백그라운드에서 실행되며, 데이터를 수신하여 사용자에게 알림을 표시합니다.
Golang에서는 라이브러리를 사용하여 암호화 및 VAPID 인증을 처리합니다. 서버는 데이터베이스에서 구독 정보를 읽어 페이로드(payload)를 암호화한 뒤 브라우저 푸시 서비스로 전송합니다.
프로덕션 환경을 위한 확장(Scaling)
소규모 프로젝트에는 간단한 설정으로 충분하지만, 대규모 시스템에는 더 많은 고려 사항이 필요합니다.
- 다중 기기 처리: 한 사용자가 휴대폰과 노트북을 모두 가질 수 있습니다. 사용자당 여러 개의 구독 정보를 저장하세요.
- 데이터 정리: 구독 정보는 만료됩니다. 404 또는 410 에러가 발생하면 데이터베이스에서 해당 구독 정보를 삭제하세요.
- 큐(Queue) 사용: 수백만 명의 사용자를 처리하려면 Kafka와 같은 도구를 사용하세요. 이를 통해 시스템이 알림을 비동기적으로 처리할 수 있습니다.
- 재시도 로직 구현: 네트워크 장애에 대비하여 지수 백오프(exponential backoff) 방식을 사용하세요.
WebSocket은 사용자가 활성화되어 있을 때 실시간 채팅에 적합합니다. Web Push는 탭이 닫혀 있을 때 사용자에게 도달하는 데 더 효과적입니다.
