Saat ini dalam pengujian: kode GitHub akan dibuka setelah selesai.

Apa itu Ticketing?

Ticketing adalah server lock khusus yang dirancang hanya untuk satu hal: distributed lock. Terdiri dari satu binary server yang ditulis dalam Rust, dan klien resmi per bahasa yang mengimplementasikan protokol biner yang sama persis hingga level byte. Hanya ada dua operasi — acquire (perolehan) dan release (pelepasan) — antrean FIFO per key, fencing token, dan cluster Raft yang bisa diaktifkan saat dibutuhkan. Semua yang diperlukan untuk distributed lock ada, sisanya dibuang.

Apa bedanya dengan lock berbasis storage

Distributed lock di dunia nyata biasanya memanfaatkan storage key-value. Skrip Lua atau Redlock dipasang di atas Redis, atau lock diimplementasikan di atas session/lease milik ZooKeeper atau etcd. Redis adalah storage yang hebat, tetapi karena distributed lock diimplementasikan di atas storage key-value serba guna — bukan sistem distributed lock khusus — muncul keterbatasan struktural. Biaya parsing protokol serba guna dan overhead struktur data serba guna selalu menyertainya.

Ticketing dirancang sejak awal khusus untuk distributed lock, sehingga setiap lapisannya dibangun berdasarkan kebutuhan lock.

  • Protokol — bukan teks, juga bukan serialisasi serba guna, melainkan field biner berlebar tetap. Dibaca langsung dari offset tanpa parsing, dan mendukung pipelining yang mengirim request berikutnya tanpa menunggu respons.
  • Internal server — antrean FIFO per key dan timer lease adalah keseluruhan state-nya. Bahkan tidak ada alokasi heap di jalur pemrosesan request.
  • Operasional — cukup jalankan satu binary server (atau container) dan atur lewat beberapa environment variable. Tidak perlu merancang skema, tidak perlu storage terpisah, tidak perlu pengetahuan operasional untuk fitur yang tidak berkaitan dengan lock.

Performa

  • Menangani lebih dari 1 juta request/detik, dengan penggunaan memori di bawah 10MB
Perbandingan kecepatan dengan Redisson (Redis), sistem distributed lock yang paling banyak digunakan.
Klien TicketingRedis (Redisson RLock)
JavaScript
210.2 ms · 190,295 ops/s
210.2 ms
Rust
225.9 ms · 177,069 ops/s
225.9 ms
Go
228.4 ms · 175,131 ops/s
228.4 ms
C#
286.9 ms · 139,421 ops/s
286.9 ms
Kotlin
443.5 ms · 90,192 ops/s
443.5 ms
Java
457.8 ms · 87,374 ops/s
457.8 ms
C/C++
659.7 ms · 60,634 ops/s
659.7 ms
Python
739.4 ms · 54,098 ops/s
739.4 ms
Ruby
1,682.4 ms · 23,776 ops/s
1,682.4 ms
Redisdasar
4,909.1 ms · 8,148 ops/s
4,909.1 ms
Panjang batang adalah waktu total (md) untuk seluruh proses — makin pendek makin cepat.
32 contended keys × 1,250 ops · concurrency 64 · mac mini m4 2024 basic (10 core), single local server, acknowledged release, 1s min-work budget

Mengapa Ticketing

🚦 Integritas urutan — antrean FIFO dan handoff langsung

Yang lebih dulu menunggu, lebih dulu mendapatkannya. Saat pemegang lock melepaskannya, lock diserahkan langsung ke antrean terdepan tanpa perebutan ulang. Tidak ada starvation akibat polling dan retry yang saling memperebutkan lock, dan tidak ada lonjakan retry.

🛟 Klien mati pun tidak akan membuat lock terkunci selamanya — lease

Jika proses yang memegang lock mati atau koneksi jaringan terputus, server akan otomatis mengambil kembali lock setelah durasi lease yang ditentukan saat acquire berlalu, lalu menyerahkannya ke antrean berikutnya. Lupa melakukan release pun tidak akan menghentikan seluruh sistem.

🔑 Mencegah urutan kerja yang salah — fencing token

Ada satu kecelakaan yang tidak bisa dicegah hanya dengan lock: klien yang bangun terlambat tanpa menyadari lease-nya sudah kedaluwarsa, lalu tetap meminta penyelesaian pekerjaan. Ticketing menerbitkan fencing token yang selalu bertambah (monotonic) di setiap acquire. Selama resource yang dilindungi hanya menegakkan satu aturan — "tolak token yang lebih rendah" — celah terakhir ini pun tertutup. Prinsip detailnya dijelaskan di Cara Kerja.

🗳️ Cluster tanpa henti berbasis Raft

Satu server saja sudah cukup untuk beroperasi, tetapi jika dibutuhkan layanan tanpa henti, Anda bisa membentuk cluster dengan 3 (atau 5) server. Setiap perubahan status lock hanya final setelah melewati konsensus mayoritas node (Raft), sehingga meski leader mati atau jaringan terpartisi, lock yang sama tidak akan pernah diterbitkan di dua tempat sekaligus. Jika leader gagal, leader baru terpilih dalam waktu sekitar 1 detik, dan klien berpindah secara otomatis. Layanan tetap berjalan bahkan saat node turun satu per satu — misalnya saat reboot instance cloud atau pemeliharaan bergilir.

🔒 Autentikasi dan TLS bawaan

Setiap koneksi melewati autentikasi token challenge-response segera setelah terhubung, dan token tidak pernah dikirim dalam bentuk plaintext di atas wire. Bila perlu, seluruh koneksi bisa dienkripsi penuh dengan TLS.

🌐 Bahasa utama, protokol yang sama hingga level byte

Rust, Java/Kotlin, JavaScript/TypeScript, Python, C#, Go, Ruby, C/C++ — klien resmi mengimplementasikan protokol biner yang sama, dan masing-masing menyediakan API (async atau blocking) yang alami untuk ekosistem bahasanya. Lock yang diperoleh dari bahasa mana pun akan antre secara adil di antrean yang sama dengan klien bahasa lain. Cara instalasi dan contohnya bisa dilihat di Libraries.

Hanya ada dua API

Sebagai server khusus lock, permukaan API-nya pun minimal.

  1. Tempelkan key pada resource yang ingin dilindungi. Contoh: order-1234, account-77, daily-batch.
  2. Acquire key tersebut sebelum mulai bekerja — jika sedang dipakai, Anda menunggu giliran di antrean FIFO.
  3. Release setelah pekerjaan selesai — antrean berikutnya langsung melanjutkan tanpa perebutan ulang.

Kedua operasi ini hanya dilengkapi opsi lease (pengambilan otomatis) dan waitTimeout (pembatalan tunggu) — itulah keseluruhan API-nya.

Bacaan selanjutnya