Pengalaman menangani 1 miliar permintaan web dengan kode yang membosankan
(notes.billmill.org)- Berbagi pengalaman membangun ulang sistem perbandingan paket asuransi kesehatan Medicare AS, dengan struktur sederhana yang hanya terdiri dari teknologi teruji (Postgres, golang, React, dll.) dan mampu menangani lebih dari 1 miliar permintaan web secara stabil
- Merancang arsitektur dengan tujuan kesederhanaan dan stabilitas, sehingga mencapai rata-rata waktu respons di bawah 10 ms dan tingkat gangguan yang sangat rendah
- Inovasi (
innovation token) diterapkan seminimal mungkin hanya pada pemisahan struktur inti (3 modul besar, komunikasi gRPC), sementara untuk selebihnya dipilih metodologi yang membosankan tetapi dapat diandalkan - Hingga pengelolaan skema DB, pipeline ETL, pengujian, logging, dokumentasi, dan alat CLI, semua elemen operasional dibangun dengan cara yang sederhana dan dapat diulang, sehingga tercipta sistem yang mudah dipahami dan dipelihara oleh seluruh tim
- Menunjukkan secara nyata bahwa pengendalian kualitas berkelanjutan dan kerja tim yang kuat juga efektif untuk proyek pemerintah berskala besar
Serving a billion web requests with boring code
Gambaran umum
- Selama dua setengah tahun, memimpin pengembangan situs web pemerintah AS untuk membandingkan dan membeli paket Medicare
- Menangani 5 juta permintaan API per hari, dengan rata-rata waktu respons di bawah 10 ms, dan 95% permintaan tetap di bawah 100 ms
- Tingkat insiden sangat rendah, sampai-sampai kasus insinyur benar-benar dipanggil dini hari dapat dihitung dengan jari
- Hanya menggunakan teknologi teruji yang dapat dipahami siapa pun, seperti Postgres, golang, React, untuk membangun sistem yang stabil secara konsisten
Boring über alles
- Prinsip utama adalah selalu mengutamakan 'teknologi membosankan dan teruji' (Choose Boring Technology)
- Upaya inovasi menggunakan innovation token dengan hemat, hanya di tempat yang benar-benar diperlukan
- Lebih memilih teknologi dan proses yang stabil serta jelas daripada solusi yang rumit dan mencolok
Bagian-bagian yang membosankan
- Postgres: inti penyimpanan data, memenuhi kebutuhan keandalan dan skalabilitas. Pencarian kompleks (seperti faceted search) juga diselesaikan dengan Postgres
- golang: build dan deployment cepat, hasil biner jelas. Penanganan error intuitif, dan anggota tim baru pun mudah beradaptasi
- React: framework SPA yang paling teruji, dan anggota tim sudah terbiasa dengannya. Aksesibilitas serta dukungan untuk berbagai perangkat juga menjadi pertimbangan penting
- Dalam jangka panjang memang muncul isu ukuran bundle dan penurunan kecepatan, tetapi pada saat itu ini adalah pilihan terbaik untuk menghasilkan hasil tepat waktu
Token inovasi
- Backend modular: seluruh backend disusun bukan sebagai microservices maupun monolitik, melainkan 3 modul besar (
druginfo,planinfo,beneinfo)- Setiap modul memakai DB Postgres terpisah, dan berbagi data hanya dilakukan melalui gRPC
druginfo: mengindeks sangat rinci informasi harga obat, di mana kombinasi apotek, asuransi, kemasan, dan lain-lain bertambah secara eksponensial, sehingga memerlukan pra-pemrosesan kompleks dan optimasi performaplaninfo: menerima data CMS baru setiap hari, lalu membangun ulang seluruh DB untuk digunakan (menjaga immutability)beneinfo: satu-satunya bagian yang menyimpan informasi pelanggan sebenarnya, dengan penyimpanan PII sensitif seminimal mungkin. Desain dan operasi sangat diperhatikan untuk meminimalkan risiko kebocoran data
- gRPC: memiliki keunggulan karena antarmuka komunikasi antar-modul dapat didefinisikan dengan jelas di dalam kode. Integrasinya dengan alat otomasi juga sangat baik
- Namun, build, tooling, dan debugging lebih kompleks, dan juga dirasakan kurang intuitif dibanding API JSON
- Dukungan web client dan trafik besar ditangani tanpa masalah melalui grpc-gateway
Kompatibilitas mundur yang ketat
- Menjaga kompatibilitas mundur API dan database dilakukan dengan sangat ketat
- Field pada API publik tidak pernah dihapus, dan akan dipertahankan seumur hidup kecuali ada masalah keamanan
- Kolom DB boleh ditambahkan dengan bebas, tetapi penghapusan harus melalui beberapa tahap verifikasi (menghapus referensi → menunggu beberapa minggu → penghapusan aktual)
- Disiplin ini menjadi fondasi utama bagi kecepatan perubahan yang tinggi sekaligus deployment dan operasi yang stabil
Faceted search
- Menerapkan faceted search hanya dengan Postgres tanpa ElasticSearch
- Seluruh logika pencarian ditangani dengan satu fungsi 250 baris yang menggabungkan kondisi pada tabel plan yang telah diindeks dengan baik
- Fokus pada kebutuhan bisnis, dan menyelesaikannya secara sederhana tanpa kompleksitas yang tidak perlu
Database
-
pembuatan
- Skema DB dikelola dengan file
.sqlbernomor dan dimuat berurutan untuk menjamin keandalan - DB
planinfo/beneinfodibuat ulang setiap hari, sehingga tidak memerlukan migrasi. Jika ada kesalahan konfigurasi seperti ketidakcocokan versi, aplikasi dirancang agar sama sekali tidak berjalan
- Skema DB dikelola dengan file
-
ETL
- Script shell per sumber data memuat data ke S3 → instance EC2 mengambil kode/data ETL terbaru lewat cron lalu membuat DB RDS baru
- Secara aktif memanfaatkan klausa
COPYmilik Postgres untuk memproses pemuatan data massal secara efisien alih-alihINSERT - Dalam 2~4 jam per hari, ratusan juta baris data dapat dipindahkan ke DB baru
-
model
- Menggunakan library xo untuk menghasilkan model DB secara otomatis, dengan template kustom untuk menghasilkan kode yang sesuai tim
-
pengujian
- Kesalahan terbesar adalah membuat terlalu banyak pengujian dengan sqlmock, sehingga dalam situasi data sering berubah, pemeliharaannya menjadi sangat merepotkan
- Jika DB nyata bersifat immutable, pengujian terhadap DB nyata kemungkinan akan lebih efisien
-
Database lokal untuk pengembangan
- Dengan script yang otomatis menghasilkan sebagian data dari tiap tabel, setiap developer dapat melakukan pengujian dan pengembangan berbasis data nyata menggunakan DB lokal kecil
- Jika alat seperti ini disiapkan sebelum DB membesar, efisiensi pengembangan seluruh tim akan meningkat drastis
Tooling lainnya
- Untuk berbagai otomasi operasional dan observabilitas, alat CLI diimplementasikan sebagai script shell, dengan semua fungsi utilitas dikelola di satu tempat
- Secara aktif mengembangkan dan memanfaatkan alat yang berfokus pada kebutuhan lapangan, misalnya memvisualisasikan log splunk langsung menjadi grafik melalui perintah Slack
Logging
- Saat permintaan masuk, dibuat request id, lalu id tersebut ditempelkan ke semua konteks log sehingga bisa dilacak dari mana pun
- Merancang logging yang aman dan terstruktur dengan zerolog
- Meninggalkan log wajib pada momen-momen penting seperti saat masuk/keluar sistem dan kondisi pengecualian
Dokumentasi
- Dokumen markdown GitHub dikonversi dengan sphinx-book-theme dan dijalankan sebagai wikibook
- Semua anggota tim aktif berkontribusi pada dokumentasi, sehingga seluruh dokumen sistem bisa ditemukan di satu tempat
- Budaya dokumentasi yang unggul sangat meningkatkan pertumbuhan tim, pemeliharaan, dan efisiensi onboarding anggota baru
Integrasi runtime
- Permintaan klien yang menurunkan performa (seperti penyisipan script analitik) diminimalkan sebisa mungkin melalui persuasi
- Query juga dipindahkan dari runtime browser ke build time agar performa layanan tetap terjaga
- Namun dalam praktiknya, tidak semua permintaan pelanggan bisa ditolak, sehingga sebagian tetap menyebabkan penurunan performa
Dan lainnya
- Ditekankan bahwa selain teknologi, suasana tim yang positif dan kolaboratif serta motivasi yang kuat adalah pendorong nyata keberhasilan sistem skala besar
- Ini menjadi contoh yang memperlihatkan secara nyata kekuatan pilihan praktis yang kecil namun penting, serta pengelolaan kualitas yang konsisten
18 komentar
Hal yang membosankan ini sampai 2,5 tahun?!
Saya penasaran apa itu Faceted Search, lalu mengikuti tautannya dan ternyata ada bacaan lain yang cukup menarik.
https://www.cybertec-postgresql.com/en/faceting-large-result-sets/
https://roaringbitmap.org/about/
https://github.com/cybertec-postgresql/pgfaceting
Pendapat tentang kata "membosankan" ternyata menarik ya haha. Kalau diganti dengan kata lain, enaknya apa ya? Klise, umum?
Menerjemahkan
boringsebagai “membosankan” benar-benar kurang menangkap makna aslinya.boringnessadalah salah satu filosofi desain Go.Sok membosankan~…
Di Korea, semuanya berujung pada Java, jadi terasa asing ya wkwk
Saya rasa
golangdan React sama-sama merupakan bahasa pemrograman enterprise yang "membosankan" (boring) di era baru.Karena
boring-> diterjemahkan menjadi "membosankan" bukanlah terjemahan yang 100% tepat, sepertinya nuansanya tidak tersampaikan dengan baik kepada pembaca Korea.Saya ingin hidup di dunia yang membosankan dengan Postgres, golang, dan React.
Betul, melihat judulnya saya juga sempat mengira itu semacam lelucon.
Di luar negeri, sepertinya itu dianggap sebagai stack yang membosankan.
Sebenarnya, Go memang pilihan paling mudah untuk sekadar membuat web server..
Sepertinya harus mengembangkan dengan bahasa seperti Rust atau yang beraliran FP supaya tidak dianggap membosankan.
Cerita yang terlalu jelas.. hal-hal penting yang terlalu jelas sampai justru terlewatkan..
Stack ini kelihatannya tidak terlalu membosankan sampai level itu. Kalau benar-benar membosankan, bukankah setidaknya harus muncul Java versi 1.8 ke bawah atau VB... entah kenapa saya jadi punya pikiran lancang seperti itu.
Di naskah aslinya ada tautan yang berkaitan dengan
boring, dan jika melihat isinya,boringtampaknya berarti = sesuatu yang sudah terlalu akrab.Ada kata yang lebih tepat seperti experienced, verified, atau skillful, tetapi memilih memakai
boringterasa seperti ada niat untuk memancing perhatian.Mungkin maksudnya bukan membosankan untuk ditulis, tetapi disebut sebagai stack
gukbapyang membosankan karena terlalu sering dipakai, bukan?Sekitar kernel Linux 2.6.29...
Fakta bahwa mereka pakai gRPC itu sendiri... wkwk
Saya juga langsung berpikir, golang itu membosankan?
Kalau classic asp, barulah mungkin pantas dibilang membosankan.