Arsitektur Telemetri Edge dan Vektor Anomali State
TEXT
[ Kompresor & Sensor ] --(MQTT/TLS)--> [ Ingress Gateway (LXC) ]
|
(UNIX Domain Socket)
v
[ Safety State Engine ] <--(virtio-blk)-- [ MicroVM Tenant (Firecracker) ]
| |
+------ [ NVMe Writeback Bottleneck ] -+Bottleneck Serialisasi: Alokasi Memori dan Beban CPU
perf pada node worker host, terlihat bahwa CPU habis terpakai bukan untuk logika validasi status pendingin, melainkan siklus spinlock alokasi memori dan serialisasi skema disk:
BASH
# Profiling call graph CPU pada thread runner microVM
perf top -p $(pgrep -f 'firecracker.*tenant-coldchain') --sort comm,dso,symbolmalloc_consolidate, memcpy_erms, dan sinkronisasi thread saat serialisasi byte stream sebelum penulisan ke disk virtio:
TEXT
Overhead Shared Object Symbol
31.20% libc.so.6 [.] _int_malloc
24.45% coldchain-agent [.] serde_json::to_writer
18.12% [kernel.kallsyms] [.] copy_user_enhanced_fast_string
11.30% [kernel.kallsyms] [.] balance_dirty_pages
6.80% coldchain-agent [.] rocksdb::DBImpl::WriteSaturasi Disk Writeback: Saat Page Cache Mengunci Virtio-blk
flush-bdi) dapat mengalirkan data ke NVMe secara berkala tanpa menghentikan thread aplikasi. Namun, ketika gelombang data masuk melampaui kemampuan transfer agregat virtio-blk microVM, persentase dirty memory di host melompat melampaui vm.dirty_ratio. Ketika ambang batas ini terlampaui, kernel beralih dari mekanisme asinkron ke mekanisme penulisan synchronous yang memblokir proses (synchronous write throttle via balance_dirty_pages_ratelimited).
Kondisi ini menciptakan rantai pemblokiran sistemik:
- Thread di dalam Firecracker microVM melakukan pemanggilan
pwrite64()ke virtual block device (/dev/vda). - Driver backend Firecracker di host mengeluarkan I/O asynchronous melalui
io_uringatau epoll-driven AIO ke file backing disk di host filesystem (ext4/XFS). - Host kernel mendeteksi bahwa dirty pages global telah melebihi batas toleransi, sehingga memaksa thread worker Firecracker masuk ke kondisi
TASK_UNINTERRUPTIBLE(D-state) untuk menuliskan blok langsung ke NVMe. - Karena thread Firecracker tertahan di kernel host, I/O queue virtio-blk di dalam microVM menjadi jenuh dan kehabisan slot ring buffer (ring buffer starvation).
- MicroVM kehabisan buffer untuk memproses pesan baru dari jaringan. Watchdog proses pendeteksi kondisi darurat mengasumsikan kegagalan I/O lokal, lalu mengalami timeout.
Analisis Telemetri Kernel dan Reproduksi Masalah
biolatency. Hasil pengukuran menunjukkan latensi penulisan disk melonjak dari normal 80 mikrosekon menjadi ratusan milisekon, bahkan beberapa request tertahan hingga lebih dari 2 detik.
BASH
# Menjalankan profiling latensi blok I/O secara real-time pada host storage
sudo biolatency-bpfcc -m -T 5TEXT
msecs : count distribution
0 -> 1 : 4210 |*** |
2 -> 3 : 8940 |******* |
4 -> 7 : 15420 |************* |
8 -> 15 : 38920 |********************************* |
16 -> 31 : 46110 |****************************************|
32 -> 63 : 18450 |**************** |
64 -> 127 : 6200 |***** |
128 -> 255 : 1104 | |
256 -> 511 : 312 | |
512 -> 1023 : 88 | |
1024 -> 2047 : 14 | |/proc/vmstat:
BASH
# Memantau throttling I/O dan dirty pages pada kernel host
watch -n 1 'grep -E "nr_dirty|nr_writeback|nr_dirtied|nr_written" /proc/vmstat'nr_dirty melampaui jutaan blok, sementara laju penulisan disk fisik melambat karena storage controller mengalami internal garbage collection saturation pada layer flash NAND NVMe akibat pola I/O yang terfragmentasi.
Perbaikan Arsitektur: Isolasi I/O, Direct I/O WAL, dan Kernel Tuning
1. Re-tuning Subsystem Virtual Memory Kernel Host
dirty_background_ratio dan dirty_ratio diganti dengan perhitungan berbasis byte absolut agar flusher thread mulai menulis ke disk jauh sebelum dirty memory menumpuk dalam volume besar.
Konfigurasi /etc/sysctl.d/99-storage-latency.conf:
INI
# Mulai background writeback saat dirty memory mencapai 512 MB
vm.dirty_background_bytes = 536870912
# Paksa proses memblokir dan menulis langsung jika dirty memory menyentuh 2 GB
vm.dirty_bytes = 2147483648
# Percepat siklus pengecekan flusher thread (100 = 1 detik)
vm.dirty_writeback_centisecs = 100
# Kurangi usia maksimum halaman dirty di memori sebelum dipaksa flush (500 = 5 detik)
vm.dirty_expire_centisecs = 500
# Kurangi agresivitas reclaim swap untuk mencegah memory latency spike
vm.swappiness = 10sysctl --system, host tidak lagi menimbun puluhan gigabyte dirty memory, sehingga penulisan ke disk menjadi lebih rata dan teratur (smooth write stream).
2. Bypass Page Cache Melalui Direct I/O pada MicroVM Backing Storage
O_DIRECT. Dengan flag ini, I/O dari dalam microVM langsung dialirkan ke drive NVMe tanpa melintasi host page cache. Hal ini mengeliminasi masalah double caching (halaman tersimpan di guest page cache dan host page cache sekaligus).
Contoh konfigurasi disk block device pada Firecracker manifest:
JSON
{
"drive_id": "rootfs",
"path_on_host": "/srv/microvm/disks/tenant-store-42.ext4",
"is_root_device": true,
"is_read_only": false,
"io_engine": "Async",
"rate_limiter": {
"bandwidth": {
"size": 104857600,
"refill_time": 100
},
"ops": {
"size": 5000,
"refill_time": 100
}
}
}io_engine Async yang memanfaatkan io_uring pada kernel Linux modern, penerapan rate limiter internal pada Firecracker mencegah satu microVM tenant memonopoli bandwidth disk host saat diserang banjir paket telemetri.
3. Isolasi I/O via cgroups v2
io.weight dan io.latency:
BASH
# Membuat cgroup khusus untuk runtime microVM pengontrol keselamatan
sudo mkdir -p /sys/fs/cgroup/system.slice/safety-critical.slice
# Menetapkan bobot I/O lebih tinggi untuk critical safety microVM
echo "8:0 800" | sudo tee /sys/fs/cgroup/system.slice/safety-critical.slice/io.weight
# Menetapkan batas proteksi latensi target untuk NVMe device (8:0)
echo "8:0 target=5000" | sudo tee /sys/fs/cgroup/system.slice/safety-critical.slice/io.latency4. Optimalisasi Engine Serialisasi Database Embeeded
- State kompresor dievaluasi langsung di memori (in-memory state machine).
- Validasi keselamatan (safety gate) dieksekusi tanpa menunggu disk fsync.
- Log telemetri dialirkan ke WAL RocksDB dengan buffer asinkron, menggunakan direct allocator jemalloc dengan memory arena terisolasi guna menghindari konkurensi alokasi.
RUST
// Cuplikan inisialisasi RocksDB WAL options pada engine microVM
let mut opts = rocksdb::Options::default();
opts.create_if_missing(true);
opts.set_use_direct_io_for_flush_and_compaction(true);
opts.set_manual_wal_flush(true); // Hindari disk flush synchronous per record
opts.set_max_background_jobs(2);
opts.set_write_buffer_size(32 * 1024 * 1024); // 32MB MemTable bufferPerbandingan Performa Sebelum dan Sesudah Remediasi
| Metrik Evaluasi | Konfigurasi Awal (Default) | Konfigurasi Pasca-Remediasi | Dampak Operasional |
|---|---|---|---|
| Max Host Dirty Memory | 48.2 GB | 2.0 GB (dibatasi sysctl) | Mencegah pembekuan flusher kernel |
| p99 Disk Write Latency | 1.840 ms | 4.2 ms | Respons I/O tetap deterministik |
| virtio-blk Queue Drops | 64.210 drops/menit | 0 drops/menit | Antrean pesan microVM tidak tersumbat |
| CPU Time in D-State | 42.8% per host | < 0.5% per host | Thread bebas dari pemblokiran writeback |
| Latensi Eksekusi Safety Override | 14.200 ms (timeout) | 12 ms | Perintah defrost liar langsung dibatalkan |
| Throughput Serialisasi Disk | 4.100 IOPS (terfragmentasi) | 38.500 IOPS (sequential stream) | Peningkatan throughput hingga 9.3x |
