Memahami kueri real-time dalam skala besar

Baca dokumen ini untuk mendapatkan panduan tentang penskalaan aplikasi tanpa server yang memiliki lebih dari ribuan operasi per detik atau ratusan ribu pengguna serentak. Dokumen ini berisi topik lanjutan untuk membantu Anda memahami sistem secara mendalam. Jika Anda baru mulai menggunakan Firestore, lihat panduan memulai.

Firestore dan SDK seluler/web Firebase menyediakan model yang andal untuk mengembangkan aplikasi tanpa server tempat kode sisi klien mengakses database secara langsung. SDK ini memungkinkan klien memproses pembaruan data secara real time. Anda dapat menggunakan update real-time untuk mem-build aplikasi responsif yang tidak memerlukan infrastruktur server. Meskipun sangat mudah untuk disiapkan dan dijalankan, SDK ini dapat membantu memahami batasan dalam sistem yang membentuk Firestore, sehingga aplikasi tanpa server Anda dapat diskalakan dan berperforma baik saat traffic meningkat.

Lihat bagian berikut untuk mendapatkan saran tentang penskalaan aplikasi.

Memilih lokasi database yang dekat dengan pengguna

Diagram berikut menunjukkan arsitektur aplikasi real-time:

Contoh arsitektur aplikasi real-time

Saat aplikasi yang berjalan di perangkat pengguna (seluler atau web) terhubung ke Firestore, koneksi dirutekan ke server frontend Firestore di region yang sama dengan lokasi database Anda. Misalnya, jika database Anda berada di us-east1, koneksi juga dirutekan ke frontend Firestore di us-east1. Koneksi ini aktif dalam waktu lama dan tetap terbuka hingga ditutup secara eksplisit melalui aplikasi. Frontend membaca data dari sistem penyimpanan Firestore yang mendasarinya.

Jarak antara lokasi fisik pengguna dan lokasi database Firestore memengaruhi latensi yang dialami pengguna. Misalnya, pengguna di India yang aplikasinya berkomunikasi dengan database di region Google Cloud di Amerika Utara mungkin merasakan pengalaman yang lebih lambat dan aplikasi yang digunakan kurang cepat dibandingkan jika database berada di lokasi yang lebih dekat, seperti di India atau di bagian Asia lainnya.

Desain keandalan

Topik berikut dapat meningkatkan atau memengaruhi keandalan aplikasi:

Mengaktifkan mode offline

Firebase SDK menyediakan persistensi data offline. Jika aplikasi di perangkat pengguna tidak dapat terhubung ke Firestore, aplikasi tersebut tetap dapat digunakan dengan menggunakan data yang di-cache secara lokal. Hal ini dapat memastikan akses data meskipun pengguna mengalami koneksi internet yang tidak stabil atau kehilangan akses selama beberapa jam atau hari. Untuk detail selengkapnya tentang mode offline, lihat Mengaktifkan data offline.

Memahami percobaan ulang otomatis

Firebase SDK menangani percobaan ulang operasi dan menghubungkan kembali koneksi yang terputus. Hal ini dapat membantu mengatasi error sementara yang disebabkan masalah server atau jaringan yang dimulai ulang antara klien dan database.

Memilih antara lokasi regional dan multi-regional

Ada beberapa konsekuensi saat memilih antara lokasi regional dan multi-regional. Perbedaan utamanya adalah bagaimana data direplikasi. Replikasi data mendorong jaminan ketersediaan aplikasi Anda. Instance multi-region dapat memberikan keandalan layanan yang lebih kuat dan meningkatkan ketahanan data Anda, tetapi konsekuensinya adalah biaya.

Memahami sistem kueri real-time

Kueri real-time, yang juga disebut pemroses snapshot, memungkinkan aplikasi memproses perubahan dalam database dan menerima notifikasi latensi rendah segera setelah data berubah. Aplikasi dapat memperoleh hasil yang sama dengan melakukan polling pada database secara berkala untuk melakukan pembaruan, tetapi sering kali lebih lambat, lebih mahal, dan memerlukan lebih banyak kode. Untuk menemukan contoh cara menyiapkan dan menggunakan kueri real-time, lihat Mendapatkan update real-time. Bagian berikut menjelaskan secara mendetail cara kerja pemroses snapshot dan menjabarkan beberapa praktik terbaik untuk menskalakan kueri real-time sambil mempertahankan performa.

Kita ambil contoh dua pengguna yang terhubung ke Firestore melalui aplikasi pesan yang dibuat dengan salah satu SDK seluler.

Klien A melakukan operasi tulis di database untuk menambahkan dan memperbarui dokumen dalam koleksi bernama chatroom:

collection chatroom:
    document message1:
      from: 'Sparky'
      message: 'Welcome to Firestore!'

    document message2:
      from: 'Santa'
      message: 'Presents are coming'

Klien B memproses pembaruan di koleksi yang sama menggunakan pemroses snapshot. Klien B mendapatkan notifikasi langsung setiap kali seseorang membuat pesan baru. Diagram berikut menampilkan arsitektur di balik pemroses snapshot:

Arsitektur koneksi pemroses snapshot

Urutan peristiwa berikut terjadi saat Klien B menghubungkan pemroses snapshot ke database:

  1. Klien B membuka koneksi ke Firestore dan mendaftarkan pemroses dengan melakukan panggilan ke onSnapshot(collection("chatroom")) melalui Firebase SDK. Pemroses ini bisa tetap aktif selama berjam-jam.
  2. Frontend Firestore membuat kueri sistem penyimpanan yang mendasarinya untuk mem-bootstrap set data. Kemudian, seluruh kumpulan hasil dokumen yang cocok akan dimuat. Kami menyebutnya sebagai kueri polling. Selanjutnya, sistem akan mengevaluasi Aturan Keamanan Firebase database untuk memverifikasi bahwa pengguna dapat mengakses data ini. Jika pengguna diberi otorisasi, database akan menampilkan data tersebut kepada pengguna.
  3. Kueri Klien B kemudian beralih ke mode proses. Pemroses didaftarkan dengan pengendali langganan dan menunggu pembaruan data.
  4. Klien A kini mengirim operasi tulis untuk mengubah dokumen.
  5. Database meng-commit perubahan dokumen ke sistem penyimpanannya.
  6. Secara transaksi, sistem meng-commit pembaruan yang sama ke log perubahan internal. Log perubahan menetapkan urutan perubahan yang ketat pada saat terjadi perubahan.
  7. Log perubahan tersebut kemudian menyebarkan data yang telah diperbarui ke kumpulan pengendali langganan.
  8. Pencocok kueri terbalik akan dijalankan untuk melihat apakah dokumen yang diperbarui cocok dengan pemroses snapshot yang saat ini terdaftar. Dalam contoh ini, dokumen cocok dengan pemroses snapshot Klien B. Sesuai dengan namanya, Anda dapat menganggap pencocok kueri terbalik sebagai kueri database normal, tetapi dilakukan secara terbalik. Alih-alih menelusuri dokumen untuk menemukan dokumen yang cocok dengan kueri, pencocok tersebut secara efisien akan menelusuri kueri yang cocok dengan dokumen yang masuk. Setelah menemukan kecocokan, sistem akan meneruskan dokumen tersebut ke pemroses snapshot. Kemudian, sistem akan mengevaluasi Aturan Keamanan Firebase database untuk memastikan bahwa hanya pengguna yang diotorisasi yang menerima data tersebut.
  9. Sistem meneruskan pembaruan dokumen ke SDK pada perangkat klien B, dan callback onSnapshot diaktifkan. Jika persistensi lokal diaktifkan, SDK juga akan menerapkan pembaruan ke cache lokal.

Bagian penting dari skalabilitas Firestore bergantung pada fan-out dari log perubahan ke pengendali langganan dan server frontend. Fan-out memungkinkan satu perubahan data diterapkan secara efisien untuk melayani jutaan kueri real-time dan pengguna yang terhubung. Dengan menjalankan banyak replika dari semua komponen ini di beberapa zona (atau beberapa region untuk kasus deployment multi-region), Firestore akan mencapai ketersediaan dan skalabilitas tinggi.

Perlu diperhatikan bahwa semua operasi baca yang dikeluarkan dari SDK seluler dan web mengikuti model di atas. Operasi baca tersebut menjalankan kueri polling yang diikuti dengan mode pemrosesan untuk mempertahankan jaminan konsistensi. Hal ini juga berlaku untuk pemroses real-time, panggilan untuk mengambil dokumen, dan kueri satu kali. Anda dapat menganggap pengambilan satu dokumen dan kueri satu kali sebagai pemroses snapshot dengan waktu aktif yang pendek yang memiliki batasan serupa terkait performa.

Menerapkan praktik terbaik untuk menentukan skala kueri real-time

Terapkan praktik terbaik berikut untuk mendesain kueri real-time yang skalabel.

Memahami traffic operasi tulis yang tinggi dalam sistem

Bagian ini membantu Anda memahami cara sistem merespons jumlah permintaan operasi tulis yang meningkat.

Log perubahan Firestore yang mendorong kueri real-time secara otomatis akan diskalakan secara horizontal saat traffic operasi tulis meningkat. Saat kecepatan operasi tulis untuk database meningkat melebihi kemampuan suatu server, log perubahan dibagi menjadi beberapa server, dan pemrosesan kueri mulai menggunakan data dari beberapa pengendali langganan, bukan dari satu pengendali. Dari perspektif klien dan SDK, semuanya transparan dan Anda tidak perlu melakukan tindakan apa pun saat pemisahan terjadi. Diagram berikut menunjukkan cara skala kueri real-time:

Arsitektur fan-out log perubahan

Penskalaan otomatis memungkinkan Anda meningkatkan traffic operasi tulis tanpa batas, tetapi seiring meningkatnya traffic, sistem mungkin memerlukan waktu untuk merespons. Ikuti rekomendasi aturan 5-5-5 untuk menghindari pembuatan hotspot operasi tulis. Key Visualizer adalah alat yang berguna untuk menganalisis hotspot operasi tulis.

Banyak aplikasi memiliki pertumbuhan organik yang dapat diprediksi, yang dapat diakomodasi oleh Firestore tanpa tindakan pencegahan. Namun, beban kerja batch seperti mengimpor set data yang besar dapat meningkatkan operasi tulis terlalu cepat. Saat mendesain aplikasi, Anda harus selalu memperhatikan asal traffic operasi tulis.

Memahami cara interaksi operasi tulis dan baca

Anda dapat menganggap sistem kueri real-time sebagai pipeline yang menghubungkan operasi tulis dengan pembaca. Setiap kali dokumen dibuat, diperbarui, atau dihapus, perubahan akan diterapkan dari sistem penyimpanan ke pemroses yang saat ini terdaftar. Struktur log perubahan di Firestore menjamin konsistensi yang kuat, yang berarti bahwa aplikasi Anda tidak pernah menerima notifikasi tentang pembaruan yang tidak berurutan dibandingkan dengan saat database melakukan perubahan data. Cara ini memudahkan pengembangan aplikasi dengan menghapus kasus ekstrem seputar konsistensi data.

Pipeline yang terhubung ini berarti bahwa operasi tulis yang menyebabkan hotspot atau pertentangan kunci dapat berdampak negatif pada operasi baca. Jika operasi tulis gagal atau mengalami throttling, operasi baca mungkin akan menunggu data yang konsisten dari log perubahan. Jika hal ini terjadi di aplikasi, Anda mungkin akan melihat operasi tulis lambat dan waktu respons lambat yang terkait untuk kueri. Menghindari hotspot adalah kunci untuk menghindari masalah ini.

Membuat dokumen dan operasi tulis tetap kecil

Saat mem-build aplikasi dengan pemroses snapshot, Anda biasanya ingin pengguna mencari tahu tentang perubahan data dengan cepat. Untuk mencapai hal ini, usahakan agar semuanya tetap kecil. Sistem dapat mengirim dokumen kecil dengan puluhan kolom melalui sistem dengan sangat cepat. Dokumen lebih besar dengan ratusan kolom dan data berukuran besar membutuhkan waktu pemrosesan yang lebih lama.

Demikian pula, pilih operasi commit dan tulis yang singkat dan cepat untuk menjaga latensi tetap rendah. Batch yang besar bisa memberikan throughput yang lebih tinggi dari perspektif penulis, tetapi sebenarnya dapat meningkatkan waktu notifikasi untuk pemroses snapshot. Hal ini sering kali tidak masuk akal dibandingkan dengan menggunakan sistem database lain karena Anda dapat menggunakan batch untuk meningkatkan performa.

Menggunakan pemroses yang efisien

Saat kecepatan operasi tulis untuk database Anda meningkat, Firestore membagi pemrosesan data ke banyak server. Algoritma sharding Firestore mencoba menempatkan beberapa data dari koleksi atau grup koleksi yang sama ke server log perubahan yang sama. Sistem mencoba memaksimalkan kemungkinan throughput operasi tulis, sekaligus menjaga jumlah server yang terlibat dalam pemrosesan kueri serendah mungkin.

Namun, pola tertentu mungkin masih menyebabkan perilaku yang kurang optimal untuk pemroses snapshot. Misalnya, jika aplikasi Anda menyimpan sebagian besar datanya dalam satu koleksi besar, pemroses mungkin perlu terhubung ke banyak server untuk menerima semua data yang diperlukan. Hal ini tetap berlaku meskipun Anda menerapkan filter kueri. Menghubungkan ke banyak server meningkatkan risiko respons yang lebih lambat.

Untuk menghindari respons yang lebih lambat ini, rancang skema dan aplikasi Anda sedemikian rupa agar sistem dapat menyalurkan pemroses tanpa harus terhubung ke berbagai server. Sebaiknya bagi data Anda menjadi beberapa koleksi yang lebih kecil dengan kecepatan operasi tulis yang lebih kecil.

Hal ini serupa dengan kueri performa dalam database relasional yang memerlukan pemindaian tabel penuh. Dalam database relasional, kueri yang memerlukan pemindaian tabel penuh setara dengan pemroses snapshot yang mengamati koleksi churn tinggi. Performanya mungkin lebih lambat dibandingkan dengan kueri yang dapat disalurkan database menggunakan indeks yang lebih spesifik. Kueri dengan indeks yang lebih spesifik serupa dengan pemroses snapshot yang mengamati satu dokumen atau koleksi yang lebih jarang berubah. Anda harus melakukan uji beban terhadap aplikasi untuk memahami perilaku dan kebutuhan kasus penggunaan Anda dengan baik.

Membuat kueri polling yang cepat

Bagian penting lainnya dari kueri real-time responsif adalah memastikan bahwa kueri polling berjalan cepat dan efisien ketika mem-bootstrap data. Ketika pertama kali pemroses snapshot baru terhubung, pemroses harus memuat seluruh kumpulan hasil dan mengirimkannya ke perangkat pengguna. Kueri yang lambat membuat aplikasi Anda kurang responsif. Ini termasuk, misalnya, kueri yang mencoba membaca banyak dokumen atau kueri yang tidak menggunakan indeks yang sesuai.

Dalam beberapa situasi, pemroses juga mungkin beralih dari status pemrosesan ke status polling. Hal ini terjadi secara otomatis serta transparan pada SDK dan aplikasi Anda. Kondisi berikut ini dapat memicu status polling:

  • Sistem menyeimbangkan kembali log perubahan karena adanya perubahan beban.
  • Hotspot menyebabkan kegagalan atau penundaan operasi tulis pada database.
  • Server sementara yang dimulai ulang akan memengaruhi pemroses.

Jika kueri polling Anda cukup cepat, status polling menjadi transparan bagi pengguna aplikasi Anda.

Mendukung pemroses aktif dalam waktu lama

Membuka dan menjaga pemroses tetap aktif selama mungkin sering kali merupakan cara yang paling hemat biaya untuk mem-build aplikasi yang menggunakan Firestore. Saat menggunakan Firestore, Anda akan ditagih atas dokumen yang ditampilkan di aplikasi, bukan karena mempertahankan koneksi terbuka. Pemroses snapshot yang aktif dalam waktu lama hanya membaca data yang diperlukan untuk menyalurkan kueri sepanjang masa aktifnya. Ini mencakup operasi polling awal yang diikuti dengan notifikasi saat data benar-benar berubah. Di sisi lain, kueri satu kali membaca ulang data yang mungkin tidak berubah sejak aplikasi terakhir kali menjalankan kueri.

Jika aplikasi Anda harus menggunakan data dengan frekuensi yang tinggi, pemroses snapshot mungkin tidak sesuai. Misalnya, jika kasus penggunaan Anda mengirim banyak dokumen per detik melalui koneksi dalam jangka waktu yang lebih panjang, sebaiknya pilih kueri satu kali yang berjalan pada frekuensi yang lebih rendah.

Langkah Berikutnya