Server Rumahan & Self-Hosting

Resource Control systemd untuk Home Server - Beri Satu Service Batas Tanpa Menganggapnya Isolasi

Resource Control systemd untuk Home Server - Beri Satu Service Batas Tanpa Menganggapnya Isolasi

Home server sering meminta satu mesin kecil mengerjakan beberapa tugas sekaligus. Aplikasi web, database, generator thumbnail, dan background worker mungkin sama-sama tertib pada hari biasa. Pertanyaan sulit muncul ketika salah satunya tidak demikian: seberapa banyak resource mesin yang boleh dihabiskan satu service sebelum sistem operasi membatasinya?

Untuk service yang dikelola systemd, resource control menawarkan jawaban praktis. Mekanisme ini memakai Linux control groups, atau cgroups, untuk mencatat dan mengatur sebuah service sebagai satu kelompok proses. Ini dapat menyisakan ruang bagi SSH, database, atau pekerjaan penting lainnya. Namun, batas tersebut tidak membuktikan bahwa service yang dibatasi aman, sehat, atau cepat. Limit adalah batas penggunaan resource, bukan security sandbox atau obat untuk memory leak.

Model mental yang berguna: anggaran rumah tangga, bukan mesin pribadi

Linux cgroups mengatur proses dalam sebuah hierarki. Limit dan accounting dapat diterapkan pada sebuah kelompok beserta turunannya, dan parent dapat memberlakukan batas yang lebih ketat daripada permintaan child. systemd memetakan unit dan slice ke hierarki tersebut, lalu menyediakan pengaturan resource dalam unit file. Dokumentasi resource control systemd menjelaskan hubungan ini secara langsung.

Ada dua jenis control yang perlu dibedakan:

  • Weight membagi kapasitas yang diperebutkan. Service dengan CPUWeight= lebih rendah menerima porsi lebih kecil daripada sibling ketika semuanya membutuhkan waktu CPU. Weight bukan reservasi maupun hard ceiling. Jika tidak ada pihak lain yang membutuhkan CPU, service tersebut tetap dapat memakai kapasitas yang tersedia.
  • Ceiling menghentikan penggunaan pada sebuah batas. CPUQuota=, MemoryMax=, dan TasksMax= menerapkan jenis maksimum yang berbeda. Ceiling dapat melindungi bagian host lainnya, tetapi workload yang dibatasi bisa melambat atau gagal saat mencapai batas itu.

Perbedaan ini mencegah kesalahan konfigurasi yang umum. CPUWeight=50 bukan berarti “50 persen CPU.” Sebaliknya, CPUQuota=50% bukan berarti “setengah dari setiap CPU di mesin.” systemd mendefinisikan quota 100% relatif terhadap kapasitas satu CPU, dan nilai di atas 100% dapat mengizinkan waktu CPU pada lebih dari satu CPU.

Ukur sebelum memilih angka

Tidak ada limit memory universal yang bisa dipertanggungjawabkan untuk “PHP worker” atau “image service.” Setiap workload memiliki steady state dan lonjakan yang sah berbeda-beda. Host juga memerlukan ruang untuk kernel, filesystem cache, login session, serta service di luar unit yang sedang diatur. Mulailah dengan mengamati operasi normal dan operasi berat yang memang disengaja, lalu tentukan jenis penurunan layanan yang masih dapat diterima.

Command berikut memberikan sudut pandang berbeda terhadap sebuah service yang sudah ada:

systemctl status example-worker.service
systemctl show example-worker.service \
  -p MemoryCurrent -p MemoryPeak -p MemoryHigh -p MemoryMax \
  -p CPUUsageNSec -p CPUQuotaPerSecUSec \
  -p TasksCurrent -p TasksMax
systemd-cgtop
journalctl -u example-worker.service --since today

systemctl show ditujukan untuk memeriksa property yang dinormalisasi dan runtime state. systemd-cgtop menyediakan tampilan control group secara live, walaupun kolom memory dan I/O dapat tidak lengkap ketika accounting terkait belum diaktifkan. Metric pada tingkat aplikasi tetap penting: grafik memory rendah tidak menunjukkan apakah request mengalami timeout atau pekerjaan berguna benar-benar selesai.

Sampel singkat tidak cukup untuk job musiman, backup, import, atau batch thumbnail. Catat peak yang representatif dari waktu ke waktu. Sisakan margin untuk variasi. Yang lebih penting, tentukan sejak awal apakah throttling, pekerjaan yang ditolak, atau service yang berhenti lebih baik daripada tekanan pada seluruh host.

Contoh drop-in yang konservatif

Anggaplah hasil observasi menunjukkan bahwa worker ilustratif biasanya berada di bawah 512 MiB, kadang membutuhkan lebih banyak, dan tidak boleh menghabiskan memory tanpa hard boundary. Sebuah drop-in dapat terlihat seperti ini:

[Service]
MemoryHigh=512M
MemoryMax=768M
MemorySwapMax=256M
CPUWeight=50
CPUQuota=100%
TasksMax=200

Nilai tersebut adalah contoh, bukan rekomendasi. Menyalinnya tanpa mengukur workload yang sebenarnya hanya mengganti satu tebakan dengan tebakan lain.

Buat override dengan:

sudo systemctl edit example-worker.service

Secara default, systemctl edit membuat drop-in alih-alih mengganti vendor unit, lalu me-reload konfigurasi manager setelah edit berhasil. Dengan demikian, kebijakan lokal tetap terpisah dari file yang dikelola package. Periksa hasil gabungannya sebelum me-restart apa pun:

systemctl cat example-worker.service
systemctl show example-worker.service \
  -p MemoryHigh -p MemoryMax -p MemorySwapMax \
  -p CPUWeight -p CPUQuotaPerSecUSec -p TasksMax

Untuk unit file yang dipelihara sebagai code, jalankan systemd-analyze verify terhadap file tersebut sebelum instalasi. Command ini dapat menemukan directive yang tidak dikenal, section yang tidak valid, serta beberapa dependency atau command yang hilang. Namun, ia tidak dapat menentukan apakah 768 MiB cukup untuk production import.

systemd-analyze verify ./example-worker.service

Terapkan restart hanya pada waktu ketika interupsi dapat diterima:

sudo systemctl restart example-worker.service
systemctl status example-worker.service
journalctl -u example-worker.service --since "5 minutes ago"

Tradeoff sebenarnya dari setiap pengaturan

MemoryHigh=: tekanan sebelum kegagalan

MemoryHigh= adalah threshold untuk throttling. Perilaku yang didokumentasikan memungkinkan penggunaan melampaui nilai tersebut jika tidak dapat dihindari, sementara reclaim menjadi agresif dan proses sangat diperlambat. systemd merekomendasikannya sebagai mekanisme utama untuk mengendalikan penggunaan memory sebuah unit. Ini membuatnya berguna sebagai zona tekanan awal, tetapi tidak cocok ketika diperlukan batas absolut.

MemoryMax=: pertahanan terakhir, bukan yang pertama

MemoryMax= adalah limit memory absolut. Jika kernel tidak dapat menjaga unit di bawahnya, out-of-memory handling dijalankan di dalam unit. Hal ini dapat menjaga host yang lebih luas sambil menyebabkan pekerjaan dalam unit gagal. Karena itu, dokumentasi merekomendasikan MemoryHigh= sebagai control utama dan MemoryMax= sebagai pertahanan terakhir.

Jarak antara kedua nilai itu disengaja: workload mendapat zona tekanan sebelum hard boundary. Seberapa besar jaraknya tetap merupakan keputusan berdasarkan workload, bukan rumus yang diberikan systemd.

MemorySwapMax=: ruang swap yang terpisah

MemorySwapMax= membatasi penggunaan swap unit secara terpisah. Nilai yang lebih kecil dapat mencegah satu service memenuhi swap dan membuat host sangat lambat merespons. Namun, ini juga menghilangkan jalan keluar dari tekanan memory, sehingga service dapat mengalami kegagalan lebih cepat. “Tanpa swap” tidak otomatis lebih aman; pilihan itu mengubah tradeoff.

CPUWeight= dan CPUQuota=: prioritas versus batas

Gunakan weight ketika tujuannya adalah fairness relatif saat terjadi perebutan resource. Gunakan quota ketika service tidak boleh melampaui batas waktu CPU meskipun mesin sedang tidak sibuk. Hard quota dapat menambah latency dan mengurangi throughput, khususnya untuk pekerjaan yang bursty. Menggabungkan keduanya bisa masuk akal, tetapi masing-masing harus menjawab pertanyaan kebijakan yang berbeda.

TasksMax=: perlindungan dari fan-out tanpa batas

TasksMax= membatasi task dalam unit melalui cgroup PIDs controller. Dalam konteks ini, thread dihitung satu per satu. Karena itu, runtime multithreaded dapat mendekati batas dengan jumlah proses yang terlihat jauh lebih sedikit daripada angka tersebut. Tetapkan nilainya dari concurrency yang teramati ditambah headroom yang disengaja, bukan hanya dari jumlah proses.

Amati perilaku efektif, bukan hanya file

Drop-in yang benar secara syntax hanyalah awal. Setelah aktivasi, periksa property efektif, jalankan operasi yang representatif, dan amati log serta hasil pada tingkat service. Manual cgroups menjelaskan mengapa hierarki penting: limit yang lebih tinggi dalam tree membatasi turunannya. Karena itu, sebuah unit dapat menerima lebih sedikit daripada yang tampak di konfigurasi lokalnya.

Perhatikan beberapa sinyal kegagalan:

  • request atau job memerlukan waktu lebih lama setelah CPU throttling;
  • tekanan memory menyebabkan reclaim berulang, OOM event, atau restart;
  • pembuatan thread atau proses gagal saat mendekati TasksMax=;
  • restart policy mengubah kegagalan resource menjadi restart loop;
  • service lain atau parent slice sudah menerapkan limit yang lebih ketat.

Jika memungkinkan, ubah satu kebijakan dalam satu waktu. Jika service menurun, longgarkan atau hapus batas terkait dan selidiki kebutuhan yang mendasarinya. Tujuannya bukan membuat grafik terlihat rapi. Tujuannya adalah memilih komponen mana yang akan menanggung tekanan ketika kapasitas mesin terbatas.

Apa yang tidak diberikan control ini

Resource limit kadang digambarkan sebagai cara untuk “menahan” service, tetapi kata tersebut dapat menyembunyikan beberapa gagasan berbeda. Control CPU dan memory tidak membatasi file mana yang dapat dibaca proses, tujuan jaringan mana yang dapat dihubungi, atau system call mana yang dapat dijalankan. Itu merupakan pertanyaan security dan sandboxing yang terpisah. Proses yang telah disusupi tetap dapat berbahaya meskipun berada di bawah 512 MiB.

Limit juga tidak menggantikan capacity planning atau perbaikan aplikasi. Jika traffic biasa memang membutuhkan memory melebihi yang dapat disediakan host, ceiling yang lebih ketat hanya memilih kegagalan yang lebih lokal. Pada shared home server, itu mungkin tetap menjadi keputusan operasional yang tepat, tetapi konsekuensinya perlu dijelaskan dengan jujur.

Checklist awal yang hati-hati

  1. Konfirmasi versi systemd dan apakah mesin memakai cgroup v2; baca dokumentasi yang sesuai dengan distribusi terpasang.
  2. Amati steady state dan lonjakan yang representatif sebelum memilih nilai.
  3. Tentukan apakah setiap pengaturan menyatakan prioritas relatif, tekanan lunak, atau hard ceiling.
  4. Gunakan drop-in alih-alih mengedit vendor unit secara langsung.
  5. Validasi syntax, periksa unit gabungan, dan jadwalkan restart dengan sengaja.
  6. Uji pekerjaan yang berguna, bukan sekadar apakah proses tetap berstatus “active.”
  7. Amati log dan property efektif, lalu revisi limit ketika bukti berubah.

Pada server kecil, resource boundary dapat menjadi bentuk kerendahan hati yang berguna: tidak ada satu service pun yang dianggap berhak menguasai seluruh mesin. Bagian sulitnya bukan menulis MemoryMax=. Bagian sulitnya adalah memilih batas kegagalan dari observasi nyata, lalu memeriksa apakah perlindungan yang diperoleh host sepadan dengan biaya yang ditanggung service.

References