||
안녕하세요. DevOps팀 아리입니다.
지난 1편에서는 시스템의 탄생 배경을 다뤘다면, 이번 글에서는 NotiHub의 기술적 설계와 그 과정에서 내린 주요 의사결정들을 깊이 있게 공유하고자 합니다.
1. 왜 만들었는가
인터널 툴에는 두 가지 측면이 있습니다. 조직적 측면과 개인적 측면입니다. NotiHub는 조직적 효율성에 무게를 둔 프로젝트라고 생각합니다.
슬랙은 보편적으로 어느 회사에서나 사용하고 있지만, NotiHub는 우리 조직만의 커스텀 도구입니다. 사용자에게는 새로운 학습 비용이 발생하게 됩니다. 그럼에도 ‘중앙 집중형 구조’를 선택한 이유는 명확한 관리의 한계 때문이었습니다.
웹훅의 종속성 문제: 특정 개인이 생성한 웹훅은 퇴사 시 계정 삭제와 함께 사라집니다. 이는 애플리케이션 에러와 긴급 배포로 이어지는 악순환을 만들었습니다.
모니터링의 부재: 어떤 팀이 어떤 채널로 알림을 보내는지 파악이 불가능해 전사적인 알림 정책을 수립하기 어려웠습니다.
또한 대부분의 SaaS 서비스는 자체적인 슬랙 연동 기능을 제공합니다. 하지만 실제 운영 환경에서 이를 그대로 사용하기에는 몇 가지 한계가 있었습니다.
제한된 포맷: SaaS가 제공하는 알림은 포맷이 고정되어 있어, 우리 팀에게 필요한 핵심 정보를 강조하거나 불필요한 노이즈를 제거하기 어려웠습니다.
라우팅의 경직성: 특정 이벤트가 발생했을 때 내용에 따라 수신 채널을 동적으로 분리하고 싶어도, SaaS 설정만으로는 세밀한 조건별 분기가 불가능한 경우가 많았습니다.
이 외에도 자세한 탄생 배경이 궁금하다면 1편을 참고해주시길 바랍니다.
트레이드오프: 편의성 vs 안정성
중앙화의 가장 큰 숙제는 단일 장애점(SPOF) 문제입니다. NotiHub가 멈추면 전사의 알림이 멈춥니다. 저희는 이를 해결하기 위해 HPA(Horizontal Pod Autoscaler) 기반의 Scale-out과 무중단 배포, 그리고 다중 레이어 캐싱을 통해 가용성을 확보했습니다. 완벽한 정답은 없겠지만 관제 효율화로 얻는 이득이 운영 리스크보다 크다고 판단하여, 아키텍처 차원의 방어 기제를 두터이 설계했습니다.
2. 전체 아키텍처 개요
NotiHub는 확장성과 독립성을 위해 세 개의 레이어로 분리되어 있습니다. 아래 시퀀스 다이어그램을 통해 이벤트가 수신되어 슬랙으로 전달되기까지의 흐름을 확인할 수 있습니다.
이 구조의 핵심은 이중화된 확장 전략에 있습니다. 급격한 트래픽 증가 시 물리적인 Pod 확장은 HPA(Horizontal Pod Autoscaler)가 담당하여 컴퓨팅 자원을 확보하고, 논리적인 작업 분배는 Kafka의 Consumer Group과 내부 샤딩 로직이 담당하여 데이터 처리의 일관성과 분산 처리를 동시에 보장합니다. 각 컴포넌트는 Kafka와 Redis를 매개체로 연결되어 있어, 특정 구간에 부하가 걸려도 전체 시스템으로 전이되지 않는 구조를 가집니다.
3. 외부와의 접점: 보안과 확장성
내부망과 외부망의 분리 설계
기존 슬랙 웹훅의 사용자 경험을 유지하는 것이 핵심이었습니다.
내부망: 인증 토큰 없이 URL 교체만으로 즉시 마이그레이션이 가능합니다.
외부망 (Jira, Slack API 등): 보안을 위해 B2B Gateway를 통한 이중 검증 구조를 도입했습니다. 엔드포인트를 분리하여 ‘가벼운 Receiver’라는 원칙을 지키면서도 보안 요구사항을 충족했습니다.
단일 키 노출 시의 위험을 방지하기 위해, 시스템 전역에서 사용하는 Static Key와 각 엔드포인트 별로 발급된 Dynamic Key를 동시에 검증하는 구조를 택했습니다.
모든 검증을 외부 저장소(Redis)에 의존하면 네트워크 레이턴시가 발생합니다. 따라서, 변경 빈도가 낮은 Static Key는 애플리케이션 기동 시 Secret Store에서 조회하여 인메모리에 캐싱함으로써 1차 검증 속도를 극대화했습니다.
4. 유실 없는 수신을 위한 전략
Receiver는 의도적으로 최소한의 역할만 수행합니다. JSON 스키마 검증과 키 확인만 마치면 즉시 이벤트를 Kafka로 발