Fencing Token Memblokir Pemegang Lock Lama di Resource

Lease terdistribusi dapat berakhir saat pemegangnya masih berjalan. Proses bisa berhenti sementara karena garbage collection, kehilangan kontak dengan coordinator, tertahan scheduler, atau aktif kembali setelah mesin mengalami suspend. Lock service dapat memberikan lease kepada worker lain secara sah sementara worker lama masih memiliki pekerjaan yang belum selesai.

Celah ini menjadi penting ketika kedua worker masih dapat mencapai resource yang dilindungi. Lease mengatur kepemilikan di coordinator; lease tidak otomatis mencabut koneksi database, request storage, atau RPC tertunda yang disiapkan pemegang sebelumnya.

Fencing token menutup celah tersebut ketika resource dapat menerapkan generasi kepemilikan yang berurutan. Setiap acquisition yang berhasil menerima token yang lebih baru daripada acquisition sebelumnya dalam conflict domain yang sama. Setiap mutation membawa token itu, lalu resource menolak operasi dari generasi yang lebih lama daripada generasi yang sudah diterimanya.

Lease yang berakhir dapat meninggalkan pemegang lama yang masih aktif

Bayangkan worker memperoleh lease untuk sebuah report:

t0   worker A memperoleh lease, token 41
t1   worker A berhenti sementara
t2   lease 41 berakhir
t3   worker B memperoleh lease, token 42
t4   worker B menulis report dengan token 42
t5   worker A aktif kembali dan mencoba menulis dengan token 41

Coordinator tetap konsisten: pada setiap titik hanya ada satu lease yang belum kedaluwarsa. Masalah muncul pada t5. Worker A tidak dapat membatalkan secara retroaktif pekerjaan yang sudah disiapkan sebelum atau selama jeda, dan pemeriksaan kepemilikan di sisi client tidak cukup. Proses dapat menjadi stale tepat setelah pemeriksaan tersebut.

Resource yang dilindungi karena itu membutuhkan informasi yang membedakan owner lama dari owner yang lebih baru.

Token mengurutkan generasi kepemilikan

Fencing token adalah nilai berurutan yang melekat pada grant lock. Jika worker A menerima 41, owner berikutnya yang berkonflik harus menerima nilai lebih besar dari 41, misalnya 42.

Resource menyimpan generasi terbaru yang sudah diterima. Request tertunda dengan token lebih lama kemudian dapat ditolak:

write(token=42) -> terima; terbaru = 42
write(token=41) -> tolak; 41 sudah stale

Identifier lock acak tidak memiliki properti ini. Nilai acak dapat membedakan acquisition, tetapi resource tidak dapat menentukan acquisition mana yang lebih baru. Timestamp wall clock juga bukan pengganti yang baik ketika correctness bergantung pada kesepakatan clock. Urutan harus berasal dari mekanisme yang mempertahankan monotonicity yang diperlukan saat failover maupun acquisition concurrent.

Scope token hanya perlu mencakup owner yang dapat berkonflik pada resource yang sama. Sequence global memadai, sedangkan epoch per-resource dapat mengurangi ordering yang tidak berkaitan jika persistence dan allocation-nya tetap aman.

Enforcement harus berada di dekat mutation

Meneruskan token melalui aplikasi saja belum cukup. Authority terakhir atas state yang dilindungi harus membandingkan token dan menerapkan mutation dalam satu atomic boundary.

Tabel relasional dapat menyimpan generasi yang diterima bersama row yang dilindungi:

UPDATE reports
SET body = :body,
    fence = :token
WHERE report_id = :report_id
  AND fence < :token;

Jika statement tidak mengubah row karena fence sudah lebih besar, caller sudah stale. Predicate yang tepat bergantung pada command model. Ketika satu generasi kepemilikan boleh mengirim beberapa mutation yang sah, token yang sama dapat membutuhkan command sequence, optimistic version, atau aturan idempotency terpisah alih-alih penolakan menyeluruh.

Read terpisah yang diikuti update tanpa syarat lebih lemah:

SELECT fence
-- owner lain menulis di sini
UPDATE reports ...

Pemeriksaan kepemilikan dan perubahan state dapat mengalami race. Fencing efektif hanya jika resource membuat admission dan mutation tidak dapat dipisahkan untuk state terkait.

Token yang lebih baru harus mencapai resource untuk membentuk fence

Urutan token tidak membuat pekerjaan lama lenyap tepat saat lease berakhir. Misalkan worker A memiliki token 41, lease-nya berakhir, lalu worker B menerima 42. Jika request A mencapai resource yang belum pernah melihat 42, resource tidak dapat menyimpulkan hanya dari token 41 bahwa lease yang lebih baru sudah ada.

Fence mulai efektif pada resource tersebut ketika generasi yang lebih baru dibentuk di sana. Sistem yang perlu memblokir pemegang lama sebelum pekerjaan berguna dimulai dapat meminta owner baru lebih dulu memublikasikan atau membentuk generasinya secara conditional pada resource.

Perbedaan ini menjaga jaminan tetap presisi: fencing mengurutkan effect yang diterima. Mekanisme ini tidak menyinkronkan setiap resource dengan clock lease milik coordinator.

Token harus melewati seluruh protected write path

Lock service dapat menerbitkan token yang sempurna tetapi tetap tidak memberi perlindungan jika komponen perantara membuangnya. Generasi kepemilikan harus menyertai setiap mutation yang ordering-nya bergantung pada lease.

Pada database, bentuknya dapat berupa column dan conditional update. Pada storage gateway, bentuknya dapat berupa metadata generasi persisten yang diperiksa sebelum write diteruskan. Pada internal RPC, service penerima mungkin perlu membawa generasi lebih jauh ke downstream hingga mencapai transisi state yang perlu dilindungi.

Side effect di luar boundary tersebut tetap berada di luar fence. Email provider, payment API, printer, atau third-party service yang tidak dapat memvalidasi generasi tidak akan menolak caller stale hanya karena caller itu pernah memegang fenced lease. Effect seperti ini membutuhkan kontrol sendiri, sering kali berupa operation identifier stabil, idempotency, transactional handoff, atau reconciliation.

Allocation token merupakan bagian dari safety property

Allocator tidak boleh menerbitkan token yang bergerak mundur relatif terhadap grant kepemilikan yang saling berkonflik. Counter lokal di dalam proses yang kembali ke nilai awal setelah restart karena itu tidak cocok kecuali mekanisme durable lain menjaga ordering-nya.

Coordinator berbasis consensus dapat menyediakan revision atau sequence berurutan yang berguna untuk peran ini, tetapi semantik API yang tepat tetap penting. Sebuah nilai cocok hanya jika ordering-nya sesuai dengan generasi kepemilikan yang hendak dipagari dan tetap valid melewati pergantian leader serta recovery.

Gap tidak menjadi masalah. Token 41, 57, dan 900 tetap dapat membentuk urutan. Uniqueness saja belum cukup; resource membutuhkan relasi andal yang menunjukkan generasi mana yang lebih baru.

Fencing melengkapi lease, bukan menggantikannya

Lease tetap memiliki fungsi operasional. Coordinator dapat berhenti menganggap holder yang tidak dapat dijangkau sebagai current owner dan memberi worker lain kesempatan melanjutkan pekerjaan tanpa menunggu selamanya.

Fencing menangani failure mode yang berbeda: pekerjaan dari holder lama dapat tiba setelah ownership berpindah. Lease mengatur siapa yang saat ini diakui coordinator. Fence mengatur generasi kepemilikan mana yang masih diterima resource.

Pemisahan ini berguna saat menganalisis insiden. Penolakan stale write tidak selalu berarti lock service gagal. Kondisi tersebut dapat menunjukkan bahwa lock service sudah memajukan ownership dengan benar sementara pekerjaan tertunda dari generasi sebelumnya masih berada dalam perjalanan.

Observability perlu menampilkan pergantian generasi dan penolakan

Telemetry yang berguna mencakup resource key, fencing token, acquisition generation, hasil conditional write, dan jumlah stale rejection. Log perlu membedakan contention biasa dari request yang ditolak karena generasinya sudah obsolete.

Stale write yang berulang dapat mengarah pada process pause yang panjang, network partition, durasi lease yang terlalu pendek dibanding waktu kerja, atau kode yang terus berjalan setelah renewal gagal. Sinyal tersebut berbeda secara operasional dari lock contention biasa.

Token tidak boleh berubah menjadi authorization credential. Authentication dan authorization tetap berlaku secara independen, dan mengetahui token yang lebih tinggi tidak boleh memberi caller izin untuk mengubah resource.

Resource adalah boundary terakhir

Distributed lock tidak dapat memaksa proses yang berhenti sementara untuk tidak melanjutkan eksekusi. Lock hanya dapat mengubah pandangan coordinator tentang ownership. Fencing membuat perubahan ownership itu dapat diterapkan pada resource dengan memberi grant yang lebih baru sebuah generasi berurutan dan menolak generasi lama setelah fence bergerak maju.

Pola ini paling kuat ketika allocation token memiliki ordering durable, token bertahan melewati setiap hop, dan validasi berlangsung atomic bersama mutation yang dilindungi. Jika destination tidak dapat berpartisipasi, desain membutuhkan mekanisme safety lain untuk side effect tersebut, bukan memperlakukan lease ownership sebagai primitive pencabutan.

References