- Redlock berbasis Redis bertujuan menyediakan distributed lock yang toleran terhadap kegagalan, tetapi kurang aman untuk pekerjaan yang bergantung pada korektness dan terlalu rumit bila hanya dipakai untuk optimasi efisiensi
- Dalam distributed lock, tujuan efisiensi untuk mengurangi pekerjaan duplikat dan tujuan korektness untuk melindungi state bersama harus dibedakan lebih dulu; patokannya adalah apakah saat gagal hanya menambah biaya atau justru merusak data
- Bahkan jika ada layanan lock yang sempurna, penghentian GC yang lama, proses yang terhenti sementara, dan latensi jaringan dapat membuat write lama tetap dieksekusi setelah lease kedaluwarsa, sehingga diperlukan fencing token
- Redlock tidak dapat membuat token yang meningkat secara monoton setiap kali lock diperoleh, dan kedaluwarsa key Redis bergantung pada jam sistem berbasis
gettimeofday, sehingga keamanan dapat rusak saat terjadi loncatan jam atau penundaan - Untuk lock yang membutuhkan korektness, gunakan sistem konsensus seperti ZooKeeper beserta pemeriksaan fencing token, dan batasi lock Redis node tunggal hanya untuk penggunaan aproksimatif dan nonkritis
Titik awal meninjau Redlock
- Redlock adalah algoritme untuk mengimplementasikan distributed lock yang toleran terhadap kegagalan di atas Redis, atau lebih tepatnya lease
- Sudah ada lebih dari 10 implementasi independen, dan karena tidak diketahui siapa saja yang bergantung pada algoritme ini, peninjauan publik layak dilakukan
- Redis sendiri sangat cocok untuk berbagi data antarpeladen yang bersifat sementara, aproksimatif, dan cepat berubah
- Contoh: penghitung request per alamat IP, himpunan IP unik per ID pengguna
- Kekhawatirannya adalah Redis makin sering dipakai untuk pengelolaan data yang mengharapkan konsistensi dan durabilitas yang lebih kuat, dan distributed lock adalah salah satu area tersebut
Tujuan lock: efisiensi atau korektness?
- Dalam aplikasi terdistribusi, lock adalah mekanisme agar saat beberapa node mencoba pekerjaan yang sama, hanya satu yang menjalankannya pada satu waktu
- Alasan memakai lock pada dasarnya terbagi menjadi dua
- Efisiensi: optimasi agar komputasi mahal tidak dilakukan dua kali; jika gagal, dampaknya mungkin hanya biaya AWS sedikit naik atau notifikasi email yang sama terkirim dua kali
- Korektness: mekanisme untuk mencegah proses konkuren merusak state yang sama; jika gagal, dapat timbul masalah serius seperti file rusak, data hilang, inkonsistensi permanen, atau pemberian obat yang salah
- Untuk lock dengan tujuan efisiensi, biaya dan kompleksitas Redlock yang memakai 5 server Redis dan verifikasi mayoritas tidak diperlukan
- Instance Redis tunggal dengan replikasi asinkron bila perlu lebih cocok dipakai
- Dalam kasus ini, sebagian lock bisa hilang karena mati listrik atau masalah pada node Redis, tetapi itu masih kegagalan yang dapat ditoleransi untuk optimasi nonkritis
- Karena memakai 5 replika dan mayoritas, Redlock tampak cocok untuk lock yang penting bagi korektness, tetapi pada praktiknya tidak sesuai untuk tujuan itu
Lease saja tidak cukup untuk melindungi resource dengan aman
- Lock dalam sistem terdistribusi berbeda dari mutex di aplikasi multithread; node dan jaringan bisa gagal secara independen sehingga jauh lebih kompleks
- Alur tipikal untuk memperbarui file di shared storage adalah memperoleh lock, membaca file, memodifikasi, menulis ulang, lalu melepas lock
- Lock dipakai untuk mencegah dua klien melakukan read-modify-write secara bersamaan dan menyebabkan update hilang
- Jika klien berhenti terlalu lama saat memegang lock, lease bisa kedaluwarsa
- GC bisa ikut campur dan menghentikan klien dalam waktu lama
- Lease adalah desain yang baik agar klien yang crash tidak memegang lock selamanya, tetapi jika waktu berhenti lebih lama daripada masa kedaluwarsa, klien bisa tetap menjalankan write berbahaya tanpa sadar lease-nya sudah habis
- Masalah ini bukan kasus teoretis; HBase juga pernah mengalami masalah serupa di masa lalu
- Ada kasus penghentian GC “stop-the-world” yang berlangsung beberapa menit
- Bahkan GC “concurrent” seperti CMS di HotSpot JVM tetap kadang harus menghentikan aplikasi
- Memeriksa apakah lock sudah kedaluwarsa tepat sebelum menulis tidak menyelesaikan masalah
- GC bisa menghentikan thread yang sedang berjalan di titik mana pun, termasuk di antara pemeriksaan terakhir dan operasi write
Penghentian proses dan latensi jaringan adalah model ancaman yang umum
- Sekalipun memakai runtime tanpa penghentian GC yang panjang, proses tetap bisa berhenti karena berbagai alasan
- Membaca alamat yang tidak ada di memori bisa memicu page fault
- Jika disk adalah EBS, membaca variabel bisa berubah menjadi request sinkron melalui jaringan Amazon
- Perebutan CPU, penundaan scheduler, atau
SIGSTOPyang terkirim secara tidak sengaja juga bisa menghentikan proses
- Latensi jaringan menimbulkan masalah yang sama
- Aplikasi mengirim request write, tetapi paket bisa tertunda dan baru tiba di storage server setelah lease kedaluwarsa
- Dalam satu insiden GitHub, paket jaringan tertunda sekitar 90 detik
- Jaringan paket seperti Ethernet dan IP dapat menunda paket secara arbitrer, dan hal itu benar-benar terjadi di dunia nyata
- Karena itu, bahkan pada jaringan yang dikelola dengan baik pun kita tidak bisa berasumsi soal timing, dan kode berbasis lease yang sederhana pada dasarnya tidak aman apa pun layanan lock yang dipakai
Write lama harus diblokir dengan fencing token
- Solusinya adalah menyertakan fencing token pada setiap request write ke storage
- Fencing token adalah angka yang bertambah setiap kali klien memperoleh lock
- Contoh: klien 1 memperoleh lease dengan token 33 lalu berhenti lama hingga lease kedaluwarsa
- Klien 2 memperoleh lease baru dengan token 34 dan mengirim request write ke storage
- Ketika klien 1 bangun kemudian dan mengirim write dengan token 33, storage menolaknya karena sudah memproses token 34 yang lebih tinggi
- Agar aman, server storage harus secara aktif memeriksa token dan menolak write dengan nilai token yang mundur
- Jika layanan lock dapat menghasilkan token yang meningkat monoton secara ketat, lock bisa dibuat aman
- Jika ZooKeeper dipakai sebagai layanan lock,
zxidatau nomor versi znode dapat digunakan sebagai fencing token
- Jika ZooKeeper dipakai sebagai layanan lock,
- Masalah besar Redlock adalah tidak memiliki kemampuan menghasilkan fencing token
- Nilai acak unik Redlock tidak memberikan sifat meningkat monoton yang dibutuhkan
- Counter pada satu node Redis tidak cukup karena node itu bisa gagal
- Counter dari beberapa node bisa saling tidak sinkron
- Bahkan untuk menghasilkan fencing token pun kemungkinan dibutuhkan algoritme konsensus
Redlock menggantungkan keamanan pada asumsi waktu
- Dalam algoritme terdistribusi, model praktisnya adalah model asinkron dengan failure detector yang tidak andal
- Proses bisa berhenti selama durasi arbitrer
- Paket bisa tertunda secara arbitrer di jaringan
- Jam bisa salah secara arbitrer
- Meski begitu, algoritme tetap harus membuat keputusan yang benar
- Jam hanya boleh dipakai untuk membuat timeout agar tidak menunggu selamanya ketika sebuah node down
- Timeout tidak perlu akurat, dan request yang timeout tidak berarti node lawan pasti down
- Bisa jadi penyebabnya latensi jaringan atau kesalahan jam lokal
- Redis memakai
gettimeofday, bukan monotonic clock, untuk menentukan kedaluwarsa keygettimeofdaymemungkinkan waktu sistem melompat secara tidak kontinu- Jika NTP menyesuaikan jam atau administrator mengubah waktu secara manual, key Redis bisa kedaluwarsa jauh lebih cepat atau lebih lambat daripada yang diperkirakan
- Algoritme dalam model asinkron umumnya menjaga safety tanpa asumsi timing, sementara failure detector seperti timeout hanya memengaruhi liveness
- Jika timing kacau, performa boleh memburuk, tetapi algoritme tidak boleh mengambil keputusan yang salah
- Redlock berbeda karena safety-nya bergantung pada berbagai asumsi timing
- Semua node Redis harus mempertahankan key kira-kira selama durasi yang benar
- Latensi jaringan harus cukup kecil dibandingkan waktu kedaluwarsa
- Penghentian proses harus jauh lebih singkat daripada waktu kedaluwarsa
Contoh Redlock rusak dalam timing yang buruk
- Dengan 5 node Redis A, B, C, D, E dan klien 1 serta 2, jika jam salah satu node melompat ke depan, kedua klien bisa sama-sama percaya bahwa mereka memegang lock
- Klien 1 memperoleh lock di A, B, C dan tidak bisa menjangkau D, E karena masalah jaringan
- Jam C melompat ke depan sehingga lock kedaluwarsa
- Klien 2 memperoleh lock di C, D, E dan tidak bisa menjangkau A, B karena masalah jaringan
- Akibatnya, klien 1 dan 2 sama-sama menyimpulkan bahwa mereka adalah pemegang lock
- Masalah serupa juga bisa terjadi jika C crash sebelum mempersistenkan lock ke disk lalu segera restart
- Dokumentasi Redlock menyarankan agar restart node yang crash ditunda setidaknya selama TTL lock terpanjang
- Penundaan restart ini juga bergantung pada pengukuran waktu yang cukup akurat, dan bisa gagal jika jam melompat
- Penghentian proses klien juga bisa merusak Redlock
- Klien 1 mengirim request lock ke A, B, C, D, E
- Saat respons sedang dalam perjalanan, klien 1 masuk ke GC stop-the-world
- Lock di semua node Redis kedaluwarsa
- Klien 2 memperoleh lock di A, B, C, D, E
- Klien 1 selesai GC dan menerima respons sukses yang sempat tertahan di kernel network buffer
- Kedua klien sama-sama yakin bahwa mereka memegang lock
- Fakta bahwa Redis ditulis dalam C dan tidak memiliki GC tidak membantu
- Masalahnya muncul pada sistem tempat klien bisa mengalami penghentian GC
- Agar aman, setelah klien 2 memperoleh lock, pekerjaan klien 1 harus diblokir dengan mekanisme seperti fencing token
- Latensi jaringan yang panjang juga dapat menghasilkan efek yang sama seperti penghentian proses
- Jika TCP user timeout disetel jauh lebih pendek daripada TTL Redis, paket yang terlambat mungkin akan diabaikan, tetapi itu tetap bergantung pada detail implementasi TCP tertentu
- Dalam kasus ini pun kita kembali ke persoalan akurasi pengukuran waktu
Asumsi sistem sinkron yang dibutuhkan Redlock
- Redlock hanya bekerja benar dalam model sistem sinkron dengan sifat berikut
- Ada batas atas yang dijamin untuk latensi jaringan
- Durasi penghentian proses dibatasi
- Error jam dibatasi
- Model sinkron bukan berarti jam tersinkronisasi secara sempurna, melainkan bahwa ada batas tetap yang diketahui untuk latensi jaringan, penghentian, dan drift jam
- Redlock berasumsi bahwa latensi, penghentian, dan drift semuanya kecil dibandingkan TTL lock
- Jika masalah timing membesar hingga mendekati TTL, algoritme akan gagal
- Di lingkungan data center umum, asumsi timing seperti ini mungkin terpenuhi pada sebagian besar waktu; ini disebut sistem partially synchronous
- Jika korektness bergantung pada lock, “sebagian besar waktu” tidaklah cukup
- Saat asumsi timing runtuh, Redlock dapat melanggar safety, misalnya memberi lease ke klien lain sebelum lease klien pertama berakhir
- Kasus penundaan paket 90 detik di GitHub adalah bukti bahwa sulit mengasumsikan model sistem sinkron dalam lingkungan nyata
- Raft, Viewstamped Replication, Zab, dan Paxos termasuk kategori algoritme konsensus yang dirancang untuk model sistem partially synchronous atau model asinkron dengan failure detector
- Algoritme semacam ini harus membuang asumsi timing dan berhati-hati agar tidak menganggap jaringan, proses, dan jam dalam sistem terdistribusi lebih andal daripada kenyataannya
Kesimpulan dan pilihan yang direkomendasikan
- Redlock terlalu berat dan mahal untuk lock optimasi efisiensi, dan tidak cukup aman untuk lock yang menyangkut korektness
- Secara khusus, Redlock pada dasarnya mengasumsikan sistem sinkron dengan batas atas pada latensi jaringan dan waktu eksekusi komputasi, dan bila asumsi itu gagal, safety dapat dilanggar
- Redlock juga tidak punya kemampuan menghasilkan fencing token untuk melindungi sistem dari latensi jaringan panjang atau proses yang berhenti
- Jika yang dibutuhkan adalah lock optimasi efisiensi berbasis best effort, lebih baik gunakan algoritme lock Redis node tunggal
- Peroleh lock dengan conditional set-if-not-exists
- Lepaskan lock dengan delete atomik hanya jika nilainya cocok
- Kode harus mendokumentasikan dengan jelas bahwa lock ini bersifat aproksimatif dan kadang bisa gagal
- Tidak perlu membangun klaster 5 node Redis
- Untuk lock yang membutuhkan korektness, jangan gunakan Redlock; pakailah sistem konsensus seperti ZooKeeper
- Jika memungkinkan, gunakan Curator recipes yang mengimplementasikan lock
- Minimal, bisa juga memakai database seperti PostgreSQL yang memberikan jaminan transaksi yang masuk akal
- Pemeriksaan fencing token harus dipaksakan pada semua akses resource di bawah lock
- Redis tetap alat yang berguna jika dipakai sesuai tujuan awalnya, dan seperti semua alat, ia punya batasan yang perlu dipahami dan direncanakan
- Dalam pembaruan 9 Februari 2016, penulis asli Redlock, Salvatore, menerbitkan tulisan bantahan, tetapi kesimpulannya tetap sama
1 komentar
Opini Hacker News
Di tempat kerja kami memakai Temporal, dan mengimplementasikan distributed lock dengan workflow serta signal khusus.
Sejauh ini berjalan baik, dan karena bagian pemrosesan terdistribusi dari lock diserahkan ke fitur Temporal, implementasinya juga cukup sederhana.
Saya penasaran apakah Temporal memang tak tertandingi di bidang ini, atau ada alternatif dengan level serupa.
Karena dipisahkan dari Uber dan dipakai vendor-vendor besar, kedengarannya sudah cukup teruji di dunia nyata.
Untuk distributed lock biasanya saya menggunakan PostgreSQL advisory lock.
Walaupun pekerjaannya tidak terkait database, jika memulai transaksi dan mengambil advisory lock, lock akan dipertahankan sampai aplikasi melepaskannya sendiri atau transaksi berakhir karena crash dan sebagainya.
Sejauh ini saya merasa ini cukup aman, tetapi baru saja sadar bahwa saya belum pernah memeriksa apakah koneksi database masih normal.
Kalau itu pekerjaan terkait database, query akan gagal dan pekerjaannya juga gagal, tetapi kalau bukan, kita bisa saja tidak sadar bahwa lock sudah hilang.
Jika menginginkan kebenaran absolut tanpa fencing token atau operasi atomik, pada akhirnya sepertinya semua pekerjaan membutuhkan two-phase commit.
Mungkin untuk melakukan hal yang dimaksud dengan benar, perlu memakai “EXCLUSIVE” atau “ACCESS EXCLUSIVE”, atau memastikan two-phase commit atau idempotensi untuk pekerjaannya.
[0] https://www.postgresql.org/docs/current/explicit-locking.htm...
Kebanyakan library biasanya memakai connection pool, jadi harus mengamankan koneksi khusus untuk lock, dan pemeriksaan lock berkala juga wajib dilakukan lewat koneksi tersebut.
Sebaiknya baca komentar saya yang dulu saya tinggalkan di komentar blog ini, serta balasan yang saya tulis di blog saya.
Kalau diurutkan secara acak, penulis melewatkan poin inti tentang bagaimana algoritma itu bekerja, lalu menolak algoritma tersebut dengan dasar-dasar yang tersisa dan lebih lemah.
Pernyataan bahwa pada komputer dan API modern mustahil menunggu kira-kira selama waktu yang benar juga tidak benar. Jeda GC itu bounded dan monotonic clock juga berfungsi, jadi itu asumsi yang dapat diterima.
Mengkritik mekanisme pelepasan otomatis itu sendiri karena membuka potensi race condition berbeda dengan mengkritik di dalam tujuan algoritma dan model sistemnya.
Redlock telah berhasil dipakai selama bertahun-tahun dalam banyak use case, dan jika timeout dibuat jauh lebih besar daripada waktu penyelesaian pekerjaan serta jeda arbitrer yang bisa terjadi pada sistem operasi umum, sangat sulit untuk memicu race condition.
Tentu saja, kalau timeout pelepasan otomatis dibuat terlalu kecil dan pekerjaan bisa dengan mudah memakan waktu selama itu, itu kesalahan desain, tetapi bukan masalah Redlock itu sendiri.
Jika timeout cukup pendek (misalnya 1–2 detik), pekerjaan biasanya memakai sekitar 90% dari timeout itu, dan pekerjaan yang dilakukan saat memegang lock RedLock sama sekali tidak boleh berjalan bersamaan dengan pemegang lock lain, apakah Anda akan memakai RedLock?
Menurut saya jawaban yang benar di sini selalu “tidak”. Karena risiko lease kedaluwarsa sebelum klien selesai bekerja sangat besar.
Karena RedLock tidak bisa menjamin mutual exclusion dalam semua situasi, pekerjaan harus diubah menjadi idempoten, dan tipe seperti ini lebih baik diimplementasikan dengan optimistic locking.
Saya sedang memperkuat kembali pengetahuan level rendah dan algoritma; buku bagus untuk topik ini apa? Saya sudah punya buku yang ditulis penulisnya.
Saya ingin membuat sesuatu untuk bersenang-senang, tetapi materi yang ada hanya level mainan atau terlalu kompleks.
Pilih satu topik lalu coba implementasikan sungguhan.
Dulu saya menulis artikel blog tentang distributed lock berdasarkan materi ini: https://medium.com/sahibinden-technology/an-easy-integration...
Penjelasan “lock punya timeout (artinya lease)” terdengar aneh.
Pertama, jika klien crash, bahkan tanpa timed lease pun OS atau supervisor seharusnya melepaskan lock, dan kalau keduanya mati pun koneksi akhirnya terputus; sistem jaringan seharusnya mendeteksinya lewat reset, timeout, tidak adanya heartbeat, dan sebagainya, lalu menginvalidasi koneksi dan melepas lock.
Kedua, jika masalahnya adalah klien terlalu lama memegang lock tanpa crash karena bug, bukankah semestinya ada supervisor yang mendeteksi itu lalu membunuh klien sebelum melepas lock untuk pihak lain?
Ketiga, jika lock dengan timeout disediakan untuk menangani corner case seperti ini, bukankah program nyata harus diberi tahu melalui exception, signal, termination, atau semacamnya? Dan bukankah harus menunggu verifikasi bahwa program sudah menerima notifikasi sebelum lock dilepas?
Gagasan membiarkan program terus menjalankan alur kontrol normal meski sudah timeout tampak seperti akar masalahnya, tetapi saya tidak mengerti mengapa semua orang melewatinya begitu saja. Apakah saya melewatkan alasan yang jelas?
Pihak yang menginvalidasi lock di sisinya adalah layanan penyimpanan, dan tanpa jaminan tambahan yang tidak disediakan Redlock, klien tidak bisa mendeteksi sendiri masalahnya.
Dalam beberapa kasus paket-paket ini di-drop, dan klien di mesin jarak jauh sudah mati tetapi koneksi terbuka bisa tetap ada di server.
Sebagai tambahan, bukan saya yang menekan downvote.
Saya mengimplementasikan distributed lock dengan Deno KV yang di-host oleh Deno dan Deno Deploy
Secara internal menggunakan FoundationDB, sebuah basis data terdistribusi, dan instance Deno yang berjalan di perangkat lokal terhubung ke Deno KV yang sama untuk memperoleh lock
Dengan PostgreSQL pun bisa bekerja menggunakan
SELECT FOR UPDATE, tetapi basis datanya sendiri bukan terdistribusiPada 2018 kami mengevaluasi Redis untuk kasus penggunaan kami, tetapi akhirnya memilih solusi yang kurang mencolok, dan benar-benar tidak pernah gagal sekalipun
Kasus penggunaannya adalah membagikan tiket beridentitas satu per satu dari sekumpulan tiket terbatas untuk sebuah kampanye, mirip seperti Ticketmaster menetapkan kursi di venue pertunjukan
Saat ada permintaan masuk, kami harus memberikan tiket yang tersedia, menempelkan metadata permintaan ke tiket yang dialokasikan, lalu mengecualikannya dari target permintaan berikutnya
Akurasi adalah hal utama karena di masa lalu ada kampanye yang gagal seperti alokasi berlebih, alokasi kurang, dan alokasi ganda
Kami juga mencoba implementasi sederhana dengan Redis untuk memperoleh lock, memeriksa lock, menjalankan pekerjaan, lalu melepas lock, tetapi saat itu beban operasionalnya terlalu besar bagi kami, dan untungnya kami tidak menempuh jalan itu
Pilihan akhirnya adalah Postgres. “Distributed lock” kami lebih mirip pernyataan
UPDATEgabungan yang memakai fitur bawaan Postgres, mengubah permintaan menjadi semacam operasi himpunan sehingga basis data mengembalikan record sukses atau penanda gagal. Transaksi ACID yang menangSetelah menyelesaikan soal akurasi, kami melihat skala dan performa; kami tidak membutuhkan jutaan permintaan per detik, tetapi punya tolok ukur untuk lonjakan sesaat
Kami mengoptimalkan instance basis data baca/tulis di dalam klaster, menempatkan kampanye yang lebih besar atau permintaannya tinggi secara strategis pada sistem yang ditentukan, dan terus mengoptimalkan selama 2 tahun, tetapi tidak pernah ada satu pun kampanye distribusi tiket yang gagal
Saya bukan pakar teknologi distributed lock; saya hanya fokus pada masalah yang perlu diselesaikan, mencoba beberapa hal, lalu menemukan solusi yang tepat
Karena transaksi
UPDATEhanya berlangsung beberapa mikrodetik, masalahnya bisa dipusatkan, dan itu lebih sederhana, cepat, serta amanNamun seperti dijelaskan dalam tulisan tersebut, ini bukan masalah terdistribusi
Lock dalam sistem terdistribusi berbeda dari mutex pada aplikasi multi-thread; ini lebih rumit karena banyak node dan jaringan bisa gagal secara independen dengan berbagai cara
Distributed lock diperlukan ketika transaksi bisa memakan waktu dari beberapa detik hingga beberapa jam, dan mesin terkait bisa gagal saat sedang memegang lock
Dalam kasus ini constraint-nya adalah “jangan jual lebih dari N tiket”, dan sebagian besar skala trafik realistis untuk masalah seperti ini bisa diselesaikan dengan perilaku transaksi basis data relasional tradisional, sementara pengelolaan lock internal diserahkan ke basis data
Saya berharap developer tidak terlalu cepat melompat ke “mari membuat distributed lock”. Hampir selalu ada jawaban yang lebih baik, tetapi jawaban itu berbeda-beda untuk tiap aplikasi
Mungkin cocok untuk sesuatu seperti SQLite baru dari Cloudflare
Tempat pertama kali saya membaca hal ini adalah di sini: https://code.flickr.net/2010/02/08/ticket-servers-distribute...
Banyak engineer tidak sungguh-sungguh peduli pada masalah correctness sampai sudah terlambat. Mirip dengan keamanan
Bahkan ketika peduli, banyak yang tidak memverifikasi apakah yang mereka lakukan sudah benar
Misalnya di bidang saya, microservice, actor, dan proses saling mengirim pesan lewat jaringan, dan lebih dari 95% implementasi yang saya lihat memiliki edge case di mana pesan bisa hilang atau diproses dengan urutan yang berubah
Namun insentif tidak cukup selaras untuk memperbaiki masalah ini. Struktur kompensasi eksekutif dan engineer tidak selaras dengan hasil terbaik bagi pelanggan dan pemegang saham
Orang ingin memasang batas jaringan di antara pemanggilan fungsi tanpa alasan kuat, lalu tanpa henti membuat server dan client HTTP, serialisasi dan deserialisasi JSON untuk pemanggilan fungsi itu, memakai gRPC kalau beruntung, dan mencoba mengimplementasikan ulang hal-hal seperti transaksi terdistribusi di seberang batas jaringan tersebut
Pada akhirnya yang muncul hanyalah pekerjaan sibuk untuk menangani “interaksi menyeramkan dari jarak jauh” yang tak terhindarkan
Tim produk dan tim engineering harus menyepakatinya, dan jika SLO dilanggar, fokus harus dialihkan ke stabilitas sistem
Sulit meyakinkan semua orang, sehingga dibutuhkan kepemimpinan yang baik
Ketika bug bermunculan, fitur baru lambat atau nyaris tidak ada, dan pelanggan mulai pergi, alasan bahwa kualitas harus dijadikan bagian dari proses menjadi sangat mudah diterima
Pemimpin yang matang bergerak mendahului tahap itu sedini mungkin
[0] https://en.wikipedia.org/wiki/British_Post_Office_scandal
Namun saya tidak melihat cara yang jelas untuk meyakinkan para manajer kemarin agar memberi waktu untuk membangunnya dengan benar
Ini membuat pekerjaan menjadi terlalu rumit
Jika ada sesuatu seperti fencing token yang dibahas dalam tulisan itu, lock tidak diperlukan
Token tidak harus meningkat secara monoton; cukup berupa nilai unik pasif yang dimiliki bersama oleh klien dan penyimpanan
Jika disebut token versi, nilainya boleh meningkat secara monoton, dan UUID yang biasanya lebih mudah dibuat juga berfungsi. Secara teknis hash dari seluruh data di penyimpanan juga memungkinkan, tetapi tidak praktis
Alurnya seperti ini. Klien mengambil token versi saat ini beserta data yang akan diubah dari penyimpanan, dan penyimpanan membaca data dan token secara atomik untuk menjamin bahwa token itu milik versi data tersebut
Setelah itu klien mengirim kembali token versi bersama perubahan, dan penyimpanan hanya menerima perubahan jika token saat ini cocok dengan token yang dikirim, lalu membuat token versi baru secara atomik
Lock bisa saja diperkenalkan karena alasan lain, tetapi dalam sistem terdistribusi ia harus independen dari integritas penyimpanan
Saya juga kurang suka istilah “lock”. Karena sifatnya sementara dan tidak terjamin, lease atau reservasi mungkin lebih tepat menyampaikan maknanya
Ini adalah cara memindahkan kompleksitas ke sisi database, tetapi perlu diingat bahwa di sini konteksnya adalah lock terdistribusi
Jika hanya satu database, semuanya sederhana sampai database crash dan kita tidak tahu penulisan CAS mana yang benar-benar diterapkan
Pada sistem besar yang membutuhkan ketersediaan tinggi dan backup multi-datacenter, skenario seputar kegagalan node membuat pendekatan ini juga bisa rusak dan menjadi cukup kompleks
Biasanya digunakan log transaksi berbentuk Paxos. Jangan berasumsi ada solusi mudah untuk sistem terdistribusi. Selalu merepotkan
Dari sudut pandang efisiensi, memegang lock dapat menghindari pengerjaan tugas yang sama dua kali secara tidak perlu. Misalnya komputasi yang mahal
Jika lock gagal dan dua node mengerjakan tugas yang sama, dampaknya mungkin sepele bila hanya berupa sedikit kenaikan biaya atau duplikasi notifikasi email yang sama
Namun menurut saya, beberapa node mengerjakan tugas yang sama bisa jauh lebih buruk daripada contoh yang disebutkan. Karena itu dapat menghambat pemrosesan terdistribusi yang scalable itu sendiri
Misalkan sistem penyimpanan memiliki dua node, dan ada dua proses baca-ubah-tulis yang berjalan. Proses 1 dan 2 sama-sama mendapatkan token awal
abcProses 1 melakukan commit sehingga token berubah menjadi
cde, dan perubahan itu di-stream ke node 2, tetapi karena latensi jaringan, perubahan tersebut terlambat tiba di node 2Sementara itu, jika proses 2 melakukan commit ke node 2 dengan token
abc, node 2 belum menerima pesan dari node 1, sehingga ia menerima perubahan tersebut dan sistem menjadi tidak konsistenDengan fencing token yang meningkat secara monoton, hal seperti ini tidak terjadi. Sebab persyaratan itu memaksa node-node menyepakati urutan keseluruhan operasi sebelum memberikan token