LA NINA // BLOG
Kembali ke Indeks Catatan

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/24 TEST-NET-1 untuk Node Interconnect & Host Management, 198.51.100.0/24 TEST-NET-2 untuk Dedicated DRBD9 Storage Replication Mesh, serta 203.0.113.0/24 TEST-NET-3 untuk Corosync Redundant Ring & IPMI/BMC STONITH Fencing Network).


DAFTAR ISI

  1. 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
  2. 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)
  3. 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)
  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
    • 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
  5. 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).

TEXT
+---------------------------------------------------------------------------------------------------+
|                                      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:

TEXT
[ 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:

  1. Blok data baru ditulis ke lokasi disk yang belum teralokasi (free space yang dipilih oleh SPA).
  2. Pointer ke blok tersebut di dalam parent indirect block diperbarui untuk menunjuk ke alamat fisik baru (DVA - Data Virtual Address).
  3. Pembaruan merambat ke atas pohon objek (Merkle Tree) hingga mencapai MOS (Meta Object Set).
  4. 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:

C
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):
    1. By-Size Tree: Mengindeks rentang blok bebas berdasarkan ukuran untuk memfasilitasi algoritma alokasi first-fit atau best-fit secara instan.
    2. 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.

TEXT
+------------------------------------------------------------------------------------+
|                                    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:

  1. MRU ($T_1$): Berisi halaman yang baru saja diakses satu kali (menangkap lokalitas temporal).
  2. 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_thread secara 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.

TEXT
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

  1. In-Memory Logging (itx_t): Ketika penulisan sinkron masuk, OpenZFS membuat in-memory intent log transaction (itx).
  2. 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.
  3. 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.
  4. TXG Commit Reaping: Setiap $\approx 5\text{ detik}$ (diatur oleh zfs_txg_timeout), thread txg_sync memproses 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:

TEXT
+-----------------------------------------------------------------------------------+
|               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 dnode baru dan menduplikasi blkptr_t yang 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.

TEXT
       [ 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/drbd0 hanya dianggap selesai setelah:
    1. I/O lokal sukses ditulis ke disk backend lokal.
    2. 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:

  1. 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).
  2. 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 1 di bitmap. Begitu link jaringan pulih, engine Quicksync mentransfer hanya blok-blok yang bernilai 1 ke 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).

TEXT
+-----------------------------------------------------------------------------------+
|                        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

  1. VM-Entry: Host CPU mengeksekusi instruksi VMLAUNCH atau VMRESUME. 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).
  2. 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.
  3. 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:

  1. Guest Virtual Address (GVA) $\rightarrow$ Guest Physical Address (GPA): Dikelola oleh Page Table di dalam Guest OS (CR3 register di dalam guest).
  2. Guest Physical Address (GPA) $\rightarrow$ Host Physical Address (HPA): Dikelola oleh Extended Page Tables (EPT) di dalam KVM Hypervisor (EPTP register di hardware MMU).
TEXT
   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-scsi atau vhost-blk memindahkan 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

TEXT
+-----------------------------------------------------------------------------------+
|                        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:

  1. 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).
  2. 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).

TEXT
+-----------------------------------------------------------------------------------+
|               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:

INI
# /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:

BASH
#!/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:

INI
# /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:

INI
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:

BASH
# 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:

XML
<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:

INI
# /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:

BASH
#!/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)

INI
# /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:

BASH
#!/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:

BASH
#!/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:

BASH
#!/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 Timeout di API gateway).
  • Pada host hypervisor, metrik CPU utilisasi normal ($20%$), tetapi iowait melonjak drastis hingga $60%$.
  • Perintah zpool iostat -v 1 menunjukkan penulisan disk berhenti sepenuhnya selama 4 detik, diikuti oleh semburan penulisan masif sebesar $1.8\text{ GB/s}$ selama 2 detik.
  • Utility vmstat 1 menunjukkan angka antrean blok kotor (b column) melompat dari 0 ke 85.

Investigasi Mendalam & Root Cause Analysis (RCA)

  1. Analisis Transaksi TXG: Pemeriksaan kstat internal OpenZFS via /proc/spl/kstat/zfs/txg_history:

    BASH
    cat /proc/spl/kstat/zfs/txg_history | tail -n 10

    Output menunjukkan:

    TEXT
    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    5200ms

    Kolom ndirty menunjukkan bahwa jumlah dirty data sebelum di-sync mencapai $\approx 8.4\text{ GB}$. Kolom wait dan sync mencapai $> 4000\text{ ms}$, yang berarti proses penulisan terhambat selama 4 detik saat data dikomit ke disk.

  2. Mekanika Lock Contention:

    • Parameter default zfs_dirty_data_max pada 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 fungsi txg_wait_open() untuk menunggu thread txg_sync mengosongkan 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.

Mitigasi & Langkah Remediasi Permanen

  1. 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}$:

    BASH
    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 detik
  2. Pasang 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}$):

    BASH
    zpool add rpool-data log mirror /dev/disk/by-id/nvme-optane-part1 /dev/disk/by-id/nvme-optane-part2
  3. Ganti I/O Subsystem Driver KVM ke io_uring: Ubah konfigurasi disk domain VM dari io='threads' atau io='native' menjadi io='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)

  1. 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/drbd0 dalam 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-peer tidak 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.
  2. 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 UUID pada kedua node bertransisi menjadi divergen sepenuhnya tanpa parent-child history yang valid. Sesuai RFC protokol DRBD, DRBD secara otomatis memutus koneksi dan masuk ke state StandAlone untuk mencegah penulisan silang yang saling menghancurkan blok.

Mitigasi & Langkah Remediasi Permanen

  1. Terapkan STONITH Fencing Terintegrasi dengan DRBD: Ubah handler di /etc/drbd.d/global_common.conf:

    INI
    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.sh akan 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.

  2. 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:

    INI
    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 top pada host menunjukkan thread kernel kcompactd0 mengonsumsi $100%$ CPU core.
  • Perintah perf top pada host kernel mendeteksi fungsi compact_zone dan alloc_pages_slowpath berada di urutan teratas overhead eksekusi CPU ($> 45%$).

Root Cause Analysis (RCA)

  1. 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.
  2. 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

  1. Reservasi 1GB Static HugePages Eksklusif: Matikan Transparent HugePages pada host dan alokasikan static 1GB HugePages di boot time via GRUB: Edit /etc/default/grub:

    BASH
    GRUB_CMDLINE_LINUX_DEFAULT="quiet default_hugepagesz=1G hugepagesz=1G hugepages=128 transparent_hugepage=never"

    Jalankan update-grub dan reboot host.

  2. Kunci Memori VM di Domain XML: Konfigurasikan libvirt domain XML agar mengunci memori di DRAM dan mencegah host melakukan memory overcommit atau compaction:

    XML
    <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:
    TEXT
    [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)

  1. 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 scrub selesai dan cron job mentransmisikan replikasi ZFS ZVOL sebesar $800\text{ GB}$ menggunakan zfs send | ssh, bandwidth 10GbE fisik mengalami saturasi $100%$.
  2. 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_dropped meningkat).
    • Parameter token pada 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.

Mitigasi & Langkah Remediasi Permanen

  1. 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.
  2. Perbesar Ambang Batas Token Timeout & Retransmit: Tingkatkan parameter token di /etc/corosync/corosync.conf dari 1000ms ke 3000ms atau 5000ms untuk menoleransi micro-burst congestion:

    INI
    totem {
        token: 3000
        token_retransmits_before_loss_const: 5
        consensus: 3600
    }
  3. Terapkan QoS Traffic Shaping & DSCP Tagging: Tandai paket Corosync dengan DSCP Expedited Forwarding (EF - CoS 5) dan berikan prioritas antrean pada switch network:

    BASH
    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 SubsystemKonfigurasi Default / Sub-OptimalKonfigurasi Enterprise Production HardeningManfaat & Justifikasi Arsitektur
ZFS Storage PoolRAID-Z2 Standar (Single disk rebuild)dRAID2 dengan Dedicated Optane NVMe SLOGParalelisasi resilvering disk ke seluruh vdev, memangkas MTTR hingga $85%$.
ZFS Dirty Memory10% dari RAM (Hingga 25GB+)Maksimum 4GB (zfs_dirty_data_max=4G)Mengeliminasi TXG sync stall freeze pada vCPU KVM selama write burst.
ZFS Block SizeDefault volblocksize=8kDisesuaikan dengan DB Guest (volblocksize=16k / 64k)Menghindari write amplification dan fragmentasi record DMU.
DRBD9 ProtocolProtocol A / AsynchronousProtocol C (Fully Synchronous) + Activity Log 6433 extentsMenjamin $RPO=0$ tanpa risiko kehilangan transaksi saat host crash.
DRBD Fencingfencing dont-care;fencing resource-and-network; + STONITH CRMMencegah split-brain hazard dan data divergence saat link network putus.
KVM I/O EngineQEMU Userspace Threads (io=threads)Native Kernel io_uring + vhost-scsi multiqueueMemotong latensi I/O disk hingga $60%$ via zero-copy in-kernel submission.
KVM Memory PagingStandard 4KB Pages / THP Always1GB Static HugePages (hugetlb) + Memory LockingMengeliminasi EPT page-walk penalty dan memory compaction stalls.
NUMA TopologyNon-Pinned Dynamic SchedulingStrict vCPU Core Pinning & NUMA Node BindingMenghilangkan penalti $120\text{ns}$ cross-socket interconnect latency.
Cluster HeartbeatSingle Multicast / Unicast LinkCorosync 3.x Kronosnet Dual-Link (Data + Mgmt)Failover token sub-detik jika satu kabel fisik mengalami saturasi/putus.
Cluster FencingSoftware Reboot / Manual RecoveryHardware IPMI / Redfish STONITH Power-CutIsolasi 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.

Kembali ke Atas ↑