Fencing Token Menghentikan Pemegang Lease yang Sudah Stale

Distributed lease memberi satu worker izin sementara untuk bertindak sebagai owner. Lease akhirnya kedaluwarsa agar worker lain dapat mengambil alih setelah crash atau gangguan jaringan. Mekanisme itu menjaga availability, tetapi expiry saja tidak menjamin worker lama sudah berhenti.

Sebuah process dapat pause cukup lama hingga lease kedaluwarsa, lalu kembali berjalan dengan local state yang sudah stale. Garbage-collection pause yang panjang, scheduler stall, virtual machine yang disuspend, atau network path yang tertunda dapat menciptakan kondisi ini. Jika worker lama melakukan write setelah pengganti mengambil ownership, dua worker dapat memengaruhi resource yang sama meskipun lease service tidak pernah menganggap kedua lease valid pada saat yang sama.

Fencing token menutup celah tersebut dengan membuat urutan ownership terlihat oleh resource yang menerima write.

Lease expiry tidak dapat mencabut process yang sedang pause

Bayangkan worker A memegang lease:

waktu ---->

A: acquire lease 41 ---- pause ---------------------- resume -> write
                         |
                         | lease expires
                         v
B:                    acquire lease 42 -> write

Worker A tidak menerima stop signal secara ajaib ketika lease 41 kedaluwarsa. Selama pause, process mungkin tidak menjalankan code, menerima message, atau memeriksa deadline. Ketika kembali berjalan, memory-nya masih dapat menyatakan bahwa ia memiliki job.

Memeriksa lease tepat sebelum write mempersempit race, tetapi tidak menghapusnya. Process dapat pause setelah pemeriksaan dan sebelum protected operation mencapai storage.

Karena itu, keputusan correctness tidak dapat berada hanya di worker.

Setiap ownership grant mendapat token yang lebih besar

Fencing token adalah angka monotonically increasing yang terkait dengan ownership grant yang berhasil. Owner berikutnya menerima token yang lebih besar daripada semua owner sebelumnya untuk protected scope yang sama.

worker A -> lease granted, token 41
worker B -> later lease granted, token 42
worker C -> later lease granted, token 43

Setiap write membawa token. Protected resource menyimpan token tertinggi yang pernah diterima dan menolak operasi dengan token yang lebih lama.

WRITE resource=X token=42  -> accept
WRITE resource=X token=41  -> reject as stale

Resource tidak perlu mengetahui apakah worker A masih hidup. Resource hanya perlu membandingkan ownership epoch.

Token harus berasal dari sumber yang dapat memberikan ordering yang diperlukan. UUID acak berguna sebagai unique identifier, tetapi tidak menyediakan relasi greater-than untuk fencing.

Enforcement berada di protected resource

Membuat token tanpa memeriksanya pada write boundary tidak menghasilkan fencing. Database, storage service, coordinator, atau authoritative component lain harus menolak token stale.

Relational table dapat menyimpan epoch terbaru yang diterima:

UPDATE jobs
SET output = :output,
    fence_token = :token
WHERE job_id = :job_id
  AND fence_token < :token;

Application kemudian memeriksa bahwa tepat satu row diperbarui. Token stale memengaruhi nol row.

Pada resource yang mendukung conditional write, aturan yang sama dapat dinyatakan melalui version field atau compare-and-set operation. Properti pentingnya adalah comparison dan mutation yang atomik. Read terpisah yang diikuti unconditional write menciptakan race kembali.

Jika final destination tidak dapat menegakkan urutan token, component lain mungkin perlu menjadi mediator akses. Mediator tersebut menjadi bagian dari correctness boundary dan harus menyediakan durable ordering serta atomic enforcement.

Token dan lease menyelesaikan bagian masalah yang berbeda

Lease mengatur liveness: ownership dapat berpindah ketika holder saat ini berhenti melakukan renewal. Fencing token mengatur safety pada resource: owner sebelumnya tidak dapat menimpa pekerjaan owner yang lebih baru setelah takeover.

Menggunakan fencing token saja tanpa lease tidak menentukan kapan worker lain boleh mengambil alih. Menggunakan lease saja tidak menghentikan delayed operation dari holder yang sudah expired.

Jika digabungkan, flow menjadi:

1. acquire lease -> token 57
2. perform work
3. write with token 57
4. renew lease while active

after expiry:
5. replacement acquires lease -> token 58
6. resource accepts token 58
7. delayed token 57 is rejected

Worker tetap perlu berhenti ketika renewal gagal. Fencing adalah safety boundary terakhir, bukan alasan untuk terus mengirim operasi yang sudah diketahui stale.

Scope token harus sama dengan scope ownership

Satu global counter sederhana, tetapi dapat menciptakan contention yang tidak diperlukan. Banyak sistem hanya memerlukan ordering dalam satu resource, shard, tenant, atau job.

Jika worker memiliki job-A dan job-B secara independen, token keduanya tidak memerlukan ordering yang bermakna lintas job. Sequence per resource dapat mempertahankan properti yang dibutuhkan dengan koordinasi lebih sedikit.

Resource harus membandingkan token dalam scope yang sama dengan lease service. Mencampur scope dapat menolak write yang valid atau menerima write stale.

Persistensi token juga penting saat coordinator restart. Menerbitkan token yang lebih kecil setelah kehilangan counter state dapat membuat stale holder terlihat lebih baru daripada owner fresh. Sequence karena itu memerlukan durability atau konstruksi lain yang mempertahankan monotonic ownership epoch melewati failover.

Side effect di luar fenced store tetap terpisah

Fenced database update tidak otomatis melakukan fencing terhadap email, payment provider call, filesystem write, atau external API arbitrer. Token hanya melindungi boundary yang memvalidasinya.

Misalnya, worker mengirim remote command lalu mencatat completion di fenced table. Worker stale masih dapat mencapai remote service sebelum database update-nya ditolak. Jika remote effect tersebut juga harus menolak stale owner, remote service memerlukan idempotency, fencing, atau coordination mechanism lain yang kompatibel.

Batas ini perlu membentuk workflow. Sering kali lebih aman melakukan commit terhadap fenced state transition terlebih dahulu lalu menyerahkan external work ke durable mechanism yang dirancang untuk retry, daripada menganggap satu fenced row melindungi setiap downstream effect.

Pekerjaan panjang memerlukan renewal tanpa bergantung pada renewal saja

Lease duration perlu menoleransi variasi scheduling dan jaringan yang normal sambil tetap memungkinkan takeover tepat waktu. Lease yang terlalu pendek meningkatkan false expiry saat pause biasa. Lease yang terlalu panjang memperlambat recovery setelah failure nyata.

Worker biasanya melakukan renewal sebelum deadline dan berhenti memulai pekerjaan baru setelah renewal gagal. Operation yang sudah in flight tetap menjadi kasus sulit, dan pada titik itulah fencing berperan.

Asumsi clock juga perlu diperhatikan. Centralized lease service dapat menentukan expiry menggunakan time base miliknya sendiri daripada mempercayai client clock. Fencing sequence kemudian menyediakan ownership order yang tidak bergantung pada wall-clock timestamp.

Metric perlu memperlihatkan aktivitas stale

Telemetry yang berguna mencakup lease acquisition rate, renewal failure, takeover count, token allocation, stale-write rejection count, dan umur active lease.

Stale-write rejection bukan sekadar noise. Signal itu membuktikan owner lama mencoba melakukan operasi setelah epoch yang lebih baru sudah ada. Rejection sesekali dapat menjadi konsekuensi failover yang wajar, sedangkan rate yang terus tinggi dapat menandakan process pause, network delay, worker overload, atau lease duration yang terlalu agresif.

Log sebaiknya memuat resource scope, presented token, accepted token, dan operation identity tanpa mengekspos sensitive payload. Field tersebut membuat ownership transition dapat ditelusuri saat incident analysis.

Fencing memindahkan authority ke write boundary

Failure utamanya bukan dua lease overlap di coordinator. Masalahnya adalah holder lama dapat terus bertindak setelah authority-nya kedaluwarsa. Lease service tidak dapat menghapus stale state dari process yang sedang pause.

Fencing token membuat ownership yang lebih baru mengalahkan ownership lama pada tempat state berubah. Lease kemudian menangani takeover untuk liveness, sementara protected resource menolak delayed work untuk safety. Kombinasi ini mengubah konsep current ownership yang bersifat advisory menjadi ordering rule yang dapat ditegakkan.