SSD Nodes Learn 🎉 VPS dari $5.50/bln
Panduan Matt ConnorOleh Matt Connor

Cara Urus Log Sendiri pada Satu VPS

Ketahui cara mengurus log pada satu VPS menggunakan journald, logrotate, Loki atau OpenSearch. Kami bandingkan penggunaan RAM dan aturan pengekalan data untuk pelayan kecil.

Kos sebenar pengurusan log yang dihoskan sendiri pada satu VPS

Pengurusan log yang dihoskan sendiri pada satu VPS (virtual private server) berbalik kepada satu soalan tunggal: adakah anda memerlukan kluster carian, atau adakah anda hanya memerlukan putaran log dan grep? Kebanyakan panduan vendor menjawab soalan itu dengan bermula pada tiga nod dan 12 GB RAM sebelum satu baris log pun dihantar. Pada satu pelayan, jawapan tersebut tidak berguna, jadi perbandingan di bawah adalah berdasarkan keperluan setiap pilihan daripada sebuah kotak kecil sebelum ia menyimpan apa-apa data.

Jika anda menjalankan satu atau dua pelayan dan anda ingin mengetahui apa yang berlaku pada hari Selasa lepas, systemd-journald dan logrotate sudah pun melakukan tugas itu, dan anda boleh berhenti selepas bahagian seterusnya. Jika beberapa mesin perlu menghantar log ke satu tempat dengan keupayaan carian merentasi tempoh beberapa minggu, Grafana Loki sesuai untuk kotak kecil, kerana ia mengindeks label dan bukannya teks baris tersebut. Elasticsearch dan OpenSearch memberikan anda carian teks penuh yang sebenar, dan ia mengenakan kos dalam bentuk memori, kerana heap JVM (Java virtual machine) mempunyai had minimum yang tidak boleh dikurangkan.

Mulakan dengan journald, kerana kebanyakan orang berhenti di sini

systemd-journald sudah berjalan pada mana-mana pelayan Ubuntu atau Debian semasa. Ia menangkap output standard bagi setiap unit servis, mesej kernel, dan apa sahaja yang dihantar ke syslog. Empat arahan merangkumi kebanyakan insiden.

journalctl -u nginx.service --since "2026-08-14 09:00" --until "2026-08-14 10:00"
journalctl -p err -b
journalctl -f -u ssh.service
journalctl --disk-usage

Arahan terakhir mencetak baris seperti Archived and active journals take up 1.1G in the file system.. Itu adalah nombor yang menentukan sama ada anda memerlukan perkara lain. Jika ia membaca beberapa ratus megabait dan anda boleh mencari apa yang anda perlukan dengan -u dan --since, anda sudah selesai.

Sama ada jurnal bertahan selepas but semula bergantung pada Storage= dan sama ada /var/log/journal wujud. Dengan tetapan Storage=auto yang biasa, journald menulis ke /var/log/journal apabila direktori itu hadir, dan ke /run/log/journal apabila ia tidak hadir. /run disokong oleh memori, jadi pada kotak tanpa direktori tersebut, setiap log dipadamkan semasa but semula, iaitu saat tepat anda ingin membacanya. Imej Ubuntu menyertakan direktori tersebut. Imej minimal dan berasaskan kontena selalunya tidak.

ls -d /var/log/journal
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usage

Selepas but semula, journalctl --disk-usage sepatutnya melaporkan saiz di bawah /var/log/journal dan bukannya /run. Nilai lalai sudah dihadkan, yang merupakan sebab utama journald adalah jawapan yang serius dan bukan sekadar sandaran. Halaman manual journald.conf menetapkan SystemMaxUse= kepada 10% daripada saiz sistem fail dan SystemKeepFree= kepada 15%, serta mengehadkan setiap lalai yang dikira pada 4G. SystemMaxFileSize= secara lalainya adalah satu perlapan daripada SystemMaxUse=, dihadkan pada 128M, jadi anda biasanya menyimpan tujuh fail yang diputar. MaxRetentionSec= secara lalainya adalah 0, yang mematikan pemadaman berasaskan umur. Baca lalai terakhir itu sekali lagi: secara lalai, jurnal hanya dihadkan oleh saiz, bukan oleh umur.

[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30day

Tulis itu ke /etc/systemd/journald.conf.d/99-size.conf, mulakan semula journald, kemudian semak sama ada journalctl --disk-usage bergerak ke arah had baharu anda. Untuk menuntut semula ruang sekarang dan bukannya menunggu putaran seterusnya, jalankan sudo journalctl --vacuum-size=500M atau sudo journalctl --vacuum-time=14d. Kedua-duanya mencetak setiap fail yang mereka alih keluar, jadi pelaksanaan senyap bermakna tiada apa yang perlu dipadamkan.

Segala-galanya di luar jurnal, seperti /var/log/nginx/access.log, adalah tugas logrotate, dan ia berjalan setiap hari daripada pemasa systemd. Satu kegagalan perlu diketahui kerana ia kelihatan seperti pepijat dalam df. Selepas putaran, fail lama hilang daripada senarai direktori sementara daemon masih membukanya, jadi df -h melaporkan cakera penuh manakala du -sh /var/log melaporkan jauh lebih sedikit. Ruang tersebut kembali hanya apabila proses membuka semula lognya, iaitu tujuan baris muat semula postrotate dalam konfigurasi. sudo lsof -nP +L1 menyenaraikan fail yang dipadamkan yang masih dibuka, dan menamakan proses yang memegang setiap satu daripadanya. Uji peraturan tanpa menyentuh apa-apa menggunakan sudo logrotate -d /etc/logrotate.d/nginx.

Menghantar log daripada beberapa pelayan ke satu pengumpul

Apabila terdapat lebih daripada satu mesin, mengurus beberapa pelayan Linux serentak menjadi lebih mudah apabila lognya tiba di satu lokasi. rsyslog sudah dipasang pada kebanyakan pengedaran, jadi pengumpul pusat yang paling murah ialah satu fail pada setiap penghantar.

*.* action(type="omfwd" target="logs.example.com" port="514" protocol="tcp")

Simpan fail tersebut sebagai /etc/rsyslog.d/50-forward.conf, semak dengan sudo rsyslogd -N1 yang mengesahkan konfigurasi dan keluar tanpa memulakan apa-apa, kemudian mulakan semula rsyslog. Pada pengumpul, aktifkan input TCP.

module(load="imtcp")
input(type="imtcp" port="514")

Dua amaran, kedua-duanya bersifat mekanikal. Syslog biasa tidak membawa penyulitan dan tiada pengesahan, jadi sesiapa yang boleh mencapai port 514 boleh menyuntik baris log yang kelihatan sama seperti milik anda. Ikat (bind) ia kepada rangkaian peribadi atau VPN dan pasang firewall pada port tersebut. Kedua, baris gilir tindakan lalai berada dalam memori, jadi apabila pengumpul tidak dapat dicapai, baris gilir akan penuh dan mesej akan digugurkan tanpa salinan disimpan. rsyslog mendokumentasikan baris gilir bantuan cakera untuk kes tersebut dalam tutorial penghantaran boleh harap mereka.

Mengapa ELK stack tidak sesuai untuk VPS kecil

ELK bermaksud Elasticsearch untuk storan dan carian, Logstash untuk saluran penghantaran data, dan Kibana untuk antara muka. Asasnya ialah JVM heap, dan ia ditetapkan sebelum sebarang log tiba.

Dokumentasi Elastic menyatakan untuk menetapkan heap tidak melebihi 50% daripada jumlah memori yang tersedia untuk setiap nod Elasticsearch, kerana proses tersebut juga menggunakan penimbal luar heap dan bergantung pada cache fail sistem pengendalian untuk membaca fail indeks dengan pantas. Jadi, heap 2 GB memerlukan mesin 4 GB, itu belum termasuk Kibana, dan belum termasuk aplikasi yang sebenarnya ingin dijalankan pada pelayan tersebut. Elastic juga menyatakan bahawa Elasticsearch menetapkan saiz heap secara automatik berdasarkan peranan nod dan jumlah memori, yang bermaksud kotak kecil akan mendapat heap kecil dan kemudian menghabiskan masanya melakukan garbage collection.

Logstash adalah bahagian yang membebankan bajet kecil secara langsung. Halaman tetapan JVM Elastic sendiri mengesyorkan heap tidak kurang daripada 4GB dan tidak melebihi 8GB untuk penghantaran data biasa. Itu adalah keseluruhan kapasiti VPS 4 GB, hanya untuk satu proses di tengah-tengah saluran penghantaran.

ChartDocumented JVM heap settings, from each project's own docs
The data behind this chart
[
  {
    "label": "Loki plus Alloy (no JVM)",
    "documented_heap_mb": 0
  },
  {
    "label": "OpenSearch demo compose",
    "documented_heap_mb": 512
  },
  {
    "label": "OpenSearch production example",
    "documented_heap_mb": 2048
  },
  {
    "label": "Logstash recommended minimum",
    "documented_heap_mb": 4096
  }
]

Itu adalah nilai yang diterbitkan oleh setiap projek dalam dokumentasi masing-masing. Ia bukan ukuran yang diambil pada kotak ujian, dan beban kerja anda akan mengubahnya. Fail compose contoh OpenSearch menetapkan 512 MB setiap nod untuk demo dan 2048 MB dalam contoh pengeluaran, manakala had bawah yang disyorkan untuk Logstash ialah 4096 MB. Lajur heap menunjukkan 0 untuk Loki dan Alloy kerana ia adalah program Go tanpa JVM heap untuk dikhaskan. Itulah perbezaan keseluruhan dalam satu nombor: komponen JVM mengambil tempahan memorinya sama ada log tiba atau tidak.

Jika anda tetap mahukan Elastic stack pada satu pelayan kecil, buang Logstash dan hantar terus ke Elasticsearch menggunakan pengumpul yang ringan. Logstash wujud untuk menghurai dan mengubah data pada volum tinggi, dan pada satu kotak anda boleh melakukan kerja itu di bahagian tepi (edge) atau melangkauinya.

Kedua-dua Elasticsearch dan OpenSearch juga memerlukan vm.max_map_count ditingkatkan kepada 262144, kerana ia memetakan fail indeks ke dalam memori dan had lalai Linux terlalu rendah untuknya. Bekas (container) yang keluar beberapa saat selepas dimulakan pada kotak baharu biasanya disebabkan oleh perkara ini dan tiada sebab lain.

OpenSearch atau Elasticsearch: yang mana satu boleh anda gunakan?

Sejarah ringkas lesen, kerana ia menentukan apa yang dibenarkan untuk anda jalankan. Pada Januari 2021, Elastic menukar Elasticsearch dan Kibana daripada Apache 2.0 kepada model dwi-lesen SSPL (server side public license) dan Elastic License 2.0. AWS melakukan fork pada kod Apache 2.0 terakhir sebagai OpenSearch, yang kekal di bawah Apache 2.0. Pada September 2024, Elastic menambah AGPLv3 (GNU Affero General Public License version 3) sebagai pilihan lain untuk kod sumber percuma. Bagi individu yang melakukan self-hosting pada satu VPS, setiap lesen tersebut membenarkan apa yang anda lakukan. Lesen-lesen ini menjadi isu apabila anda menawarkan perisian tersebut kepada orang lain sebagai perkhidmatan terurus.

Perbezaan praktikal pada pelayan kecil adalah lebih kecil daripada sejarahnya, kerana kedua-duanya menggunakan enjin yang sama di bawahnya. Namanya berbeza: kitaran hayat indeks ialah ISM (index state management) dalam OpenSearch dan ILM (index lifecycle management) dalam Elasticsearch. Sehingga Ogos 2026, OpenSearch 2.12 dan versi seterusnya enggan bermula tanpa kata laluan pentadbir ditetapkan pada permulaan pertama.

sudo sysctl -w vm.max_map_count=262144
printf 'vm.max_map_count = 262144\n' | sudo tee /etc/sysctl.d/99-opensearch.conf
docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" \
  -e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<custom-admin-password>" \
  opensearchproject/opensearch:latest

Baris sysctl -w menggunakan tetapan tersebut sekarang dan fail dalam /etc/sysctl.d/ adalah bahagian yang kekal selepas reboot. Semak sama ada kontena telah naik dengan curl -k -u admin:<password> https://localhost:9200. Ia menjawab melalui https menggunakan sijil demo, jadi -k melangkau pengesahan, dan balasan yang sihat ialah blok JSON kecil yang menamakan kluster dan versinya. Halaman pemasangan OpenSearch juga memberitahu pengguna Docker Desktop untuk memperuntukkan sekurang-kurangnya 4 GB memori kepada hos, yang merupakan petunjuk jelas tentang jangkaan sumber oleh proses tersebut.

Bagaimana Loki kekal kecil: label berbanding indeks teks penuh

Loki mengekalkan satu indeks ke atas label dan menyimpan baris log sebagai ketulan (chunks) yang dimampatkan. Pertanyaan (query) memilih strim terlebih dahulu dan menapis teks kemudian. {unit="ssh.service"} |= "Failed password" memilih strim berdasarkan labelnya, kemudian mengimbas ketulan tersebut untuk mencari rentetan (string) yang dikehendaki. Tiada apa-apa yang mengindeks kandungan baris, jadi proses penyerapan (ingestion) kekal murah dan tiada indeks songsang (inverted index) yang perlu disimpan dalam memori. Kos beralih kepada masa pertanyaan, dan ini merupakan pertukaran yang baik apabila anda biasanya mengetahui servis mana yang sedang diperiksa.

Dokumentasi Grafana meletakkan mod monolitik, yang bermaksud keseluruhan Loki berada dalam satu proses dengan -target=all, pada volum baca dan tulis kecil sehingga kira-kira 20GB sehari. Satu VPS berada dalam julat kapasiti tersebut.

Perangkapnya ialah kardinaliti label. Setiap kombinasi nilai label yang berbeza adalah satu strim, dan bilangan strim memacu penggunaan memori serta saiz indeks Loki. Label yang menyimpan alamat IP pelanggan atau pengecam permintaan akan mencipta satu strim bagi setiap nilai, jadi pelayan web yang sibuk boleh menghasilkan puluhan ribu strim dalam sehari dan proses tersebut akan membesar sehingga kernel menghentikannya. Pastikan label terhad kepada nilai yang boleh anda kira di atas kertas: unit, host, job, level. Letakkan perincian berubah-ubah di dalam baris itu sendiri, di mana ungkapan penapis (filter expression) akan mencarinya semasa masa pertanyaan.

Memasang Loki dan Alloy pada satu VPS

Dua proses melaksanakan kerja ini. Loki menyimpan dan menjawab pertanyaan. Grafana Alloy membaca log dan menghantarnya. Promtail dahulunya digunakan sebagai penghantar, dan ia mencapai penghujung hayat pada 2 Mac 2026, jadi pemasangan baharu kini menggunakan Alloy dan contoh Docker Loki sendiri kini menyertakan konfigurasi Alloy.

wget https://raw.githubusercontent.com/grafana/loki/v3.7.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml

Baca fail tersebut sebelum menggunakannya. Ia menetapkan path_prefix: /tmp/loki dengan ketulan (chunks) di bawah /tmp/loki/chunks, yang betul untuk demo tetapi salah untuk pelayan: tiada apa-apa di bawah /tmp bekas akan kekal apabila bekas dicipta semula, jadi sejarah anda akan hilang pada kemas kini imej seterusnya. Halakan ia ke laluan yang anda lekapkan (mount).

common:
  instance_addr: 127.0.0.1
  path_prefix: /loki
  storage:
    filesystem:
      chunks_directory: /loki/chunks
      rules_directory: /loki/rules
  replication_factor: 1
  ring:
    kvstore:
      store: inmemory
docker volume create loki-data
docker run --name loki -d \
  -v $(pwd):/mnt/config -v loki-data:/loki \
  -p 127.0.0.1:3100:3100 \
  grafana/loki:3.7.0 -config.file=/mnt/config/loki-config.yaml
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3100/ready

Perintah terakhir itu sepatutnya mencetak 200, kerana /ready mengembalikan HTTP 200 sebaik sahaja Loki sedia menerima trafik. Sebarang hasil lain bermakna proses masih bermula atau konfigurasi ditolak, dan docker logs loki menyatakan puncanya. Dua perincian dalam perintah run adalah disengajakan. Port diterbitkan pada 127.0.0.1 sahaja, kerana konfigurasi contoh membawa auth_enabled: false dan Loki tidak menyertakan pengesahan pengguna sendiri, jadi sesiapa yang boleh mencapai port 3100 boleh membaca setiap log dan menulis log palsu. Pastikan ia pada loopback, atau di sebalik VPN atau reverse proxy yang mempunyai pengesahan. Volume bernama adalah penting kerana imej berjalan sebagai pengguna loki dengan UID 10001, jadi direktori hos yang dilekapkan (bind mount) yang dimiliki oleh root tidak boleh ditulis oleh bekas tersebut.

sudo apt-get update && sudo apt-get install -y gpg wget
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" \
  | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y alloy

Alloy membaca /etc/alloy/config.alloy. Fail ini mengambil journal sistem dan satu set fail, kemudian menghantar kedua-duanya ke Loki tempatan.

loki.write "local" {
  endpoint {
    url = "http://127.0.0.1:3100/loki/api/v1/push"
  }
}

loki.relabel "journal" {
  forward_to = []
  rule {
    source_labels = ["__journal__systemd_unit"]
    target_label  = "unit"
  }
}

loki.source.journal "read" {
  forward_to    = [loki.write.local.receiver]
  relabel_rules = loki.relabel.journal.rules
  labels        = {job = "systemd-journal", host = "app-01"}
}

local.file_match "nginx" {
  path_targets = [{"__path__" = "/var/log/nginx/*.log", "job" = "nginx", "host" = "app-01"}]
}

loki.source.file "nginx" {
  targets    = local.file_match.nginx.targets
  forward_to = [loki.write.local.receiver]
}

Peraturan relabel menyalin medan journal __journal__systemd_unit ke dalam label bernama unit, yang menjadikan {unit="ssh.service"} berfungsi kemudian. Tanpa peraturan itu, nama unit berada di dalam entri dan bukannya dalam label, jadi anda tidak boleh membuat pemilihan berdasarkan unit tersebut dan setiap pertanyaan perlu mengimbas segala-galanya.

sudo systemctl reload alloy
systemctl show -p User alloy
sudo journalctl -n 5
sudo -u alloy journalctl -n 5

Di sinilah kebanyakan persediaan terhenti. Alloy berjalan sebagai akaun servisnya sendiri, bukan sebagai root, dan membaca journal sistem memerlukan keahlian kumpulan systemd-journal, manakala fail di bawah /var/log/nginx dimiliki oleh kumpulan adm pada Debian dan Ubuntu. Gantikan akaun yang dicetak oleh systemctl show ke dalam perintah terakhir. Jika ia mengembalikan entri yang jauh lebih sedikit daripada jalankan root, akaun tersebut tidak boleh membaca journal sistem, dan Loki akan kekal kosong walau betapa betul pun konfigurasi anda. Tambahkan kumpulan tersebut dan mulakan semula dengan sudo usermod -aG systemd-journal,adm alloy diikuti oleh sudo systemctl restart alloy.

curl -G -s "http://127.0.0.1:3100/loki/api/v1/query_range" \
  --data-urlencode 'query={job="systemd-journal"}' \
  --data-urlencode 'limit=5' | jq '.data.result | length'

Nombor melebihi 0 bermakna aliran (streams) wujud dengan label tersebut dan mengandungi entri. 0 bermakna tiada apa-apa yang tiba di bawah label tersebut lagi. Satu tetapan lalai menjelaskan penggera palsu yang biasa: loki.source.journal menetapkan max_age kepada 7h, jadi permulaan baharu membaca tujuh jam terakhir journal dan tiada yang lebih lama. Untuk antara muka manusia, jalankan Grafana pada kotak yang sama dan halakan sumber data Loki ke http://127.0.0.1:3100.. Log bekas memerlukan sumber yang berbeza: Alloy menemui bekas Docker yang sedang berjalan dan mengekorinya (tail), itulah yang dilakukan oleh contoh permulaan Loki sendiri, dan pada kluster k3s nod tunggal pada VPS tugasan itu beralih ke direktori log pod yang ditulis oleh kubelet.

Pengekalan: tentukan tempoh hayat log anda

Hampir tiada sesiapa yang menetapkan tempoh pengekalan sehingga cakera penuh, dan biasanya mereka melakukannya pada pukul 3 pagi semasa servis tergendala. Tentukan tempoh ini pada hari pertama berdasarkan dua soalan: sejauh mana anda benar-benar perlu menyemak log, dan apakah yang mesti ada semasa semakan insiden pada bulan hadapan. Untuk pelayan tunggal, 14 hingga 30 hari adalah jawapan bagi kedua-dua soalan tersebut.

Loki tidak memadamkan apa-apa sehingga anda mendayakan compactor. Pengekalan dinyahdayakan secara lalai, yang sering mengejutkan pengguna apabila storan mereka penuh sementara retention_period dibiarkan dalam konfigurasi tanpa melakukan apa-apa.

limits_config:
  retention_period: 744h

compactor:
  working_directory: /loki/retention
  compaction_interval: 10m
  retention_enabled: true
  retention_delete_delay: 2h
  retention_delete_worker_count: 150
  delete_request_store: filesystem

744h bersamaan dengan 31 hari. Empat peraturan yang didokumentasikan mengawal blok tersebut:

  • Pengekalan dilaksanakan oleh compactor, dan dokumentasi Grafana menyatakan untuk menjalankan compactor sebagai satu instans sahaja. Pada satu VPS, perkara ini berlaku secara automatik.
  • Tempoh pengekalan minimum ialah 24h, dan pengekalan hanya berfungsi apabila tempoh indeks adalah 24h. Contoh schema_config sudah menggunakan period: 24h, jadi jangan ubah nilainya.
  • delete_request_store diperlukan sebaik sahaja retention_enabled ditetapkan kepada true. Ia menamakan stor yang menyimpan permintaan pemadaman, jadi pada nod tunggal yang disokong oleh sistem fail, ia sepadan dengan object_store: filesystem yang sudah ada dalam skema.
  • Chunks ditanda terlebih dahulu dan dialih keluar selepas retention_delete_delay, iaitu 2h dalam kes ini, jadi ruang kosong akan kembali lewat daripada yang dijangkakan oleh polisi. Jangan nilai tetapan tersebut melalui df lima minit selepas memuat semula.

OpenSearch memadamkan keseluruhan indeks dan bukannya baris individu, itulah sebabnya indeks log dicipta setiap hari. Polisi ISM akan membawa indeks melalui pelbagai keadaan dan memadamkannya sebaik sahaja ia cukup lama, dan ism_template akan melampirkan polisi tersebut pada indeks baharu supaya anda tidak perlu mengingatinya.

Polisi ISM yang memadamkan indeks log selepas 14 hari
{
  "policy": {
    "description": "delete log indexes after 14 days",
    "default_state": "hot",
    "states": [
      {
        "name": "hot",
        "actions": [],
        "transitions": [
          { "state_name": "delete", "conditions": { "min_index_age": "14d" } }
        ]
      },
      {
        "name": "delete",
        "actions": [ { "delete": {} } ],
        "transitions": []
      }
    ],
    "ism_template": { "index_patterns": ["logs-*"], "priority": 100 }
  }
}

Ciptakannya dengan arahan PUT ke _plugins/_ism/policies/logs-retention. Templat ini terpakai pada indeks yang dicipta selepas polisi wujud, jadi mana-mana indeks yang sudah ada pada cakera perlu dilampirkan polisi tersebut secara manual.

Walau apa pun sistem yang anda jalankan, nombor pengekalan hanya berguna jika disokong oleh pemeriksaan ruang kosong. Memadamkan log pada hari ke-14 tidak akan membantu jika log selama 10 hari sudah memenuhi volum, jadi gandingkan polisi tersebut dengan pemantauan kesihatan cakera pada VPS dan makluman pada penggunaan 80%.

Berapakah saiz cakera bagi setiap GB log

Jawapan jujur bergantung pada baris dan medan anda, jadi ukurlah berdasarkan data anda sendiri dan jangan bergantung pada nisbah yang diterbitkan. Mekanismenya cukup berbeza untuk meramalkan arah aliran. OpenSearch dan Elasticsearch menulis inverted index bagi setiap medan yang diindeks di samping dokumen yang disimpan, jadi apa yang disimpan pada cakera adalah lebih besar daripada teks asal, dan setiap replika akan menggandakannya. Pada satu nod, tetapkan kiraan replika kepada 0, kerana shard replika pada nod yang sama tidak dapat bertahan jika nod tersebut gagal: membiarkannya pada 1 akan menggandakan penggunaan cakera dan mengekalkan kesihatan kluster pada tahap kuning selama-lamanya. Loki menulis ketulan (chunks) yang dimampatkan berserta indeks label yang kecil, jadi jejaknya mengikut saiz baris yang telah dimampatkan.

sudo du -sh /var/lib/docker/volumes/loki-data/_data
curl -k -u admin:<password> "https://localhost:9200/_cat/indices?v&h=index,docs.count,store.size"

Jalankan mana-mana yang berkenaan selama dua hari berturut-turut. Perbezaannya ialah pertumbuhan harian anda. Darabkan dengan hari pengekalan anda, tambah kira-kira 30% ruang tambahan untuk pemadatan (compaction) dan penggabungan, kemudian bandingkan dengan jumlah volum. Jika ia tidak muat, kurangkan tempoh pengekalan sebelum anda membeli cakera, kerana volum yang lebih besar hanya menangguhkan masalah yang sama beberapa minggu sahaja.

Perkara yang gagal dahulu pada pelayan kecil

Memori akan habis dahulu. Kernel OOM (out of memory) killer akan memilih proses yang besar, dan proses paling besar pada pelayan log biasanya adalah JVM. journalctl -k | grep -i "killed process" menunjukkan proses yang ditamatkan dengan nama proses di dalam kurungan. Mangsanya tidak semestinya tindanan log: sshd atau pangkalan data anda mungkin dipilih sebaliknya, yang menyebabkan eksperimen log menjatuhkan aplikasi yang anda ingin pantau lognya. Berikan had yang jelas kepada kontena supaya kegagalan berlaku di tempat yang anda tentukan, itulah tujuan had memori dalam Docker Compose.

Cakera akan penuh seterusnya, dan enjin carian akan gagal dengan cara yang khusus dan boleh dikenal pasti. Elasticsearch dan OpenSearch memantau penggunaan cakera pada beberapa tahap. Tanda aras rendah (low watermark) berada pada 85% dan tanda aras tinggi (high watermark) pada 90%. Pada tahap banjir (flood stage) 95%, setiap indeks dengan shard pada nod tersebut akan menerima sekatan index.blocks.read_only_allow_delete, dan penulisan akan gagal dengan blocked by: [FORBIDDEN/12/index read-only / allow delete (api)]. Sekatan ini akan dilepaskan sebaik sahaja penggunaan turun di bawah tanda aras tinggi. Kosongkan ruang dahulu, kemudian bersihkan sekatan secara manual hanya jika ia masih berlarutan.

curl -k -u admin:<password> -X PUT "https://localhost:9200/_all/_settings" \
  -H 'Content-Type: application/json' \
  -d '{"index.blocks.read_only_allow_delete": null}'

Loki gagal dengan lebih senyap. Ia tidak mempunyai mod baca-sahaja (read-only) untuk beralih, jadi volum yang penuh akan kelihatan sebagai kegagalan push pada penghantar dan jurang dalam hasil carian, manakala masalah kardinaliti muncul sebagai peningkatan memori yang perlahan dan bukannya ralat. Pantau saiz direktori chunks mengikut jadual, bukan selepas sesuatu insiden berlaku.

Kegagalan terakhir ialah memasukkan data yang salah. Sistem log bukanlah sistem metrik: beban CPU yang disampel setiap 10 saat dan disimpan sebagai teks adalah mahal untuk dikekalkan dan sukar untuk digrafkan, dan tugas itu milik sesuatu seperti pelayan pemantauan Zabbix pada Ubuntu 24.04. Pengecualian aplikasi memerlukan pengumpulan, penyahduplikasian dan paparan stack trace, yang merupakan tugas penjejak ralat yang dihoskan sendiri. Mengetahui sama ada tapak web sedang down adalah tugas berasingan, yang dijawab oleh halaman uptime dan status seperti Uptime Kuma. Kekalkan sistem log untuk baris teks yang akan dibaca oleh manusia.

FAQ

Adakah saya memerlukan Elasticsearch untuk mencari log pelayan saya?

Tidak perlu untuk satu atau dua pelayan. journalctl sudah menapis mengikut unit, keutamaan, but dan julat masa, manakala fail yang diputar (rotated) boleh diakses melalui grep dan zgrep. Kluster carian hanya berbaloi apabila anda mempunyai banyak mesin, apabila anda perlu melakukan carian teks bebas merentasi kesemuanya serentak, atau apabila beberapa orang memerlukan antara muka yang dikongsi. Selain daripada itu, journald dengan had saiz dan tempoh pengekalan melakukan tugas yang sama tanpa penggunaan RAM tambahan.

Berapa banyak RAM yang saya perlukan untuk pengurusan log yang dihoskan sendiri?

Gunakan angka yang diterbitkan oleh setiap projek dan bukannya anggaran kasar. Loki dan Alloy adalah program Go yang tidak mempunyai heap untuk dikhaskan di awal, dan Grafana mendokumentasikan Loki monolitik sehingga kira-kira 20GB sehari. Contoh compose OpenSearch menetapkan 512 MB heap untuk demo dan 2 GB dalam contoh pengeluaran (production), dan Elastic menyatakan heap mesti kekal pada atau di bawah 50% daripada jumlah memori, jadi heap 2 GB memerlukan mesin 4 GB sebelum mengambil kira Kibana. Dokumentasi Logstash mengesyorkan tidak kurang daripada 4GB heap untuk kegunaan sendiri. Ini adalah tetapan yang didokumentasikan, bukan penanda aras (benchmark), jadi ukur beban anda sendiri sebelum menetapkan saiz pelan.

Apakah perbezaan sebenar antara Loki dan OpenSearch untuk log?

Model indeks. Loki hanya mengindeks label dan menyimpan badan log sebagai ketulan termampat yang diimbas semasa pertanyaan (query), jadi penulisan adalah murah dan pertanyaan memakan kos lebih tinggi apabila ia luas. OpenSearch mengindeks kandungan medan, jadi carian teks penuh yang arbitrari adalah pantas dan kedua-dua memori serta cakera menanggung kos untuk indeks tersebut. Pilih Loki apabila anda tahu servis dan tetingkap masa yang anda mahukan. Pilih OpenSearch apabila anda perlu mencari teks yang tidak dapat diramal lebih awal.

Berapa lama saya perlu menyimpan log pada VPS?

Pilih tempoh masa sebelum cakera anda kehabisan ruang. Tetapkannya di satu tempat sahaja bagi setiap sistem: MaxRetentionSec= dan SystemMaxUse= untuk journald, retention_period dengan compactor diaktifkan untuk Loki, dan polisi ISM dengan min_index_age untuk OpenSearch. Bagi kebanyakan persediaan pelayan tunggal, 14 hingga 30 hari sudah memadai untuk penyahpepijatan (debugging) dan semakan insiden. Sebarang data yang perlu disimpan lebih lama harus disalin dan disimpan di luar pelayan, kerana log yang hanya disimpan pada pelayan yang gagal bukanlah rekod yang selamat.

Adakah Promtail masih cara untuk menghantar log ke Loki?

Tidak. Promtail mencapai penghujung hayat pada 2 Mac 2026, dan Grafana Alloy menggantikannya. Contoh pemasangan Docker untuk Loki kini menghantar konfigurasi Alloy, dan Grafana menyediakan penukar yang menukarkan konfigurasi Promtail sedia ada kepada sintaks Alloy. Pemasangan Promtail sedia ada akan terus berjalan, tetapi ia tidak lagi menerima sebarang pembaikan, jadi anggap migrasi sebagai penyelenggaraan dan bukannya naik taraf yang boleh ditangguhkan selama-lamanya.

#logging#loki#opensearch#journald#monitoring