EN Versiyonu
Echo Echo Support / SRE • • 3.795 kelime • 19 dk okuma

NTP Zaman Kayması ve Artık Saniye Krizlerinin Anatomisi

Tek bir artık saniye ve NTP saat kayması küresel sunucuları nasıl çökertir? Linux kernel kilitlenmeleri, TrueTime, HLC ve Leap Smear mimarisi.

#ntp #distributed-systems #sre #linux-kernel
NTP Zaman Kayması ve Artık Saniye Krizlerinin Anatomisi

Kısa Özet (TL;DR — Doğrudan Yanıt): NTP zaman kayması (clock drift) ve artık saniye (leap second) enjeksiyonları, dağıtık sistemlerde nedensellik ihlallerine, Linux çekirdeğinde %100 CPU hrtimer kilitlenmelerine (livelock) ve veri bozulmalarına yol açar. Donanım kuvars osilatörleri sıcaklığa bağlı olarak günde 10 ila 100 ppm (parts per million) sapma gösterir; standart NTPv4 genel internet üzerinde 1-50 ms belirsizlik sunarken, PTP donanım damgalama <1 µs ve Google TrueTime <7 ms ($\epsilon$) garanti eder. Üretim sistemlerinde kesintileri önlemek için CLOCK_REALTIME yerine CLOCK_MONOTONIC kullanılmalı, chrony ile 24 saatlik leap smear (artık saniye yayma) uygulanmalı ve veritabanı sıralamalarında Hybrid Logical Clocks (HLC) tercih edilmelidir.

Gece Yarısı Felaketi: 1 Saniyelik Zaman Geriye Sarma ve Küresel CPU Kilitlenmesi

UTC 23:59:60 Anomalisi ve Çekirdek Panik Dalgaları

Gece yarısı UTC 23:59:59. Dünya dönüş hızı yavaşlar. Uluslararası Yer Dönme ve Referans Sistemleri Servisi (IERS) takvime bir artık saniye ekler. Saatler 00:00:00 yerine 23:59:60 gösterir. POSIX standardı gün içinde tam 86.400 saniye varsayar. 61. saniye POSIX zaman tasarımında yoktur.

NTP sunucusu (Stratum 1) paket başlığında LI (Leap Indicator) bitlerini 01 olarak işaretler. Bu bayrak son dakikada 61 saniye olacağını bildirir. Linux çekirdeği do_adjtimex() sistem çağrısı üzerinden STA_INS (Insert Leap Second) bayrağını alır. Saat gece yarısına ulaştığında çekirdek zaman alt sistemi (timekeeping) sistem saatini tam 1 saniye geriye sarar. Aynı saniye iki kez yaşanır.

Çekirdek zamanı geriye sarar. Yüksek çözünürlüklü zamanlayıcı alt sistemi (hrtimer) bu değişikliği anında fark etmez. CLOCK_REALTIME tabanlı zamanlayıcılar gelecekteki bir zaman damgasını beklerken, duvar saati geriye düşer. Çekirdek kesme (interrupt) işleyicisi hrtimer_interrupt() döngüye girer. Süresi dolmuş görünen zamanlayıcıları sürekli yeniden çalıştırır. Tüm CPU çekirdekleri ksoftirqd işlemi altında %100 kullanıma vurur. Sistem kilitlenir (livelock).

Binlerce fiziksel sunucu aynı saniyede yanıt vermeyi keser. Yük dengeleyiciler (load balancer) arka uç düğümlerini ölü ilan eder. BGP oturumları zaman aşımına uğrar. Küresel ölçekte kaskad (cascading) çöküş başlar.

Gözlemlenebilirlik Körlüğü ve Metrik Zaman Serisi Çöküşü

Felaket anında SRE ekibi ekranlara bakar. Metrik sistemleri çöker. Zaman serisi veritabanları (TSDB) tekdüze (monotonik) artan zaman damgaları bekler. Sunucu saati 1 saniye geriye gittiğinde yeni üretilen metrikler mevcut veri bloklarının geçmişine düşer.

Prometheus ve VictoriaMetrics gibi sistemler "out-of-order sample" hatası fırlatır. Gelen metrik paketlerini çöpe atar. Grafiklerde veri boşlukları (gap) oluşur. Dağıtık izleme (distributed tracing) sistemlerinde alt çağrılar (child span), ana çağrıdan (parent span) daha önce başlamış görünür.

Negatif süre (negative duration) hesaplamaları izleme arayüzlerini çökertir. Log toplama ajanları (fluentbit, vector) zaman damgası çakışması yüzünden günlük satırlarını yanlış sıralar. Kök neden analizi (RCA) sırasında hangi servisin önce çöktüğü bilinemez. Gözlemlenebilirlik katmanı tamamen körleşir.

Donanım Osilatörlerinden Dağıtık Saatlere: Zamanın Derin Mimarisi

CLOCK_REALTIME ve CLOCK_MONOTONIC Ayrımı ve TSC Kayması

Anakart üzerinde ucuz bir kuvars kristali bulunur. Kristal piezoelektrik etkiyle titreşir. Üretim kusurları, kasa içi sıcaklık değişimleri ve voltaj dalgalanmaları titreşim frekansını bozar. Tipik sunucu kristali 10 ila 100 ppm (parts per million) kayma (drift) yapar. Bu oran günde 1 ila 8.6 saniye sapma demektir.

Modern x86_64 işlemciler zamanı TSC (Time Stamp Counter) adlı 64-bit donanım yazmacında (register) tutar. İşlemci her saat döngüsünde TSC değerini artırır. RDTSC veya sıralı RDTSCP makine komutu bu yazmacı nanosaniye mertebesinde okur. Eski işlemcilerde CPU frekans ölçekleme (Turbo Boost, C-states) TSC hızını değiştirirdi. Güncel işlemciler constant_tsc ve nonstop_tsc bayrakları ile sabit frekanslı TSC sunar. Çok soketli (NUMA) sunucularda ise soketler arası TSC senkronizasyonu MSR_IA32_TSC_ADJUST yazmacı üzerinden yapılır; donanım hatası olursa süreç bir çekirdekten diğerine geçtiğinde zaman geriye gider.

Linux çekirdeği bu donanım sayaçlarını soyutlar ve kullanıcı alanına vDSO (Virtual Dynamic Shared Object) üzerinden iki temel saat sunar:

  • CLOCK_REALTIME (Duvar Saati): 1 Ocak 1970 00:00:00 UTC (Epoch) referanslı mutlak zamandır. NTP veya yönetici müdahalesi (settimeofday) ile ileri/geri atlayabilir (step) veya hızlandırılıp yavaşlatılabilir (slew). Süre ölçümü ve zaman aşımı (timeout) hesaplamaları için kesinlikle kullanılmaz.
  • CLOCK_MONOTONIC (Monotonik Saat): Sistemin açılışından (boot) itibaren geçen süreyi tutar. İleri doğru akışı garantidir; asla geriye gitmez. NTP bu saati zıplatamaz, yalnızca frekans eğimini (adjtimex slew) çok küçük oranlarda düzeltir.
  • CLOCK_MONOTONIC_RAW: NTP frekans düzeltmelerinden bile etkilenmeyen saf donanım osilatör zamanıdır.

Kullanıcı alanı uygulamaları clock_gettime() çağırdığında çekirdek bağlam değiştirmesi (context switch) yapmaz. vDSO paylaşımlı bellek sayfasındaki tk_core yapısını (seqcount_latch kilit mekanizması ile) doğrudan okur. Maliyet sadece 15-20 nanosaniyedir.

NTPv4 Protokol Matematiği, Stratum Hiyerarşisi ve PTP Donanım Damgalama

NTP (Network Time Protocol) UDP 123 portu üzerinden çalışan hiyerarşik bir mimaridir. En tepede Stratum 0 bulunur: Sezyum/Rubidyum atom saatleri ve GPS/GNSS uydu alıcıları. Bu cihazlar doğrudan ağa bağlanmaz; Stratum 1 sunucularına PPS (Pulse Per Second) sinyali ile nanosaniye hassasiyetinde darbe gönderir. Veri merkezlerindeki sunucular genellikle Stratum 2 veya Stratum 3 seviyesinde çalışır.

NTPv4 paketi 48 bayttır. İçinde dört kritik 64-bit zaman damgası (32-bit saniye, 32-bit kesirli saniye) taşır:

  1. $T_1$ (Origin Timestamp): İstemcinin isteği gönderdiği kendi yerel zamanı.
  2. $T_2$ (Receive Timestamp): Sunucunun isteği aldığı kendi yerel zamanı.
  3. $T_3$ (Transmit Timestamp): Sunucunun yanıtı gönderdiği kendi yerel zamanı.
  4. $T_4$ (Destination Timestamp): İstemcinin yanıtı aldığı kendi yerel zamanı.

İstemci bu dört değerden saat farkını ($\theta$ - offset) ve ağ gidiş-dönüş gecikmesini ($\delta$ - round-trip delay) hesaplar:

$$\theta = \frac{(T_2 - T_1) + (T_3 - T_4)}{2}$$

$$\delta = (T_4 - T_1) - (T_3 - T_2)$$

NTP'nin temel darboğazı asimetrik ağ gecikmesi ve işletim sistemi kuyruklarıdır. Paket NIC (Ağ Kartı) tamponuna girer, kesme (IRQ) bekler, çekirdek TCP/IP yığınından geçer, kullanıcı alanındaki ntpd veya chronyd sürecinin CPU zamanlamasını bekler. Bu belirsizlik (jitter) milisaniyeler sürer. Ayrıca gidiş yolu 10 ms, dönüş yolu 50 ms sürerse (asimetrik yönlendirme), NTP formülü yolu simetrik (30 ms / 30 ms) varsayar ve saati tam 20 ms yanlış ayarlar.

Bu sorunu PTP (Precision Time Protocol - IEEE 1588) çözer. PTP zaman damgasını yazılımda değil, doğrudan ağ kartının (NIC) fiziksel katmanında (PHY / MAC donanım seviyesinde) basar (SO_TIMESTAMPING). İşletim sistemi çekirdek gecikmesi denklemden tamamen çıkar. Ağ anahtarları (switch) Boundary Clock veya Transparent Clock olarak çalışır; paketin switch içinde beklediği nanosaniyeleri (residence time) paket başlığına işler. Sonuç: mikrosaniye altı (<1 µs) senkronizasyon. Bu tür hassas protokol davranışlarını ve paket gecikmelerini AI Playground ortamında test etmek, üretim öncesi darboğazları görmeyi sağlar.

Hybrid Logical Clocks (HLC) ve Nedensellik Sıralaması

Fiziksel saatler (NTP/PTP) asla %100 senkronize olamaz. Dağıtık veritabanlarında (CockroachDB, MongoDB, YugabyteDB) "A olayı B olayından önce mi oldu?" sorusunu yanıtlamak için Leslie Lamport'un mantıksal saatleri ile fiziksel saatler birleştirilir: Hybrid Logical Clocks (HLC).

HLC 64-bit bir tam sayıdır. İlk 48-bit fiziksel zamanı ($l$ - milisaniye veya mikrosaniye), son 16-bit ise mantıksal sayacı ($c$) tutar. Her düğüm kendi fiziksel saatini ($pt$) okur:

  • Yerel bir olay olduğunda: Yeni $l' = \max(l, pt)$. Eğer $l' == l$ ise (fiziksel saat ilerlememiş veya geriye gitmişse) mantıksal sayaç $c$ bir artırılır ($c' = c + 1$). Fiziksel saat ilerlemişse $c' = 0$ sıfırlanır.
  • Başka düğümden mesaj ($l_m, c_m$) geldiğinde: Düğüm kendi $l$ değerini $\max(l, l_m, pt)$ olarak günceller. Eşitlik durumlarında $c$ sayacı en yüksek değerin bir fazlasına ayarlanır.

HLC sayesinde NTP saati geriye gitse bile zaman damgaları kesinlikle monotonik kalır. Fiziksel zamana yakınlık korunur, Google TrueTime gibi özel donanımlara ihtiyaç duymadan nedensellik (causality) sıralaması garanti edilir.

Zaman Senkronizasyon Mimarileri Karşılaştırma ve Performans Kriterleri

Dağıtık sistem mimarisinde doğru zaman protokolünü seçmek, donanım maliyeti ile veri tutarlılığı (consistency) arasındaki doğrudan bir ödünleşimdir.

Mimari / Yöntem Gecikme (Latency) Bellek / CPU Avantaj Üretim Riski
Geleneksel NTPv4 (ntpd) 1 ms - 50 ms (WAN), 200 µs (LAN) ~4 MB RAM / <%0.1 CPU Evrensel uyumluluk, sıfır ek donanım maliyeti Asimetrik rota sapması, yavaş yakınsama (saatler sürer), artık saniye hrtimer krizi
Modern NTP (chronyd) 50 µs - 2 ms (LAN) ~2 MB RAM / <%0.1 CPU Hızlı yakınsama, yerleşik leap smear desteği, sanal makine duraklamalarına dayanıklı Yazılım tabanlı zaman damgalama nedeniyle yoğun ağ trafiğinde jitter artışı
Donanım Destekli PTP (IEEE 1588) 10 ns - 1 µs ~10 MB RAM / <%0.5 CPU (NIC offload) Çekirdek kuyruklarını atlar, finansal HFT ve telekom için mutlak hassasiyet PTP uyumlu switch ve NIC zorunluluğu, yanlış SFP modülünde asimetri hatası
Google TrueTime API (GPS + Atomik) 1 ms - 7 ms ($\epsilon$ belirsizlik sınırı) Özel Donanım + Daemon (<%1 CPU) Küresel ölçekte dışsal tutarlılık (external consistency), kilit gerektirmeyen salt-okunur işlemler Sadece Google Cloud (Spanner) altyapısında mevcut, $\epsilon$ artarsa yazma işlemleri yavaşlar
Hybrid Logical Clocks (HLC) <50 ns (Belлек içi işlem) <1 KB RAM / İhmal edilebilir CPU Saat geriye gitse bile monotonik ilerleme, donanım bağımsız nedensellik max_offset (örn. 500 ms) aşılırsa düğüm veri bozulmasını önlemek için kendini kapatır (panic)

Google TrueTime API ve Belirsizlik Sınırları (Epsilon) Analizi

Standart zaman API'leri tek bir sayı döndürür (time.Now()). Bu bir yalandır çünkü her saatin bir hata payı vardır. Google Spanner tarafından kullanılan TrueTime API, zamanı kesin bir nokta olarak değil, $[earliest, latest]$ şeklinde bir aralık olarak döndürür.

$$\text{TrueTime.now()} = [t - \epsilon, t + \epsilon]$$

Burada $\epsilon$ (epsilon), o anki maksimum saat belirsizliğidir. Google veri merkezlerinde her sunucu kabininde hem GPS alıcıları hem de Rubidyum atom saatleri (Time Master) bulunur. GPS antenleri atmosferik parazit, güneş patlamaları veya RF sinyal karıştırma (jamming) nedeniyle çökebilir. Atom saatleri ise GPS koptuğunda sadece 1 µs/gün kayma ile sistemi ayakta tutar.

Sunucular her 30 saniyede bir bu referans saatlerle senkronize olur. İki senkronizasyon arasında yerel kuvars kristali en kötü ihtimalle 200 µs/saniye hızla kayar. Dolayısıyla $\epsilon$ değeri testere dişi (sawtooth) grafiği çizer: senkronizasyon anında ~1 ms seviyesindedir, 30 saniye boyunca ~7 ms seviyesine kadar çıkar.

Spanner dışsal tutarlılığı (Linearizability) sağlamak için Commit Wait (Onay Beklemesi) kuralını uygular. Bir işlem $T_1$ zamanında onaylandığında, sistem işlemin sonuçlarını diğer düğümlere açmadan önce tam $2\epsilon$ süresi kadar bekler. Eğer $\epsilon = 7\text{ ms}$ ise, her yazma işlemi zorunlu olarak 14 ms bekletilir. Ağ arızası olur ve sunucu Time Master'lara ulaşamazsa $\epsilon$ hızla büyür; yazma gecikmeleri (latency) fırlar.

Üretim Ortamı Yapılandırması, Kod Denetimi ve Dağıtık Sıralama

Chrony Leap Smear Yapılandırması ve Sistem Doğrulaması

Üretim ortamında artık saniye krizini önlemenin altın standardı Leap Smearing (Artık Saniye Yayma) tekniğidir. Saati gece yarısı 1 saniye zıplatmak veya geriye sarmak yerine, 1 saniyelik fark 24 saatlik (86.400 saniye) bir zaman dilimine yayılır. Sistem saati bu süre boyunca saniyede yaklaşık 11.57 mikrosaniye (~11.6 ppm) yavaşlatılır. Hiçbir uygulama veya çekirdek zamanlayıcısı bu mikro yavaşlamayı hissetmez; zaman asla geriye gitmez.

Aşağıdaki üretim yapılandırması, iç ağdaki bir NTP katmanında chrony kullanarak artık saniyeyi güvenli şekilde yayar ve çekirdek saat sıçramalarını sınırlar:

# Donanım zaman damgalama destekleyen iç Stratum-1/2 kaynakları
server time1.internal.corp iburst minpoll 2 maxpoll 4 xleave
server time2.internal.corp iburst minpoll 2 maxpoll 4 xleave
server time3.internal.corp iburst minpoll 2 maxpoll 4 xleave

# NIC donanım zaman damgalamayı (PTP/Hardware Timestamping) tüm arayüzlerde aç
hwtimestamp *

# Kuvars kristali frekans kayma oranını (ppm) kaydet
driftfile /var/lib/chrony/drift

# Sadece başlangıçta (ilk 3 güncellemede) fark 1.0 saniyeden büyükse saati zıplat (step).
# Çalışma zamanında (runtime) ASLA step yapma, her zaman slew (eğim düzeltme) kullan!
makestep 1.0 3

# Artık saniye (Leap Second) geldiğinde çekirdeğe STA_INS bayrağı gönderme!
# Bunun yerine 1 saniyeyi 86400 saniye (24 saat) boyunca kosinüs eğrisiyle erit (smear).
leapsecmode slew
maxslewrate 1000.0
smoothtime 400 0.001024 leaponly

# İstemcilere smear edilmiş zamanı dağıt
allow 10.0.0.0/8

Yapılandırma sonrası çalışma zamanı doğrulama ve çekirdek donanım saati denetim komutları:

# 1. Mevcut saat kaynağını (clocksource) doğrula (tsc olmalı, hpet veya acpi_pm değil!)
cat /sys/devices/system/clocksource/clocksource0/current_clocksource

# 2. Chrony senkronizasyon metriklerini, skew ve root dispersion değerlerini incele
chronyc tracking

# 3. NIC donanım zaman damgalama (SOF_TIMESTAMPING_TX_HARDWARE) desteğini doğrula
ethtool -T eth0

Skipped: Dinamik NTP havuz keşfi ve NTS (Network Time Security) TLS anahtar rotasyonu. Add when: Sunucular güvenli özel VLAN yerine genel internet üzerinden senkronize olduğunda.

Önemli Mimari Uyarı: Google (time.google.com) veya AWS (169.254.169.123) gibi zaten leap smear uygulayan dış kaynakları kullanıyorsanız, kendi chrony sunucunuzda leapsecmode slew açmayın. Smear edilmiş zamanla ham UTC zaman kaynaklarını aynı havuzda karıştırmak, NTP'nin falseticker (yanlış saat) algoritmasını tetikler ve tüm senkronizasyonu bozar.

Uygulama Katmanında Monotonik Zaman Zorlaması ve HLC Doğrulaması

Uygulama geliştiricileri süre ölçerken veya dağıtık olayları sıralarken sıkça duvar saatine (time.time()) güvenir. Aşağıdaki sıfır bağımlılıklı (stdlib) Python kodu, NTP saat geriye sarmasına karşı dayanıklı bir Hybrid Logical Clock (HLC) gerçeklemesi ve kendi kendini doğrulayan (self-check) kaos testini içerir:

import time

class HLC:
    # ponytail: 48-bit ms + 16-bit counter (65535 events/ms ceiling); upgrade to 64-bit ns when throughput > 65k/ms.
    def __init__(self, max_drift_ms=500):
        self.l = 0
        self.c = 0
        self.max_drift_ms = max_drift_ms

    def now(self, phys_ms=None):
        pt = int(time.time() * 1000) if phys_ms is None else phys_ms
        if pt > self.l:
            self.l, self.c = pt, 0
        else:
            self.c += 1
            if self.c > 0xFFFF:
                raise OverflowError("HLC logical counter overflow")
        return (self.l << 16) | self.c

    def update(self, msg_hlc, phys_ms=None):
        pt = int(time.time() * 1000) if phys_ms is None else phys_ms
        msg_l, msg_c = msg_hlc >> 16, msg_hlc & 0xFFFF
        if msg_l - pt > self.max_drift_ms:
            raise RuntimeError(f"Clock skew {msg_l - pt}ms exceeds max_drift {self.max_drift_ms}ms")
        if pt > self.l and pt > msg_l:
            self.l, self.c = pt, 0
        elif self.l == msg_l:
            self.c = max(self.c, msg_c) + 1
        elif self.l > msg_l:
            self.c += 1
        else:
            self.l, self.c = msg_l, msg_c + 1
        return (self.l << 16) | self.c

# Runnable self-check: Simulate 1000ms NTP backward step + future message skew
clock = HLC(max_drift_ms=500)
t1 = clock.now(phys_ms=2000)
t2 = clock.now(phys_ms=1000)  # NTP rewound wall clock by 1 full second!
assert t2 > t1, "Monotonicity violated on backward clock step!"
assert (t2 >> 16) == 2000 and (t2 & 0xFFFF) == 1, "Logical counter failed to increment!"

remote_msg = (2300 << 16) | 5  # Node B is 300ms ahead (within 500ms budget)
t3 = clock.update(remote_msg, phys_ms=2000)
assert t3 > remote_msg and (t3 >> 16) == 2300 and (t3 & 0xFFFF) == 6

Skipped: Disk kalıcılığı (WAL) ve thread-safe mutex kilitlemesi. Add when: Çok iş parçacıklı (multi-threaded) üretim veritabanı motoruna entegre edildiğinde.

Saat Kayması Altında Dağıtık İşlem Serileştirme Mimarisi

Dağıtık bir veritabanında (örneğin CockroachDB veya Spanner) iki farklı düğüm arasındaki saat kayması, okuma/yazma işlemlerinin serileştirilmesini (serializability) doğrudan tehdit eder. Aşağıdaki mimari diyagram, Node A ve Node B arasındaki 150 ms saat farkının HLC ve Uncertainty Interval (Belirsizlik Aralığı) ile nasıl çözüldüğünü gösterir. Benzer dağıtık mutabakat ve saat kayması senaryolarını İnteraktif Simülasyon Araçları üzerinden adım adım görselleştirebilirsiniz.

+-----------------------------------------------------------------------------------+
|               DAĞITIK İŞLEM SERİLEŞTİRME VE BELİRSİZLİK (UNCERTAINTY)             |
+-----------------------------------------------------------------------------------+

  NODE A (Koordinatör - Saat: 100ms)             NODE B (Replika - Saat: 250ms [+150ms Kayma])
  ==================================             =============================================
  |                                              |
  | 1. Tx1 Başlat (Okuma/Yazma)                  |
  |    Fiziksel Saat (pt) = 100ms                |
  |    HLC_A = (100ms, c=0)                      |
  |    Max_Offset (Epsilon) = 500ms              |
  |    Belirsizlik Sınırı = [100ms, 600ms]       |
  |                                              |
  |                                              | 2. Bağımsız Tx2 Yazma İşlemi (Anahtar: X)
  |                                              |    Yerel Saat = 250ms (İleride!)
  |                                              |    MVCC Kayıt: X = "Yeni_Deger" @ ts=250ms
  |                                              |
  | 3. RPC Okuma İsteği: Oku(X)                  |
  |    Okuma_TS = 100ms, Üst_Sınır = 600ms       |
  +=============================================>|
  |                                              | 4. ÇAKIŞMA TESPİTİ (Uncertainty Violation!)
  |                                              |    Kayıt_TS (250ms) > Okuma_TS (100ms)
  |                                              |    FAKAT Kayıt_TS (250ms) <= Üst_Sınır (600ms)
  |                                              |    (Gerçekte Tx2 mi önce oldu, Tx1 mi? Bilinemez!)
  |                                              |
  | 5. ReadRestartError (HLC_B = 250ms, c=1)     |
  |<=============================================+
  |                                              |
  | 6. HLC Güncelle ve İşlemi Yeniden Başlat     |
  |    Yeni HLC_A = (250ms, c=2)                 |
  |    Yeni Okuma_TS = (250ms, c=2)              |
  |    (Artık X @ 250ms güvenle okunabilir!)     |
  v                                              v

Hata Modları, Split-Brain Senaryoları ve SRE Ödünleşimleri

Step ve Slew Düzeltme Stratejileri Arasındaki Mimari Savaş

NTP istemcisi yerel saat ile referans saat arasında büyük bir fark (offset) tespit ettiğinde iki düzeltme mekanizmasından birini seçer:

  1. Step (Sıçrama): Sistem saati clock_settime() çağrısı ile anında yeni değere eşitlenir. Saat ileri sıçrarsa; zamanlayıcılar (timer), önbellek TTL süreleri ve oturumlar anında sona erer. Saat geriye sıçrarsa; zaman damgası çakışmaları, negatif süre hataları ve dosya sistemi (make derleme araçları, veritabanı WAL günlükleri) bozulmaları yaşanır.
  2. Slew (Eğim Düzeltme): Çekirdek adjtimex() sistem çağrısını kullanarak sanal saatin tik (tick) frekansını hızlandırır veya yavaşlatır. Linux çekirdeğinde maksimum slew hızı 500 ppm (0.05%) ile sınırlıdır. Bu hız sınırıyla 1 saniyelik bir saat farkını kapatmak tam 2.000 saniye (~33.3 dakika) sürer. 10 dakikalık bir saat kaymasını slew ile düzeltmek ise 13.8 gün sürer!

SRE Ödünleşimi: 13 gün boyunca yanlış saatle çalışmak Kerberos kimlik doğrulamasını (maksimum 5 dakika tolerans) ve TLS/TOTP sistemlerini tamamen bozar. Bu yüzden üretim sunucularında önyükleme (boot) sırasında makestep (Step) izin verilir; ancak servisler trafiği almaya başladıktan sonra sadece slew uygulanır. Eğer çalışma zamanında saat farkı 500 ms sınırını aşarsa, düğüm üzerinde çalışan sağlık kontrolü (healthcheck) servisi düğümü yük dengeleyiciden düşürmeli ve trafiği kesmelidir.

Dağıtık Kilitler, Kira Süresi (Lease Expiration) ve Split-Brain Çöküşü

Dağıtık sistemlerde (etcd, Consul, ZooKeeper, Chubby) lider seçimi ve kaynak kilitleme işlemleri Lease (Kira Süresi) kavramına dayanır. Bir düğüm kilidi 10 saniyeliğine alır. Eğer uygulama bu süreyi CLOCK_REALTIME ile ölçerse veya sanal makine duraklaması (VM pause / GC pause) yaşanırsa felaket kaçınılmazdır.

Senaryo: Node 1 liderdir ve kilidin bitmesine 5 saniye vardır. Bu sırada Node 1 üzerinde yanlış yapılandırılmış bir NTP istemcisi saati 6 saniye geriye alır (veya diğer düğümlerin saati ileri sıçrar).

  • Kümenin geri kalanı (Node 2 ve Node 3) kiranın bittiğini görür. Yeni bir Raft seçimi başlatır ve Node 2 yeni lider seçilir.
  • Node 1 ise kendi yerel saatine bakar; kiranın bitmesine hala süre olduğunu sanır ve kendisini lider kabul etmeye devam eder.
  • Split-Brain (Bölünmüş Beyin): İki düğüm aynı anda paylaşımlı depolama alanına (shared storage) veya veritabanına yazma yapar. Veri geri döndürülemez şekilde bozulur.

Bu durumu önlemek için tüm kira hesaplamaları CLOCK_MONOTONIC üzerinden yapılmalı ve depolama katmanında mutlaka Fencing Token (her yeni kilit verildiğinde artan monotonik sıra numarası) zorunlu tutulmalıdır.

Kriptografik Protokollerde Zaman Doğrulaması: TLS ve DNSSEC Krizleri

Kriptografi zamana bağımlıdır. Bir sunucunun saati yanlışsa ağ güvenliği tamamen çöker:

  • X.509 TLS Sertifikaları: Her sertifikanın bir notBefore (başlangıç) ve notAfter (bitiş) zaman damgası vardır. Otomatik sertifika yenileme araçları (Let's Encrypt / Certbot) yeni sertifika ürettiğinde, saatleri geride kalmış istemciler veya arka uç mikroservisler yeni sertifikanın notBefore zamanını "gelecekte" görür. SSL_ERROR_CERT_NOT_YET_VALID hatası ile tüm mTLS (hizmetler arası şifreli iletişim) trafiği kesilir.
  • DNSSEC (RRSIG) Doğrulaması: DNS kayıtlarının kriptografik imzaları (RRSIG), belirli bir zaman penceresi için geçerlidir. Çözümleyici (resolver) sunucunun saati kayarsa, dünyadaki tüm alan adlarının imzalarını geçersiz sayar ve SERVFAIL döndürerek tüm internet erişimini keser.
  • Kerberos ve AWS SigV4: AWS API çağrıları (SigV4) istemci saati ile AWS sunucu saati arasında maksimum 15 dakika (900 saniye) fark kabul eder. Fark aşılırsa tüm S3, EC2 ve IAM çağrıları RequestTimeTooSkewed hatasıyla reddedilir.

Gerçek Dünya Vaka Analizleri: 2012 Linux Kernel ve 2017 Cloudflare Kesintileri

30 Haziran 2012: Linux Kernel hrtimer Livelock ve Futex Fırtınası

30 Haziran 2012 gece yarısı UTC 23:59:60 artık saniyesi uygulandığında Reddit, Mozilla, LinkedIn, Gawker ve Qantas Havayolları dahil binlerce şirketin sunucuları anında kilitlendi.

Kök Neden (Kernel Seviyesi): Linux çekirdeğinde (2.6.22 ile 3.3 arası sürümler) artık saniye eklendiğinde timekeeping alt sistemi CLOCK_REALTIME değerini 1 saniye geriye çekti. Normal şartlarda bu işlemden sonra clock_was_set() fonksiyonu çağrılarak hrtimer (High-Resolution Timer) alt sisteminin zaman ofsetlerini güncellemesi gerekirdi. Ancak clock_was_set() fonksiyonunu kesme (interrupt) bağlamında doğrudan çağırmak ölü kilitlenmeye (deadlock) yol açabileceği için bu çağrı bir ertelenmiş çalışma kuyruğuna (clock_was_set_delayed) alınmıştı. Hatadan dolayı bu bildirim hrtimer alt sistemine asla ulaşmadı.

Sonuç olarak hrtimer alt sisteminin tuttuğu zaman ile çekirdeğin gerçek zamanı arasında tam 1 saniyelik bir kopukluk oluştu. Özellikle Java (JVM) ve MySQL gibi yoğun futex (FUTEX_WAIT_BITSET_PRIVATE | FUTEX_CLOCK_REALTIME) kullanan uygulamalar, milisaniyelik bekleme (sleep/cond_wait) çağrıları yaptığında, hrtimer bu zamanlayıcıların süresinin "zaten dolmuş" olduğunu düşündü. Donanım zamanlayıcı kesmesi saniyede yüz binlerce kez ateşlendi. Sunuculara sadece date -s "$(date)" komutu çalıştırılarak (clock_was_set() tetiklenerek) müdahale edilebildi.

1 Ocak 2017: Cloudflare RRSIG Negatif Süre ve Go time.Now() Hatası

31 Aralık 2016 gece yarısı uygulanan artık saniye, bu kez çekirdeği değil, modern bir programlama dilinin standart kütüphanesini vurdu: Cloudflare DNS (RRDNS) küresel çapta kesintiye uğradı.

Kök Neden (Uygulama/Dil Seviyesi): Cloudflare o dönemde public DNS sunucularında leap smear kullanmıyordu; Linux çekirdeğinin saati geriye sarmasına izin veriyordu. Go (Golang) dilinin 1.8 öncesi sürümlerinde time.Now() fonksiyonu yalnızca duvar saatini (CLOCK_REALTIME) okuyordu; içinde monotonik saat bileşeni yoktu.

Cloudflare'in Go ile yazılmış DNS sunucusu, yukarı akış (upstream) sunucuların yanıt sürelerini ölçüyordu:

start := time.Now()
// ... DNS sorgusu yap (örneğin 2 milisaniye sürsün) ...
// Bu sırada artık saniye vurur ve saat 1 saniye geriye gider!
elapsed := time.Now().Sub(start) // Sonuç: -998 milisaniye (NEGATİF SÜRE!)

Sunucu seçimi algoritması, bu negatif süreyi (-998 ms) en iyi performanslı sunucu seçimi için rand.Int63n(max) fonksiyonuna parametre olarak verdi. Go standart kütüphanesindeki rand.Int63n() fonksiyonu, kendisine 0 veya negatif bir sayı verildiğinde doğrudan panic("invalid argument to Int63n") fırlatacak şekilde kodlanmıştı. Tek bir satırdaki negatif zaman farkı hesaplaması, dünya genelindeki Cloudflare DNS süreçlerinin aynı anda çökmesine (crash loop) neden oldu. Bu olaydan sonra Go 1.9 sürümüyle birlikte time.Time yapısının içine gizli bir monotonik saat işaretçisi eklendi.

Sıkça Sorulan Sorular (SSS)

Sanal makine canlı taşıma (VM Live Migration) işlemi sistem saatini nasıl bozar?

VMware vMotion veya KVM/QEMU canlı taşıma sırasında sanal makinenin belleği ağ üzerinden kopyalanırken vCPU'lar birkaç yüz milisaniye ile birkaç saniye arasında tamamen dondurulur (stun time). Sanal makine yeni fiziksel sunucuda uyandığında TSC donanım sayacı ve sistem saati geride kalmıştır. Hipervizör (hypervisor) zamanı yakalamak için saati aniden ileri sıçratır veya zamanlayıcı kesmelerini arka arkaya gönderir. Bu durum uygulama katmanında sahte zaman aşımlarına ve Raft/Paxos küme kopmalarına yol açar.

Linux konteynerlerinde (Docker ve Kubernetes) ayrı bir NTP servisi çalıştırılmalı mıdır?

Hayır, konteyner içinde ntpd veya chronyd kesinlikle çalıştırılmamalıdır. Konteynerler, üzerinde çalıştıkları ana sunucunun (host) Linux çekirdeğini paylaşır. Saat donanımı ve timekeeping alt sistemi çekirdek seviyesinde tekildir; bir konteynerin CAP_SYS_TIME yetkisiyle saati değiştirmesi aynı düğümdeki tüm diğer konteynerlerin ve Kubernetes kubelet sürecinin saatini bozar. Zaman senkronizasyonu yalnızca alttaki fiziksel sunucu veya sanal makine (Node) katmanında yönetilmelidir (Linux 5.6+ Time Namespace sadece ofset sağlar, frekansı yönetmez).

Cassandra ve DynamoDB tarzı veritabanlarında Last-Write-Wins (LWW) neden veri kaybına yol açar?

Apache Cassandra gibi sistemler, çakışan yazma işlemlerini çözmek için istemci veya koordinatör düğümün duvar saati (CLOCK_REALTIME) zaman damgasına bakar ve en büyük zaman damgalı veriyi saklar (Last-Write-Wins). Eğer Düğüm A'nın saati NTP kayması nedeniyle 50 ms ilerideyse ve t=1050 damgasıyla bir veri yazarsa; 10 ms sonra Düğüm B kendi doğru saatiyle (t=1010) aynı satırı güncellediğinde veritabanı yeni veriyi "eski" sanarak sessizce çöpe atar.

NTP havuzlarında Leap Smear ve standart UTC sunucularını karıştırmak neden tehlikelidir?

Leap smear uygulayan sunucular (örneğin Google veya AWS NTP) artık saniye gününde zamanı 24 saat boyunca kademeli olarak yavaşlatırken, standart NTP havuzu (pool.ntp.org) sunucuları normal hızda ilerleyip gece yarısı 1 saniye sıçrama yapar. Bu iki farklı kaynak aynı chrony.conf veya ntp.conf dosyasında tanımlanırsa, gün ortasında iki kaynak arasında 500 ms fark oluşur. NTP kesişim algoritması hangi kaynağın doğru olduğuna karar veremez ve senkronizasyon tamamen kilitlenir.

Kubernetes ortamında Pod'ların zaman senkronizasyonu durumunu nasıl izleyebiliriz?

Kubernetes düğümlerinde (Node) çalışan node-exporter bileşeninin timex toplayıcısı aktif edilmelidir. Prometheus üzerinden node_timex_offset_seconds (yerel saat ile NTP arasındaki sapma), node_timex_sync_status (1 ise senkronize, 0 ise kopuk) ve node_timex_maxerror_seconds metrikleri izlenir. Üretim ortamlarında abs(node_timex_offset_seconds) > 0.05 (50 ms sapma) koşulu için kritik uyarı (alert) tanımlanmalı ve sapma yaşayan düğümler kubectl cordon ile yeni iş yüklerine kapatılmalıdır.

İlgili Derin Teknik Makaleler

Tüm Makaleler →