Penyimpanan SQLite tanpa latensi di setiap Durable Object
(simonwillison.net)- Durable Object milik Cloudflare berubah dari penyimpanan key/value menjadi penyimpanan relasional berbasis SQLite, sehingga logika aplikasi dan data berjalan pada host fisik yang sama
- Skalabilitas dilakukan dengan membagi Durable Object berdasarkan unit status logis seperti dokumen, pengguna, atau shard database, alih-alih memperbesar satu objek; satu objek tunggal memiliki batas berupa satu mesin dan satu thread
- Pada sistem dengan unit status yang jelas seperti pemesanan penerbangan, setiap penerbangan dapat memiliki Durable Object khusus beserta database SQLite-nya sendiri, sehingga ribuan database baru bisa muncul setiap hari untuk tiap maskapai
- Durabilitas dibangun dengan streaming entri WAL, penyimpanan object storage, dan replikasi ke data center terdekat; batching dilakukan setiap 16MB atau 10 detik, dan mendukung point-in-time recovery hingga 30 hari
- API JavaScript memilih pendekatan blocking untuk operasi persistensi single-thread yang cepat, dan lokasi Durable Object tetap setelah dibuat, meski relokasi dinamis direncanakan di masa depan
Desain Durable Object yang beralih ke SQLite
- Durable Object milik Cloudflare ditingkatkan dari penyimpanan key/value menjadi sistem relasional berbasis SQLite
- Intinya adalah menempatkan logika aplikasi di lokasi yang sama dengan data yang dikelola logika tersebut
- Satu Durable Object terdiri dari kode yang berjalan pada host fisik yang sama dengan database SQLite yang digunakannya
- Arah desainnya adalah memproses baca dan tulis tanpa round-trip jaringan, sehingga lebih mudah menurunkan latensi
- Pemrosesan skala besar didekati dengan membuat lebih banyak objek, bukan menaikkan throughput satu objek
- Satu objek tunggal berjalan pada satu thread di satu mesin, sehingga memiliki batas throughput yang inheren
- Jika unit status logis yang berbeda seperti dokumen, pengguna, atau shard database ditangani objek terpisah, sistem lebih mudah diskalakan
- Dalam sistem pemesanan penerbangan, tiap penerbangan dapat dipetakan ke Durable Object khusus dan database SQLite-nya sendiri
- Dalam struktur ini, ribuan database baru bisa dibuat setiap hari untuk tiap maskapai
- Setiap Durable Object memiliki nama unik, dan jaringan Cloudflare akan merutekan permintaan ke lokasi objek tersebut di dalam jaringan globalnya
Durabilitas melalui streaming WAL dan replikasi
- Sistem berbasis Durable Object terinspirasi oleh Litestream dan terus melakukan streaming urutan entri WAL tiap objek ke object storage
- Batching dilakukan setiap 16MB atau setiap 10 detik
- Dengan memutar ulang transaksi yang tercatat, point-in-time recovery hingga 30 hari dimungkinkan
- Untuk melengkapi durabilitas dalam jendela 10 detik itu, setelah commit, penulisan langsung dikirim ke 5 replika di data center terdekat yang berbeda
- Respons penulisan baru disetujui jika 3 di antaranya telah mengonfirmasi
- Sistem dasar di balik Durable Objects adalah Storage Relay Service, dan ini telah menjalankan D1 SQLite system terpisah milik Cloudflare selama lebih dari setahun
API dan perilaku lokasi objek
- API JavaScript menggunakan pendekatan blocking, bukan async
- Tujuan desainnya adalah menyediakan operasi persistensi single-thread yang cepat
- Kode contoh sengaja menggunakan pola kueri N+1: mengambil daftar dokumen lalu mengambil nama penulis tiap dokumen dengan kueri terpisah
- Ini dihubungkan sebagai contoh kasus yang cocok ditangani SQLite
- Saat ini Durable Object tidak berpindah lokasi setelah dibuat
- Secara default, objek diinstansiasi di data center yang dekat dengan lokasi tempat permintaan
get()pertama dibuat - Untuk membuatnya secara manual di lokasi lain, parameter opsional
locationHintdapat diberikan keget() - Relokasi dinamis untuk Durable Object yang sudah ada direncanakan untuk masa depan
- Secara default, objek diinstansiasi di data center yang dekat dengan lokasi tempat permintaan
- where.durableobjects.live adalah situs untuk melacak di mana Durable Object baru dibuat di jaringan Cloudflare
- Pada kunjungan contoh, saat halaman dimuat dari Half Moon Bay, ditunjukkan bahwa worker di San Jose membuat Durable Object di San Jose
1 komentar
Komentar Hacker News
Ada beberapa hal menarik lainnya: API penulisan bersifat sinkron, tetapi ada penantian asinkron tersembunyi, sehingga jika penulisan gagal saat respons berikutnya dikeluarkan, runtime akan mengubah respons itu menjadi kegagalan HTTP
Jadi tanpa pengguna harus menangani error atau penantian secara eksplisit, runtime bisa melakukan batching otomatis untuk penulisan dan secara optimistis menganggapnya berhasil
Tidak ada transaksi baca, padahal sepertinya itu akan berguna untuk mendapatkan pointer snapshot pada titik waktu tertentu
Setiap instance runtime dibatasi hingga 128MB RAM
WebSocket bisa masuk hibernasi dan tidak ditagih selama tidur, jadi klien bisa tetap terhubung meski DO sedang tidur
Ada juga fitur mirip RPC otomatis yang memungkinkan DO atau Worker lain diperlakukan seperti pemanggilan JS biasa, padahal sebenarnya bisa memanggil data center lain dan serialisasi serta parsing ditangani oleh runtime
Litestream yang disebut di tulisan itu juga mengusulkan teknik serupa
Di SQLite biasa, transaksi baca berguna karena beberapa proses bisa mengakses database yang sama secara bersamaan
Di sini hanya satu proses yang bisa mengakses database, jadi efek yang sama bisa dicapai dengan menjalankan semua pembacaan di dalam satu fungsi sinkron atau mengimplementasikan lock tingkat proses secara manual
Fakta bahwa entri WAL di-streaming secara batch ke object storage setiap 16MB atau setiap 10 detik tampaknya berarti butuh hingga 10 detik sebelum penulisan dapat dibaca secara andal secara global
Saya kurang paham bagaimana ini bisa menggantikan klaster database regional yang memberi respons milidetik lintas benua
Saya paham mereka menggunakan stream, tetapi tujuannya hanya 5 follower, sementara Cloudflare punya ratusan data center
Jika semua instance SQLite tidak selalu terhubung, rasanya mustahil menjamin pembacaan dalam hitungan detik, dan bahkan jika terhubung, latensi paket bisa menimbulkan masalah
Jika menulis lalu langsung membaca, hasilnya akan langsung terlihat. Ini karena penulisan dan pembacaan juga memperbarui state memori proses saat ini
Jika proses lain, misalnya DO atau Worker lain, perlu mengakses data itu, mereka harus lewat DO yang memilikinya, sehingga mereka akan mengirim permintaan RPC atau HTTP dan mendapatkan informasi terbaru
Hibernasi terjadi setelah periode tidak aktif tertentu, jadi kasus penulisan tiba-tiba menjadi unavailable tampaknya hanya saat DO atau Worker crash segera setelah menulis
Tulisan blog Cloudflare membahas bagian ini lebih rinci. Jadi penulisan tetap cepat sekaligus memperoleh durabilitas
Mesin itu selalu memiliki pandangan yang konsisten terhadap database SQLite miliknya
Anda bisa membuat miliaran objek, tetapi setiap objek memiliki database terpisah
Tidak ada cara untuk membaca langsung database itu dari mesin lain selain mesin tempat DO tersebut berjalan
Setiap DO bersifat unik secara global, dan DO dengan ID tertentu hanya berjalan di satu tempat pada satu waktu, menjalankan SQLite dari penyimpanan lokal di data center tersebut
Bagian yang masih belum saya pahami tentang Durable Objects adalah lokasi fisik-nya
Saya penasaran apakah ia berada di region yang meng-host panggilan API yang pertama kali menyebabkannya dibuat
Jika begitu, ketika terungkap situasi seperti dibuat di Amerika Utara tetapi setelah itu seluruh trafik baca/tulis datang dari Australia, saya juga penasaran apakah ada mekanisme untuk otomatis memindahkan DO ke lokasi lain
locationHint. Untuk Australia gunakan"oc": https://developers.cloudflare.com/durable-objects/reference/...Perlu juga dicatat bahwa “relokasi dinamis Durable Objects yang sudah ada direncanakan untuk masa depan”
Hanya sekitar 10–11% PoP Cloudflare yang meng-host Durable Objects
Permintaan yang masuk ke PoP lain untuk membuat DO akan diteruskan ke salah satu PoP terdekat yang meng-host-nya
Kalau tidak salah, Orleans(https://www.microsoft.com/en-us/research/wp-content/uploads/...) bisa memindahkan actor antar mesin, dan model ini tampaknya cocok untuk cara memindahkan DO antar lokasi
Namun tidak ada panggilan API untuk memindahkan Durable Object
Ia harus tidak memiliki koneksi, lalu akan dibuat ulang di data center terdekat pada koneksi berikutnya atau koneksi pertama
Pada saat itu memorinya hilang, tetapi penyimpanannya tetap ada
Baru-baru ini ada detail fitur terkait hibernasi, jadi penjelasan ini mungkin agak usang
Apakah ada orang lain yang juga merasa sulit memahami teknologi cloud baru seperti ini?
Saya sudah lebih dari 15 tahun berkarier di pengembangan web dan memakai stack Laravel / Postgres / Redis, tetapi saat membaca tulisan seperti ini saya hanya merasa ini bukan untuk saya
Aplikasi kolaborasi real-time yang langsung terlintas adalah Google Docs/Sheets, Notion, Miro, dan Figma
Semuanya adalah aplikasi kolaborasi berskala global, dan saya tidak yakin stack Laravel bisa mendukung use case seperti ini
Google mungkin harus membangun sebagian besar sendiri dan tampaknya memelopori penggunaan CRDT
Namun ketika polanya mulai terlihat dan komponen-komponennya menjadi SaaS, kolaborasi real-time skala besar tidak lagi menjadi masalah rekayasa raksasa, dan hal ini memungkinkan produk-produk yang lebih menarik
Saya sangat menyukai desain Durable Object. Terutama karena mudah memahami cara kerjanya di dalam
Tidak seperti banyak solusi lain yang dirancang untuk data real-time, Durable Objects punya kesederhanaan seperti Redis dan masakan Italia. Semua bahannya terlihat
Dengan waktu, sumber daya, dan data center yang cukup, rasanya programmer yang kompeten bisa membaca dokumentasi DO dan mengimplementasikan ulang sesuatu yang mirip
Karena itu lebih mudah menilai trade-off yang terlibat
Namun saya khawatir meskipun DO bagus untuk membuat pengalaman real-time yang cepat dan overhead rendah, misalnya lima orang mengedit dokumen secara real-time, ia bisa membuat analitik dan pembuatan ringkasan menjadi sangat sulit
Pertanyaan seperti dokumen mana yang diedit kelompok tertentu minggu lalu adalah contohnya, dan jika datanya dimasukkan ke dalam SQLite hal itu bisa menjadi lebih sulit
Anda harus entah bagaimana melakukan query ke banyak instance SQLite kecil lalu menggabungkan hasilnya, jadi saya penasaran apakah DO punya sesuatu untuk ini
Pada akhirnya inilah alasan saya terus kembali ke Postgres. Karena bisa dipakai untuk fitur inti aplikasi, sekaligus untuk ringkasan dan BI
Ini benar-benar desain yang menarik, tetapi sistem pintar seperti ini secara pribadi selalu terasa berada di uncanny valley
Hanya ada tepat dua kasus ketika ini dibutuhkan: ketika Anda harus menskalakan sistem dengan beban yang sangat tinggi secara cerdas, atau ketika Anda membuat proyek mainan untuk bersenang-senang
Kalau proyek mainan, pakai apa saja tidak masalah
Tetapi kalau untuk produksi atau pekerjaan, yang dibutuhkan adalah sesuatu yang sudah terbukti
Jika Anda tidak tahu bahwa Anda membutuhkannya, berarti Anda tidak membutuhkannya, dan Anda bisa memakai database Postgres yang membosankan serta VM atau semacamnya
Sebaliknya, jika Anda tahu bahwa Anda membutuhkannya, justru itu jadi masalah. Ini masih baru dan belum cukup matang, jadi kemungkinan besar Anda akan menemui banyak edge case aneh, dan Anda mungkin tidak ingin men-debug atau menanggung itu
Pada akhirnya saya tidak tahu sistem seperti ini sebenarnya untuk siapa
Ini terlalu niche, sehingga sulit matang dengan mudah lewat banyak pemain serius yang memakainya, dan terlalu kompleks serta penuh trade-off untuk dipakai 99,9% perusahaan
Rasanya satu-satunya target yang pasti adalah para developer yang melihat sesuatu yang mengilap lalu mendirikan perusahaan di atasnya, atau lebih buruk lagi, membangun perusahaan orang lain di atasnya lalu segera menyesal dan pindah ke sesuatu yang lebih membosankan
Jika Anda ingin membuat Figma atau Google Docs berikutnya, model pemrograman Durable Objects sangat nyaman
Artikel ini membahasnya lebih detail: https://digest.browsertech.com/archive/browsertech-digest-cl...
Artikel lama ini juga cukup relevan: http://ithare.com/scaling-stateful-objects/
Bagi orang yang membaca tulisan Figma tentang multiplayer lalu berpikir, “kurang lebih inilah yang saya butuhkan”, Durable Objects tampaknya sangat cocok: https://www.figma.com/blog/rust-in-production-at-figma/
Ada juga pendekatan lain. Saya pernah mencoba memakai CRDT di atas WebRTC, dan itu benar-benar terasa seperti teknologi masa depan
Tetapi itu jauh lebih rumit dibanding fondasi berupa WebSocket di suatu tempat di cloud dan satu instance kelas tunggal
Menempatkan data dan perilaku di lokasi yang sama benar-benar mengurangi kompleksitas secara terukur
Karena ini menghilangkan kekhawatiran soal latensi dan bandwidth, hal itu mengurangi baik kekhawatiran operasional maupun kekhawatiran pengembangan. Dampak masalah N+1 yang terkenal juga jauh berkurang
Anda bisa berargumen bahwa Postgres yang terhubung lewat jaringan lebih baik karena alasan lain, dan itu mungkin benar
Tetapi SQLite termasuk yang paling membosankan dan bisa diprediksi, dan kekuatan-kekuatannya yang sudah dikenal juga jelas
Karena itu, popularitasnya di server juga sedang naik
Namun saya tidak terlalu suka pendekatan membuat banyak database kecil seperti yang diusulkan Durable Objects
Itu mengingatkan pada mimpi buruk NoSQL, dan bisa merusak invariant penting dari database relasional
Menurut saya SQLite jauh lebih baik dipakai sebagai database tunggal, seperti pada produk D1 milik Cloudflare
Cloudflare membutuhkan kisah sukses pelanggan yang bagus, dan kemungkinan besar para engineer hebat di sana akan mau membantu melihat bagaimana ini bekerja, bagaimana ini bisa membantu, dan bagaimana bug akan ditangani, sebagai imbalan untuk mendapatkan kisah sukses
Setelah tervalidasi, hubungan itu akan berubah menjadi hubungan layanan, tetapi pada awalnya ini lebih mendekati kemitraan
Ada banyak layanan, seperti alat internal, yang tidak membutuhkan tuning performa atau pengamatan internal yang mendalam
Untuk kasus seperti ini, framework serverless menurut saya cocok karena sangat mengurangi waktu yang dihabiskan untuk deployment
Cepat itu bagus, tetapi jarang menjadi kebutuhan inti
Biasanya kebutuhan intinya adalah bisa dibuat dengan cepat dan perawatannya minim
Cloudflare mungkin bisa memberikan pengalaman pengembang yang baik di sini, tetapi itu bukan poin promosi utama mereka, dan ada banyak layanan pesaing yang juga bisa mempercepat jenis pengembangan seperti ini
Sebaliknya, ketika dibutuhkan kemampuan debugging tinggi dan observabilitas internal yang mendalam, layanan seperti ini menurut saya kurang cocok
Yang penting adalah metrik apa yang bisa didapat, apakah ada informasi untuk memahami mengapa sebagian Durable Objects lambat, apakah itu bisa diperbaiki, bagaimana logging-nya, dan berapa biayanya
Layanan seperti ini mungkin bagus bagi startup untuk membangun sistem terdistribusi yang cerdas sejak hari pertama dan menunda kekhawatiran soal skalabilitas
Tetapi untuk perusahaan pada skala scale-up, kemungkinan mereka akan ingin pindah ke sesuatu yang bisa ditelusuri lebih dalam, dan transisi itu akan sulit
Seperti yang dikatakan orang lain, use case-nya adalah multiplayer, karena agar aplikasi terasa bagus semua orang harus melihat perubahan secepat mungkin
Secara lebih luas, industri penyimpanan sudah lama berusaha membuat sesuatu yang konsisten, berlatensi rendah, dan cocok untuk banyak pengguna
Bahkan secara fisik pun biasanya ada trade-off antara konsistensi dan latensi, jadi ini sangat sulit
Karena itu berbagai model sedang dicoba, dan cukup banyak eksperimen tersebut terjadi di sekitar SQLite. Tidak semuanya; ada pengecualian seperti Yugabyte dan Cockroach
Saya terus dibuat kagum oleh desain DO
Memang mudah muncul reaksi refleks bahwa ada sesuatu yang salah dengan pendekatan seperti ini, tetapi sebenarnya saya rasa banyak produk nyata secara implisit memang disusun seperti ini
Untuk setiap unit atomik yang membutuhkan konsistensi transaksional, ada banyak pekerjaan kompleks yang dilakukan pada skala yang sangat kecil
Kalau dipikir-pikir, apa yang kami buat di Framer untuk proyek dukungan multiplayer juga merupakan versi yang lebih terapan dari apa yang DO lakukan sekarang
Hasil edit direplikasi pada 60 FPS dan diterapkan ke semua klien dalam urutan yang benar, dan pada akhirnya kami juga membuat sesuatu yang mirip WAL untuk pengeditan objek JSON
Jadi meskipun instance proyek crash, cadangan bisa mengambil alih seolah tidak terjadi apa-apa
Bahkan ketika tidak ada waktu untuk me-commit patch JSON ke objek data proyek yang besar, pendekatannya seperti yang dijelaskan di sini: memprosesnya setiap N pembaruan atau setiap M detik
Mungkin ini pertanyaan bodoh, tetapi saya penasaran bagaimana migrasi skema ditangani dalam konfigurasi seperti ini
Dari pemahaman saya, sepertinya tujuannya adalah database per-tenant, atau struktur yang bahkan lebih terpecah dari itu
Saya penasaran apakah ada cara yang masuk akal untuk menangani migrasi skema, atau apakah database seperti ini diasumsikan lebih berumur pendek sehingga kita harus mendukung beberapa versi DB/DO sampai database tersebut dihapus
Di kepala saya, akan seru membuat layanan bookmark dengan DO per-pengguna
Tetapi saat ingin menambahkan field baru ke tabel yang sudah ada, kita langsung menghadapi masalah yang cukup rumit karena perubahan itu harus diterapkan ke setiap DO secara terpisah
Mungkin contoh itu menyangkut data yang bertahan terlalu lama, jadi bisa jadi desain ini lebih ditujukan untuk penggunaan yang lebih sementara
Jika ada yang benar-benar sudah mencobanya, saya ingin tahu bagaimana caranya
Ada versi untuk SQLite yang ditulis dengan Python, tetapi saya tidak tahu apakah itu bisa dijalankan di Durable Objects. Mungkin bisa lewat WASM dan PyOdide
Atau harus di-port ke JavaScript
https://github.com/simonw/sqlite-migrate
Belakangan ini rasanya Cloudflare mendorong developer untuk memakai DO di mana-mana alih-alih Worker
Koneksi WebSocket di Worker juga timeout setelah sekitar 30 detik, dan pendekatan yang direkomendasikan adalah menggunakan DO
Demo chat aslinya juga sudah memakai DO dan WebSocket sejak 2020: https://github.com/cloudflare/workers-chat-demo
Apakah ini berarti SQLite untuk DO bisa kehilangan data hingga 10 detik saat DO mengalami kegagalan?
Di sini Simon tampaknya bermaksud mengatakan within, bukan “beyond”