MeetBack 2026.08.19 7 min read

MeetBack, 약속을 정하는 순간부터 운영까지 직접 만들어 가는 팀 프로젝트

약속 가능 시간을 조율하는 MeetBack 팀 프로젝트에서 내가 맡은 Google 로그인, Redis 실시간 공통 모듈과 Docker Swarm 기반 인프라 구축 범위를 정리했다.

프로젝트 기간: 2026-08-18 ~ 2026-09-02
작성 기준: 2026-08-29, 프로젝트 진행 중

사람들과 만날 약속을 잡다 보면 장소보다 먼저 부딪히는 질문이 있다. “그래서 우리 언제부터 언제까지 만날 수 있지?” MeetBack은 여러 사람이 가능한 시간을 공유하고, 모임을 만들고, 실시간으로 의견을 나누며 약속을 정할 수 있도록 만드는 팀 프로젝트다.

나는 2026년 8월 18일부터 9월 2일까지 진행되는 이 프로젝트에서 백엔드 기능과 인프라를 함께 담당하고 있다. 개발만 끝내고 실행 환경은 남에게 맡기는 방식보다는, 내가 만든 기능이 여러 서버에서 실제로 어떻게 동작하고 장애가 생겼을 때 어떤 모습이 되는지까지 확인해 보고 싶었다. 그래서 Google 로그인과 Redis Pub/Sub 실시간 공통 모듈을 구현하는 한편, Docker Swarm 기반 실행 환경과 데이터베이스·스토리지·모니터링·외부 진입 경로도 직접 설계하고 구축했다.

내가 맡은 개발 영역

첫 번째는 Google Identity Services 로그인이다.

브라우저가 전달하는 이메일이나 이름을 그대로 신뢰하지 않고, Google이 서명한 OpenID Connect ID Token을 백엔드에서 공식 검증기로 확인하도록 구현했다. 이때 이메일이 아니라 Google 계정의 안정적인 식별자인 sub를 서비스의 providerId로 사용했다. 같은 이메일의 일반 계정이 존재하더라도 자동으로 계정을 합치지 않도록 막아, 이메일 문자열 일치만으로 계정 소유권을 넘길 수 없게 했다.

내가 처음 구현했을 때는 신규 Google 사용자를 즉시 가입시키는 흐름이었다. 이후 팀의 인증 기능과 통합되면서, 내가 만든 Token 검증과 계정 매핑 기반 위에 10분짜리 SOCIAL_SIGNUP JWT를 이용한 2단계 가입 흐름이 확장됐다. 지금은 Google 인증 후 사용자가 닉네임과 필수 약관을 직접 선택해야 최종 가입된다. 후속 통합 전체를 내가 혼자 만들었다고 표현할 수는 없지만, 그 흐름이 안전하게 확장될 수 있는 검증 경계와 계정 식별 기반을 구현한 것은 내 역할이었다.

두 번째는 Docker Swarm의 여러 애플리케이션 replica에서 실시간 이벤트를 공유하기 위한 Redis Pub/Sub 공통 모듈이다.

Spring의 SimpleBroker는 JVM 내부에만 상태가 존재한다. 따라서 사용자가 서로 다른 replica에 WebSocket으로 연결되면, 한 replica가 보낸 채팅·투표 같은 이벤트를 다른 replica의 사용자가 받지 못할 수 있다. Swarm VIP는 연결을 분산해 줄 뿐 JVM 메모리까지 공유하지 않는다.

나는 기존 SimpleBroker와 클라이언트 메시지 계약은 유지하고, replica 사이의 이벤트만 Redis Pub/Sub으로 전달하는 공통 계층을 만들었다. 업무 이벤트와 Redis 전송용 envelope를 분리했고, 현재 요청을 처리한 replica에는 먼저 로컬 전달을 시도한 뒤 Redis로 전파하는 local-first 구조를 사용했다. Redis 장애가 곧 현재 replica의 로컬 전달 실패가 되지 않도록 경계를 나눈 것이다.

다만 이 모듈이 모든 채팅·투표·강퇴 기능에 이미 연결됐다는 의미는 아니다. 공통 모듈은 main에 병합됐지만 기존 기능의 직접 방송 코드를 RealtimeEventPublisher 호출로 바꾸는 작업, 실제 WebSocket 세션 종료 구현, Redis 기반 전역 Presence는 다음 연동 범위로 남아 있다. Redis Pub/Sub 역시 메시지 영속성이나 exactly-once를 보장하지 않으며, 현재 계획한 단일 Redis는 장애점이 될 수 있다.

내가 구축한 인프라 영역

실행 환경은 단일 서버가 아니라 역할을 분리한 구조로 만들었다.

  • Docker Swarm Manager 3대와 Worker 2대
  • MySQL Primary 1대와 Read Only Replica 1대
  • 서비스 파일용 NFS와 백업·로그용 NFS
  • Prometheus, Grafana, Alertmanager, Loki, Alloy를 운영하는 모니터링 서버
  • 서비스망과 DB 전용망을 연결하는 VyOS 라우터

Swarm에서는 overlay network와 Service DNS/VIP를 확인했고, 데이터베이스는 MySQL 8의 GTID와 TLS 기반 비동기 복제로 구성했다. Replica에는 read_onlysuper_read_only를 적용해 평상시 쓰기를 차단했다. 자동 승격보다 데이터 정합성과 원인 확인을 우선해 수동 failover 절차를 선택했다.

스토리지는 하드웨어 RAID5 위에 LVM과 ext4를 구성하고 NFS 역할을 분리했다. MySQL 데이터 디렉터리를 NFS에 올리지는 않았다. DB 데이터는 로컬 디스크에 두고, mysqldump 결과를 압축하고 SHA-256 체크섬과 함께 별도 NFS에 보관하는 방식으로 만들었다. 백업 파일이 만들어지는 것에 그치지 않고 별도 시험 DB에 복원해 보는 과정까지 확인했다.

운영 가시성을 위해 전체 노드와 컨테이너, MySQL, NFS 상태를 Prometheus로 수집하고 Grafana 대시보드를 구성했다. Alertmanager는 Telegram으로 알림을 전달하도록 연결했다. 외부 진입의 기본 경로는 Cloudflare Tunnel로 두고, 각 Swarm 노드의 cloudflared connector가 애플리케이션 Service DNS/VIP를 바라보도록 설계했다. NGINX Proxy Manager와 DNS-01 wildcard 인증서도 준비했지만, 공인 IP와 NAT를 사용할 수 없는 현재 환경에서는 예비 외부 경로의 E2E 검증을 완료했다고 말하지 않는다.

지금 어디까지 왔는가

현재는 핵심 인프라와 운영 기반을 구축했고, 실제 애플리케이션 stack 연결을 기다리는 단계다. 애플리케이션 개발이 끝나면 NFS 권한, Docker Secret, placement와 rolling update 정책을 실제 서비스에 맞춰 확정해야 한다. Redis 공통 모듈 역시 실제 기능 호출부와 두 replica 환경의 WebSocket E2E 검증이 남아 있다.

CI/CD는 이번 프로젝트 범위에서 제외했다. 제한된 기간 안에 모든 키워드를 얕게 넣기보다, 서비스 실행에 필요한 네트워크·데이터·스토리지·관측 경계를 직접 구성하고 각 한계를 명확히 기록하는 데 집중했다.

이번 연재에서는 내가 구현한 Google 로그인과 Redis 실시간 모듈, 그리고 MeetBack 인프라를 나눠서 기록하려 한다. 완성된 결과만 나열하기보다 어떤 문제가 있었고, 왜 그 구조를 선택했으며, 어디까지 검증했고 무엇이 아직 남았는지를 솔직하게 남길 예정이다.

다음 글에서는 흔히 “Google OAuth 로그인”이라고 부르는 기능을 왜 더 정확하게는 “Google ID Token 검증 기반 로그인”이라고 설명해야 하는지, 그리고 이메일 대신 sub를 식별자로 선택한 이유부터 정리해 보겠다.