Firebase Realtime Database là một cơ sở dữ liệu JSON đám mây thời gian thực được Google ra mắt vào năm 2012 dành cho các ứng dụng di động và web. Tất cả dữ liệu được lưu trữ trong một cây JSON lớn duy nhất và được đồng bộ giữa các client đã kết nối trong thời gian thực qua kết nối WebSocket. Theo tài liệu chính thức Firebase, 2025, Realtime Database có thể phục vụ tới 200.000 kết nối đồng thời và hỗ trợ tới 1.000 ghi đồng thời mỗi giây. Cơ sở dữ liệu không yêu cầu cơ sở hạ tầng máy chủ và cung cấp SDK cho iOS, Android, Web và các nền tảng máy chủ.
Điểm chính
Firebase Realtime Database là một cơ sở dữ liệu NoSQL đám mây lưu trữ và đồng bộ dữ liệu theo thời gian thực giữa tất cả các client đã kết nối. Ra mắt năm 2012 với tên Firebase (trước khi được Google mua lại), nó trở thành cơ sở dữ liệu đám mây thời gian thực đầu tiên dành cho các nhà phát triển di động. Dữ liệu được biểu diễn ở định dạng JSON và được tổ chức thành cây phân cấp, mỗi nút có một đường dẫn duy nhất.
Giá trị cốt lõi của Realtime Database là cơ chế đồng bộ tích hợp sẵn. Khi một ứng dụng thay đổi dữ liệu trên bất kỳ thiết bị nào, tất cả các client đã kết nối khác sẽ ngay lập tức nhận được bản cập nhật qua kết nối liên tục. Điều này giúp nhà phát triển không cần phải triển khai cơ chế đồng bộ riêng, máy chủ WebSocket hoặc API REST để truyền dữ liệu giữa các client.
Cơ sở dữ liệu cung cấp SDK cho tất cả các nền tảng chính: Android (Java, Kotlin), iOS (Swift, Objective-C), Web (JavaScript) và môi trường máy chủ qua Admin SDK. Theo Google, Realtime Database được sử dụng trong hơn 1,5 triệu dự án Firebase đang hoạt động trên toàn thế giới. Mặc dù Firestore hiện đại hơn đã xuất hiện, Realtime Database vẫn là lựa chọn phổ biến cho các dự án có cấu trúc dữ liệu đơn giản.
Khác với cơ sở dữ liệu quan hệ, Realtime Database không sử dụng bảng và hàng. Tất cả dữ liệu là một cây JSON duy nhất trông giống như các đối tượng JavaScript lồng nhau. Ví dụ, để lưu trữ người dùng và tin nhắn của họ, một hệ thống phân cấp được tạo ra: users/userId/name và messages/messageId/text. Mỗi đường dẫn trong cây là một chuỗi và có thể truy cập dữ liệu trực tiếp qua đường dẫn này.
{
"users": {
"user1": {
"name": "Ivan Petrov",
"email": "ivan@example.com"
},
"user2": {
"name": "Maria Sokolova",
"email": "maria@example.com"
}
},
"messages": {
"-Nabc123": {
"text": "Xin chào!",
"userId": "user1"
}
}
}
Một đặc điểm quan trọng là việc lồng ghép sâu ảnh hưởng đến hiệu suất. Khi ứng dụng đọc dữ liệu tại một đường dẫn nhất định, nó sẽ tải tất cả các nút con của đường dẫn đó. Do đó, nên thiết kế cấu trúc dữ liệu càng phẳng càng tốt, tránh lồng ghép sâu hơn 3-4 cấp. Để giải quyết vấn đề này, người ta sử dụng phương pháp phi chuẩn hóa dữ liệu (denormalization) — sao chép thông tin trong các nút khác nhau của cây.
Realtime Database và Firestore thường được so sánh như hai cơ sở dữ liệu đám mây thời gian thực của Google. Việc lựa chọn giữa chúng phụ thuộc vào yêu cầu cụ thể của dự án: độ phức tạp truy vấn, tính nhất quán yêu cầu và tải dự kiến. Hiểu được điểm mạnh của mỗi cơ sở dữ liệu giúp đưa ra quyết định kiến trúc đúng đắn.
Lợi thế chính của Realtime Database là độ trễ đồng bộ thấp. Vì tất cả dữ liệu được lưu trữ trong một cây JSON duy nhất mà không có các lớp trừu tượng bổ sung, việc đồng bộ diễn ra nhanh hơn Firestore. Đối với các ứng dụng mà tốc độ cập nhật là quan trọng (trò chuyện, trò chơi trực tuyến, hệ thống chỉnh sửa cộng tác), Realtime Database có thể là lựa chọn phù hợp hơn.
Realtime Database phù hợp hơn cho các tình huống có cấu trúc dữ liệu đơn giản và tần suất cập nhật cao. Ví dụ điển hình: trò chuyện, lượt thích thời gian thực, chỉ báo đang nhập, trạng thái hiện diện của người dùng. Đây cũng là lựa chọn tốt cho các nguyên mẫu và dự án có ngân sách hạn chế, vì giá cả dựa trên khối lượng dữ liệu chứ không phải số lượng thao tác.
Mặt khác, đối với các ứng dụng có truy vấn phức tạp (lọc theo nhiều trường, sắp xếp, tổng hợp), Firestore cung cấp khả năng mạnh mẽ hơn nhiều. Realtime Database chỉ hỗ trợ lọc theo một tham số và không thể sắp xếp kết quả theo nhiều trường cùng lúc. Nếu một dự án dự định phân tích dữ liệu phức tạp ở phía client, Firestore sẽ là lựa chọn thiết thực hơn.
Realtime Database sử dụng kết nối WebSocket liên tục để đồng bộ dữ liệu hai chiều. Khi một client gọi setValue hoặc updateChildren trên một đường dẫn cụ thể, dữ liệu sẽ được gửi đến máy chủ Firebase qua kênh đang mở. Máy chủ áp dụng các thay đổi và phân phối bản cập nhật cho tất cả client đã đăng ký trong vòng mili giây. Mỗi kết nối được xác định bằng một khóa phiên duy nhất.
Cơ chế đăng ký hoạt động thông qua các listener. Nhà phát triển có thể đăng ký thay đổi trên một nút cụ thể (addListenerForSingleValueEvent) hoặc nhận các bản cập nhật liên tục (addValueEventListener). Mỗi khi dữ liệu thay đổi, callback onDataChange sẽ được kích hoạt với một ảnh chụp toàn bộ dữ liệu tại đường dẫn đã chỉ định. Điều này khác với Firestore, nơi chỉ các tài liệu đã thay đổi mới được nhận.
Realtime Database hỗ trợ chế độ ngoại tuyến trên Android và iOS thông qua bộ nhớ đệm đĩa. SDK giữ một bản sao dữ liệu cục bộ và tiếp tục xử lý các thao tác ghi khi không có mạng. Khi kết nối được khôi phục, tất cả các thay đổi tích lũy sẽ được gửi đến máy chủ. Chiến lược ghi cuối cùng thắng (last-write-wins) được sử dụng để giải quyết xung đột, nhưng nhà phát triển có thể triển khai logic tùy chỉnh thông qua ServerValue.TIMESTAMP để giải quyết xung đột.
val database = FirebaseDatabase.getInstance()
val myRef = database.getReference("messages")
// Ghi dữ liệu
myRef.push().setValue(
hashMapOf(
"text" to "Tin nhắn mới",
"timestamp" to ServerValue.TIMESTAMP
)
)
// Đọc với cập nhật liên tục
myRef.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val data = snapshot.getValue()
Log.d("TAG", "Dữ liệu: $data")
}
override fun onCancelled(error: DatabaseError) {
Log.w("TAG", "Lỗi: ${error.message}")
}
})
Để tối ưu hóa lưu lượng truy cập và hiệu suất, nên sử dụng child listeners thay vì value listeners khi theo dõi các thay đổi trên các nút con cụ thể. ChildEventListener cung cấp các callback riêng biệt cho việc thêm, sửa, xóa và di chuyển các phần tử con, cho phép kiểm soát chính xác hơn các bản cập nhật giao diện và tránh vẽ lại tất cả các mục danh sách mỗi khi dữ liệu thay đổi.
Realtime Database sử dụng ngôn ngữ quy tắc khai báo để kiểm soát truy cập dữ liệu. Các quy tắc mô tả ai có thể đọc và ghi dữ liệu tại mỗi đường dẫn của cây JSON. Chúng được kiểm tra trên máy chủ Firebase trước mỗi yêu cầu và không yêu cầu logic phía máy chủ để ủy quyền. Các quy tắc hỗ trợ biến, đối tượng tích hợp sẵn và hàm để cấu hình truy cập linh hoạt.
Theo mặc định, quyền truy cập cơ sở dữ liệu bị từ chối đối với tất cả người dùng. Nhà phát triển mở dần quyền truy cập bằng cách sử dụng các quy tắc ".read" và ".write" ở các cấp khác nhau của cây. Các điều kiện có thể kiểm tra xác thực thông qua biến auth, loại yêu cầu (đọc/ghi) và dữ liệu hiện có thông qua đối tượng data. Ngoài ra, các quy tắc hỗ trợ xác thực dữ liệu được ghi thông qua đối tượng newData.
{
"rules": {
"users": {
"$uid": {
// Chủ sở hữu mới có thể đọc dữ liệu của mình
".read": "$uid === auth.uid",
// Chỉ chủ sở hữu mới có thể ghi
".write": "$uid === auth.uid",
// Xác thực trường khi ghi
".validate": "newData.hasChildren(['name', 'email'])"
}
},
"messages": {
// Bất kỳ người dùng đã xác thực nào cũng có thể đọc
".read": "auth !== null",
// Chỉ người dùng đã xác thực mới có thể ghi
".write": "auth !== null",
".indexOn": ["timestamp"]
}
}
}
Các quy tắc cũng hỗ trợ lập chỉ mục dữ liệu thông qua chỉ thị ".indexOn". Nếu không có chỉ thị này, các truy vấn có sắp xếp (orderByChild) sẽ bị từ chối hoặc thực thi không hiệu quả. Chỉ mục được chỉ định cho mỗi đường dẫn nơi thực hiện sắp xếp theo một trường cụ thể. Các quy tắc có tính thứ bậc: các quy tắc sâu hơn ghi đè lên quy tắc cha và nếu quyền truy cập không được xác định ở một cấp nào đó, nó sẽ được coi là được phép hoặc từ chối tùy thuộc vào quy tắc cha.
Realtime Database hỗ trợ năm loại dữ liệu: String, Number, Boolean, Map (đối tượng) và List (mảng). Độ sâu lồng ghép bị giới hạn ở 32 cấp và kích thước tối đa của một nút không được vượt quá 256 MB. Để làm việc hiệu quả với cơ sở dữ liệu, nên thiết kế cấu trúc dữ liệu phẳng và sử dụng phi chuẩn hóa để tránh các truy vấn sâu tải lượng lớn dữ liệu.
Hãy xem xét một ví dụ thực tế về việc tích hợp Realtime Database vào ứng dụng Android để quản lý trạng thái người dùng (trực tuyến/ngoại tuyến). Ứng dụng sẽ hiển thị danh sách người dùng với trạng thái hiện tại của họ, được cập nhật theo thời gian thực. Để minh họa, sử dụng Firebase Authentication để nhận dạng người dùng và coroutines cho các thao tác bất đồng bộ.
Để bắt đầu, hãy thêm phụ thuộc firebase-database-ktx vào tệp build.gradle của mô-đun ứng dụng. Phiên bản thư viện được quản lý thông qua Firebase BoM để đảm bảo tương thích của tất cả các thành phần. Sau khi thêm phụ thuộc, Firebase cần được khởi tạo trong lớp Application hoặc thông qua khởi tạo lười trong 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"
}
Sau khi cấu hình, một kho lưu trữ (repository) được tạo để làm việc với người dùng. Mỗi người dùng được đại diện bởi một nút trong cây /users/{uid} với các trường name, email và status. Để theo dõi trạng thái, sử dụng onDisconnect — một cơ chế đặc biệt của Firebase tự động thực hiện thao tác ghi khi kết nối client bị gián đoạn. Điều này đảm bảo trạng thái người dùng chuyển thành "offline" khi đóng ứng dụng hoặc mất mạng mà không cần mã bổ sung ở phía client.
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()
}
}
Yếu tố chính của ví dụ là onDisconnect. Cơ chế này cho phép thiết lập một thao tác ghi sẽ được thực hiện trên máy chủ khi kết nối client bị gián đoạn. Trong trường hợp này, khi người dùng ngắt kết nối, trạng thái của họ tự động được đặt thành "offline" mà không cần xử lý sự kiện đóng ứng dụng. Nếu ứng dụng bị treo, Firebase sẽ tự thực hiện thao tác onDisconnect và những người dùng khác sẽ thấy trạng thái chính xác.
Câu hỏi thường gặp
Realtime Database lưu trữ dữ liệu trong một cây JSON duy nhất và có độ trễ đồng bộ thấp hơn. Firestore sử dụng bộ sưu tập tài liệu, hỗ trợ truy vấn phức tạp và tính nhất quán mạnh. Realtime Database tốt hơn cho các cuộc trò chuyện đơn giản và trạng thái, Firestore tốt hơn cho các ứng dụng có cấu trúc dữ liệu phức tạp và phân tích.
Kích thước tối đa của một nút Realtime Database là 256 MB. Độ sâu lồng ghép bị giới hạn ở 32 cấp. Cho một dự án Firebase, có thể tạo nhiều phiên bản Realtime Database (tới 5 trên gói Spark và tới 100 trên gói Blaze), cho phép phân phối dữ liệu giữa các phiên bản khác nhau.
Realtime Database tích hợp với Firebase Authentication. Biến auth chứa uid của người dùng đã xác thực có sẵn trong các quy tắc bảo mật. Nhà phát triển có thể giới hạn quyền truy cập ở cấp nút riêng lẻ của cây JSON bằng cách kiểm tra uid của chủ sở hữu dữ liệu. Người dùng ẩn danh và chưa xác thực có auth = null.
Có, Realtime Database hỗ trợ giao dịch thông qua phương thức runTransaction. Giao dịch đảm bảo tính nguyên tử của thao tác đọc-sửa-ghi cho một nút. Khi có các thay đổi đồng thời, giao dịch sẽ được thử lại với dữ liệu hiện tại. Điều này hữu ích cho bộ đếm, xếp hạng và các tình huống khác mà tính nhất quán dữ liệu là quan trọng.
Có, Realtime Database hỗ trợ chế độ ngoại tuyến trên Android và iOS. SDK lưu trữ dữ liệu vào bộ nhớ đệm cục bộ và tiếp tục xử lý các thao tác ghi khi không có mạng. Khi kết nối được khôi phục, tất cả các thay đổi tích lũy sẽ được đồng bộ với máy chủ. Để bật chế độ ngoại tuyến, hãy sử dụng phương thức keepSynced(true) trên nút mong muốn.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm