Firebase Realtime Database — это облачная JSON-база данных реального времени, запущенная Google в 2012 году для мобильных и веб-приложений. Все данные хранятся в одном большом JSON-дереве и синхронизируются между подключёнными клиентами в реальном времени через WebSocket-соединение. Согласно официальной документации Firebase, 2025, Realtime Database может обслуживать до 200 000 одновременных соединений и поддерживает до 1000 одновременных записей в секунду. База данных не требует серверной инфраструктуры и предоставляет SDK для iOS, Android, Web и серверных платформ.
Главное
Firebase Realtime Database — это облачная NoSQL база данных, которая хранит синхронизирует данные в реальном времени между всеми подключёнными клиентами. Запущенная в 2012 году как Firebase (до приобретения Google), она стала первой облачной базой реального времени для мобильных разработчиков. Данные представлены в формате JSON и организованы в иерархическое дерево, где каждый узел имеет уникальный путь.
Основная ценность Realtime Database — встроенная синхронизация. Когда приложение изменяет данные на любом устройстве, все остальные подключённые клиенты мгновенно получают обновление через постоянное соединение. Это избавляет разработчика от реализации собственного механизма синхронизации, WebSocket-сервера или REST API для передачи данных между клиентами.
База данных предоставляет SDK для всех основных платформ: Android (Java, Kotlin), iOS (Swift, Objective-C), Web (JavaScript) и серверных сред через Admin SDK. По данным Google, Realtime Database используется более чем в 1,5 миллионах активных проектов Firebase по всему миру. Несмотря на появление более современной Firestore, Realtime Database остаётся популярным выбором для проектов с простой структурой данных.
В отличие от реляционных баз, Realtime Database не использует таблицы и строки. Все данные представляют собой одно JSON-дерево, которое выглядит как вложенные объекты JavaScript. Например, для хранения пользователей и их сообщений создаётся иерархия: users/userId/name и messages/messageId/text. Каждый путь в дереве — это строка, и к данным можно обращаться напрямую по этому пути.
{
"users": {
"user1": {
"name": "Иван Петров",
"email": "ivan@example.com"
},
"user2": {
"name": "Мария Соколова",
"email": "maria@example.com"
}
},
"messages": {
"-Nabc123": {
"text": "Привет!",
"userId": "user1"
}
}
}
Важная особенность — глубокая вложенность влияет на производительность. Когда приложение читает данные по определённому пути, оно загружает все дочерние узлы этого пути. Поэтому рекомендуется проектировать структуру данных как можно более плоской, избегая вложенности глубже 3–4 уровней. Для обхода этой проблемы используется денормализация данных — дублирование информации в разных узлах дерева.
Realtime Database и Firestore часто сравниваются как две облачные базы реального времени от Google. Выбор между ними зависит от конкретных требований проекта: сложности запросов, требуемой согласованности и планируемой нагрузки. Понимание сильных сторон каждой базы помогает принять правильное архитектурное решение.
Основное преимущество Realtime Database — низкая задержка синхронизации. Так как все данные хранятся в одном JSON-дереве без дополнительных слоёв абстракции, синхронизация происходит быстрее, чем в Firestore. Для приложений, где критична скорость доставки обновлений (чаты, онлайн-игры, системы совместного редактирования), Realtime Database может быть более подходящим выбором.
Realtime Database лучше подходит для сценариев с простой структурой данных и высокой частотой обновлений. Типичные примеры: чаты, лайки в реальном времени, индикаторы набора текста, статусы присутствия пользователей. Это также хороший выбор для прототипов и проектов с ограниченным бюджетом, так как ценообразование основано на объёме данных, а не на количестве операций.
С другой стороны, для приложений со сложными запросами (фильтрация по нескольким полям, сортировка, агрегация) Firestore предоставляет гораздо более мощные возможности. Realtime Database поддерживает только фильтрацию по одному параметру и не умеет сортировать результаты по нескольким полям одновременно. Если проект планирует сложную аналитику данных на клиенте, Firestore будет более практичным выбором.
Realtime Database использует постоянное WebSocket-соединение для двусторонней синхронизации данных. Когда клиент вызывает setValue или updateChildren на определённом пути, данные отправляются на сервер Firebase через открытый канал. Сервер применяет изменения и рассылает обновления всем подписанным клиентам в течение миллисекунд. Каждое подключение идентифицируется уникальным сессионным ключом.
Механизм подписки работает через listeners. Разработчик может подписаться на изменение конкретного узла (addListenerForSingleValueEvent) или получать постоянные обновления (addValueEventListener). При каждом изменении данных вызывается callback onDataChange с полным снимком данных по указанному пути. Это отличается от Firestore, где приходят только изменённые документы — в Realtime Database всегда загружаются все данные узла.
Realtime Database поддерживает офлайн-режим на Android и iOS через дисковое кэширование. SDK сохраняет локальную копию данных и продолжает обрабатывать операции записи при отсутствии сети. Когда соединение восстанавливается, все накопленные изменения отправляются на сервер. Для разрешения конфликтов используется стратегия last-write-wins, но разработчик может реализовать кастомную логику через ServerValue.TIMESTAMP для разрешения коллизий.
val database = FirebaseDatabase.getInstance()
val myRef = database.getReference("messages")
// Запись данных
myRef.push().setValue(
hashMapOf(
"text" to "Новое сообщение",
"timestamp" to ServerValue.TIMESTAMP
)
)
// Чтение с постоянным обновлением
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val data = snapshot.getValue()
Log.d("TAG", "Данные: $data")
}
override fun onCancelled(error: DatabaseError) {
Log.w("TAG", "Ошибка: ${error.message}")
}
})
Для оптимизации трафика и производительности рекомендуется использовать child listeners вместо value listeners, когда нужно следить за изменениями конкретных дочерних узлов. ChildEventListener предоставляет отдельные callback для добавления, изменения, удаления и перемещения дочерних элементов, что позволяет точнее контролировать обновления UI и избегать перерисовки всех элементов списка при каждом изменении данных.
Realtime Database использует декларативный язык правил для контроля доступа к данным. Правила описывают, кто может читать и писать данные по каждому пути JSON-дерева. Они проверяются на сервере Firebase перед каждым запросом и не требуют серверной логики для авторизации. Правила поддерживают переменные, встроенные объекты и функции для гибкой настройки доступа.
По умолчанию доступ к базе данных запрещён для всех пользователей. Разработчик последовательно открывает доступ, используя правило ".read" и ".write" на различных уровнях дерева. Условия могут проверять аутентификацию через переменную auth, тип запроса (read/write) и существующие данные через объект data. Кроме того, правила поддерживают валидацию записываемых данных через объект newData.
{
"rules": {
"users": {
"$uid": {
// Только владелец может читать свои данные
".read": "$uid === auth.uid",
// Только владелец может писать
".write": "$uid === auth.uid",
// Валидация полей при записи
".validate": "newData.hasChildren(['name', 'email'])"
}
},
"messages": {
// Любой аутентифицированный может читать
".read": "auth !== null",
// Только аутентифицированный может писать
".write": "auth !== null",
".indexOn": ["timestamp"]
}
}
}
Правила также поддерживают индексацию данных через директиву ".indexOn". Без неё запросы с сортировкой (orderByChild) будут отклонены или выполняться неэффективно. Индексы указываются для каждого пути, где выполняется сортировка по определённому полю. Правила каскадные: более глубокие правила переопределяют родительские, и если на каком-то уровне доступа нет, он считается разрешённым или запрещённым в зависимости от родительского правила.
Realtime Database поддерживает пять типов данных: String, Number, Boolean, Map (объект) и List (массив). Глубина вложенности ограничена 32 уровнями, а максимальный размер одного узла не должен превышать 256 MB. Для эффективной работы с базой рекомендуется проектировать плоскую структуру данных и использовать денормализацию для избежания глубоких запросов, загружающих большие объёмы данных.
Рассмотрим практический пример интеграции Realtime Database в Android-приложение для статусов пользователей (online/offline). Приложение будет отображать список пользователей с их текущим статусом, обновляемым в реальном времени. Для демонстрации используются Firebase Authentication для идентификации пользователей и корутины для асинхронных операций.
Для начала работы добавьте зависимость firebase-database-ktx в файл build.gradle модуля приложения. Версия библиотеки управляется через Firebase BoM для обеспечения совместимости всех компонентов. После добавления зависимости необходимо инициализировать Firebase в классе Application или через ленивую инициализацию во ViewModel.
dependencies {
implementation platform("com.google.firebase:firebase-bom:33.0.0")
implementation "com.google.firebase:firebase-database-ktx"
implementation "com.google.firebase:firebase-auth-ktx"
}
После настройки создаётся репозиторий для работы с пользователями. Каждый пользователь представлен узлом в дереве /users/{uid} с полями name, email и status. Для отслеживания статуса используется onDisconnect — специальный механизм Firebase, который автоматически выполняет операцию записи при обрыве соединения клиента. Это гарантирует, что статус пользователя сменится на "offline" при закрытии приложения или потери сети без дополнительного кода на клиенте.
class PresenceRepository {
private val database = FirebaseDatabase.getInstance()
private val auth = FirebaseAuth.getInstance()
private val presenceRef = database
.getReference("presence")
fun trackPresence() {
val uid = auth.currentUser?.uid ?: return
val userRef = presenceRef.child(uid)
userRef.onDisconnect().setValue("offline")
userRef.setValue("online")
}
fun getPresenceStream(): Flow<Map<String, String>> =
presenceRef.snapshotFlow()
.map { snapshot ->
(snapshot.value as? Map<*, *>)
?.mapKeys { it.key.toString() }
?.mapValues { it.value.toString() }
?: emptyMap()
}
}
Ключевой элемент примера — onDisconnect. Этот механизм позволяет задать операцию записи, которая будет выполнена на сервере при обрыве соединения клиента. В данном случае при отключении пользователя его статус автоматически устанавливается в "offline" без необходимости обрабатывать событие закрытия приложения. Если приложение аварийно завершится, Firebase сам выполнит onDisconnect-операцию, и другие пользователи увидят корректный статус.
Часто задаваемые вопросы
Realtime Database хранит данные в одном JSON-дереве и обеспечивает более низкую задержку синхронизации. Firestore использует коллекции документов, поддерживает сложные запросы и сильную согласованность. Realtime Database лучше для простых чатов и статусов, Firestore — для приложений со сложной структурой данных и аналитикой.
Максимальный размер одного узла Realtime Database составляет 256 MB. Глубина вложенности ограничена 32 уровнями. Для одного проекта Firebase можно создать несколько баз данных Realtime Database (до 5 на Spark-плане и до 100 на Blaze-плане), что позволяет распределить данные между разными экземплярами.
Realtime Database интегрируется с Firebase Authentication. В правилах безопасности доступна переменная auth, содержащая uid аутентифицированного пользователя. Разработчик может разграничивать доступ на уровне отдельных узлов JSON-дерева, проверяя соответствие uid владельца данных. Анонимные и неаутентифицированные пользователи имеют auth = null.
Да, Realtime Database поддерживает транзакции через метод runTransaction. Транзакция гарантирует атомарность операции чтения-изменения-записи для одного узла. При одновременных изменениях транзакция повторяется с актуальными данными. Это полезно для счётчиков, рейтингов и других сценариев, где важна консистентность данных.
Да, Realtime Database поддерживает офлайн-режим на Android и iOS. SDK кэширует данные локально и продолжает обрабатывать операции записи при отсутствии сети. При восстановлении соединения все накопленные изменения синхронизируются с сервером. Для включения офлайн-режима используется метод keepSynced(true) на нужном узле.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также