6 poin oleh GN⁺ 2023-09-25 | 1 komentar | Bagikan ke WhatsApp
  • Sebelum mengadopsi sistem antrean terpisah, jika antrean pekerjaan latar belakang bisa dibangun hanya dengan Postgres yang sudah digunakan, kesederhanaan operasional dan keakraban tim bisa dimanfaatkan secara besar
  • NOTIFY/LISTEN dan FOR UPDATE SKIP LOCKED sejak Postgres 9.5 bersama-sama menyelesaikan notifikasi pekerjaan baru dan pencegahan pemrosesan ganda antar-pekerja
  • Redis, Kafka, RabbitMQ, dan Amazon SQS adalah opsi yang kuat, tetapi dependensi baru menambahkan mode kegagalan dan biaya pembelajaran ke lingkungan pengembangan, pengujian, dan operasional
  • Antrean Postgres juga bukan solusi serba bisa: push/pop bisa lebih lambat daripada Redis, dan bisa muncul biaya operasional seperti database atau server antrean terpisah, serta VACUUM yang lebih sering
  • Lebih aman jika kode pekerjaan latar belakang diabstraksikan agar tidak terikat pada backend antrean, dan teknologi antrean lain baru dipertimbangkan saat teknologi yang sudah akrab tidak lagi memenuhi kebutuhan

Cara kerja antrean Postgres

  • Teknologi antrean Postgres terdiri dari dua elemen
    • pub/sub untuk memberi tahu dan menerima pekerjaan baru
    • penguncian baris untuk mencegah beberapa pekerja memproses pekerjaan yang sama
  • Kedua fitur ini tersedia secara bawaan sejak Postgres 9.5 yang dirilis pada 2016
  • Dengan menggunakan NOTIFY dan LISTEN bersama, pub/sub dapat ditambahkan ke aplikasi
  • FOR UPDATE SKIP LOCKED mengambil kunci baris pada record yang sesuai kondisi, lalu melewati record yang sudah terkunci
    • Jika diterapkan pada record pekerjaan, kita bisa membuat kueri pemrosesan antrean seperti SELECT * FROM jobs ORDER BY created_at FOR UPDATE SKIP LOCKED LIMIT 1
  • SKIP LOCKED memberikan tampilan data yang “tidak konsisten”, tetapi sifat ini justru berguna untuk antrean
    • Pekerjaan yang sedang diproses tidak terlihat oleh pekerja lain karena kunci baris
    • Perilaku ini memungkinkan mutual exclusion terdistribusi
  • Dengan memberi tahu pekerja yang sedang LISTEN lewat NOTIFY tentang pekerjaan baru, kita bisa membangun pemrosesan batch berkala maupun pemrosesan pekerjaan real-time

Mengapa Redis menjadi pilihan default untuk pekerjaan latar belakang

  • Cara menangani pekerjaan yang berjalan lama adalah pilihan teknologi yang melibatkan banyak trade-off
  • Opsi antrean/message broker yang umum digunakan antara lain
    • Redis: penyimpanan data in-memory dan backend bagi berbagai library pekerjaan latar belakang
    • Apache Kafka: platform distributed event streaming yang dikelola Apache Foundation
    • RabbitMQ: diperkenalkan sebagai message broker yang tersebar luas
    • Amazon SQS: SaaS Amazon yang menyediakan antrean dengan skalabilitas tinggi
  • Di topik background jobs GitHub, 5 library terpopuler semuanya berbasis Redis
    1. Sidekiq — Ruby
    2. resque — Ruby
    3. rq — Python
    4. Hangfire — C#
    5. asynq — Go
  • Redis menyimpan data di memori sehingga penyisipan dan pengambilan cepat, serta menyediakan API pub/sub dan struktur data list, set yang cocok untuk implementasi antrean
  • Skalabilitas Redis menjadikannya pilihan default bagi banyak pengembang, dan default punya pengaruh besar dalam pemilihan teknologi

Kriteria yang perlu dilihat sebelum skalabilitas

  • Obsesi industri teknologi terhadap “scale” dapat mengesampingkan kesederhanaan, kemudahan pemeliharaan, dan pengurangan beban kognitif pengembang
  • Banyak aplikasi tidak membutuhkan skala setingkat Google, Facebook, atau Uber
  • Saat memulai proyek atau bisnis, alih-alih langsung mengoptimalkan hanya untuk skalabilitas, perlu lebih dulu melihat kriteria berikut
    • teknologi yang sangat dipahami tim
    • teknologi yang cukup baik untuk memenuhi kebutuhan pengguna
    • solusi yang sesuai kapasitas tim dan membutuhkan usaha paling sedikit
  • Postgres juga sebenarnya dapat diskalakan dengan baik, tetapi untuk use case antrean, ia bukan sistem antrean khusus yang paling besar skalanya
  • Sebagai perangkat lunak serbaguna, Postgres menangani cukup banyak pekerjaan dengan baik, dan antrean adalah salah satunya

Menilai dengan “teknologi yang membosankan”

  • Saat memilih teknologi antrean, pertanyaan terpenting adalah teknologi apa yang sedang digunakan saat ini dan benar-benar dipahami dengan baik
  • Teknologi yang sudah dipakai dan dipahami dengan baik menambah beban yang lebih kecil pada software stack
  • Jika sudah memakai database relasional dan database itu adalah Postgres, maka antrean Postgres bisa dipertimbangkan sebelum perangkat lunak lain
  • “Teknologi yang membosankan” bukan daftar tetap, melainkan berubah tergantung teknologi yang sedang digunakan
    • Untuk aplikasi yang berpusat pada pengiriman pesan, RabbitMQ bisa menjadi teknologi yang membosankan
    • Untuk aplikasi yang berpusat pada caching, Redis bisa menjadi teknologi yang membosankan
    • Untuk aplikasi dengan banyak data relasional, Postgres bisa menjadi teknologi yang membosankan
  • Jika Redis, Kafka, RabbitMQ, atau SQS diperkenalkan baru hanya untuk pekerjaan latar belakang, biayanya menjadi besar
    • dependensi sistem baru ditambahkan ke lingkungan pengembangan, pengujian, dan produksi
    • di masa depan Developer, DBA, dan SRE harus memahami mode kegagalan dan pengaturan sistem baru itu
    • diperlukan pengetahuan untuk pemulihan gangguan, diagnosis masalah, dan pemantauan kinerja
    • unknown unknowns yang belum diketahui tim tetap menjadi risiko

Biaya dan kriteria memilih antrean Postgres

  • Teknologi yang membosankan bukan solusi serba bisa, dan Postgres bukan pengecualian
  • Dengan memilih antrean Postgres, kita mendapat keuntungan berupa keakraban, mode kegagalan yang sudah dikenal, dan penyebaran biaya, tetapi juga harus membayar harga berikut
    • push/pop antrean Postgres jauh lebih lambat daripada Redis
    • alih-alih satu database relasional, mungkin dibutuhkan database aplikasi dan database antrean yang terpisah
    • untuk menskalakan pekerjaan latar belakang secara independen, mungkin dibutuhkan server database terpisah
    • VACUUM yang lebih sering mungkin diperlukan dan dapat menambah beban kinerja
  • Tidak satu pun dari Postgres, Redis, Kafka, RabbitMQ, atau SQS yang seharusnya menjadi default otomatis
  • Pemilihan teknologi selalu merupakan trade-off yang berkelanjutan, dan harus dinilai sesuai kebutuhan tim dan aplikasi
  • Saat ragu, kita bisa menerapkan patokan: “pertimbangkan alternatif hanya ketika sudah terbukti bahwa teknologi yang membosankan tidak memenuhi kebutuhan”

Struktur pekerjaan latar belakang yang memungkinkan antrean diganti

  • Kode pemrosesan pekerjaan latar belakang tidak boleh bergantung pada teknologi antrean tertentu
  • Saat aplikasi tumbuh, teknologi seperti memcached atau Redis bisa ditambahkan sesuai kebutuhan, dan seiring waktu teknologi itu juga bisa menjadi “teknologi yang membosankan” yang akrab bagi tim
  • Jika teknologi antrean diabstraksikan, pengguna dapat memilih antrean yang sesuai untuk pekerjaannya
  • Di antara library pekerjaan latar belakang paling populer di GitHub, selain Hangfire, tidak ada yang menyediakan jalan keluar ke teknologi antrean selain Redis
    • Dalam struktur seperti ini, untuk mengganti antrean, kode aplikasi harus ditulis ulang
  • Neoq adalah library Go yang dibuat berdasarkan filosofi ini
    • backend antreannya dapat menggunakan in-memory, Postgres, atau Redis
    • pengguna dapat menginisialisasi dengan backend antrean lain tanpa mengubah kode aplikasi
    • implementasi in-memory dan Postgres disediakan sebagai implementasi utama, sedangkan implementasi Redis menggunakan asynq
  • Redis, Kafka, RabbitMQ, dan SQS bisa menjadi teknologi yang hebat, tetapi tidak selalu merupakan antrean yang tepat atau tingkat kompleksitas yang sesuai untuk pekerjaan tersebut

1 komentar

 
GN⁺ 2023-09-25
Pendapat Hacker News
  • Sejauh ini saya sudah membuat sistem kerja terdistribusi tiga kali, dan aturan praktis yang saya sarankan selama bertahun-tahun adalah “rancang untuk 10 kali skala saat ini”
    Jika sekarang 70 request per detik, jadikan 700 request sebagai patokan; jika butuh 20 server batch job, jadikan 200 server sebagai patokan. Bahkan startup yang tumbuh 100% setiap tahun pun baru menjadi 8 kali lebih besar setelah 3 tahun, jadi masih ada waktu untuk menulis ulang sambil bertumbuh
    Sistem pertama yang saya buat menghindari SQL karena alasan “skalabilitas”, tetapi saya kesulitan karena banyak menemui kasus pengecualian yang membutuhkan integritas transaksi
    Dua sistem kerja terdistribusi yang saya buat setelahnya menggunakan PostgreSQL sebagai koordinator, dan secara harfiah dibangun di sekitar SELECT FOR UPDATE SKIP LOCKED. Yang satu biasanya mengendalikan 350 worker, dan yang lain menerapkan prioritas kompleks pada ribuan pekerjaan
    Keduanya akan bertahan tanpa masalah sampai mencapai skala pendapatan tahunan jutaan dolar, dan misalnya sistem dengan 350 worker itu, dengan sedikit penyesuaian, bisa diskalakan hingga sekitar 2.000 CPU
    Teknologi skala sangat besar tampak cukup murah sampai Anda menyadari bahwa Anda membutuhkan transaksi. Namun sejak saat itu, meniru semantik transaksi di atas penyimpanan yang bersifat eventual consistency menjadi mimpi buruk engineering
    Jadi Anda perlu duduk dan menghitungnya. Jika perusahaan menghasilkan 100 juta dolar per tahun, seberapa besar sistem terdistribusinya harus berkembang, apakah mudah mendapatkan instance PostgreSQL yang bisa menangani beban itu, atau apakah sharding per klien sudah cukup. Jika memungkinkan, PostgreSQL sangat layak dipertimbangkan. Seratus hal kecil menjadi lebih mudah

    • Saya punya pengalaman serupa. Beberapa kali saya pernah mendorong queue berbasis SQL puluhan kali lipat melampaui skala yang biasanya disebut orang sebagai “SQL akan runtuh di sini dan solusi terdistribusi wajib dipakai”
      Solusi SQL biasanya lebih sederhana, memakai sumber daya komputasi lebih sedikit, dan lebih mudah didukung secara operasional
      Namun agar bisa berfungsi, Anda harus cukup memahami database untuk tahu bahwa fitur seperti SELECT FOR UPDATE SKIP LOCKED memang ada sejak awal. Saat ini makin banyak engineer tumbuh di lingkungan tempat ORM berat menghalangi kemampuan DBMS yang sebenarnya, sehingga pengetahuan semacam ini menjadi cukup langka
    • Rancang dan uji untuk 10 kali skala saat ini, tetapi implementasikan hanya sebanyak yang dibutuhkan sekarang
      Sistem harus mampu menahan beban puncak, dan jika Anda tidak tahu puncaknya, Anda perlu memberi margin aman atau memasukkan cara untuk membuang pekerjaan atau menundanya saat diperlukan
      Semuanya adalah trade-off, dan Anda hanya perlu mengoptimalkan hal yang memang perlu dioptimalkan; kemampuan menentukan apa yang termasuk di dalamnya adalah ciri engineer yang baik
    • Kalimat “meniru semantik transaksi di atas penyimpanan yang bersifat eventual consistency adalah mimpi buruk engineering” benar-benar penting
      Jika ini hal baru bagi Anda, berarti membaca HN selama seminggu pada jam kerja baru saja terbayar; layak ditulis di kertas dan ditempelkan ke kartu ATM Anda
    • Di PostgreSQL, Anda juga bisa membuat queue berbasis advisory lock, yang jauh lebih lambat tetapi juga punya kelebihan
  • Di beberapa proyek, saya memilih pendekatan yang lebih sederhana: memakai tabel biasa dan SELECT FOR UPDATE SKIP LOCKED, yang langsung bisa digunakan dari ORM/query DSL framework di semua bahasa
    https://www.pgcasts.com/episodes/the-skip-locked-feature-in-...
    Ini bukan “skala web”, tetapi berdasarkan pengalaman saya, ia mudah diskalakan hingga ribuan background job

    • Saya juga pernah membuatnya lebih sederhana tanpa lock karena tidak ada logika transaksi. Setelah memilih satu baris, saya mencoba memperbarui field yang menandakan “sudah diambil”; jika jumlah baris terdampak 1 maka itu pekerjaan saya, jika 0 berarti ada orang lain yang mengambilnya lebih dulu, jadi pilih baris baru
      Saya menggunakan cara ini untuk pekerjaan di organisasi besar tanpa masalah. Tidak perlu deployment khusus atau infrastruktur baru; cukup jalankan beberapa worker thread di dalam aplikasi. Anda juga bisa menambahkan thread yang mereset pekerjaan yang terbengkalai
      Namun selama 3 tahun, situasi seperti itu sebenarnya tidak pernah terjadi; semuanya berada di dalam try/catch, jadi jika gagal akan dimasukkan kembali ke queue, dan aplikasi Java-nya juga sangat stabil
    • Baru-baru ini saya memublikasikan manifesto dan potongan kode untuk persis pendekatan ini di PostgreSQL
      delete from task
      where task_id in
      ( select task_id
      from task
      order by random() -- use tablesample for better performance
      for update
      skip locked
      limit 1
      )
      returning task_id, task_type, params::jsonb as params
      [1] https://taylor.town/pg-task
    • Fakta bahwa sistem queue tidak bisa diskalakan dengan baik adalah jenis masalah yang tidak boleh Anda ketahui paling belakangan. Sebab setelah Anda mengetahui bahwa sistem queue secara struktural tidak bisa diskalakan, sulit memperbaikinya tanpa kehilangan data
      Anda menyebut “ribuan background job”, tetapi queue biasanya harus dilihat berdasarkan Hukum Little, dan yang perlu disebut adalah rasio seperti rata-rata laju masuk pekerjaan per detik dan rata-rata durasi pekerjaan. Jumlah mentah saja tidak terlalu bermakna
      Pada awalnya, UPDATE ... SET yang naif pun bisa berjalan, tetapi ia mengambil terlalu banyak lock. Anda bisa memakai subquery SELECT dalam UPDATE, atau mengefisienkan lock pengambilan dengan SELECT FOR UPDATE SKIP LOCKED, tetapi pada akhirnya query pengambilan saling memblokir lock satu sama lain dan queue bisa berhenti
      Saat itu Anda bisa mematikan pemasukan pekerjaan untuk memberi DB ruang bernapas, tetapi kehilangan pemasukan tersebut menyebabkan kehilangan data, dan biasanya masalah intinya adalah proses pengambilan saling memblokir
      Anda juga bisa buru-buru melakukan sharding pada tabel pekerjaan untuk menghindari lock, tetapi ini rapuh untuk didistribusikan ke banyak worker dan bisa berujung pada kehilangan data. Anda bisa membuang sebagian pekerjaan secara acak, tetapi tentu saja itu kehilangan data
      Pilihan-pilihan seperti ini sangat menegangkan saat sistem sedang berjalan, dan pemulihannya juga sangat sulit tanpa mendesain ulang dari nol. Kecuali Anda hanya punya beberapa pelanggan dan yakin selamanya hanya akan berada di level puluhan pekerjaan per detik, setelah mengalami situasi seperti ini sendiri, saya memilih teknologi queue sungguhan dibanding database jika memungkinkan
    • https://github.com/graphile/worker dari Graphile juga diimplementasikan kurang lebih dengan cara seperti ini
  • Saya sering melihat kritik seperti “para engineer meniru infrastruktur FAANG agar terlihat keren, padahal kebutuhannya sama sekali berbeda”, tetapi menurut saya sebagian besarnya adalah masalah pengetahuan dan dokumentasi
    Jika ingin mengikuti FAANG atau startup lain untuk membuat arsitektur berbasis antrean yang dapat diskalakan tanpa batas, ada puluhan panduan, tutorial, dan whitepaper berkualitas tinggi yang memungkinkan Anda menyiapkan solusi yang skalabel seperti Redis atau SQS dalam beberapa jam
    Biaya pemeliharaannya memang lebih tinggi, tetapi Anda bisa memulai dengan menyalin-tempel perintah, kode, dan konfigurasi dari sumber bereputasi
    Sebaliknya, jika ingin memakai NOTIFY PostgreSQL lalu mencari “SQLALchemy notify listen postgres”, yang muncul hanya beberapa pertanyaan Stack Overflow tanpa jawaban dan GitHub Gist tanpa konteks
    Saya benar-benar ingin mencoba pendekatan ini di proyek sampingan, tetapi tidak punya kelonggaran untuk menghabiskan 2–3 hari sendirian mencari tahu
    Dari luar, pilihannya tampak seperti “sederhana tetapi tidak skalabel, yaitu hanya memakai PostgreSQL” versus “rumit tetapi skalabel, yaitu Redis/SQS dan sejenisnya”, sehingga seolah-olah saya memilih skalabilitas yang tidak diperlukan karena silau oleh teknologi keren dan FAANG
    Namun jika panduan dan materi juga diperhitungkan, pilihan sebenarnya lebih dekat ke “rumit dan skalabilitasnya pun tidak terprediksi, karena saya tidak tahu cara implementasi dan jebakannya” versus “sederhana dan skalabel, cara yang memang dilakukan semua orang”. Dengan begitu, pilihan engineer yang mengikuti FAANG terlihat jauh lebih masuk akal

    • Keunggulan teknologi yang “membosankan” seperti PostgreSQL adalah dokumentasinya bagus. Jika ingin memakai NOTIFY, cukup baca https://www.postgresql.org/docs/current/sql-notify.html, tidak perlu kemampuan pencarian khusus
    • Skalabilitas ada harganya. Jika dimasukkan saat tidak diperlukan, fleksibilitas berkurang, dan bagi startup justru itulah kondisi yang tidak diinginkan
      Misalnya, dengan PostgreSQL yang bebannya rendah, migrasi skema, penambahan constraint baru, analitik, dan semacamnya hampir menjadi hal sepele
      Jika memakai SQS, Cassandra, dan sebagainya, Anda memperoleh skalabilitas/ketersediaan, tetapi ketika menyadari desain awalnya tidak cocok, mengubahnya akan memakan waktu jauh lebih lama. Contohnya saat bisnis meminta menambahkan constraint seperti “pengguna tipe foo tidak boleh mengombinasikan nilai bar secara bersamaan”
      Implementasinya mungkin saja dilakukan tanpa PostgreSQL, tetapi terutama bila perlu perubahan, itu tidak mudah atau sederhana
      Karena itu, menurut saya lebih baik memakai PostgreSQL untuk menjaga fleksibilitas, lalu memakai hal lain di atas PostgreSQL ketika sudah tahu bahwa bagian tersebut tidak akan berubah. Tentu saja dalam kasus ini ada overhead infrastruktur dan pemeliharaan tambahan
      Pada akhirnya selalu ada kompromi, dan kita harus tahu apa yang ditukar dengan apa, serta kapan
    • Tulisan ini lebih ditujukan kepada pengembang library daripada pengembang aplikasi
      Menurut saya, tidak ideal jika semua orang mengimplementasikan sendiri worker background job kustom di dalam aplikasi, entah dengan backend PostgreSQL maupun antrean lain
      Background job memiliki banyak nuansa dan detail implementasi yang mudah salah, sehingga biasanya lebih baik ditangani oleh library atau framework khusus yang lebih menyeluruh
      Jika setiap aplikasi Rails tidak memiliki Sidekiq/Active Jobs dan masing-masing mengimplementasikan worker background kustom sendiri, kemungkinan besar aplikasi Rails akan punya reputasi reliabilitas yang jauh lebih buruk daripada sekarang
    • Poin bahwa “pemeliharaannya lebih tinggi” itulah yang membunuh startup kecil. Tentu ada banyak hal yang didapat, tetapi jika perusahaannya bangkrut, semuanya tidak ada artinya
      Pilih saja solusi yang memberi keuntungan terbesar tanpa terlalu menjauh dari tujuan utama
      Saya pernah melihat startup yang para developernya menghabiskan sekitar 80% waktu untuk bergulat dengan tooling dan infrastruktur. Runway-nya tinggal 3 bulan, dan sekarang yang tersisa di ujungnya hanya lubang besar. Memikirkannya saja masih membuat saya bergidik
    • Jika logikanya adalah desain setingkat FAANG akan menghemat waktu, dasar utamanya hanyalah bahwa panduan online bisa ditemukan
      Rasanya belum ada penghormatan terhadap kompleksitas yang cukup
  • Kelemahan terbesar saat memakai PostgreSQL sebagai bus publish/subscribe bersama LISTEN/NOTIFY adalah LISTEN merupakan fitur sesi, sehingga tidak cocok dengan connection pooling per statement
    Jika memakai pendekatan ini, sebaiknya gunakan advisory lock. Lock eksplisit lain memberi beban lebih besar pada database, tetapi advisory lock sengaja dibuat sangat ringan
    Contoh implementasi yang saya suka adalah que, yang telah di-port ke beberapa bahasa

    • Salah satu alasan saya tidak suka NOTIFY/LISTEN adalah karena ketika terjadi masalah, sulit didiagnosis
      Baru-baru ini pun ada masalah di mana setelah beberapa waktu semua NOTIFY/LISTEN berhenti, dan hanya bisa diselesaikan dengan me-restart database, sehingga kami harus berhenti menggunakannya https://dba.stackexchange.com/questions/325104/error-could-n...
    • Saya penasaran apakah ada versi Node dari Que
  • Bertahun-tahun lalu, Skype menggunakan PostgreSQL sebagai queue bersama sebuah plugin kecil untuk memproses semua CDR. Entah apakah masih dipakai sekarang, tetapi menurut standar 10 tahun lalu itu sudah “skala web”, dan sementara orang-orang di internet berdebat bahwa memakai database sebagai queue adalah antipattern, sistem itu berjalan baik-baik saja
    Adanya transaksi itu cukup praktis
    https://wiki.postgresql.org/wiki/SkyTools
    Karena saya cukup banyak memakainya di pekerjaan, saya juga beberapa kali memberi presentasi tentang topik ini di Sydpy. Berguna kalau Anda sudah mengoperasikan dan mendukung PostgreSQL dengan baik
    Namun kalau sekarang, sepertinya saya akan memakai queue khusus, dan akan menghindari RabbitMQ khususnya

    • Akan bagus kalau bagian “akan menghindari RabbitMQ khususnya” dijelaskan lebih lanjut. Saya juga penasaran dengan pengalaman atau pendapat orang lain
    • Saya setuju bahwa sekarang lebih baik memakai queue khusus. Alasan utamanya, kalau di lingkungan cloud, sebagian besar penyedia cloud menawarkan teknologi queue terkelola yang sangat mudah dipakai dan murah
      Bahkan jika khawatir soal vendor lock-in, operasi dasar queue pada dasarnya kecil, hanya semacam push/pop, jadi relatif mudah juga menulisnya agar gampang dipindahkan bila perlu
    • Saya penasaran apakah ada pengalaman buruk dengan RabbitMQ. Kalau ada, apakah karena teknologinya sendiri, atau karena faktor sekitarnya seperti dokumentasi atau komunitas
    • Pendekatan memakai database sebagai queue itu bagus saat berjalan baik, tetapi cara rusaknya bisa membawa Anda ke kondisi yang sangat sulit dipulihkan
      Jika Anda memasukkan queue ke database hanya karena database sudah dioperasikan, logika itu adalah pedang bermata dua. Bukan sesuatu yang patut dirayakan, tetapi kekacauan queue kini bisa ikut menjatuhkan penyimpanan data utama
  • Salah satu keunggulan terbesar saat memakai PostgreSQL sebagai queue aplikasi adalah semua pekerjaan asinkron yang dijadwalkan mendapat manfaat dari transaksionalitas
    Misalnya ada perubahan backend yang kompleks setelah pendaftaran pengguna, lalu setelah memasukkan pekerjaan pengiriman email, bagian berikutnya dalam transaksi yang sama gagal dan di-rollback; maka pekerjaan email itu sejak awal tidak akan masuk ke queue

    • Perlu ditegaskan bahwa saat terhubung dengan sistem lain yang tidak idempoten, mau tidak mau kita harus memilih salah satu semantik setidaknya sekali atau paling banyak sekali
      Untuk email, jika menunggu konfirmasi pengiriman lalu gagal, Anda harus memilih apakah menggagalkan transaksi dan menerima kemungkinan email ganda, atau melanjutkan dan menerima kemungkinan email hilang
      Keuntungan besarnya muncul pada jalur kode yang memodifikasi DB secara asinkron. Karena konsumsi pekerjaan dan pembaruan DB berada dalam transaksi yang sama, semantik tepat sekali dapat ditangani sepenuhnya secara transaksional
    • Ini poin yang sangat penting. Saya sering memakai kombinasi PostgreSQL dan SQS karena SQS memudahkan autoscaling cluster pemroses pekerjaan
      Di PostgreSQL, saya menaruh tabel log transaksi yang berisi event yang terpicu dan pg_current_xact_id() dari transaksi tersebut. Bisa juga memakai xmin bawaan baris, tetapi harus memperhatikan transaction wraparound. Penyisipan ke baris ini memicu NOTIFY
      Sebuah proses latar belakang berjalan berulang; dari tabel transaksi ia memilih semua baris dengan ID transaksi di antara xmin dari eksekusi sebelumnya dan pg_snapshot_xmin(pg_current_snapshot()) saat ini. Event-event itu dipetakan menjadi pekerjaan dan dikirim ke SQS, lalu xmin dicatat dan proses menunggu NOTIFY berikutnya dengan LISTEN
    • Kami juga sedikit meredakan masalah ini dengan menjadwalkan penambahan queue agar dieksekusi setelah commit. Meski begitu masih ada bagian yang tidak aman, dan akan merepotkan kalau koneksi RabbitMQ turun
    • Memberi tahu database bahwa sesuatu sudah diproses dan mengirim pesan ke tempat seperti RabbitMQ tidak bisa 100% transaksional. Inilah alasan terbesar dari pendekatan ini
      Pada queue PostgreSQL, benar bahwa jika setelah memasukkan pekerjaan pengiriman email transaksi kemudian gagal, email tidak akan masuk queue
      Kode database yang memang harus sepenuhnya terpisah layak dipisahkan ke transaksi yang berbeda. Sebaliknya, jika pengguna belum dibuat di DB, Anda mungkin juga tidak ingin mengirim email pendaftaran, jadi tergantung situasinya
    • Keunggulan lain adalah selesainya transaksi dijamin sebelum pekerjaan diambil
      Dengan queue berbasis Redis atau pada dasarnya queue lain mana pun, Anda akan segera menemui situasi ketika pekerjaan yang mengasumsikan record database sudah ada dijalankan sebelum transaksi di-commit. Kode untuk memperbaiki ini biasanya canggung dan rumit
  • Hal yang saya sukai dari Kafka adalah ia sekadar log append-only, dan klien pada dasarnya hanya memegang offset
    Secara konsep sangat sederhana untuk dipahami, persisten, dan cukup tangguh terhadap kegagalan, karena bisa kembali ke offset mana pun dan membaca ulang
    Sayangnya, karena sifat terdistribusinya, Kafka membawa kompleksitas yang cukup besar sehingga untuk sebagian besar use case akhirnya tidak sepadan
    Secara pribadi, saya ingin ada sesuatu yang mirip tetapi lebih mudah dioperasikan. Di satu node, seharusnya bisa menangani ratusan, mungkin ribuan event per detik, dan tanpa kompleksitas distribusi itu akan cukup bagus
    Secara teori ini juga bisa dilakukan dengan PostgreSQL, cukup jangan pernah menghapus baris. Mungkin itu jawabannya

    • PostgreSQL memiliki ID auto-increment yang setara dengan “offset” native dan juga bisa dipartisi berdasarkan tanggal, jadi menurut saya ini kandidat yang sangat baik sebagai pengganti Kafka sederhana
      Jika tidak membutuhkan seluruh fitur seperti consumer group dan partition, konfigurasi consumer juga akan jauh lebih sederhana
    • Saya dulu berharap FasterLog suatu hari akan cukup matang
  • Di Windmill kami memakai pendekatan persis ini. Windmill adalah alternatif Retool open source sekaligus alat yang lebih mirip Airflow modern, dan kami menjalankan benchmark setiap hari
    Jika satu worker Windmill dan PostgreSQL dijalankan sebagai container di instance GitHub CI yang biasa saja, benchmark memproses 1.200 pekerjaan per detik. Jika worker ditambah, skalanya stabil hingga 5.000 pekerjaan per detik
    Kami sedang mempertimbangkan penggunaan Citus untuk menembus batas 5.000 pekerjaan per detik pada instance multitenant
    https://github.com/windmill-labs/windmill/tree/benchmarks

  • Pada masa ketika volumenya sekitar 10 pesan per detik, kami memakai PostgreSQL untuk sebagian antrean, dan memang cukup bisa diskalakan. Namun jujur saja, menyiapkan SQS atau stack antrean lain di AWS, GCP, atau Azure itu sangat mudah, dibuat khusus untuk tujuan tersebut, dan hal seperti DLQ juga sudah bawaan
    Saya tidak tahu mengapa harus memilih jalan ini sambil khawatir sistem itu runtuh lalu ikut memengaruhi kondisi DB lainnya
    Saya suka prinsip “pakai alat yang paling sederhana”, tetapi kadang para engineer tampaknya melangkah terlalu jauh, sampai yang tersisa hanya alat paling bodoh dengan catatan peringatan yang samar, padahal alternatif arus utama relatif murah dan sederhana

    • Pendekatan yang akhirnya saya pakai adalah menyimpan sebagian besar status pekerjaan di DB, dan memakai antrean pekerjaan hanya untuk membangunkan worker agar memproses pekerjaan tersebut
      Jika status pekerjaan disimpan di DB, status itu bisa di-query dengan nyaman. Meski tidak selalu menunjukkan status sebenarnya secara akurat, ini membantu saat menganalisis insiden operasional. Terutama karena kebanyakan antrean pekerjaan akan begitu saja menghapus record yang sudah diproses
      Dan jika semua pekerjaan latar belakang dibuat idempoten, pendekatan seperti “mengirim pesan ke antrean pekerjaan agar pekerjaan ini diproses” hampir selalu aman
      Jika hanya bergantung pada message queue, sering kali sulit mengetahui apa yang terjadi saat muncul masalah performa. Misalnya, RabbitMQ bisa memberi tahu ukuran antrean, tetapi kemampuan untuk memeriksa data internalnya hampir tidak ada atau sangat terbatas
    • Alasannya adalah transaksi dan konsistensi data. Ini jawaban yang tidak bisa didapat dari SQS
    • Karena tiap perangkat lunak punya kebutuhan yang berbeda. Pada appliance on-premise/B2B, tidak adanya kebutuhan layanan eksternal selain PostgreSQL itu sendiri bisa menjadi sebuah fitur
      Sebagian perangkat lunak bisa diperkirakan tidak akan pernah melampaui kemampuan PostgreSQL, dan kalaupun melampauinya, bisa dibuat agar mudah dipindahkan ke layanan lain
      Dan mungkin juga ada keinginan untuk membuat sistem pekerjaan yang memiliki transaksi secara sederhana di dalam PostgreSQL
  • Kami menggunakan Oban dari Elixir untuk memproses ratusan ribu hingga jutaan pekerjaan setiap hari di dalam PostgreSQL
    Adanya semantik transaksi di sekitar pekerjaan latar belakang—misalnya hanya menjadwalkan email ketika transaksi berhasil—sangatlah praktis
    Perlu sedikit tuning pada autovacuum, tetapi setelah dibereskan, ini sangat cocok untuk kami