Firebase Realtime Database 실시간 동시 연결 수 줄이기
작성자 : 오예환 | 작성일 : 2025-10-31 | 수정일 : 2025-10-31
문제 발견
어느 날 한 PM분이 관리하고 있던 백오피스 툴(이하 버핏케어)에서 버튼이 안 나온다는 버그를 제보해주셨다.
PM쌤 : "예환쌤, 버핏케어에서 헤더에 바로가기 버튼이 안 나와요!""바로가기" 버튼은 사내에서 사용 중인 모든 사이트를 보여주고 이동시켜주는 Select 버튼이다. 사내에서 관리하는 프로덕트들이 너무 산재되어 있다는 의견이 있었고, 이것들을 한곳에 모아서 쉽게 접근할 수 있도록 해달라는 니즈가 있었다. 그래서 PM팀에서 간단하게 정리해서 넣을 수 있도록 Firebase Realtime Database를 구축했고, URL을 추가/수정하는 방법을 알려드렸다.
문제의 "바로가기" 버튼
"바로가기" 버튼의 로직을 살펴봤다. Firebase Realtime Database의 연결이 끊기거나 데이터가 없으면 버튼이 나타나지 않도록 설계되어 있었다. 혹시 이 부분이 문제의 원인일까?
백오피스 툴에서 직접 확인해봤지만, 글로벌 헤더의 "바로가기" 버튼은 잘 보이고 있었다. 그래서 PM에게 물어봤다. "혹시 지금은 정상적으로 보이나요?"
PM쌤 : "어, 지금은 잘 나오네요. 근데 간헐적으로 안 나올 때가 있어요!"접속했을 때는 항상 바로가기 버튼이 잘 나오고 있었고, 똑같은 현상을 재현하는 게 어려운 문제가 있었다. 따라서 우선적으로 Firebase 콘솔에 들어가서 어떤 일이 벌어지고 있는지 확인해보았다.
원인 파악
실시간 DB 연결 수
Firebase Realtime Database의 사용량을 확인해보니 실시간 DB 연결 수가 100/100으로 되어 있었다. 월,화,수,목,금,토요일은 모두 100으로 동시 연결이 되어 있었고, 일요일에만 77 정도로 떨어지는 패턴을 보이고 있었다.
버핏케어의 특성상 지점에 계시는 쌤들만 사용하고, 지점에는 보통 3 ~ 4분이 상주하고 계신다. 총 10개 정도의 지점이 있으니 최대 30 ~ 40 연결을 기대하였으나, 아무리 동시에 접속한다 한들 100대가 연결된다는 것은 말이 안 된다고 생각했다.
😭 첫 번째 시도: AI의 도움
처음에는 코드만 보고 어디가 문제인지 파악해보려고 했다. AI의 도움을 받아 어디가 문제인지 파악해달라고 요청했더니, AI는 Firebase의 앱을 초기화하고 생성하는 부분이 잘못되었다고 알려주었다.
import { initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";
const firebaseConfig = {
...firebase 연결정보
}
export const initFirebase = () => {
const config = firebaseConfig;
return initializeApp(config);
};
export const database = () => {
const app = initFirebase(); // ⚠️ 여기가 문제!
return getDatabase(app);
};문제가 되는 코드
위와 같은 코드가 존재할 때, 글로벌 헤더 컴포넌트에서 database() 함수를 사용하여 DB와 연결하고 데이터를 호출해서 URL 주소를 보여주고 있었다.
AI는 database()를 호출하는 방식이 새로운 Firebase 앱 인스턴스를 생성한다고 알려주었고, 컴포넌트가 리렌더링되거나 여러 곳에서 호출할 때마다 인스턴스가 계속 생성되기 때문에 연결 수가 증폭된다고 설명했다.
import { FirebaseApp, getApp, getApps, initializeApp } from "firebase/app";
import { getDatabase } from "firebase/database";
const firebaseConfig = {
...firebase 연결정보
}
// ✅ 앱 인스턴스를 한 번만 생성
export const initFirebase = (): FirebaseApp => {
// 이미 초기화된 앱이 있으면 그것을 반환
if (getApps().length > 0) {
return getApp();
}
// 없으면 새로 생성
return initializeApp(firebaseConfig);
};
export const database = () => {
const app = initFirebase();
return getDatabase(app);
};AI가 제안한 해결책
따라서 AI는 Firebase 앱을 싱글톤 패턴으로 수정해야 한다고 알려주었고, 그 코드를 적용하여 배포를 해보았다.
하지만... 연결 수는 줄어들지 않았다.
그 후로 AI에 물어보는 일은 뒤로 미루어두고, 우선적으로 실제로 접속하는 인원이 몇 명이나 되는지 파악하기 위해 Firebase의 Realtime Analytics 서비스를 적용해보기로 했다.
😎 두 번째 시도: 실제 사용자 수 측정
Realtime Analytics 측정 결과
평일 기준으로 30분 동안의 활성 사용자는 42명 정도로 측정되었고, 5분 동안의 활성 사용자 수는 20명으로 측정되었다. 따라서 DB의 실시간 최대 연결 수가 100이라는 수치가 나오는 것은 뭔가 잘못되었다는 의미였다.
일차적으로 코드를 한번 훑어본 뒤에는 코드상으로는 이상이 없다는 판단을 했고, 최대한 비슷한 상황을 만들어내기 위해 여러 가지 테스트를 해봤다. 새로고침도 여러 번 하고 버튼을 여러 번 눌러보기도 했다.
그러던 중 문득 생각이 들었다. "탭을 여러 개 띄워둔다면?"
버핏케어에서는 회원에 멤버십을 추가하는 과정에서 탭이 새로 생성된다. 탭이 2 ~ 3개가 되는 순간 100이라는 연결 수치가 나올 가능성이 생기게 된다. 테스트를 해보니 순간적으로 연결 수가 3 ~ 5가 오르는 것을 확인할 수 있었다.
해결 방법
브라우저의 탭을 전환할 때 Firebase에서 제공하는 goOffline() 함수와 goOnline() 함수를 이용하여 DB 연결을 끊어주고 연결해주는 기능을 추가했다. 브라우저의 탭 전환을 감지하기 위해서 visibilitychange 이벤트를 사용했다.
import { database } from "@shared/api/firebase";
import { goOffline, goOnline } from "firebase/database";
...
const GlobalHeader = () => {
useEffect(() => {
const db = database();
// 데이터 로드...
const handleVisibilityChange = () => {
if (document.visibilityState === "visible") {
goOnline(db);
} else {
goOffline(db);
}
};
// 초기 상태
handleVisibilityChange();
document.addEventListener("visibilitychange", handleVisibilityChange);
return () => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
goOffline(db);
};
}, []);
return (
...
)
}visibilitychange 이벤트는 같은 브라우저에서의 탭 전환을 감지할 뿐만 아니라 다른 프로그램으로의 전환, 브라우저의 최소화까지 감지하기 때문에 여러 가지 상황을 대처할 수 있다고 판단하여 사용했다.
초기 상태를 확인하는 부분의 경우, 사용자가 한꺼번에 5개의 탭을 열었다고 가정했을 때 초기 상태 확인이 존재하지 않는다면 5개의 탭이 모두 연결될 테니까 그것을 방지하기 위해 작성했다.
결과
점점 줄어드는 실시간 연결 수
해당 코드를 적용하고 나서는 연결 수가 25~30으로 유지되었다!
배운 점
1. AI 제안 코드는 비판적으로 검토하자
AI가 제안해준 코드는 최대한 비판적인 시선으로 바라봐야 할 것 같다. 한 번 더 물어보거나 실제 적용 전에 검색을 해봐야겠다고 생각하게 되었다. 또한 사용할 것이라면 프롬프트를 상세하게 작성해야겠다고 생각했다.
2. 사용자의 실제 사용 패턴을 먼저 파악하자
개발할 때는 "정상적인 사용"을 상정하고 코드를 짠다. 그런데 실제 사용자는 그렇게 사용하지 않는다. 탭을 여러 개 띄우고, 다양한 환경에서 사용한다. 이번 버그를 해결하면서 느낀 것은, 기술적 원인 찾기보다 사용자의 실제 행동 패턴을 먼저 파악하는 게 얼마나 중요한지였다.
3. 브라우저 탭의 독립성
브라우저의 각 탭은 다음과 같은 특성을 가진다:
- 독립적인 JavaScript 실행 환경
- 독립적인 메모리 공간
- 독립적인 전역 변수/객체
따라서 Firebase 인스턴스도 각 탭마다 별도로 생성되며, Firebase의 싱글톤은 "탭 내부"에서만 유효하다는 것을 알게 되었다.
요약
백오피스 툴에서 간헐적으로 버튼이 안 나오는 버그를 조사하던 중, Firebase Realtime Database의 동시 연결 수가 100/100으로 한계에 도달한 것을 발견했다. 실제 사용자는 20 ~ 40명인데 연결 수가 100이 되는 이유를 찾기 위해 여러 테스트를 진행했고, 사용자가 여러 탭을 띄워서 사용할 때 각 탭마다 독립적인 Firebase 인스턴스가 생성되는 것이 원인임을 파악했다. visibilitychange 이벤트를 활용해 비활성 탭의 DB 연결을 끊는 방식으로 문제를 해결하여, 연결 수를 25 ~ 30으로 줄일 수 있었다.