Arsitektur Advanced OpenZFS 2.2+ Enterprise Storage, DRBD9 Synchronous Block Replication, dan KVM/VFIO Hyper-Converged Clustering
๐๏ธ ADVANCED OPENZFS 2.2+ ENTERPRISE STORAGE, DRBD9 SYNCHRONOUS BLOCK REPLICATION & KVM/VFIO HYPER-CONVERGED CLUSTERING
[Riset Mandiri ๐ค] โ Dokumen kurasi dan riset mandiri tingkat DEEP-DIVE & EXHAUSTIVE oleh La Nina.
Pilar: Cloud/Infrastructure & Hyper-Converged Virtualization
Target: Enterprise Tier-1 Mission-Critical Virtualization, Low-Latency Database Storage & High-Availability HCI Clusters
Catatan Implementasi Data Sintetis:
Seluruh diagram topologi, parameter jaringan, skrip otomasi, dan konfigurasi kluster dalam artikel ini disajikan menggunakan data sintetis sesuai standar RFC 5737 (192.0.2.0/24TEST-NET-1 untuk Node Interconnect & Host Management,198.51.100.0/24TEST-NET-2 untuk Dedicated DRBD9 Storage Replication Mesh, serta203.0.113.0/24TEST-NET-3 untuk Corosync Redundant Ring & IPMI/BMC STONITH Fencing Network).
DAFTAR ISI
- Analisis Arsitektur Mendalam & Low-Level Mechanics
- 1.1 OpenZFS Storage Engine Internals: SPA, DMU, ZPL, dan Transaksi Copy-on-Write (CoW)
- 1.2 Adaptive Replacement Cache (ARC/L2ARC) & ARC Ghost Lists Eviction Mathematics
- 1.3 ZFS Intent Log (ZIL), Dedicated SLOG (Separate ZIL) & O_DIRECT In-Memory Pipeline
- 1.4 Declustered Parity (dRAID) vs Standard RAID-Z & Block Cloning (
copy_file_range) - 1.5 DRBD9 (Distributed Replicated Block Device) Kernel Engine & Protocol C Synchronous Datapath
- 1.6 Linux KVM / QEMU Virtualization: VMX Transitions, EPT Two-Dimensional Paging & vhost Multiqueue
- 1.7 VFIO / IOMMU Device Isolation, DMA Remapping & NUMA Socket Affinity
- 1.8 Hyper-Converged Consensus: Corosync 3.x Kronosnet Dual-Link & STONITH Hardware Fencing
- Konfigurasi Nyata & Production-Ready Hardening
- 2.1 Enterprise OpenZFS 2.2+ Kernel Module Tuning (
/etc/modprobe.d/zfs.conf) & Pool Settings - 2.2 DRBD9 Multi-Node Dual-Primary Synchronous Mesh Definition (
/etc/drbd.d/r0.res) - 2.3 Hardened KVM/QEMU Domain XML Definition dengan NUMA Pinning & vhost-scsi Multiqueue
- 2.4 Corosync 3.x Dual-Link Kronosnet & Pacemaker STONITH Configuration (
/etc/corosync/corosync.conf) - 2.5 Linux Host Virtualization, Storage I/O & HugePages Sysctl Tuning (
/etc/sysctl.d/75-kvm-zfs-storage.conf)
- 2.1 Enterprise OpenZFS 2.2+ Kernel Module Tuning (
- Script Otomatisasi, Validasi, dan Benchmarking
- 3.1 ZFS Pool, ARC, dan DRBD9 Replication FIO Benchmark Suite (
benchmark-zfs-drbd-storage.sh) - 3.2 Hyper-Converged Infrastructure Health, NUMA & Storage Latency Auditor (
validate-hci-cluster-health.sh) - 3.3 DRBD9 Split-Brain Chaos Injection & Automated Fence-Peer Simulator (
test-drbd-splitbrain-recovery.sh)
- 3.1 ZFS Pool, ARC, dan DRBD9 Replication FIO Benchmark Suite (
- Skenario Troubleshooting Kasus Nyata (Root Cause Analysis & Mitigation)
- 4.1 Kasus 1: ZFS Transaction Group (TXG) Sync Stall & SPA Lock Contention Menyebabkan I/O Freeze pada VM
- 4.2 Kasus 2: DRBD9 Split-Brain Hazard pada Asymmetric Network Flapping Cluster Live-Migration
- 4.3 Kasus 3: KVM Extended Page Table (EPT) Walk Latency & Memory Compaction Stalls pada High-Concurrency VM
- 4.4 Kasus 4: Corosync Token Ring Timeout & Split-Brain Node Eviction Akibat ZFS Scrubbing / Replication Congestion
- Ringkasan Arsitektur & Rekomendasi Best Practices
1. Analisis Arsitektur Mendalam & Low-Level Mechanics
Hyper-Converged Infrastructure (HCI) modern menggabungkan komputasi tervirtualisasi (KVM/QEMU), storage terdistribusi berkinerja tinggi (OpenZFS & DRBD9), serta clustering consensus (Corosync/Pacemaker) ke dalam node fisik yang sama tanpa ketergantungan pada SAN (Storage Area Network) monolitik eksternal. Memahami low-level kernel datapath dari setiap komponen adalah kunci untuk mencapai latensi sub-milidetik dan keandalan $99.999%$ (five-nines).
+---------------------------------------------------------------------------------------------------+
| KVM GUEST VIRTUAL MACHINE |
| +-------------------------------------------------------------------------------------------+ |
| | User Applications / High-Performance DB (PostgreSQL / MySQL / Redis) | |
| +-------------------------------------------------------------------------------------------+ |
| | Guest OS Kernel: Page Cache -> Filesystem (ext4/xfs) -> virtio-blk / virtio-scsi Driver | |
+---+---------------------------------------------+---------------------------------------------+---+
| Guest DMA / I/O Ring Buffer (Split/Packed)
v
+---------------------------------------------------------------------------------------------------+
| KVM / QEMU HYPERVISOR (HOST KERNEL) |
| +-------------------------------------------------------------------------------------------+ |
| | VMX Non-Root Operation | vhost-kernel / virtio-scsi-pci Worker Threads (iothread per vCPU) | |
| | Memory: Guest Physical Address (GPA) --[ EPT / SLAT Walking ]--> Host Physical (HPA) | |
+---+---------------------------------------------+---------------------------------------------+---+
| Raw Block Device I/O (/dev/drbd0)
v
+---------------------------------------------------------------------------------------------------+
| DRBD9 KERNEL SUBSYSTEM (drbd.ko) |
| +---------------------------------------------+---------------------------------------------+ |
| | Activity Log (AL) Ring Buffer (4096 extents)| Quicksync Bitmap Engine (Dirty Bit Tracker) | |
| +---------------------------------------------+---------------------------------------------+ |
| | Protocol C Synchronous Engine: Local Write + In-Flight Network Transmission (TCP/RDMA) | |
+---+---------------------+-------------------------------------------------------+-------------+---+
| Local Storage Write | Network Replication (Mesh)
v v
+---------------------------------------------+ +---------------------------------------------+
| OPENZFS 2.2+ STORAGE ENGINE | | REMOTE PEER NODE (REDUNDANT HCI) |
| +-------------------------------------+ | | +-------------------------------------+ |
| | ZPL (ZFS POSIX Layer) / ZVOL Engine | | | | DRBD9 Receiver Kernel Thread | |
| +-------------------------------------+ | | +-------------------------------------+ |
| | DMU (Data Management Unit) - CoW | | | | OpenZFS 2.2+ ZVOL Local Commit | |
| +-------------------------------------+ | | +-------------------------------------+ |
| | ARC / L2ARC Adaptive Memory Cache | | | | Dedicated NVMe ZIL / SLOG Flush | |
| +-------------------------------------+ | | +-------------------------------------+ |
| | ZIL / SLOG NVMe Intent Log Pipeline | | +---------------------------------------------+
| +-------------------------------------+ |
| | SPA (Storage Pool Allocator) Metaslab| |
| +-------------------------------------+ |
| | VDEV Tree: NVMe / SAS (dRAID / Mirr)| |
+---------------------------------------------+
1.1 OpenZFS Storage Engine Internals: SPA, DMU, ZPL, dan Transaksi Copy-on-Write (CoW)
OpenZFS dibangun di atas arsitektur berlapis yang mengeliminasi konsep sistem file tradisional dengan menyatukan manajemen volume dan filesystem ke dalam satu kesatuan pohon objek transaksional:
[ Application / ZVOL (/dev/zvol/...) ]
|
v
+-----------------------------+
| ZPL (ZFS POSIX Layer) | -> Mengimplementasikan POSIX VFS API (open, read, write, fsync)
+-----------------------------+
|
v
+-----------------------------+
| DMU (Data Management Unit) | -> Abstraksi objek abstrak berindeks (dnode_t), snapshot, kloning
+-----------------------------+
|
v
+-----------------------------+
| ARC (Adaptive Repl. Cache) | -> Cache memori DRAM adaptif (MRU + MFU + Ghost Lists)
+-----------------------------+
|
v
+-----------------------------+
| SPA (Storage Pool Allocator)| -> Alokasi blok fisik pada vdev menggunakan Metaslabs & AVL Trees
+-----------------------------+
|
v
[ Physical VDEVs: NVMe / SSDs / HDDs ]
Transaksional Copy-on-Write (CoW) & Uberblock Ring
Setiap modifikasi data pada ZFS tidak pernah menimpa blok yang ada (in-place overwrite dilarang secara desain). Sebaliknya:
- Blok data baru ditulis ke lokasi disk yang belum teralokasi (free space yang dipilih oleh SPA).
- Pointer ke blok tersebut di dalam parent indirect block diperbarui untuk menunjuk ke alamat fisik baru (
DVA- Data Virtual Address). - Pembaruan merambat ke atas pohon objek (Merkle Tree) hingga mencapai MOS (Meta Object Set).
- Transaksi ditutup pada tingkat global dengan penulisan atomik sebuah Uberblock. ZFS mengelola 128 array Uberblock melingkar pada setiap leaf vdev. Uberblock dengan Transaction Group (
TXG) number tertinggi yang memiliki checksum SHA-256/fletcher4 valid adalah titik root dari konsistensi seluruh pool (self-consistent world state).
Struktur blok pointer ZFS (blkptr_t) berukuran 128 byte dan menyimpan metadata kritis:
typedef struct blkptr {
dva_t blk_dva[3]; /* Hingga 3 Data Virtual Addresses (multi-copy redundancy) */
uint64_t blk_prop; /* Enkripsi, kompresi (ZSTD/LZ4), checksum type, object type */
uint64_t blk_pad[2];
uint64_t blk_birth; /* TXG ID saat blok ini diciptakan */
uint64_t blk_fill; /* Jumlah blok anak non-zero di bawah blok ini */
zio_cksum_t blk_cksum; /* 256-bit cryptographically secure or fletcher checksum */
} blkptr_t;
SPA (Storage Pool Allocator) & Metaslabs
Ruang penyimpanan fisik pada setiap top-level Virtual Device (vdev) dibagi menjadi segmen-segmen besar berukuran seragam (biasanya $512\text{ MB} - 16\text{ GB}$) yang disebut Metaslabs.
- Setiap metaslab mengelola alokasi spasial internalnya menggunakan dua AVL trees (Adelson-Velsky and Landis self-balancing binary search trees):
- By-Size Tree: Mengindeks rentang blok bebas berdasarkan ukuran untuk memfasilitasi algoritma alokasi first-fit atau best-fit secara instan.
- By-Offset Tree: Mengindeks blok bebas berdasarkan offset logis pada disk untuk memfasilitasi penggabungan (coalescing) blok-blok yang berdekatan saat terjadi pelepasan ruang (deallocation).
- Algoritma alokasi OpenZFS mengevaluasi metrik Space-Check dan Weight Calculation. Ketika fragmentasi metaslab melebihi ambang batas tertentu (
zfs_metaslab_fragmentation_threshold = 70%), SPA beralih dari mode alokasi linear ke mode best-fit allocation, yang membutuhkan pencarian pohon AVL lebih dalam dan dapat meningkatkan CPU overhead.
1.2 Adaptive Replacement Cache (ARC/L2ARC) & ARC Ghost Lists Eviction Mathematics
OpenZFS ARC menggantikan algoritma LRU (Least Recently Used) standar dengan algoritma Adaptive Replacement Cache yang dirancang oleh Nimrod Megiddo dan Dharmendra S. Modha (IBM Research), yang dimodifikasi untuk ukuran buffer dinamis bervariasi.
+------------------------------------------------------------------------------------+
| TOTAL DRAM ARC |
| +---------------------------------------+------------------------------------+ |
| | MRU (Most Recently Used) | MFU (Most Frequently Used) | |
| | Halaman data baru dibaca 1 kali | Halaman data dibaca >= 2 kali | |
| | Ukuran target: p | Ukuran target: (c - p) | |
| +-------------------+-------------------+-------------------+----------------+ |
| | | |
+-----------------------+---------------------------------------+--------------------+
| (Eviction ke Ghost) | (Eviction ke Ghost)
v v
+-------------------------------+ +-------------------------------+
| B1 (MRU Ghost List) | | B2 (MFU Ghost List) |
| Hanya menyimpan Header Blok | | Hanya menyimpan Header Blok |
| (Data fisik telah dibuang) | | (Data fisik telah dibuang) |
+-------------------------------+ +-------------------------------+
Mekanika Matematis Tuning Target Size ($p$)
ARC membagi memori aktif menjadi dua daftar utama:
- MRU ($T_1$): Berisi halaman yang baru saja diakses satu kali (menangkap lokalitas temporal).
- MFU ($T_2$): Berisi halaman yang diakses berulang kali (menangkap frekuensi akses).
Selain itu, ARC mengalokasikan memori virtual untuk menyimpan header metadata dari blok yang baru saja dibuang (ghost caches):
- $B_1$ (Ghost MRU): Metadata blok yang dibuang dari $T_1$.
- $B_2$ (Ghost MFU): Metadata blok yang dibuang dari $T_2$.
Variabel target $p \in [0, c]$ merepresentasikan batas alokasi dinamis untuk MRU ($T_1$), di mana $c$ adalah total kapasitas ARC (zfs_arc_max). Ketika cache miss terjadi pada blok $x$:
Kasus 1: Jika header blok $x$ ditemukan di $B_1$ (Ghost MRU), ini membuktikan bahwa cache membutuhkan lebih banyak kapasitas temporal (recency). Parameter $p$ ditingkatkan secara adaptif: $$\Delta p = \begin{cases} 1 & \text{jika } |B_1| \ge |B_2| \ \frac{|B_2|}{|B_1|} & \text{jika } |B_1| < |B_2| \end{cases}$$ $$p \leftarrow \min(p + \Delta p, c)$$
Kasus 2: Jika header blok $x$ ditemukan di $B_2$ (Ghost MFU), ini membuktikan bahwa beban kerja lebih menyukai frekuensi (frequency). Parameter $p$ dikurangi: $$\Delta p = \begin{cases} 1 & \text{jika } |B_2| \ge |B_1| \ \frac{|B_1|}{|B_2|} & \text{jika } |B_2| < |B_1| \end{cases}$$ $$p \leftarrow \max(p - \Delta p, 0)$$
L2ARC (Level 2 ARC) Asynchronous Feed Engine
L2ARC menggunakan fast secondary SSD/NVMe untuk menampung blok data yang dikeluarkan dari DRAM ARC:
- Thread
l2arc_feed_threadsecara periodik memindai ekor daftar $T_1$ dan $T_2$. - Blok yang memenuhi syarat dikompresi (biasanya via LZ4) dan ditulis secara berurutan (sequential striping) ke device L2ARC guna mencegah write amplification pada SSD.
- Header L2ARC di dalam DRAM membutuhkan sekitar $160\text{ byte}$ per blok disk L2ARC ($128\text{ KB}$ blok $\rightarrow \sim 1.25\text{ GB}$ DRAM per $1\text{ TB}$ L2ARC). Sejak OpenZFS 2.2+, header L2ARC dapat dipangkas secara substansial jika mengaktifkan persistent L2ARC.
1.3 ZFS Intent Log (ZIL), Dedicated SLOG (Separate ZIL) & O_DIRECT In-Memory Pipeline
Setiap penulisan sinkron (fsync(), O_SYNC, atau protokol NFS/iSCSI) mengharuskan penyimpanan persisten sebelum mengembalikan status sukses ke aplikasi klien.
Synchronous Write Request (O_SYNC / fsync)
|
+---------------------------------------+
| (Asinkron dalam DRAM) | (Sinkron ke NVMe SLOG)
v v
+---------------------------+ +---------------------------+
| DMU Transaction Open | | ZIL Log Record (itx) |
| Alokasi Memori di DRAM | | Diserialisasi ke SLOG |
+---------------------------+ +---------------------------+
| |
| (Tunggu commit TXG ~5 detik) | (DMA Latensi Rendah < 20ยตs)
v v
+---------------------------+ +---------------------------+
| SPA Metaslab Write | | PLP SSD / Optane Disk |
| Flush ke Main Pool Disk | | Write Confirmed (ACK) |
+---------------------------+ +---------------------------+
| |
+<--------------------------------------+
|
Aplikasi Mendapatkan ACK Return
Alur Transaksi ZIL vs SLOG
- In-Memory Logging (
itx_t): Ketika penulisan sinkron masuk, OpenZFS membuat in-memory intent log transaction (itx). - SLOG Dispatch:
- Jika SLOG (Separate Intent Log) hadir (misal: Intel Optane SSD atau enterprise NVMe dengan Power Loss Protection/PLP), payload blok segera dikirim ke perangkat SLOG sebagai log record ZIL via DMA.
- Jika write berukuran kecil ($\le 64\text{ KB}$, diatur oleh
zfs_immediate_write_sz), blok data ditulis langsung ke dalam stream log ZIL. - Jika write berukuran besar ($> 64\text{ KB}$), ZFS mengalokasikan blok data langsung di main pool menggunakan alokasi CoW biasa, dan hanya pointer alamat (
blkptr_t) yang dicatat ke dalam ZIL record.
- Penyelesaian Transaksi (Return ACK): Begitu blok log ZIL ter-flush ke non-volatile media SLOG (membutuhkan waktu $\sim 10 - 30\ \mu\text{s}$ pada Optane NVMe), syscall
fsync()selesai dan mengembalikan eksekusi ke thread aplikasi. - TXG Commit Reaping: Setiap $\approx 5\text{ detik}$ (diatur oleh
zfs_txg_timeout), threadtxg_syncmemproses seluruh transaksi kotor di DRAM, menghitung checksum, mengalokasikan blok permanen pada vdev utama, menulis Uberblock baru, dan menghapus log record ZIL yang sudah usang (log discard). SLOG tidak pernah dibaca selama operasi normal; SLOG hanya dibaca saat proses Pool Import Recovery pasca-insiden unclean shutdown atau kernel panic.
1.4 Declustered Parity (dRAID) vs Standard RAID-Z & Block Cloning (copy_file_range)
dRAID (Declustered RAID) Architecture
Pada arsitektur RAID-Z tradisional (misal: RAID-Z2 8+2), jika 1 disk berukuran $18\text{ TB}$ mengalami kegagalan, proses resilvering akan membaca 8 disk yang tersisa dan menulis seluruh data rekonstruksi ke 1 disk spare pengganti tunggal. Kecepatan pemulihan dibatasi oleh batas fisik write IOPS/bandwidth dari satu disk spare tersebut, yang memakan waktu 36โ72 jam dan memperlebar window of vulnerability.
OpenZFS dRAID (Declustered RAID) merevolusi ketahanan data dengan mendistribusikan blok paritas, blok data, dan ruang spare secara seragam di seluruh disk fisik dalam pool:
+-----------------------------------------------------------------------------------+
| dRAID2 Array (12 Physical Disks, 8+2 Striping, 1 Virtual Spare) |
+---------+---------+---------+---------+---------+---------+---------+---------+---+
| Disk 0 | Disk 1 | Disk 2 | Disk 3 | Disk 4 | Disk 5 | ... | Disk 11 |
+---------+---------+---------+---------+---------+---------+---------+---------+---+
| D0_blk1 | D1_blk1 | D2_blk1 | P_blk1 | Q_blk1 | S_slot1 | ... | D7_blk1 |
| S_slot2 | D0_blk2 | D1_blk2 | D2_blk2 | P_blk2 | Q_blk2 | ... | D6_blk2 |
| D7_blk3 | S_slot3 | D0_blk3 | D1_blk3 | D2_blk3 | P_blk3 | ... | D5_blk3 |
+---------+---------+---------+---------+---------+---------+---------+---------+---+
- Mekanika Parallel Resilver: Ruang spare (
S_slot) bukan disk fisik yang berdiri sendiri dan menganggur, melainkan celah logis terdistribusi (distributed spare slices) di setiap disk dalam pool. - Ketika Disk 0 gagal, rekonstruksi paritas Reed-Solomon dibaca dari disk 1โ11 secara paralel, dan blok hasil hitungan paritas ditulis ke slot-slot spare yang tersebar di disk 1โ11 secara simultan. Akibatnya, bandwidth penulisan resilver terdistribusi ke seluruh spindle yang aktif, memangkas waktu rekonstruksi dari 48 jam menjadi kurang dari 4 jam.
Block Cloning (copy_file_range) Mechanics (OpenZFS 2.2+)
Sebelum OpenZFS 2.2+, kloning file VM disk (.qcow2 atau .raw) pada dataset yang sama membutuhkan salinan blok penuh atau pembuatan snapshot + dataset klon terpisah.
- Dengan fitur Block Cloning berbasis syscall Linux
copy_file_range(2), OpenZFS memungkinkan kloning file cross-directory pada dataset yang sama tanpa menyalin data byte fisik di disk. - DMU hanya membuat
dnodebaru dan menduplikasiblkptr_tyang menunjuk ke Data Virtual Address (DVA) fisik yang sama, sambil menaikkan reference count pada blok tersebut. Operasi kloning image disk VM berukuran $500\text{ GB}$ selesai dalam tempo $< 100\text{ milidetik}$ dengan penggunaan disk $0\text{ byte}$ tambahan, yang berperilaku persis seperti snapshot pada level individual file.
1.5 DRBD9 (Distributed Replicated Block Device) Kernel Engine & Protocol C Synchronous Datapath
DRBD9 beroperasi pada layer Linux Virtual Block Device (drivers/block/drbd/). DRBD mengekspos perangkat blok virtual (misal: /dev/drbd0) yang berada di atas perangkat penyimpanan lokal (seperti ZVOL OpenZFS /dev/zvol/rpool/data/vm-100-disk-0) dan mereplikasikannya melalui jaringan ke peer node secara transparan.
[ KVM Hypervisor Write to /dev/drbd0 ]
|
v
+----------------------------------+
| DRBD9 Engine (drbd.ko) |
+----------------------------------+
| |
| (1. Submit Local Bio) | (2. Send via TCP/RDMA Socket)
v v
+-------------------+ +-------------------+
| Local Disk ZVOL | | Network Adapter |
| (OpenZFS Backend)| | (10/25/100 GbE) |
+-------------------+ +-------------------+
| | (Transfer wire)
| (3. Local I/O Complete) v
| +-------------------+
| | Remote Node NIC |
| +-------------------+
| |
| v
| +-------------------+
| | Remote drbd_recv |
| +-------------------+
| |
| v
| +-------------------+
| | Remote Disk ZVOL |
| +-------------------+
| |
| v
| +-------------------+
| | (4. Remote Disk |
| | Write Complete) |
| +-------------------+
| |
| (5. Receive Replication ACK) v
+<-------------------------------+
|
[ 6. DRBD Returns I/O Completion to KVM ]
Replikasi Protokol A, B, dan C
- Protocol A (Asynchronous): Penulisan lokal dianggap selesai begitu paket data masuk ke local network socket send buffer. Sangat rentan kehilangan data jika terjadi kegagalan node lokal sebelum paket terkirim.
- Protocol B (Memory-Synchronous): Penulisan lokal selesai setelah paket data diterima di memory buffer remote node (remote TCP stack menerima dan mengirimkan TCP ACK), sebelum remote node melakukan flush ke disk fisik.
- Protocol C (Fully Synchronous - Enterprise Standard): Penulisan lokal ke
/dev/drbd0hanya dianggap selesai setelah:- I/O lokal sukses ditulis ke disk backend lokal.
- Data ditransmisikan melalui jaringan, ditulis ke disk backend remote node, dan remote node mengirimkan paket balik
DP_WRITE_ACK. Hal ini menjamin zero data loss ($RPO = 0$) jika terjadi crash pada salah satu node.
Activity Log (AL) Ring Buffer & Quicksync Bitmaps
Untuk menghindari resinkronisasi seluruh disk pasca-reboot mendadak atau terputusnya link jaringan:
- Activity Log (AL): DRBD membagi disk menjadi extents berukuran $4\text{ MB}$. Sebelum data ditulis ke extent tertentu, nomor extent tersebut dicatat terlebih dahulu ke dalam on-disk metadata ring buffer (Activity Log). Jika crash terjadi, DRBD hanya perlu memindai dan meresinkronisasi extent yang aktif tercatat di dalam AL (maksimal beberapa puluh megabyte, bukan terabyte).
- Quicksync Bitmap: DRBD mengelola bitmap memori di mana setiap 1 bit merepresentasikan 1 blok data ($4\text{ KB}$). Selama koneksi jaringan terputus (Disconnected Mode), penulisan lokal tetap berlangsung pada node Primary, dan setiap blok yang dimodifikasi ditandai sebagai bit
1di bitmap. Begitu link jaringan pulih, engine Quicksync mentransfer hanya blok-blok yang bernilai1ke node Secondary tanpa memindai seluruh sistem file.
1.6 Linux KVM / QEMU Virtualization: VMX Transitions, EPT Two-Dimensional Paging & vhost Multiqueue
KVM memodifikasi Linux kernel menjadi Type-1 Bare-Metal Hypervisor dengan mengeksploitasi instruksi ekstensi CPU Intel VT-x (vmx) atau AMD-V (svm).
+-----------------------------------------------------------------------------------+
| PHYSICAL CPU CORE EXECUTION MODES |
+-----------------------------------------+-----------------------------------------+
| VMX ROOT OPERATION (HOST) | VMX NON-ROOT OPERATION (GUEST) |
+-----------------------------------------+-----------------------------------------+
| - Host Kernel Mode (Ring 0): | - Guest Kernel Mode (Ring 0): |
| Scheduler, KVM Kernel Module (kvm.ko) | Guest Linux OS Drivers & Subsystems |
| - Host User Mode (Ring 3): | - Guest User Mode (Ring 3): |
| QEMU Process Memory Space | Guest User Applications |
+-----------------------------------------+-----------------------------------------+
| ^
| VMLAUNCH / VMRESUME (VM-Entry Execution) |
+---------------------------------------------------+
|
| VM-Exit (Trap via I/O Port, EPT Violation, HLT, CPUID, MMIO)
v
+-----------------------------------------------------------------------------------+
| VMCS (Virtual Machine Control Structure): |
| Guest-State Area, Host-State Area, VM-Execution Controls, VM-Exit Information |
+-----------------------------------------------------------------------------------+
Siklus Hidup VM-Entry dan VM-Exit
- VM-Entry: Host CPU mengeksekusi instruksi
VMLAUNCHatauVMRESUME. CPU memuat status register dari VMCS (Virtual Machine Control Structure) dan beralih ke VMX Non-Root Operation. Di sini, Guest OS mengeksekusi instruksi mesin dengan kecepatan penuh tanpa emulasi software (bare-metal execution). - VM-Exit: Ketika Guest OS mencoba menjalankan instruksi istimewa yang dilarang atau berinteraksi dengan hardware (misal: mengakses kontroler disk virtual, membaca register APIC, atau mengeksekusi instruksi I/O port), CPU secara otomatis membekukan eksekusi guest, menyimpan status guest ke VMCS, beralih kembali ke VMX Root Operation (Host Ring 0), dan menyerahkan kendali ke fungsi
kvm_intel.ko/kvm_amd.ko. - Biaya latensi CPU untuk setiap siklus VM-Exit berkisar antara $500 - 1500\text{ siklus CPU}$. Oleh karena itu, arsitektur modern berfokus pada eliminasi VM-Exit yang tidak perlu menggunakan paravirtualisasi virtio, APICv (Virtual APIC), dan Posted Interrupts.
EPT (Extended Page Tables) Two-Dimensional Paging
Dalam lingkungan virtual, terdapat dua lapisan translasi alamat memori:
- Guest Virtual Address (GVA) $\rightarrow$ Guest Physical Address (GPA): Dikelola oleh Page Table di dalam Guest OS (CR3 register di dalam guest).
- Guest Physical Address (GPA) $\rightarrow$ Host Physical Address (HPA): Dikelola oleh Extended Page Tables (EPT) di dalam KVM Hypervisor (EPTP register di hardware MMU).
Guest Virtual Address (GVA)
|
v (Translasi via Guest Page Table)
Guest Physical Address (GPA)
|
v (Translasi via Hardware EPT Paging Engine)
Host Physical Address (HPA)
|
v
Physical DRAM Cell
Pada skenario terburuk, sebuah TLB miss pada level guest membutuhkan two-dimensional page walk sebanyak hingga 24 kali akses memori ($4 \text{ level guest} \times 4 \text{ level host} + \text{offsets}$). Penggunaan 1 GB Static HugePages pada host secara drastis memangkas kedalaman pohon EPT dari 4 level menjadi 2 level, meningkatkan throughput memori VM hingga $25 - 40%$.
vhost-scsi & virtio-blk Multiqueue Engine
- Emulasi QEMU Klasik: Setiap I/O disk dari guest memicu VM-Exit ke host kernel, lalu dialihkan ke userspace QEMU melalui sinyal UNIX, diproses oleh event loop QEMU, dan ditulis ke disk via blocking write. Latensi sangat tinggi ($> 500\ \mu\text{s}$) dan terhambat oleh Big QEMU Lock (BQL).
- vhost-kernel Architecture: Driver
vhost-scsiatauvhost-blkmemindahkan pemrosesan antrean virtqueue langsung ke dalam Linux kernel space. KVM menyuntikkan I/O langsung ke ring buffer vhost tanpa beralih ke userspace QEMU. - Multiqueue Scaling: Dengan mengaktifkan
virtio multiqueue, setiap vCPU di dalam VM memiliki dedicated pair of request/response virtqueues yang terikat langsung ke dedicated worker thread di host kernel, menghilangkan lock contention antar vCPU saat mengeksekusi operasi disk secara paralel.
1.7 VFIO / IOMMU Device Isolation, DMA Remapping & NUMA Socket Affinity
+-----------------------------------------------------------------------------------+
| NUMA NODE 0 (Socket 0 - PCIe Root Complex 0) |
| +--------------------+ +---------------------+ +---------------------------+ |
| | Cores 0-15 (vCPUs) | | Local DRAM (128GB) | | NVMe Controller (ZFS SLOG)| |
| +--------------------+ +---------------------+ +---------------------------+ |
+-----------------------------------------+-----------------------------------------+
| UPI / QPI Inter-Socket Bus
| (High Latency Cross-Traffic: ~120ns)
+-----------------------------------------+-----------------------------------------+
| NUMA NODE 1 (Socket 1 - PCIe Root Complex 1) |
| +--------------------+ +---------------------+ +---------------------------+ |
| | Cores 16-31 | | Local DRAM (128GB) | | 100GbE Dual-Port NIC | |
| | | | | | (DRBD9 Mesh Replication) | |
| +--------------------+ +---------------------+ +---------------------------+ |
+-----------------------------------------------------------------------------------+
IOMMU (Input-Output Memory Management Unit) & VFIO
IOMMU menyediakan translasi alamat dan isolasi perangkat fisik di tingkat hardware:
- DMA Remapping (Intel VT-d / AMD-Vi): Membatasi perangkat PCIe (seperti NIC atau NVMe HBA) agar hanya dapat mengakses rentang memori fisik yang dialokasikan khusus untuknya. Ketika perangkat PCIe diserahkan langsung ke VM (PCI Passthrough via VFIO - Virtual Function I/O), IOMMU memetakan DMA address yang dikeluarkan perangkat langsung ke Guest Physical Address (GPA) VM tersebut. Host terlindungi secara mutlak dari akses memori liar (rogue DMA attacks).
- Interrupt Remapping: Menjamin bahwa interupsi hardware dari perangkat PCIe diteruskan secara aman langsung ke virtual APIC ID dari vCPU VM target tanpa intervensi host OS (Direct Vector Injection).
Dampak NUMA Node Cross-Talk pada Latensi Storage
Dalam sistem dual-socket (NUMA):
- Akses memori lokal (Core di Socket 0 membaca RAM di Socket 0) memiliki latensi $\approx 60 - 70\text{ ns}$.
- Akses memori remote (Core di Socket 0 membaca RAM di Socket 1 melalui bus UPI/QPI) memiliki latensi $\approx 120 - 150\text{ ns}$ dan memakan bandwidth inter-socket interconnect.
- Critical Architecture Rule: KVM vCPU threads, alokasi memori QEMU, backend storage pool ZFS, dan thread jaringan DRBD9 untuk sebuah VM mission-critical wajib di-pinning secara kaku pada NUMA node yang sama. Pelanggaran NUMA affinity menyebabkan penurunan throughput I/O hingga $35%$ akibat overhead cross-socket cache coherency snoop traffic.
1.8 Hyper-Converged Consensus: Corosync 3.x Kronosnet Dual-Link & STONITH Hardware Fencing
High-Availability pada cluster KVM/DRBD9 membutuhkan konsensus terdistribusi yang deterministik untuk mencegah bencana split-brain (di mana dua node mengklaim hak eksklusif untuk menjalankan VM yang sama dan merusak integritas filesystem blok).
+-----------------------------------------------------------------------------------+
| KRONOSNET (knet) REDUNDANT TRANSPORT ARCHITECTURE |
+-----------------------------------------------------------------------------------+
| Node A (192.0.2.11 / 198.51.100.11) Node B (192.0.2.12 / 198.51.100.12) |
| +--------------------------+ +--------------------------+ |
| | Corosync 3.x / Pacemaker | | Corosync 3.x / Pacemaker | |
| +--------------------------+ +--------------------------+ |
| | | |
| +---------+---------+ +---------+---------+ |
| | | | | |
| v v v v |
| [ Link 0: 10GbE ] [ Link 1: 1GbE ] [ Link 0: 10GbE ] [ Link 1: 1GbE ]|
| (Data Fabric) (Mgmt Network) (Data Fabric) (Mgmt Network) |
| | | | | |
| +===================|====== KNET Heartbeat ======|===================+ |
| +====== KNET Heartbeat ======+ |
+-----------------------------------------------------------------------------------+
Kronosnet (knet) Failover Engine
Corosync 3.x menggantikan protokol Totem ring multicast lama dengan Kronosnet (knet):
- Kronosnet mendukung transmisi heartbeat point-to-point melalui beberapa interface fisik secara simultan (multi-link active/passive atau active/active round-robin).
- Knet secara kontinu memantau latensi dan packet drop pada setiap link menggunakan paket probing sub-detik.
- Jika kabel Link 0 (10GbE Data) terputus atau switch mengalami crash, Kronosnet mengalihkan aliran token konsensus ke Link 1 (1GbE Management) dalam tempo $< 50\text{ milidetik}$ tanpa memicu fluktuasi quorum atau false-positive node eviction.
STONITH (Shoot The Other Node In The Head) & Hardware Fencing
Dalam sistem clustering dual-primary:
- Prinsip Utama: "Kematian sebuah node jauh lebih aman daripada ketidakpastian status node tersebut."
- Jika Node A kehilangan kontak komunikasi dengan Node B, Node A dilarang keras mengasumsikan kepemilikan storage atau menjalankan VM milik Node B sebelum Node A berhasil mengeksekusi fencing terhadap Node B.
- Mekanisme Fencing: Pacemaker mengirimkan perintah Hardware Power Cut ke kartu IPMI / iLO / iDRAC remote node atau memicu Hardware Watchdog internal (
/dev/watchdog). Setelah controller IPMI mengonfirmasi pemutusan daya (Chassis Power Off: Success), status Node B dijamin mati secara fisik, dan Node A aman untuk mempromosikan DRBD resource serta melakukan startup VM.
2. Konfigurasi Nyata & Production-Ready Hardening
2.1 Enterprise OpenZFS 2.2+ Kernel Module Tuning (/etc/modprobe.d/zfs.conf) & Pool Settings
Konfigurasi kernel module OpenZFS yang dioptimalkan untuk hyper-converged host dengan RAM $256\text{ GB}$, disk array NVMe PCIe Gen4/Gen5, dan dedicated Optane SLOG:
# /etc/modprobe.d/zfs.conf - Hardened Production ZFS Kernel Parameters
# Arsitektur: 256GB Host RAM, NVMe Storage Pool, Low-Latency KVM Workloads
# 1. ARC Memory Allocation Boundaries
# Batasi ARC maksimum ke 50% RAM sistem (128GB) agar 128GB tersisa untuk KVM VMs & OS
options zfs zfs_arc_max=137438953472
options zfs zfs_arc_min=17179869184
# 2. Transaction Group (TXG) Commit Tuning
# Batasi durasi timeout TXG agar tidak terjadi akumulasi dirty data masif yang memicu I/O latency spike
options zfs zfs_txg_timeout=5
# Batasi dirty data maksimum di DRAM ke 4GB (default 10% RAM seringkali terlalu besar dan memicu stall)
options zfs zfs_dirty_data_max=4294967296
options zfs zfs_dirty_data_max_max=8589934592
options zfs zfs_dirty_data_sync_percent=20
# 3. ZIL / SLOG Pipeline Tuning
# Maksimalkan ukuran penulisan langsung ke ZIL tanpa pemesanan blok SPA ganda
options zfs zfs_immediate_write_sz=65536
# Aktifkan asynchronous write queuing ke disk backend
options zfs zfs_sync_task_abort_delay=10
# 4. Asynchronous I/O Concurrency & Scheduler Tuning
# Maksimalkan antrean concurrent I/O untuk storage flash/NVMe
options zfs zfs_vdev_async_read_min_active=4
options zfs zfs_vdev_async_read_max_active=32
options zfs zfs_vdev_async_write_min_active=4
options zfs zfs_vdev_async_write_max_active=32
options zfs zfs_vdev_sync_read_min_active=10
options zfs zfs_vdev_sync_read_max_active=64
options zfs zfs_vdev_sync_write_min_active=10
options zfs zfs_vdev_sync_write_max_active=64
# Maksimalkan throughput scrub dan resilver tanpa merusak latensi guest
options zfs zfs_vdev_scrub_min_active=2
options zfs zfs_vdev_scrub_max_active=4
options zfs zfs_resilver_min_time_ms=3000
# 5. Block Cloning & Zero-Copy Optimizations (OpenZFS 2.2+)
# Aktifkan copy_file_range accelerated cloning
options zfs zfs_bclone_enabled=1
options zfs zfs_bclone_wait_dirty=1
# 6. Prefetch Subsystem Tuning
# Matikan prefetch agresif untuk beban kerja database/random read I/O KVM
options zfs zfs_prefetch_disable=1
Eksekusi pembuatan zpool production dengan alokasi dRAID2 dan dedicated NVMe SLOG:
#!/usr/bin/env bash
# Provisioning Production ZFS Pool: dRAID2 with Dedicated Optane SLOG
set -euo pipefail
# Buat zpool dengan ashift=12 (4KB sector alignment fisik)
zpool create -f -o ashift=12 \
-o autotrim=on \
-O acltype=posixacl \
-O xattr=sa \
-O normalization=formD \
-O dnodesize=auto \
-O compression=zstd-3 \
-O atime=off \
-O redundant_metadata=most \
rpool-data \
draid2:8d:11c:1s \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100001 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100002 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100003 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100004 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100005 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100006 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100007 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100008 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100009 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100010 \
/dev/disk/by-id/nvme-SAMSUNG_MZQL23T8HCLS-00A07_S64HNA0R100011 \
log mirror \
/dev/disk/by-id/nvme-INTEL_MEMPEK1W016GA_PHBT741501GY016G-part1 \
/dev/disk/by-id/nvme-INTEL_MEMPEK1W016GA_PHBT741501GY016G-part2
# Buat ZVOL khusus backend DRBD dengan volblocksize 16KB (optimal untuk RDBMS guest VM)
zfs create -s -V 500G -b 16k -o sync=always -o logbias=latency rpool-data/drbd-vm101-disk0
2.2 DRBD9 Multi-Node Dual-Primary Synchronous Mesh Definition (/etc/drbd.d/r0.res)
Konfigurasi DRBD9 production untuk dual-node active-active cluster dengan hardware fence handler dan Protocol C:
# /etc/drbd.d/global_common.conf
global {
usage-count no;
udev-always-use-vnr;
}
common {
handlers {
# Handler otomatis saat terjadi inkonsistensi split-brain
split-brain "/usr/lib/drbd/notify-split-brain.sh root";
pri-lost-after-sb "/usr/lib/drbd/notify-pri-lost-after-sb.sh root";
fence-peer "/usr/lib/drbd/crm-fence-peer.9.sh";
unfence-peer "/usr/lib/drbd/crm-unfence-peer.9.sh";
outdate-peer "/usr/lib/drbd/crm-fence-peer.9.sh";
}
startup {
# Timeout menunggu koneksi peer saat node boot
wfc-timeout 15;
degr-wfc-timeout 30;
outdated-wfc-timeout 10;
# Izinkan startup dual-primary untuk kebutuhan KVM live-migration
become-primary-on both;
}
options {
auto-promote yes;
# Matikan auto-unfreeze untuk mencegah penulisan pada node yang terisolasi
on-no-quorum freeze;
}
disk {
# Fencing resource-level jika koneksi terputus saat write aktif
fencing resource-and-network;
# Batasi ukuran disk activity log extents
al-extents 6433;
al-updates yes;
# Disk flush barrier hardening
disk-barrier no;
disk-flushes yes;
disk-drain yes;
md-flushes yes;
resync-rate 1G; # Bandwidth maksimum resynchronization (1 GB/s pada 10GbE+)
}
net {
# Protokol C: Fully Synchronous
protocol C;
# Ukuran buffer socket TCP 10GbE
sndbuf-size 10M;
rcvbuf-size 10M;
max-buffers 36864;
max-epoch-size 16384;
ping-int 1;
ping-timeout 2;
connect-int 2;
timeout 50; # 5.0 seconds
# Penanganan Otomatis Split-Brain Algoritmik
after-sb-0pri discard-younger-primary;
after-sb-1pri consensus;
after-sb-2pri violently-asymmetric-split-brain;
# Integritas Kriptografis Paket Replikasi
csums-alg sha256;
}
}
Definisi resource /etc/drbd.d/r0.res:
resource r0 {
template-file "global_common.conf";
connection-mesh {
hosts node01 node02;
}
on node01 {
node-id 0;
device /dev/drbd0;
disk /dev/zvol/rpool-data/drbd-vm101-disk0;
meta-disk internal;
address 192.0.2.11:7788;
}
on node02 {
node-id 1;
device /dev/drbd0;
disk /dev/zvol/rpool-data/drbd-vm101-disk0;
meta-disk internal;
address 192.0.2.12:7788;
}
}
Inisialisasi metadata dan koneksi DRBD:
# Inisialisasi metadata DRBD pada kedua node
drbdadm create-md r0
drbdadm up r0
# Pada node01: paksa primary untuk inisialisasi sync awal
drbdadm primary --force r0
2.3 Hardened KVM/QEMU Domain XML Definition dengan NUMA Pinning & vhost-scsi Multiqueue
File domain XML /etc/libvirt/qemu/prod-db-vm01.xml yang menerapkan hardware isolation penuh:
<domain type='kvm'>
<name>prod-db-vm01</name>
<uuid>b3e2b4f9-251c-4b51-912b-3a216f4d5471</uuid>
<memory unit='GiB'>64</memory>
<currentMemory unit='GiB'>64</currentMemory>
<!-- 1. Alokasi 1GB Static HugePages -->
<memoryBacking>
<hugepages>
<page size='1048576' unit='KiB' nodeset='0'/>
</hugepages>
<locked/>
<access mode='shared'/>
</memoryBacking>
<!-- 2. vCPU Tuning & NUMA Affinity Pinning -->
<vcpu placement='static'>8</vcpu>
<cputune>
<vcpupin vcpu='0' cpuset='2'/>
<vcpupin vcpu='1' cpuset='3'/>
<vcpupin vcpu='2' cpuset='4'/>
<vcpupin vcpu='3' cpuset='5'/>
<vcpupin vcpu='4' cpuset='6'/>
<vcpupin vcpu='5' cpuset='7'/>
<vcpupin vcpu='6' cpuset='8'/>
<vcpupin vcpu='7' cpuset='9'/>
<emulatorpin cpuset='0-1'/>
<iothreadpin iothread='1' cpuset='10'/>
<iothreadpin iothread='2' cpuset='11'/>
</cputune>
<numatune>
<memory mode='strict' nodeset='0'/>
</numatune>
<cpu mode='host-passthrough' check='none' migratable='on'>
<topology sockets='1' dies='1' cores='8' threads='1'/>
<feature policy='require' name='invtsc'/>
<feature policy='require' name='pcid'/>
<feature policy='require' name='spec-ctrl'/>
<numa>
<cell id='0' cpus='0-7' memory='64' unit='GiB' memAccess='shared'/>
</numa>
</cpu>
<iothreads>2</iothreads>
<!-- 3. Hardware Features & Hypervisor Enlightenment -->
<features>
<acpi/>
<apic/>
<kvm>
<hidden state='on'/>
</kvm>
<vmport state='off'/>
<ioapic driver='kvm'/>
</features>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<!-- Virtio SCSI Multiqueue Controller terikat ke iothread -->
<controller type='scsi' index='0' model='virtio-scsi'>
<driver queues='8' iothread='1'/>
<address type='pci' domain='0x0000' bus='0x04' slot='0x00' function='0x0'/>
</controller>
<!-- Disk terikat langsung ke Block Device DRBD9 (/dev/drbd0) dengan native io_uring -->
<disk type='block' device='disk'>
<driver name='qemu' type='raw' cache='none' error_policy='stop' io='io_uring' discard='unmap'/>
<source dev='/dev/drbd0'/>
<target dev='sda' bus='scsi'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<!-- Virtio Network Interface dengan vhost-net multiqueue -->
<interface type='bridge'>
<source bridge='vmbr0'/>
<model type='virtio'/>
<driver name='vhost' queues='8' rx_queue_size='1024' tx_queue_size='1024'/>
<address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
</interface>
<serial type='pty'>
<target type='isa-serial' port='0'/>
</serial>
<console type='pty'>
<target type='serial' port='0'/>
</console>
</devices>
</domain>
2.4 Corosync 3.x Dual-Link Kronosnet & Pacemaker STONITH Configuration (/etc/corosync/corosync.conf)
Konfigurasi clustering deterministik dengan Kronosnet multi-link transport:
# /etc/corosync/corosync.conf - Production Dual-Link KNET Configuration
totem {
version: 2
cluster_name: pve-hci-prod
crypto_cipher: aes256
crypto_hash: sha256
transport: knet
# Kronosnet Transport Engine Tuning
link_mode: passive
ip_version: ipv4
# Timing Thresholds
token: 3000 # 3000ms token rotation timeout
token_retransmits_before_loss_const: 5
join: 50
consensus: 3600
max_messages: 50
clear_node_high_bit: yes
}
nodelist {
node {
ring0_addr: 192.0.2.11
ring1_addr: 198.51.100.11
nodeid: 1
name: node01
}
node {
ring0_addr: 192.0.2.12
ring1_addr: 198.51.100.12
nodeid: 2
name: node02
}
}
quorum {
provider: corosync_votequorum
two_node: 1
wait_for_all: 1
last_man_standing: 0
auto_tie_breaker: 1
}
logging {
to_logfile: yes
logfile: /var/log/corosync/corosync.log
to_syslog: yes
timestamp: on
logger_subsys {
subsys: KNET
debug: off
}
}
Aktivasi STONITH Hardware Fencing menggunakan Pacemaker CRM:
#!/usr/bin/env bash
# Hardened STONITH Configuration via Pacemaker CLI
set -euo pipefail
# Aktifkan STONITH secara global (Wajib untuk cluster dual-node/multi-node)
crm configure property stonith-enabled=true
crm configure property stonith-action=reboot
crm configure property no-quorum-policy=freeze
# Daftarkan IPMI Hardware Fence Device untuk node01
crm configure primitive fence_node01 stonith:fence_ipmilan \
params ip="203.0.113.11" username="stonith_admin" password="SecurePassword123!" \
pcmk_host_list="node01" method="cycle" power_timeout="60" \
op monitor interval="60s" timeout="30s"
# Daftarkan IPMI Hardware Fence Device untuk node02
crm configure primitive fence_node02 stonith:fence_ipmilan \
params ip="203.0.113.12" username="stonith_admin" password="SecurePassword123!" \
pcmk_host_list="node02" method="cycle" power_timeout="60" \
op monitor interval="60s" timeout="30s"
# Pasang constraint lokasi agar device fence tidak memantau dirinya sendiri
crm configure location loc_fence_node01 fence_node01 -inf: node01
crm configure location loc_fence_node02 fence_node02 -inf: node02
2.5 Linux Host Virtualization, Storage I/O & HugePages Sysctl Tuning (/etc/sysctl.d/75-kvm-zfs-storage.conf)
# /etc/sysctl.d/75-kvm-zfs-storage.conf - Kernel Subsystem Hardening
# 1. Virtual Memory & 1GB HugePages Reservation
# Alokasi statis 64 halaman x 1GB = 64GB untuk KVM VM
vm.nr_hugepages = 64
vm.hugetlb_shm_group = 0
vm.overcommit_memory = 1
# Minimalisasi agresivitas swap (ZFS ARC dan QEMU tidak boleh di-swap)
vm.swappiness = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 3
vm.dirty_expire_centisecs = 500
vm.dirty_writeback_centisecs = 100
# Cegah memory compaction stalls yang membekukan eksekusi guest
vm.compact_unevictable_allowed = 0
vm.zone_reclaim_mode = 0
# 2. Kernel Scheduler & I/O Latency Optimization
# Minimum granularity dan latency targeting
kernel.sched_min_granularity_ns = 10000000
kernel.sched_wakeup_granularity_ns = 15000000
kernel.sched_migration_cost_ns = 5000000
# 3. Network Stack Tuning untuk Replikasi DRBD9 10GbE+
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.core.rmem_max = 67108864
net.core.wmem_max = 67108864
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.tcp_wmem = 4096 65536 33554432
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
# Nonaktifkan slow start after idle untuk menjaga throughput DRBD konstan
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_low_latency = 1
# 4. Storage & File Descriptors Hardening
fs.file-max = 2097152
fs.aio-max-nr = 1048576
3. Script Otomatisasi, Validasi, dan Benchmarking
3.1 ZFS Pool, ARC, dan DRBD9 Replication FIO Benchmark Suite (benchmark-zfs-drbd-storage.sh)
Script produksi untuk menguji beban I/O sintetis terhadap storage ZVOL mentah dan device DRBD tereplikasi menggunakan engine fio dengan engine io_uring:
#!/usr/bin/env bash
# ==============================================================================
# Script: benchmark-zfs-drbd-storage.sh
# Author: La Nina ๐
# Description: Automated Enterprise Storage Benchmarking for OpenZFS & DRBD9
# Metrics: IOPS, P99 Latency, Bandwidth, ARC Hit Ratio & Replication Overhead
# ==============================================================================
set -euo pipefail
TARGET_DEV="${1:-/dev/drbd0}"
REPORT_DIR="/var/log/storage-benchmarks"
DATE_STR="$(date +'%Y%m%d_%H%M%S')"
REPORT_FILE="${REPORT_DIR}/bench_${DATE_STR}.json"
mkdir -p "${REPORT_DIR}"
log() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] \033[1;34m[INFO]\033[0m $*"
}
warn() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] \033[1;33m[WARN]\033[0m $*"
}
error() {
echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] \033[1;31m[ERROR]\033[0m $*" >&2
}
if [[ ! -b "${TARGET_DEV}" ]]; then
error "Block device target ${TARGET_DEV} tidak ditemukan!"
exit 1
fi
if ! command -v fio >/dev/null 2>&1; then
error "fio tidak terinstal. Jalankan: apt-get install -y fio"
exit 1
fi
log "Memulai audit baseline performa sebelum benchmark..."
log "Target Device: ${TARGET_DEV}"
log "Checking ZFS ARC Status..."
ARC_SIZE_MB=$(awk '/^size/ {print int($3/1024/1024)}' /proc/spl/kstat/zfs/arcstats || echo "N/A")
log "Current ZFS ARC Size: ${ARC_SIZE_MB} MB"
cat << 'EOF' > /tmp/fio_workloads.ini
[global]
ioengine=io_uring
direct=1
runtime=30
time_based=1
group_reporting=1
filename=${TARGET_DEV}
[4k_randwrite_sync]
stonewall
bs=4k
rw=randwrite
iodepth=1
numjobs=1
sync=1
[4k_randread_parallel]
stonewall
bs=4k
rw=randread
iodepth=32
numjobs=4
[128k_seqwrite_highthroughput]
stonewall
bs=128k
rw=write
iodepth=16
numjobs=2
[16k_oltp_mixed_70_30]
stonewall
bs=16k
rw=randrw
rwmixread=70
iodepth=16
numjobs=4
EOF
export TARGET_DEV
log "Menjalankan FIO Comprehensive Test Suite..."
fio /tmp/fio_workloads.ini --output-format=json --output="${REPORT_FILE}"
rm -f /tmp/fio_workloads.ini
log "Benchmark selesai. Mengurai metrik performa utama:"
python3 -c "
import json
with open('${REPORT_FILE}') as f:
data = json.load(f)
print('=' * 80)
print(f'{\"WORKLOAD NAME\":<30} | {\"IOPS\":<12} | {\"BW (MB/s)\":<12} | {\"P99 LATENCY (us)\":<15}')
print('=' * 80)
for job in data['jobs']:
name = job['jobname']
read_iops = job['read']['iops']
write_iops = job['write']['iops']
tot_iops = read_iops + write_iops
read_bw = job['read']['bw'] / 1024
write_bw = job['write']['bw'] / 1024
tot_bw = read_bw + write_bw
# Calculate weighted p99
p99 = 0
if job['read']['clat_ns']['percentile']:
p99 = max(p99, job['read']['clat_ns']['percentile'].get('99.000000', 0) / 1000)
if job['write']['clat_ns']['percentile']:
p99 = max(p99, job['write']['clat_ns']['percentile'].get('99.000000', 0) / 1000)
print(f'{name:<30} | {tot_iops:<12.1f} | {tot_bw:<12.2f} | {p99:<15.2f}')
print('=' * 80)
"
log "Laporan lengkap disimpan di: ${REPORT_FILE}"
3.2 Hyper-Converged Infrastructure Health, NUMA & Storage Latency Auditor (validate-hci-cluster-health.sh)
Script audit otomatis untuk memvalidasi kesehatan ZFS pool, status DRBD9 replication mesh, alokasi NUMA, status HugePages, dan token ring Corosync:
#!/usr/bin/env bash
# ==============================================================================
# Script: validate-hci-cluster-health.sh
# Author: La Nina ๐
# Description: Production Audit Suite for ZFS, DRBD9, KVM & Corosync Topology
# ==============================================================================
set -euo pipefail
RED='\033[1;31m'
GREEN='\033[1;32m'
YELLOW='\033[1;33m'
BLUE='\033[1;34m'
NC='\033[0m'
ERRORS=0
WARNINGS=0
pass() { echo -e " [${GREEN}PASSED${NC}] $*"; }
fail() { echo -e " [${RED}FAILED${NC}] $*"; ((ERRORS++)); }
warn() { echo -e " [${YELLOW}WARNING${NC}] $*"; ((WARNINGS++)); }
echo -e "\n${BLUE}===================================================================${NC}"
echo -e "${BLUE} HYPER-CONVERGED INFRASTRUCTURE (HCI) PRODUCTION AUDIT SUITE ${NC}"
echo -e "${BLUE}===================================================================${NC}\n"
# 1. Audit OpenZFS Pool Health
echo -e "${BLUE}[1/5] Memeriksa Kesehatan OpenZFS Storage Subsystem...${NC}"
if ! command -v zpool >/dev/null 2>&1; then
fail "OpenZFS utilities (zpool) tidak ditemukan!"
else
ZPOOL_STATUS=$(zpool status -x)
if [[ "${ZPOOL_STATUS}" == "all pools are healthy" ]]; then
pass "Semua ZFS Pool dalam kondisi HEALTHY."
else
fail "ZFS Pool mengalami degradasi: ${ZPOOL_STATUS}"
fi
# Cek fragmentasi pool
while read -r POOL FRAG; do
FRAG_NUM="${FRAG%\%}"
if [[ "${FRAG_NUM}" -gt 60 ]]; then
warn "Pool ${POOL} memiliki fragmentasi tinggi: ${FRAG} (Dapat menurunkan write IOPS)"
else
pass "Pool ${POOL} fragmentasi optimal: ${FRAG}"
fi
done < <(zpool list -H -o name,fragmentation)
# Cek ketersediaan SLOG
if zpool status | grep -q "log"; then
pass "Dedicated SLOG vdev terdeteksi pada konfigurasi pool."
else
warn "Tidak ada dedicated SLOG vdev. Penulisan sinkron (sync=always) akan membentur disk pool utama."
fi
fi
# 2. Audit DRBD9 Subsystem Status
echo -e "\n${BLUE}[2/5] Memeriksa Status DRBD9 Replication Mesh...${NC}"
if ! command -v drbdsetup >/dev/null 2>&1; then
warn "DRBD9 utilities tidak terdeteksi pada host ini."
else
DRBD_STATUS=$(drbdsetup status r0 --json || echo "{}")
CONNECTION_STATE=$(echo "${DRBD_STATUS}" | grep -o '"connection-state": "[^"]*"' | head -n1 | cut -d'"' -f4 || echo "Unknown")
DISK_STATE=$(echo "${DRBD_STATUS}" | grep -o '"disk-state": "[^"]*"' | head -n1 | cut -d'"' -f4 || echo "Unknown")
if [[ "${CONNECTION_STATE}" == "Connected" ]]; then
pass "DRBD9 Connection State: Connected (Mesh sehat)"
elif [[ "${CONNECTION_STATE}" == "SyncSource" || "${CONNECTION_STATE}" == "SyncTarget" ]]; then
warn "DRBD9 sedang dalam proses resinkronisasi data: ${CONNECTION_STATE}"
else
fail "DRBD9 Connection State anomali: ${CONNECTION_STATE}"
fi
if [[ "${DISK_STATE}" == "UpToDate" ]]; then
pass "DRBD9 Local Disk State: UpToDate"
else
fail "DRBD9 Disk State tidak sinkron: ${DISK_STATE}"
fi
fi
# 3. Audit NUMA Topology & Memory Alignment
echo -e "\n${BLUE}[3/5] Memeriksa Topologi NUMA & Memory Binding...${NC}"
NUMA_NODES=$(lscpu | awk '/NUMA node\(s\):/ {print $3}')
if [[ "${NUMA_NODES}" -gt 1 ]]; then
pass "Sistem multi-socket terdeteksi (${NUMA_NODES} NUMA nodes)."
# Periksa isolasi memori VM yang berjalan
if command -v virsh >/dev/null 2>&1; then
for VM in $(virsh list --name --state-running); do
MEM_MODE=$(virsh numatune "${VM}" | awk '/mode:/ {print $2}' || echo "none")
if [[ "${MEM_MODE}" == "strict" ]]; then
pass "VM ${VM} menerapkan strict NUMA memory pinning."
else
warn "VM ${VM} tidak menggunakan strict NUMA pinning (Mode: ${MEM_MODE}). Risiko latensi cross-talk."
fi
done
fi
else
pass "Sistem single-socket NUMA. Bebas dari penalti cross-socket latency."
fi
# 4. Audit HugePages Subsystem
echo -e "\n${BLUE}[4/5] Memeriksa Status Static HugePages...${NC}"
HP_TOTAL=$(awk '/HugePages_Total:/ {print $2}' /proc/meminfo)
HP_FREE=$(awk '/HugePages_Free:/ {print $2}' /proc/meminfo)
HP_SIZE_KB=$(awk '/Hugepagesize:/ {print $2}' /proc/meminfo)
if [[ "${HP_TOTAL}" -gt 0 ]]; then
pass "Static HugePages aktif: ${HP_TOTAL} total (${HP_FREE} bebas) @ ${HP_SIZE_KB} kB"
if [[ "${HP_SIZE_KB}" -ge 1048576 ]]; then
pass "1GB HugePages arsitektur aktif (Optimal untuk KVM database workloads)."
else
warn "HugePages berukuran 2MB. Disarankan migrasi ke 1GB HugePages untuk VM memory > 32GB."
fi
else
fail "Static HugePages tidak aktif! VM berjalan di atas 4KB regular pages (Tinggi TLB Miss)."
fi
# 5. Audit Corosync Kronosnet Quorum & Token Ring
echo -e "\n${BLUE}[5/5] Memeriksa Status Quorum Corosync & STONITH...${NC}"
if command -v corosync-quorumtool >/dev/null 2>&1; then
QUORUM_STATUS=$(corosync-quorumtool -s | awk '/Quorate:/ {print $2}')
if [[ "${QUORUM_STATUS}" == "Yes" ]]; then
pass "Corosync Cluster memiliki status QUORATE."
else
fail "Corosync Cluster TIDAK memiliki Quorum! (Risiko Split-Brain)"
fi
# Cek status STONITH
if command -v crm_mon >/dev/null 2>&1; then
if crm_mon -1 | grep -q "stonith-enabled: true"; then
pass "Pacemaker STONITH Hardware Fencing aktif dan ditegakkan."
else
fail "STONITH TIDAK AKTIF! Cluster dual-node sangat rentan terhadap data corruption!"
fi
fi
else
warn "Corosync utilities tidak terpasang."
fi
echo -e "\n${BLUE}===================================================================${NC}"
echo -e "Audit Selesai. Total Errors: ${RED}${ERRORS}${NC} | Total Warnings: ${YELLOW}${WARNINGS}${NC}"
echo -e "${BLUE}===================================================================${NC}\n"
if [[ "${ERRORS}" -gt 0 ]]; then
exit 1
fi
exit 0
3.3 DRBD9 Split-Brain Chaos Injection & Automated Fence-Peer Simulator (test-drbd-splitbrain-recovery.sh)
Script simulasi pengujian kegagalan jaringan terkontrol untuk memvalidasi eksekusi STONITH dan pemulihan konsistensi blok secara algoritmik:
#!/usr/bin/env bash
# ==============================================================================
# Script: test-drbd-splitbrain-recovery.sh
# Author: La Nina ๐
# Description: Automated Chaos Injection & Split-Brain Handler Validation
# ==============================================================================
set -euo pipefail
RESOURCE="r0"
PEER_IP="${1:-192.0.2.12}"
log() { echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] \033[1;34m[CHAOS]\033[0m $*"; }
warn() { echo -e "[$(date +'%Y-%m-%d %H:%M:%S')] \033[1;33m[WARN]\033[0m $*"; }
log "Memulai simulasi controlled partition pada link DRBD..."
log "Memastikan status awal resource ${RESOURCE}..."
CURRENT_CONN=$(drbdadm cstate "${RESOURCE}")
if [[ "${CURRENT_CONN}" != "Connected" ]]; then
echo "Error: Resource ${RESOURCE} sedang dalam state '${CURRENT_CONN}', bukan 'Connected'."
exit 1
fi
log "Menyuntikkan isolasi jaringan via iptables DROP ke peer: ${PEER_IP}..."
iptables -I OUTPUT -p tcp -d "${PEER_IP}" --dport 7788 -j DROP
iptables -I INPUT -p tcp -s "${PEER_IP}" --sport 7788 -j DROP
log "Memverifikasi transisi state ke StandAlone atau Disconnected..."
sleep 3
NEW_STATE=$(drbdadm cstate "${RESOURCE}")
log "Current DRBD Connection State: ${NEW_STATE}"
log "Menulis data independen ke local disk untuk mensimulasikan divergent blocks..."
dd if=/dev/urandom of=/dev/drbd0 bs=4k count=256 oflag=direct seek=1000 status=none
log "Melepaskan isolasi firewall (memulihkan konektivitas fisik)..."
iptables -D OUTPUT -p tcp -d "${PEER_IP}" --dport 7788 -j DROP
iptables -D INPUT -p tcp -s "${PEER_IP}" --sport 7788 -j DROP
log "Memicu rekonsiliasi koneksi DRBD..."
drbdadm connect "${RESOURCE}" || true
sleep 5
POST_STATE=$(drbdadm cstate "${RESOURCE}")
log "Status pasca pemulihan link: ${POST_STATE}"
if [[ "${POST_STATE}" == "StandAlone" ]]; then
warn "DRBD mendeteksi Split-Brain dan masuk ke mode StandAlone (Sesuai Desain Proteksi)."
log "Mengeksekusi automated resolution: Mengalah sebagai SyncTarget..."
# Skenario pemulihan manual otomatis
drbdadm secondary "${RESOURCE}"
drbdadm connect --discard-my-data "${RESOURCE}"
log "Menunggu resinkronisasi dari peer yang menang..."
sleep 4
FINAL_STATE=$(drbdadm cstate "${RESOURCE}")
log "Final State setelah pemulihan terarah: ${FINAL_STATE}"
elif [[ "${POST_STATE}" == "Connected" ]]; then
log "DRBD berhasil menyelesaikan split-brain secara otomatis via handler 'discard-younger-primary'."
fi
log "Simulasi chaos testing selesai dengan aman."
4. Skenario Troubleshooting Kasus Nyata (Root Cause Analysis & Mitigation)
4.1 Kasus 1: ZFS Transaction Group (TXG) Sync Stall & SPA Lock Contention Menyebabkan I/O Freeze pada VM
Gejala & Observasi Metrik
Pada cluster virtualisasi KVM yang menampung 40 VM database PostgreSQL, terjadi guest I/O pause periodik setiap 15โ30 detik selama 3 hingga 8 detik. Selama periode freeze:
- Aplikasi di dalam VM mencatat timeout koneksi database (
504 Gateway Timeoutdi API gateway). - Pada host hypervisor, metrik CPU utilisasi normal ($20%$), tetapi iowait melonjak drastis hingga $60%$.
- Perintah
zpool iostat -v 1menunjukkan penulisan disk berhenti sepenuhnya selama 4 detik, diikuti oleh semburan penulisan masif sebesar $1.8\text{ GB/s}$ selama 2 detik. - Utility
vmstat 1menunjukkan angka antrean blok kotor (bcolumn) melompat dari 0 ke 85.
Investigasi Mendalam & Root Cause Analysis (RCA)
Analisis Transaksi TXG: Pemeriksaan kstat internal OpenZFS via
/proc/spl/kstat/zfs/txg_history:cat /proc/spl/kstat/zfs/txg_history | tail -n 10Output menunjukkan:
txg birth_time read write free ndirty open quiesce wait sync 481921 1758410291481029 0 18429184 40960 8294102 5000ms 12ms 3412ms 4810ms 481922 1758410296481029 0 24102912 32768 8491024 5000ms 18ms 4102ms 5200msKolom
ndirtymenunjukkan bahwa jumlah dirty data sebelum di-sync mencapai $\approx 8.4\text{ GB}$. Kolomwaitdansyncmencapai $> 4000\text{ ms}$, yang berarti proses penulisan terhambat selama 4 detik saat data dikomit ke disk.Mekanika Lock Contention:
- Parameter default
zfs_dirty_data_maxpada mesin dengan RAM 256GB bernilai $10%$ dari RAM ($\approx 25\text{ GB}$). - Ketika transaksi database menghasilkan burst write yang besar, OpenZFS membiarkan dirty data menumpuk di DRAM hingga ambang batas tersebut.
- Begitu dirty data mencapai batas
zfs_dirty_data_max, SPA memberlakukan hard throttling: seluruh thread I/O baru (termasuk virtio worker thread KVM) dipaksa tidur (blocked) oleh fungsitxg_wait_open()untuk menunggu threadtxg_syncmengosongkan antrean ke disk fisik. - Karena disk pool utama terdiri dari array NVMe tanpa dedicated SLOG bertipe ultra-fast low-latency, operasi penulisan metadata Uberblock dan alokasi metaslab mengalami perebutan lock (lock contention pada AVL tree allocator), membekukan seluruh antrean I/O guest.
- Parameter default
Mitigasi & Langkah Remediasi Permanen
Pangkas Akumulasi Dirty Data: Batasi jumlah maksimum dirty data yang diizinkan mengendap di DRAM agar proses flush ke disk dapat diselesaikan dalam waktu kurang dari $500\text{ milidetik}$:
echo 4294967296 > /sys/module/zfs/parameters/zfs_dirty_data_max # 4GB echo 2147483648 > /sys/module/zfs/parameters/zfs_dirty_data_sync_percent # Mulai sync di 2GB echo 5 > /sys/module/zfs/parameters/zfs_txg_timeout # Flush tiap 5 detikPasang Dedicated High-End SLOG (Intel Optane / Ultra-Low-Latency NVMe): Tambahkan perangkat mirror SLOG dengan Power Loss Protection (PLP) dan latensi write ultra-rendah ($< 15\ \mu\text{s}$):
zpool add rpool-data log mirror /dev/disk/by-id/nvme-optane-part1 /dev/disk/by-id/nvme-optane-part2Ganti I/O Subsystem Driver KVM ke
io_uring: Ubah konfigurasi disk domain VM dariio='threads'atauio='native'menjadiio='io_uring'untuk menghilangkan blocking kernel syscall overhead.
4.2 Kasus 2: DRBD9 Split-Brain Hazard pada Asymmetric Network Flapping Cluster Live-Migration
Gejala & Observasi Kasus
Pada saat pengujian live-migration antar dua node (node01 dan node02), switch top-of-rack mengalami intermittent link flapping pada interface 10GbE private replication.
- Kedua node secara tiba-tiba beralih ke status
StandAlone. - Node01 melaporkan:
drbd r0: Split-Brain detected but unresolved, dropping connection!. - VM yang sedang dalam proses live-migration mengalami disk corruption pada sistem file ext4 guest (
EXT4-fs error: double free of inode).
Root Cause Analysis (RCA)
- Kegagalan Fencing & Evaluasi Dual-Primary:
- Untuk mendukung KVM live-migration tanpa downtime, resource DRBD dikonfigurasi dengan
allow-two-primaries yes;. Hal ini memperbolehkan kedua node membuka perangkat blok/dev/drbd0dalam status read-write secara bersamaan selama beberapa detik transfer RAM berlangsung. - Ketika link jaringan terputus di tengah migrasi, kedua node kehilangan komunikasi TCP heartbeat DRBD.
- Karena handler
fence-peertidak dikonfigurasi dengan hardware STONITH IPMI yang independen, node01 dan node02 masing-masing mengasumsikan dirinya sebagai surviving primary. - Kedua node terus menerima penulisan data dari aplikasi lokal: node01 menulis I/O dari sisa proses VM lama, sedangkan node02 mulai menulis I/O dari proses VM yang baru tiba.
- Untuk mendukung KVM live-migration tanpa downtime, resource DRBD dikonfigurasi dengan
- Generational UUID Divergence:
DRBD mengelola array UUID generasi data internal:
Current UUID: Berubah setiap kali disk beralih status dari clean ke dirty.Bitmap UUID: Melacak divergensi blok. Ketika kedua node menulis data independen saat link terputus,Current UUIDpada kedua node bertransisi menjadi divergen sepenuhnya tanpa parent-child history yang valid. Sesuai RFC protokol DRBD, DRBD secara otomatis memutus koneksi dan masuk ke stateStandAloneuntuk mencegah penulisan silang yang saling menghancurkan blok.
Mitigasi & Langkah Remediasi Permanen
Terapkan STONITH Fencing Terintegrasi dengan DRBD: Ubah handler di
/etc/drbd.d/global_common.conf:handlers { fence-peer "/usr/lib/drbd/crm-fence-peer.9.sh"; unfence-peer "/usr/lib/drbd/crm-unfence-peer.9.sh"; } disk { fencing resource-and-network; }Skrip
crm-fence-peer.9.shakan memanggil Pacemaker untuk memverifikasi quorum. Jika komunikasi jaringan hilang, node yang tidak memiliki quorum akan segera dimatikan melalui IPMI power cut sebelum sempat mengeksekusi I/O liar.Konfigurasi Algoritma Auto-Recovery Split-Brain: Jika VM non-kritis mengalami split-brain tanpa dual write yang masif, tetapkan aturan resolusi otomatis berdasarkan timestamp data termuda:
net { after-sb-0pri discard-younger-primary; after-sb-1pri consensus; after-sb-2pri call-pri-lost-after-sb; }
4.3 Kasus 3: KVM Extended Page Table (EPT) Walk Latency & Memory Compaction Stalls pada High-Concurrency VM
Gejala & Observasi Kasus
Sebuah VM berukuran besar ($128\text{ GB RAM}$, 32 vCPU) yang menjalankan database Redis dan PostgreSQL mengalami latency spike mendadak: waktu eksekusi query melonjak dari $0.8\text{ ms}$ menjadi $180\text{ ms}$ secara acak setiap beberapa menit.
- Metrik
toppada host menunjukkan thread kernelkcompactd0mengonsumsi $100%$ CPU core. - Perintah
perf toppada host kernel mendeteksi fungsicompact_zonedanalloc_pages_slowpathberada di urutan teratas overhead eksekusi CPU ($> 45%$).
Root Cause Analysis (RCA)
- Transparent HugePages (THP) Compaction:
- Host Linux menggunakan mode
transparent_hugepage=always. - Ketika VM mengalokasikan memori dinamis di atas memori host yang terfragmentasi, kernel berulang kali mencoba menggabungkan (compact) halaman-halaman $4\text{ KB}$ fisik menjadi halaman contiguous $2\text{ MB}$.
- Selama proses memory compaction, kernel menahan spinlock zona memori (
zone->lock). Seluruh vCPU VM yang mencoba mengakses memori baru dipaksa menunggu (stalled) hingga operasi compaction selesai.
- Host Linux menggunakan mode
- EPT TLB Shootdowns:
- Karena VM dialokasikan menggunakan halaman $4\text{ KB}$ standar di dalam tabel EPT, hardware MMU harus menelusuri 4 level EPT untuk setiap cache miss.
- Seringnya proses alokasi dan dealokasi memori dinamis memicu inter-processor interrupt (IPI) untuk membersihkan cache EPT TLB di seluruh 32 core CPU fisik (TLB shootdown storm), memicu latensi tinggi pada instruksi CPU guest.
Mitigasi & Langkah Remediasi Permanen
Reservasi 1GB Static HugePages Eksklusif: Matikan Transparent HugePages pada host dan alokasikan static 1GB HugePages di boot time via GRUB: Edit
/etc/default/grub:GRUB_CMDLINE_LINUX_DEFAULT="quiet default_hugepagesz=1G hugepagesz=1G hugepages=128 transparent_hugepage=never"Jalankan
update-grubdan reboot host.Kunci Memori VM di Domain XML: Konfigurasikan libvirt domain XML agar mengunci memori di DRAM dan mencegah host melakukan memory overcommit atau compaction:
<memoryBacking> <hugepages> <page size='1048576' unit='KiB'/> </hugepages> <locked/> </memoryBacking>
4.4 Kasus 4: Corosync Token Ring Timeout & Split-Brain Node Eviction Akibat ZFS Scrubbing / Replication Congestion
Gejala & Observasi Kasus
Setiap hari Minggu pukul 02:00 pagi saat jadwal ZFS pool scrub dan replikasi dataset massal (zfs send/receive) dijalankan, node02 terputus dari cluster Corosync.
- Log
/var/log/corosync/corosync.log:[TOTEM ] Token has not been received in 1000 ms [TOTEM ] A processor failed, forming new configuration [QUORUM] Members: 1 [CRM ] Notice: node02 is UNCLEAN (offline) [STONITH] Executing reboot fence against node02 - Node02 tiba-tiba mati mendadak (fenced by IPMI) padahal mesin tersebut tidak mengalami kernel panic.
Root Cause Analysis (RCA)
- Penyatuan Interface Jaringan Storage & Heartbeat:
- Link komunikasi Corosync dikonfigurasi melalui interface jaringan yang sama (
vmbr0/ VLAN 10) dengan lalu lintas replikasi ZFS dan throughput backup storage. - Ketika proses
zpool scrubselesai dan cron job mentransmisikan replikasi ZFS ZVOL sebesar $800\text{ GB}$ menggunakanzfs send | ssh, bandwidth 10GbE fisik mengalami saturasi $100%$.
- Link komunikasi Corosync dikonfigurasi melalui interface jaringan yang sama (
- Buffer Bloat & Packet Drops pada Antrean NIC:
- Antrean transmit ring buffer NIC penuh, menyebabkan paket UDP heartbeat Corosync mengalami antrean panjang (buffer bloat) dan di-drop oleh kernel network stack (
rx_dropped/tx_droppedmeningkat). - Parameter
tokenpada Corosync hanya disetel sebesar $1000\text{ ms}$ (1 detik). Karena token gagal diterima dalam 1 detik, node01 menganggap node02 telah mati dan memicu fencing hardware.
- Antrean transmit ring buffer NIC penuh, menyebabkan paket UDP heartbeat Corosync mengalami antrean panjang (buffer bloat) dan di-drop oleh kernel network stack (
Mitigasi & Langkah Remediasi Permanen
Terapkan Kronosnet Multi-Link Redundancy: Pisahkan jalur komunikasi heartbeat menjadi dua interface fisik independen:
- Link 0: Dedicated 10GbE storage network (prioritas tinggi).
- Link 1: Dedicated 1GbE management/out-of-band network sebagai failover pasif. Corosync akan secara instan mengalihkan transmisi token ke Link 1 jika Link 0 mengalami saturasi.
Perbesar Ambang Batas Token Timeout & Retransmit: Tingkatkan parameter
tokendi/etc/corosync/corosync.confdari 1000ms ke 3000ms atau 5000ms untuk menoleransi micro-burst congestion:totem { token: 3000 token_retransmits_before_loss_const: 5 consensus: 3600 }Terapkan QoS Traffic Shaping & DSCP Tagging: Tandai paket Corosync dengan DSCP Expedited Forwarding (
EF- CoS 5) dan berikan prioritas antrean pada switch network:iptables -t mangle -A OUTPUT -p udp -m multiport --dports 5405:5412 -j DSCP --set-dscp-class EF
5. Ringkasan Arsitektur & Rekomendasi Best Practices
Untuk menjamin kinerja optimal dan stabilitas jangka panjang dalam arsitektur Hyper-Converged Infrastructure (HCI) berbasis OpenZFS, DRBD9, dan KVM, berikut adalah matriks best practice production yang wajib dipatuhi:
| Komponen Subsystem | Konfigurasi Default / Sub-Optimal | Konfigurasi Enterprise Production Hardening | Manfaat & Justifikasi Arsitektur |
|---|---|---|---|
| ZFS Storage Pool | RAID-Z2 Standar (Single disk rebuild) | dRAID2 dengan Dedicated Optane NVMe SLOG | Paralelisasi resilvering disk ke seluruh vdev, memangkas MTTR hingga $85%$. |
| ZFS Dirty Memory | 10% dari RAM (Hingga 25GB+) | Maksimum 4GB (zfs_dirty_data_max=4G) | Mengeliminasi TXG sync stall freeze pada vCPU KVM selama write burst. |
| ZFS Block Size | Default volblocksize=8k | Disesuaikan dengan DB Guest (volblocksize=16k / 64k) | Menghindari write amplification dan fragmentasi record DMU. |
| DRBD9 Protocol | Protocol A / Asynchronous | Protocol C (Fully Synchronous) + Activity Log 6433 extents | Menjamin $RPO=0$ tanpa risiko kehilangan transaksi saat host crash. |
| DRBD Fencing | fencing dont-care; | fencing resource-and-network; + STONITH CRM | Mencegah split-brain hazard dan data divergence saat link network putus. |
| KVM I/O Engine | QEMU Userspace Threads (io=threads) | Native Kernel io_uring + vhost-scsi multiqueue | Memotong latensi I/O disk hingga $60%$ via zero-copy in-kernel submission. |
| KVM Memory Paging | Standard 4KB Pages / THP Always | 1GB Static HugePages (hugetlb) + Memory Locking | Mengeliminasi EPT page-walk penalty dan memory compaction stalls. |
| NUMA Topology | Non-Pinned Dynamic Scheduling | Strict vCPU Core Pinning & NUMA Node Binding | Menghilangkan penalti $120\text{ns}$ cross-socket interconnect latency. |
| Cluster Heartbeat | Single Multicast / Unicast Link | Corosync 3.x Kronosnet Dual-Link (Data + Mgmt) | Failover token sub-detik jika satu kabel fisik mengalami saturasi/putus. |
| Cluster Fencing | Software Reboot / Manual Recovery | Hardware IPMI / Redfish STONITH Power-Cut | Isolasi deterministik node bermasalah sebelum data dapat dikorupsi. |
Dokumen riset teknis mandiri ini disusun dan divalidasi oleh La Nina ๐ untuk keunggulan arsitektur infrastruktur cloud & virtualisasi Kapten Panca.