Cron, her birkaç saniyede bir çalışması gereken veya sıkı zamanlama gerektiren görevler için istenmeyen gecikme eklediği için kullanıyorum; çünkü cron’un dakika hassasiyeti bu tür görevler için uygun değil. Ortamımda, systemd zamanlayıcıları alt-dakika hassasiyeti sağlar ve planlayıcının ne kadar sapabileceğini kontrol etme imkanı verir. Bu, sağlık kontrolleri, log taşıyıcıları veya zamanında başlatmak yaklaşık çalıştırmadan daha önemli olan herhangi bir iş için özellikle faydalıdır.
systemd zamanlayıcıları, yüksek frekanslı işler için cron'dan daha iyi neden?
Cron, bir şeyi belirli bir dakika, saat veya gün çalıştırmak istediğinizi varsayar. Her 30 saniyede bir çalıştırmasını söylerseniz, iki giriş elde edersiniz ya da uyuyan bir sarma betiği kullanırsınız — her ikisi de karmaşıklık ekler ve başlangıç zamanlarını öngörülemez kılar. systemd zamanlayıcıları ise, birimleri saniyede bir kez kadar sık sık tetikleyebilir ve hassasiyetini yapılandırabilir. Onları konteynırlardaki sidecar süreçleri ve hatta birkaç milisaniyelik bir penceri kaçırılsa bile metrikleri eğrebilecek host‑düzeyindeki kontroller için kullanıyorum.
Bir zamanlayıcıyı OnUnitActiveSec ve AccuracySec ile kurma
Zamanlama davranışını kontrol eden iki anahtar OnUnitActiveSec ve AccuracySec'tir. OnUnitActiveSec, birimden son aktivasyon zamanına göre ölçülen aralığı tanımlar, sabit bir saat zamanına göre değil. Bu, bir işin aralığından daha uzun sürede çalışması durumunda kaymayı önler. AccuracySec, systemd'ye zamanlayıcının ne kadar geç çalışabileceğini söyler; 1ms olarak ayarlandığında gerçek-zamanlı davranışa yakın olur, 1s ise güç tasarrufu için birleştirmeyi (coalescing) izin verir.
Bir log iletici için her 10 saniyede bir çalışması gereken birim dosyası şu şekilde kullanıyorum:
# /etc/systemd/system/log-forwarder.service
[Unit]
Description=Merkezi toplayıcıya logları ilet
[Service]
Type=oneshot
ExecStart=/usr/local/bin/log-forwarder.sh
# /etc/systemd/system/log-forwarder.timer
[Unit]
Description=Log-forwarder'ı her 10 saniyede bir yüksek doğrulukla çalıştır
[Timer]
OnUnitActiveSec=10s
AccuracySec=1ms
Persistent=true
[Install]
WantedBy=timers.target
Bu dosyaları yerleştirdikten sonra, zamanlayıcıyı yeniden yükler ve etkinleştiririm:
sudo systemctl daemon-reload
sudo systemctl enable --now log-forwarder.timer
systemctl list-timers --all komutuyla aktif olup olmadığını kontrol eder ve sonraki tetikleme zamanına bakar.
Jitteri Kontrol Etme ve Çakışmayı Önleme
OnUnitActiveSec, son aktivasyon zamanından ölçtüğü için, log-forwarder.sh betiğim 8 saniye sürüyorsa, bir sonraki başlangıç, betiğin bitişinden 2 saniye sonra olur — önceki başlangıçtan 10 saniye sonra değil. Bu, iş yükleri değişse bile zamanlamanın stabil kalmasını sağlar. Çalışma süresinden bağımsız sabit aralık davranışı istersem, OnUnitSec kullanırdım, ancak bu çakışma riski oluşturur.
Tamamen çakışmayı önlemek için, hizmetin Type=oneshot özelliğine güvenirim ve betiğin temiz bir şekilde çıkmasını sağlarım. Çakışma kabul edilebilir ise, Type=simple geçerim ve RefuseManualStart=no ile RestartPreventExitStatus= seçeneklerini kullanarak yeniden başlatmaları yönetirim.
AccuracySec trade‑offs: precision vs. power
AccuracySec=1ms ayarlanması, zamanlayıcıyı sık sık uyandırır ve bu da boşta olan sistemlerde CPU uyandırma sayısını artırabilir. Batarya ile çalışan cihazlar veya düşük güç sanal makineler için, bunu 50ms veya 100ms gibi daha yüksek bir değere yükseltirim. Zamanlayıcı hâlâ bu pencere içinde tetiklenecektir ve systemd, birden fazla zamanlayıcıyı gruplayarak uyandırmaları azaltabilir. Beklenmedik zamanlayıcı uyandırmalarının olup olmadığını görmek için /proc/timer_list dosyasını izler veya systemd-analyze blame komutunu kullanırım.
Debugging timer misfires
Bir zamanlayıcı beklendiği gibi tetiklenmediğinde şunları kontrol ederim:
- Servis biriminin yanlış yapılandırılıp yapılandırılmadığı (
systemctl status log-forwarder.servicekomutunu manuel olarak çalıştırarak) - Zamanlayıcının aktif olup olmadığı (
systemctl status log-forwarder.timer) - Zamanlayıcıya ait günlük girdileri (
journalctl -u log-forwarder.timer) AccuracySeckısıtlaması (systemd, bazı çekirdeklerde çok düşük değerleri artırabilir)
Kullanışlı bir ipucu: Servise ExecStartPre=/bin/echo 'Timer fired at: $(date +%s.%N)' satırını eklemek, nanosaniye hassasiyetinde gerçek başlangıç zamanlarını görmemizi sağlar.
Cron Kullanmaya Devam Etme Durumları
Günlük yedeklemeler, haftalık raporlar veya dakika seviyesinde zamanlama yeterli ve basitlik öncelikli olan herhangi bir iş için hâlâ cron kullanıyorum. Ancak bir dakikadan kısa süreli işler için veya jitter’i (zaman sapması) katı bir şekilde kontrol etmem gerektiğinde, şimdi sistemd zamanlayıcıları varsayılan tercihimdir. Daha önce Restic’in --password-file seçeneğiyle cron’u güvenli hale getirme konulu yazımda da belirttiğim gibi, cron’un ortam değişkeni mirasalma bağımlılığını azaltmak güvenliği da artırır — zamanlayıcılar varsayılan olarak temiz bir hizmet bağlamında çalışır.
Özet
OnUnitActiveSec ve AccuracySec ile systemd zamanlayıcıları, cron’un alt-dakikali aralıklarla eşleşemediği şekilde, jitter kontrolüyle hassas ve tekrarlanabilir planlama sağlar. Son aktivasyon zamanından ölçülen aralıklar ve hassasiyet ayarıyla, zaman duyarlı iş yükleri için karmaşık bir kurulum yapmadan tekrarlanabilir davranış elde edebilirim.
Kapak görseli: Unknown · CC0 (Openverse / kamu malı) · https://www.rawpixel.com/image/5924954/photo-image-background-public-domain-technology
