Nanosaniye zaman damgası çakışmaları yaygındır
(evanjones.ca)- Birden çok fiziksel çekirdeğin aynı anda saati okuduğu modern sistemlerde nanosaniye zaman damgaları bile kolayca çakışır; 4 fiziksel çekirdekte eşzamanlı ölçümde toplam örneklerin yaklaşık %5’i çakışır
- Ham zaman damgalarını benzersiz tanımlayıcı gibi kullanan tasarımlar risklidir ve çakışma sıklığı işletim sistemi ile çalıştırma biçimine göre değişir
- Go’nun
time.Now()fonksiyonu mutlak zamanı ve monoton saat tabanlı göreli zamanı birlikte kaydeder; böylece ardışık çağrılar arasındaki fark ile mutlak zaman damgası tekrarları ayrı ayrı incelenebilir - Linux’ta tek iş parçacığında zaman her zaman arttı ve en küçük artış aralığı 32ns idi; ancak iş parçacıkları ayrıldığında aynı mutlak zaman gözlemlendi
- Mac OS X’te mutlak zamanın mikrosaniye çözünürlüğünde olması nedeniyle çakışmalar çok daha fazladır ve tek iş parçacığında bile monoton saatin artmadığı durumlar sıkça görülür
Eşzamanlı okumalarda ortaya çıkan çakışma sıklığı
- Temel soru, modern sistemlerde nanosaniye zaman damgası çakışmalarının gerçekte ne kadar sık meydana geldiğidir
- 4 fiziksel çekirdekte aynı anda saat okunursa toplam örneklerin yaklaşık %5’i çakışır
- 4 çekirdekli bir sistemde yalnızca 2 iş parçacığı kullanılsa bile zaman damgalarının yaklaşık %2’si çakışır
- Bu nedenle yalnızca ham nanosaniye zaman damgalarıyla benzersiz ID üretilebileceğini varsaymak güvenli değildir
Test yöntemi ve işletim sistemine göre farklar
- Test programı Go ile yazılmıştır
- Go’nun
time.Now()fonksiyonu her çağrıda mutlak zaman ile monoton saat tabanlı göreli zamanı kaydeder- Test, ardışık zaman damgaları arasındaki göreli farkı karşılaştırır
- Mutlak zaman damgasının kendisindeki tekrarlar da birlikte kontrol edilir
-
Linux
- Tek iş parçacığında mutlak zaman ve monoton zaman her zaman artar
- Ölçüm yapılan sistemde en küçük artış aralığı 32ns idi
- İş parçacıkları arasında mutlak zamanın başka bir iş parçacığıyla tamamen aynı olduğu durumlar yaklaşık %5 oranında görüldü
-
Mac OS X
- Mutlak zaman mikrosaniye çözünürlüğünde olduğu için aynı testte çok sayıda çakışma meydana gelir
- Tek iş parçacığında bile monoton saatin artmadığı durumlar sıkça gözlemlenir
1 yorum
Hacker News yorumları
Bu tür sorunlardan kaçınmanın yolu, zaman bileşeniyle sıra numarasını birlikte içeren bir ID kullanmaktır
Örneğin UUIDv7’de milisaniye düzeyinde bir zaman bileşeni, aynı milisaniye içindeki her olay için artan bir alan ve farklı makinelerde üretilen ID’ler arasında çakışma olasılığını astronomik ölçüde düşürecek kadar rastgele bit bulunur
Elbette bit sayısı sonlu olduğundan aynı zaman aralığında çok fazla olay olursa sıra numarası taşabilir, makineler arası çakışmalar gerçekten yaşanabilir ve artırma işlemi CPU senkronizasyonu gerektirdiği için olay üretim hızı sınırlanabilir
Yine de pratik ölçekte UUIDv7 çok iyi çalışır
UUIDv7’nin ne kadar eski olduğunu internette pek bulamıyorum
UUID içindeki bitleri tüketmekten başka bir işe yaramıyor ve entropiye pek katkı sağlamıyor
Henüz çekirdeğe girmiş değil, ancak uygulama düzeyinde doğrudan kullanmanın yanı sıra uuidv7 sağlayan birkaç harika pg eklentisi var
Anlaşılması zor olmanın ötesinde, gözle birbirinden ayırt etmek bile çok güçtür
Bu yüzden bazı durumlarda, gereken asgari bilgi dışında hiçbir bilgi veya gürültü içermeyen bir tanımlayıcı kullanışlıdır
Herhangi bir biçimde taşan bir artırma sayacı ve biraz rastgele bit çoğu zaman yeterlidir; iyi tasarlanırsa ikisi de dallanma olmadan yapılabilir
Bununla bağlantılı olarak, eskiden Windows’un güvenlik olay günlüğünden sorumlu program yöneticisiydim
Çok çekirdekli sistemlerde işler aynı anda ya da birbirine çok yakın zamanlarda gerçekleştiğinde, iş parçacığı zamanlaması gözlemlenen sonuçları büyük ölçüde etkileyebilir
Örneğin iş parçacığının zaman dilimi, zaman damgasını alan sistem çağrısına ulaşmadan önce ya da daha sonra zaman damgası basmak üzere olayı kuyruğa koymak için tamponu teslim etmeden önce sona erebilir
Gerçekten de 2000’lerde Windows’un çok işlemcili sistemlerinde olay günlüğü girdilerinin sırası değişmiş gibi görünmesi çok yaygındı ve günlük zaman damgası doğruluğuna da fazla hassas biçimde güvenilemezdi
Güvenli alt sınır fiilen 1 saniyeydi; bazı bileşenlerin zaman damgalarını kestiğini ya da yuvarladığını hatırlıyorum
Benzersiz bir tanımlayıcı gerekiyorsa sürüm 4 UUID, yani rastgele UUID kullanın
Çakışma olasılığı, kuantum dalgalanması yüzünden yetişkin bir dinozorun yatak odanızda aniden belirme olasılığına benzer
Biraz daha ciddi konuşursak, kullanılabiliyorsa eski usul artan değer muhtemelen en iyisidir
Hızlı ve ucuzdur; özellikle veritabanlarında böyledir, ancak ID değerinden bilgi çıkarılabilmesi gibi gizlilik ve güvenlik sorunları vardır
Bu tür durumlarda ya da dağıtık sistemlerle uğraşırken UUID daha iyidir
Çözünürlük nanosaniye olsa bile, gerçek bilgisayar saatinin hassasiyetinin ne düzeyde olduğunu merak ediyorum
Gerçekten nanosaniye düzeyinde olacağını hayal etmek zor; fizik laboratuvarı dersinde öğrencilere ölçüm cihazının gösterdiği en küçük sayının doğrulukla aynı şey olmadığını sürekli vurguladığım zamanları hatırlatıyor
Ancak bu, o düzeyde doğru olduğu anlamına gelmez; çok çekirdekli sistemlerde çekirdekler arasındaki saatler o seviyede senkronize olmayabilir
ARMv8, saatin en az 1GHz hızında arttığını garanti eder, ancak Intel ve önceki ARM daha karmaşıktır
Erlang/Elixir’in BEAM VM’i bu farkı çok net biçimde ortaya koyar. Bu, monoton artış ile katı monoton artış arasındaki ayrımdır
https://www.erlang.org/doc/apps/erts/time_correction.html#mo...
“Monoton artan bir değerler dizisinde, kendinden önce bir değer bulunan her değer, o önceki değerden büyük ya da ona eşittir”
Bu, https://www.erlang.org/doc/man/erlang.html#monotonic_time-0 fonksiyonuyla kullanılabilir
https://www.erlang.org/doc/apps/erts/time_correction.html#st...
“Katı biçimde monoton artan bir değerler dizisinde, kendinden önce bir değer bulunan her değer, o önceki değerden büyüktür”
Katı monoton değerler bir tür senkronizasyon ya da koordinasyon anlamına gelir ve çok sayıda eşzamanlı süreç olduğunda performans maliyeti getirir
Bu özellik https://www.erlang.org/doc/man/erlang.html#unique_integer-1 fonksiyonuyla sağlanır; belgelerde de katı biçimde monoton artan değerlerin doğası gereği üretim maliyetinin yüksek olduğu ve iyi ölçeklenmediği uyarısı yapılıp,
monotonicdeğiştiricisinin yalnızca gerçekten gerektiğinde geçirilmesi söylenirBaşka bir deyişle UUIDv1’e ya da https://en.wikipedia.org/wiki/Snowflake_ID’ye benzer
Katı monoton küresel tanımlayıcılara gerçekten yalnızca anında tutarlı ilk/son yazan kazanır semantiğine ihtiyaç duyulduğunda gerek vardır
Bunun yerine nihai tutarlı ilk/son yazan kazanır yaklaşımını kullanabiliyorsanız; örneğin yazma olayları ID’ye göre doğrusallaştırılan bir event store’a ya da kuyruğa giriyor ve “eşzamanlı” yazmalar arasında yalnızca ID önceliği en yüksek olanı bırakıp diğerlerini işleme sırasında veya okuma anında atabiliyorsanız, önce sıkıştırılmış bir
(nodeID, seq)çifti düşünürdümKüresel olay sıralaması gerekiyorsa, özellikle Snowflake ID biçimindeki
(timestampMajor, nodeID, timestampMinor, seq)dikkate alınmaya değerFreeBSD’de
CLOCK_MONOTONIC_RAWolmadığı için yorum satırına aldım; iyi görünüyorÇakışma varsa bazı zaman damgalarının tekrarlanması gerektiğini sanmıştım, ama çakışma oluşturamıyorum
clock_getres(CLOCK_REALTIME, ...)=1 ns,clock_getres(CLOCK_MONOTONIC, ...)=1 nsolarak çıkıyor ve 30 örnekte de fark yaklaşık 29~71 ns aralığında sürekli artmaya devam ettiSonuçta bir noktada bunun komut kümesi mimarisi meselesine indiğini düşünüyorum
3 GHz’de çalışan bir CPU, nanosaniye başına 3 saat döngüsü elde eder
Derleyici optimizasyonuyla saat kaydını okuyan assembly çağrılarının arka arkaya gelmesi oldukça olası görünüyor
Ardışık
time.Now()çağrıları 3 saat döngüsü içinde gerçekleşiyorsa, gerçekten benzersiz nanosaniye hassasiyeti beklemek adil mi, emin değilimÇakışmalar biraz nadir olsa bile, günde birkaç kez meydana gelmesi “neredeyse asla olmaz”dan çok daha kötüdür
Lotus Notes ile ilgili efsane aklıma geldi
Eskiden benzersiz ID olarak 1 saniye çözünürlüklü zaman damgaları kullanıldığı söylenir
Çakışma olursa sadece 1 saniye eklenirmiş; sonunda çakışmalar o kadar çoğalmış ki öğeler gelecek zamanlara sahip olmaya başlamış
Mutlak olarak doğru zaman bir güvenlik sorunudur
CPU tasarımcıları, tam öngörülebilirliği engellemek için DEC’in Alpha dönemindeki gibi çok eskiden beri kasıtlı olarak saat jitter’ı eklemiştir
x86’da da 3~4 kez çalıştırıp değerleri bir register’a kaydettikten sonra en sonda raporlarsanız, zaman farklarının tam olarak aynı olmadığını görebileceğinizi düşünüyorum
Aramada pek bulamadım; eğer bu ifade erken dönem x86’yı da kapsıyorsa, doğru saatin güvenlik sorunlarının bu kadar erken fark edilmiş olması şaşırtıcı
Kişisel olarak bu milenyumdan önce böyle bir sorunun bilinmediğini, gözlenen saat jitter’ının da kesmeler gibi şeylerle açıklanacağını tahmin ederdim
Yanlış demiyorum, sadece daha fazlasını öğrenmek istiyorum
Milisaniye ya da mikrosaniye zaman damgası çakışmalarına şaşıran çok fazla kişi gördüm
En akılda kalan ve en sevmediğim tür, zaman damgasını iki sistem çağrısıyla birleştirme yöntemiydi
Biri üst basamaklar, diğeri alt basamaklar için çağrılıyor; ama süreç preemption’ı nedeniyle üst basamak okunduktan sonra alt basamak 99x’ten 00x’e geçerse, bir varlığı oluşturan nedenden daha erken bir zamana ait zaman damgası üretebilirsiniz
Bu durumda bazı kodlar oldukça gösterişli biçimde bozulur ve en az iki kez sonsuz döngü gördüm
Bunu her zaman kaçınılması gereken bir şey olarak ezberlemezseniz testler %99,5 oranında geçer ve örüntü yakalama sezgisi çok iyi olan birinin “aynı test bir buçuk ay boyunca haftada bir kez kırmızıya döndü” durumunu fark etmesi gerekir
CI/CD kodunun içinde bir mantık bombası düzeltilmeden önce yaşayamayacak kadar uzun bir süredir bu