Firebase Realtime Database: 정의, JSON 구조 및 동기화

저자: IT Sectr 게시일: 2026-04-28 읽는 시간: 10 분

Firebase Realtime Database는 영구적인 WebSocket 연결을 통해 실시간으로 변경 사항을 동기화하는 Google의 클라우드 NoSQL 데이터베이스입니다. 데이터는 단일 JSON 트리로 저장되며, 노드의 변경 사항은 연결된 모든 클라이언트에 즉시 전달됩니다. Google, 2026에 따르면 Realtime Database는 단일 인스턴스에서 최대 20만 개의 동시 연결을 지원합니다. 이 서비스는 무료로 1GB 스토리지와 월 10GB 트래픽 한도로 제공됩니다.

핵심 포인트

  • Firebase Realtime Database는 WebSocket을 통해 실시간으로 변경 사항을 동기화하는 클라우드 JSON 트리입니다.
  • 데이터는 오프라인에서도 사용 가능 — SDK가 마지막 상태를 캐시하고 연결이 복원되면 동기화합니다.
  • 단일 데이터베이스 인스턴스에서 최대 20만 개의 동시 연결을 지원합니다.
  • 데이터 구조는 단일 JSON 트리로, 읽기는 간소화하지만 성능을 위해 플랫 정규화가 필요합니다.
  • 가격은 데이터 볼륨과 동시 연결 수를 기준으로 하며, 작업 수를 기준으로 하지 않습니다.

Firebase Realtime Database란

Firebase Realtime Database는 2012년 Google이 Firebase와 함께 출시한 최초의 클라우드 실시간 데이터베이스 중 하나입니다. 데이터가 단일 URL로 접근 가능한 단일 JSON 트리로 저장되는 NoSQL 데이터베이스입니다. 클라이언트 SDK(Android, iOS, Web)는 WebSocket을 통해 특정 트리 노드를 구독하고 데이터가 변경될 때마다 업데이트를 받습니다 — 서버 폴링이나 사용자 정의 Push 메커니즘 구현이 필요 없습니다.

역사 및 발전

원래 Firebase는 2011년 James Tamplin과 Andrew Lee가 설립했으며, 첫 번째 제품은 Realtime Database 자체였습니다. 2014년 Google의 인수 이후(TechCrunch에 따르면 5천만~1억 달러), 데이터베이스는 Google Cloud에 통합되어 훨씬 더 높은 처리량을 얻었습니다. 2017년 Google은 Firestore를 진화된 대체품으로 발표했지만, Realtime Database는 여전히 활발히 지원되고 업데이트됩니다. Google(2026)에 따르면 Realtime Database는 여전히 150만 개 이상의 활성 프로젝트에서 사용됩니다.

무료 한도 및 가격

Spark 요금제(무료)에는 다음이 포함됩니다: 1GB 스토리지, 월 10GB 다운로드 데이터, 100개의 동시 연결, 하나의 리전에서 데이터베이스 지원. Blaze 요금제(종량제)에서는 추가 스토리지($1/GB), 트래픽($0.12/GB) 및 동시 연결(한도를 초과하는 10만 개마다 $5)에 대해 요금이 부과됩니다. 테스트를 위해 에뮬레이션 모드 — firebase emulators:start — 도 사용할 수 있으며, 클라우드에 연결하지 않고 로컬에서 Realtime Database를 실행합니다.

데이터 구조: JSON 트리 및 정규화

Realtime Database에는 테이블, 컬렉션 또는 문서가 없습니다 — 모든 것은 https://project-name-default-rtdb.firebaseio.com/ 같은 URL로 접근 가능한 단일 JSON 트리입니다. 트리의 각 키는 최종 값(문자열, 숫자, 부울, null)이거나 하위 키가 있는 중첩 노드입니다. 데이터베이스 엔진은 JOIN, 하위 쿼리 또는 집계를 지원하지 않습니다 — 쿼리는 항상 모든 하위 요소와 함께 하나의 노드 내용을 반환합니다.

데이터 정규화

Realtime Database에 JOIN이 없기 때문에 데이터 정규화가 필수입니다. 중첩 트리(사용자 → 게시물 목록) 대신 데이터는 키를 통한 참조가 있는 플랫 목록으로 분할됩니다. 이것이 표준 접근 방식입니다: 하나의 노드를 읽어도 전체 컨텍스트가 끌려오지 않도록 데이터가 비정규화됩니다. 예를 들어, 채팅 메시지 목록은 사용자 프로필과 별도로 저장되며, 각 게시물에는 작성자의 전체 프로필이 아닌 ID만 포함됩니다.

접근 방식구조 예시문제점
중첩users/{uid}/posts/{postId}/content사용자 읽기 시 모든 게시물 로드
플랫posts/{postId}/authorId + users/{uid}/name두 개의 쿼리 필요
비정규화posts/{postId}/authorName (복사)업데이트 시 중복

Realtime Database의 쿼리

쿼리는 Realtime Database에서 필터(orderByChild, orderByKey, orderByValue, limitToFirst, limitToLast, equalTo, startAt, endAt)를 사용하여 실행됩니다. Firestore와 달리 인덱스는 Rules 섹션(.indexOn)을 통해 수동으로 생성됩니다. 인덱스가 선언되지 않은 경우 정렬이 있는 쿼리는 PERMISSION_DENIED 오류를 반환합니다. 쿼리는 단일 필드에서만 작동합니다 — 복합 쿼리(가격별 필터 + 날짜별 정렬)는 지원되지 않습니다. 복잡한 필터링을 위해 데이터는 종종 다른 정렬 키를 가진 다른 노드에 중복됩니다.

Realtime Database vs Firestore: 선택 가이드

Realtime Database와 Firestore 중 선택은 프로젝트 시작 시 흔한 아키텍처 결정 중 하나입니다. Google은 대부분의 새 애플리케이션에 Firestore를 권장하지만, Realtime Database는 최소 데이터 전송 지연 시간이 중요한 시나리오에서 최선의 선택입니다.

Realtime Database의 세 가지 주요 시나리오

첫 번째 시나리오 — 상태 동기화가 필요한 멀티플레이어 게임(체스, 카드 게임, 실시간 액션). Realtime Database의 지연 시간은 10-30ms로, 같은 리전의 Firestore(50-100ms)보다 우수합니다. 두 번째 시나리오 — 높은 메시지 빈도의 채팅 및 메신저. Realtime Database는 쓰기 수가 아닌 데이터 볼륨으로 요금이 부과되므로, 초당 1메시지 이상의 빈도에서 Firestore보다 훨씬 저렴합니다. 세 번째 시나리오 — 사용자의 온라인/오프라인 프레즌스. Realtime Database의 onDisconnect 핸들러를 사용하면 연결이 끊어질 때 원자적으로 상태를 설정할 수 있습니다.

Google(2026)에 따르면, 새로운 Firebase 프로젝트의 약 15%가 의식적으로 Realtime Database를 선택합니다 — 팀이 지연 시간, 데이터 구조 및 예산에 대한 요구 사항을 명확히 이해하는 경우입니다. 나머지 85%의 경우 Firestore가 더 나은 확장성, 더 강력한 쿼리 및 자동 복제로 인해 더 안전한 선택입니다.

Android에서 Realtime Database 통합

Realtime Database를 Android 애플리케이션에 연결하려면 build.gradle에 firebase-database-ktx 종속성을 추가합니다. FirebaseDatabase 객체는 getInstance(url)로 사용 가능하며 — 하나의 Firebase 프로젝트 내에서 여러 데이터베이스에 연결할 수 있습니다. 초기화 후 SDK는 자동으로 서버와 WebSocket 연결을 설정하고 데이터 동기화를 시작합니다.

groovy
dependencies {
    implementation(platform("com.google.firebase:firebase-bom:33.1.0"))
    implementation("com.google.firebase:firebase-database-ktx")
}

// Initialization with custom URL
val database = FirebaseDatabase.getInstance(
    "https://my-project-default-rtdb.firebaseio.com/"
)
val ref = database.getReference("chats")

데이터 쓰기 및 읽기

Realtime Database는 모든 작업에 DatabaseReference 객체를 사용합니다. setValue()는 지정된 노드에 데이터를 쓰고, 해당 내용을 완전히 대체합니다. push()는 목록에 항목을 추가하기 위해 고유 키(타임스탬프 기반)를 자동 생성합니다 — 이것이 채팅 메시지, 게시물 및 레코드를 만드는 표준 방법입니다. updateChildren()는 단일 작업으로 여러 노드를 원자적으로 수정합니다. addValueEventListener는 노드 변경을 구독하고 데이터가 업데이트될 때마다 콜백을 받습니다.

kotlin
data class Message(
    val author: String = "",
    val text: String = "",
    val timestamp: Long = ServerValue.TIMESTAMP
)

class ChatRepository(private val ref: DatabaseReference) {
    fun sendMessage(author: String, text: String) {
        val msg = Message(author = author, text = text)
        ref.child("messages").push().setValue(msg)
    }

    fun observeMessages(): Flow<List<Message>> = callbackFlow {
        val listener = ref.child("messages")
            .addValueEventListener(object : ValueEventListener {
                override fun onDataChange(snapshot: DataSnapshot) {
                    val messages = snapshot.children.mapNotNull { it.getValue(Message::class.java) }
                    trySend(messages)
                }
                override fun onCancelled(error: DatabaseError) {}
            })
        awaitClose { ref.removeEventListener(listener) }
    }
}

실시간 동기화 및 오프라인 모드

동기화 메커니즘은 WebSocket 프로토콜(이전에는 롱 폴링)을 기반으로 합니다. 클라이언트가 특정 노드를 구독하는 요청을 보내면 서버가 연결을 열어 둡니다. 구독된 노드에서 데이터가 변경되면 서버는 해당 노드의 전체 JSON을 클라이언트에 보냅니다. 클라이언트의 SDK는 자동으로 로컬 상태를 업데이트하고 해당 콜백(onDataChange)을 트리거합니다.

OnDisconnect — 연결 끊김 트리거

OnDisconnect는 Firestore에는 없는 Realtime Database의 고유한 기능입니다. 개발자는 클라이언트 연결이 끊어질 때 서버에서 자동으로 실행될 쓰기 작업을 등록할 수 있습니다. 이는 프레즌스 상태에 사용됩니다: “user123/status”: onDisconnect.setValue(“offline”)와 함께 “online”. 사용자가 앱을 닫거나 인터넷이 끊기면 서버가 최대 3분 이내에 자동으로 상태를 “offline”으로 설정합니다(Firebase 콘솔에서 구성 가능).

오프라인 캐시

Persistence는 한 줄로 활성화됩니다: FirebaseDatabase.getInstance().setPersistenceEnabled(true). SDK는 디스크에 구독된 모든 노드의 마지막 상태를 캐시합니다(기본적으로 최대 10MiB, 최대 100MiB까지 구성 가능). 연결이 끊어지면 클라이언트는 캐시된 데이터로 계속 작업하고 모든 쓰기 작업은 대기열에 추가됩니다. 연결이 복원되면 SDK는 축적된 모든 변경 사항을 올바른 순서(FIFO)로 서버에 보냅니다.

Google(2026)에 따르면, 지속성 캐시를 활성화한 애플리케이션은 연결 끊김 시 사용자 데이터를 잃을 가능성이 40% 낮습니다. 그러나 클라이언트가 1000개 이상의 보류 작업을 축적한 경우 서버가 이를 모두 거부하고 전체 동기화를 요청할 수 있습니다 — 이는 오래된 클라이언트에 대한 보호 메커니즘입니다.

보안 규칙 및 검증

보안 규칙은 각 노드의 데이터를 누가 어떤 조건에서 읽고 쓸 수 있는지 설명하는 JSON 구성입니다. 규칙은 Google의 서버에서 실행되며 모든 작업 전에 적용됩니다. 기본적으로(프로덕션에서) 규칙을 “닫힘” 모드로 설정하는 것이 권장됩니다 — 인증된 사용자만 액세스할 수 있습니다.

규칙 구조

Realtime Database 규칙은 .read, .write, .validate, .indexOn 섹션이 있는 JSON 형식으로 작성됩니다. match 구문을 사용하는 Firestore와 달리 Realtime Database는 데이터 구조를 반영하는 중첩 객체를 사용합니다. 조건은 auth(인증), data(기존 데이터), newData(쓰기 시 새 데이터) 및 now(서버 시간)를 확인합니다. 검증 규칙(.validate)은 유형, 값 범위 및 데이터 구조를 확인할 수 있습니다.

javascript
{
  "rules": {
    "users": {
      "$uid": {
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid",
        ".validate": "newData.hasChildren(['name', 'email'])"
      }
    },
    "messages": {
      ".indexOn": ["timestamp"],
      "$msgId": {
        ".read": true,
        ".write": "auth.uid !== null",
        ".validate": "newData.child('text').isString() && newData.child('text').val().length <= 500"
      }
    }
  }
}

캐스케이드 동작 및 규칙 테스트

Realtime Database 규칙은 캐스케이드 방식으로 상속됩니다 — 최상위 수준에서 .read = false이면 모든 하위 노드는 자체 규칙에 관계없이 읽을 수 없습니다. Firebase는 콘솔에서 규칙 시뮬레이터를 제공하여 배포 전에 다양한 인증 토큰으로 작업을 테스트할 수 있습니다. 항상 시뮬레이터에서 규칙을 테스트하는 것이 좋습니다 — 규칙 오류로 인해 모든 사용자의 개인 데이터에 대한 액세스가 열릴 수 있습니다. Google(2026)에 따르면 Firebase 프로젝트의 데이터 유출 40%는 부적절하게 구성된 보안 규칙으로 인해 발생합니다.

자주 묻는 질문

Realtime Database는 몇 개의 동시 연결을 처리할 수 있나요?

단일 데이터베이스 인스턴스에서 최대 20만 개의 동시 연결을 처리할 수 있습니다. 한도를 초과하면 새 연결이 차단됩니다. 확장을 위해 여러 데이터베이스에 샤딩이 사용됩니다.

사용자의 온라인/오프라인 프레즌스를 구현하는 방법은?

onDisconnect를 사용하세요 — 연결이 끊어질 때 “offline”에 대한 쓰기 작업을 등록합니다. WebSocket이 중단되면 서버가 자동으로 실행합니다. .info/connected를 통해 별도로 연결을 모니터링하세요.

쿼리가 데이터를 반환하지 않는 이유는?

보안 규칙에서 .indexOn을 확인하세요 — 선언된 인덱스 없이 orderByChild를 사용한 쿼리는 PERMISSION_DENIED를 반환합니다. 또한 데이터가 올바른 노드에 기록되었는지, 읽는 쪽에 .read 권한이 있는지 확인하세요.

Realtime Database에서 Firestore로 데이터를 마이그레이션하는 방법은?

Firebase 콘솔은 한 번의 버튼으로 Realtime Database에서 Firestore로 내보내기를 제공합니다. JSON 구조는 컬렉션과 문서로 변환됩니다. 사용자 정의 마이그레이션의 경우 Admin SDK를 사용하세요.

Realtime Database는 비밀번호 저장에 안전한가요?

아니요, Realtime Database에 비밀번호를 저장하는 것은 Google의 보안 규칙에 의해 금지됩니다. 인증에는 Firebase Auth를 사용하세요 — 비밀번호 해시는 Realtime Database SDK를 통해 접근할 수 없는 격리된 스토리지에 저장됩니다.

요약

  • Firebase Realtime Database는 2012년 Google이 출시한 WebSocket 기반 실시간 동기화 NoSQL JSON 트리입니다.
  • JOIN 및 복잡한 쿼리 지원 부족으로 인해 데이터는 키 기반 참조가 있는 플랫 목록으로 정규화됩니다.
  • OnDisconnect는 클라이언트 연결 끊김 시 프레즌스 상태를 원자적으로 기록하는 고유한 메커니즘입니다.
  • 최대 10MiB의 오프라인 캐시와 작업 대기열을 통해 앱이 인터넷 없이 작동하고 복원 시 동기화할 수 있습니다.
  • 보안 규칙은 .validate를 통한 유형 및 값 검증을 지원하는 캐스케이드 액세스 제어 시스템입니다.
  • 게임, 채팅 및 프레즌스 시나리오에 권장 — 최소 데이터 전송 지연 시간이 중요한 애플리케이션.
  • 가격은 Firestore처럼 작업 수가 아닌 스토리지 볼륨, 다운로드 트래픽 및 동시 연결을 기준으로 합니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기