Yeni içerik geldiğinde bildirim almak ister misiniz?
Günlükleri derinlemesine inceleme
Üniversiteden mezun olduktan sonra Amazon'a katıldığımda, ilk çalışmalarımdan biri geliştirici masaüstü bilgisayarımda amazon.com web sunucusunu çalışır hale getirmekti. İlk denememde başaramadım ve neyi yanlış yaptığımdan emin değildim. Yardımsever bir iş arkadaşım neyin yanlış olduğunu görmek için günlüklere bakmamı önerdi. Bunu yapmak için "günlük dosyasına 'cat' komutu uygulamam" gerektiğini söyledi. Bana bir oyun oynadıklarını ya da anlamadığım bir şaka yaptıklarını düşünmüştüm. Linux'u üniversitedeyken sadece derlemek, kaynak denetimi yapmak ve metin düzenleyicisinden yararlanmak için kullanmıştım. Bu nedenle, "cat" komutunun benzerlikleri bulması amacıyla başka bir programa aktarmak üzere terminale bir dosya yazdırmak için kullanılan bir komut olduğunu bilmiyordum.
İş arkadaşlarım beni cat, grep, sed ve awk gibi araçlara yönlendirdi. Bu yeni araç takımını kullanarak geliştirici masaüstümdeki amazon.com web sunucusu günlüklerini incelemeye başladım. Web sunucusu uygulaması, halihazırda günlüklerine her türlü yararlı bilgiyi aktarmak üzere yapılandırılmıştı. Bu sayede web sunucusunun başlamasını engelleyen, nerede kilitlenmiş olabileceğini gösteren ya da bir aşağı akış hizmetiyle iletişim kuramadığı yeri belirten yapılandırmayı görebildim. Web sitesi çok sayıda hareketli parçadan oluştuğundan, başlangıçta bana bir kara kutu gibi geliyordu. Ancak sistemi derinlemesine inceledikten sonra yalnızca izleme çıktısına bakarak sunucunun nasıl çalıştığını ve bağımlılıklarıyla nasıl iletişim kurduğunu çözmeyi öğrendim.
Neden izleme kullanıyoruz?
Neler ölçülmelidir?
Hizmetleri erişilebilirlik ve gecikme süresi konusundaki yüksek standartlarımıza göre yönetmek için hizmet sahipleri olarak sistemlerimizin nasıl davrandığını ölçmemiz gereklidir.
Hizmet sahipleri, gerekli telemetriyi elde etmek için sistemdeki uçtan uca davranışlara dair birden fazla bakış açısı elde etmek üzere birden fazla yerde operasyonların performansını ölçer. Bu işlem basit bir mimaride bile karmaşıktır. Müşterilerin yük dengeleyici üzerinden kullandığı bir hizmeti düşünün. Bu hizmet, uzaktan bir önbellek ve uzaktan bir veritabanıyla iletişime geçer. Her bileşenin davranışıyla ilgili ölçümleri aktarmasını isteriz. Ayrıca, her bileşenin diğer bileşenlerin davranışını nasıl algıladığına ilişkin ölçümler de isteriz. Tüm bu yerlerden gelen ölçümler bir araya getirildiğinde, hizmet sahibi sorunların kaynağını hızlı bir şekilde belirleyip nedeni bulmak için derine inebilir.
Birçok AWS hizmeti, otomatik olarak kaynaklarınız hakkında operasyonel bilgiler sağlar. Örneğin Amazon DynamoDB, hizmet tarafından ölçülen, başarı ve hata oranları ile gecikme süresiyle ilgili Amazon CloudWatch ölçümlerini sağlar. Ancak bu hizmetleri kullanan sistemler oluşturduğumuzda, sistemlerimizin nasıl davrandığı konusunda daha fazla görünürlük elde etmemiz gerekir. İzleme için görevlerin ne kadar sürdüğünü, belirli kod yollarının ne sıklıkta kullanıldığını, görevin ne üzerinde çalıştığını ve görevlerin hangi kısımlarının başarılı olduğunu veya hata verdiğini kaydeden açık bir kod gereklidir. Ekip bu tür bir açık izleme eklemezse, kendi hizmetini kara kutu olarak çalıştırmak zorunda kalır.
Örneğin ürün bilgilerini ürün kimliğine göre alan bir hizmet API işlemi uygulamamız durumunda, kod şu örnektekine benzer olabilir. Bu kod yerel bir önbellekte, ardından uzak bir önbellekte ve sonrasında ise bir veritabanında ürün bilgilerini arar:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest request) {
// check our local cache
ProductInfo info = localCache.get(request.getProductId());
// check the remote cache if we didn't find it in the local cache
if (info == null) {
info = remoteCache.get(request.getProductId());
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {
info = db.query(request.getProductId());
localCache.put(info);
remoteCache.put(info);
}
return info;
}
Bu hizmeti yönetiyor olsaydım, üretim adımında sergilediği davranışları anlayabilmek için bu kodda birçok izlemeye ihtiyacım olurdu. Hata veren veya yavaş yanıtlanan isteklerdeki sorunları giderebilmem ve farklı bağımlılıkların yetersiz ölçeklendirildiği veya doğru davranmadığına dair eğilimleri ve işaretleri izleyebilmem gerekirdi. Belirli bir istek için veya bir bütün olarak üretim sistemi hakkında cevaplayabiliyor olmam gereken birkaç sorunun bulunduğu aynı kodu görebilirsiniz:
public GetProductInfoResponse getProductInfo(GetProductInfoRequest request) {
// Which product are we looking up?
// Who called the API? What product category is this in?
// Did we find the item in the local cache?
ProductInfo info = localCache.get(request.getProductId());
if (info == null) {
// Was the item in the remote cache?
// How long did it take to read from the remote cache?
// How long did it take to deserialize the object from the cache?
info = remoteCache.get(request.getProductId());
// How full is the local cache?
localCache.put(info);
}
// finally check the database if we didn't have it in either cache
if (info == null) {
// How long did the database query take?
// Did the query succeed?
// If it failed, is it because it timed out? Or was it an invalid query? Did we lose our database connection?
// If it timed out, was our connection pool full? Did we fail to connect to the database? Or was it just slow to respond?
info = db.query(request.getProductId());
// How long did populating the caches take?
// Were they full and did they evict other items?
localCache.put(info);
remoteCache.put(info);
}
// How big was this product info object?
return info;
}
Tüm bu soruları (ve daha fazlasını) yanıtlamak için kod, gerçek iş mantığından oldukça uzundur. Bazı kitaplıklar izleme kodu miktarını azaltmaya yardımcı olabilir ancak geliştiricinin kitaplıkların ihtiyaç duyacağı görünürlük hakkındaki soruları yine de sorması ve ardından izleme ekleme konusunda ne yaptığını bilmesi gereklidir.
Dağıtılmış sistemden geçen bir istekle ilgili sorunları giderirken yalnızca bir etkileşime dayanarak bu isteği incelerseniz, ne olduğunu anlamak zor olabilir. Parçaları bir araya getirmek için tüm bu sistemlerden elde edilen ölçümlerin tamamını tek bir yerde toplamanın işe yaradığını düşünüyoruz. Bunu yapmadan önce hizmetlerin her görev için bir izleme kimliği kaydedecek ve bu izleme kimliğini, söz konusu görevde iş birliği yapan diğer hizmetlere aktaracak izleme özellikleriyle donatılması gereklidir. Belirli bir izleme kimliği için sistem genelinde izlemenin toplanması, durum gerçekleştikten sonra gerekmesi halinde veya AWS X-Ray gibi bir hizmet yardımıyla neredeyse gerçek zamanlı olarak yapılabilir.
Derine inme
İzleme, alarmları tetikleyecek belirgin olmayan anormallikler bulunup bulunmadığını görmek için ölçümlere bakmaktan bu anormalliklerin nedenini bulmak için araştırma yapmaya kadar birçok düzeyde sorun gidermeye olanak sağlar.
En üst düzeyde; izleme, alarmları tetikleyebilen ve panolarda görüntülenebilecek ölçümler şeklinde toplanabilir. Bu toplu ölçümler; operatörlerin genel istek oranını, hizmet çağrılarındaki gecikme süresini ve hata oranlarını izlemesini sağlar. Bu alarmlar ve ölçümler, bizi araştırılması gereken anormallikler veya değişikliklerden haberdar eder.
Bir anormalliği tespit ettikten sonra bunun neden meydana geldiğini çözmemiz gerekir. Bu soruyu cevaplamak için daha da fazla izlemeyle mümkün olan ölçümlere güveniyoruz. Bir isteğin karşılanmasındaki süreci oluşturan çeşitli bölümleri gerçekleştirme sırasında geçen süreyi izleyerek, işlemin hangi bölümünün normalden daha uzun sürdüğünü veya hataları daha sık tetiklediğini görebiliriz.
Toplu süreler ve ölçümler, nedenleri ortadan kaldırmamıza veya bir araştırma alanını vurgulamamıza yardımcı olsa da her zaman tam bir açıklama sunmazlar. Örneğin, ölçümlere bakarak hataların belirli bir API işleminden geldiğini söyleyebiliriz ancak bu ölçümler operasyonun neden hata verdiği hakkında yeterince ayrıntılı bilgi vermeyebilir. Bu noktada, hizmet tarafından bu zaman aralığı için aktarılan ham, ayrıntılı günlük verilerini inceleriz. Ardından, ham günlükler meydana gelen belirli bir hatayı ya da bazı uç durumları tetikleyen isteğin belirli yönlerini göstererek sorunun kaynağını ortaya çıkarabilir.
Nasıl izleme yapıyoruz?
İzlemek için kodlama gereklidir. Bu; yeni işlevler uygularken ne meydana geldiğini, işlevin başarılı olup olmadığını ve ne kadar sürdüğünü belirtmek için daha fazla kod eklemeye vakit ayırmamız gerektiği anlamına geliyor. İzleme oldukça yaygın bir kodlama işi olduğu için ortak izleme kitaplıkları ve yapılandırılmış günlük tabanlı ölçüm raporlarına yönelik standartlaştırma gibi ortak modelleri ele almak adına yıllar içinde Amazon'da çeşitli uygulamalar ortaya çıktı.
Ölçüm izleme kitaplıklarını standartlaştırma, kitaplık yazarlarının kullanıcılara kitaplığın nasıl çalıştığını göstermelerini sağlamada yardımcı olur. Örneğin, yaygın olarak kullanılan HTTP istemcileri bu ortak kitaplıklara entegre olur. Böylece bir hizmet ekibi başka bir hizmete uzaktan çağrı yaparsa, bu aramalar hakkında otomatik olarak izleme edinir.
İzleme özelliğine sahip bir uygulama çalışıp iş yaptığında, elde edilen telemetri verileri yapılandırılmış bir günlük dosyasına yazılır. İster bir HTTP hizmetine yapılan bir istek ister kuyruktan alınan bir mesaj olsun, genel olarak "iş birimi" başına bir günlük girdisi olarak hazırlanır.
Amazon'da, uygulamadaki ölçümler toplanmaz ve zaman zaman bir ölçüm toplama sistemine taşınır. Her iş parçası için tüm zamanlayıcılar ve sayaçlar bir günlük dosyasına yazılır. Daha sonra günlükler işlenir ve toplu ölçümler olayın ardından başka bir sistem tarafından değerlendirilir. Bu sayede, üst düzey toplu operasyon ölçümlerinden istek düzeyinde ayrıntılı sorun giderme verilerine kadar her şeyi izleme koduna yönelik tek bir yaklaşımla elde ederiz. Amazon'da önce günlüğe kaydedip daha sonra toplu ölçümler üretiriz.
Günlüğe kaydederek izleme
Hizmetlerimizi en yaygın olarak istek verileri ve hata ayıklama verileri olmak üzere iki tür günlük verisi elde etmek için izleriz. İstek günlüğü verileri, genellikle her iş birimi için tek bir yapılandırılmış günlük girdisi olarak gösterilir. Bu veriler; istekle ilgili özellikleri ve isteği kimin yaptığını, isteğin ne için olduğunu, ne sıklıkta olay gerçekleştiğini gösteren sayaçları ve olayların ne kadar sürdüğünü belirten zamanlayıcıları içerir. İstek günlüğü, denetim günlüğü işlevi görür ve hizmette meydana gelen her olayla ilgili bir iz oluşturur. Hata ayıklama verileri, uygulamanın aktardığı tüm hata ayıklama satırlarının yapılandırılmamış veya yetersiz yapılandırılmış verilerini içerir. Bunlar genellikle Log4j hatası veya uyarı günlüğü satırları gibi yapılandırılmamış günlük girdileridir. Amazon'da bu iki tür veri, kısmen tarihsel nedenlerden dolayı ve aynı zamanda homojen bir günlük girdisi biçiminde günlük analizi yapmak uygun olabileceği için ayrı günlük dosyalarına aktarılır.
CloudWatch Logs Aracısı gibi aracılar, her iki günlük verisi türünü gerçek zamanlı olarak işler ve günlükleri CloudWatch Logs'a gönderir. Buna karşılık, CloudWatch Logs hizmetle ilgili neredeyse gerçek zamanlı toplu ölçümler oluşturur. Amazon CloudWatch Alarmları bu toplu ölçümleri okur ve alarmları tetikler.
Her istek hakkında günlüğe çok fazla ayrıntı girmek maliyetli olsa da Amazon olarak bunu yapmanın inanılmaz derecede önemli olduğunu düşünüyoruz. Sonuçta erişilebilirlik uyarılarını, gecikme süresindeki ani artışları ve müşteri tarafından bildirilen sorunları araştırmamız gereklidir. Ayrıntılı günlükler olmadan müşterilere cevap veremez ve aldıkları hizmeti iyileştiremeyiz.
Ayrıntılara girme
İzleme ve alarm verme konusu oldukça geniştir. Bu makalede alarm eşikleri oluşturup ayarlama, operasyon panoları oluşturma, hem sunucu hem de istemci tarafından performansın ölçülmesi, devamlı çalışan "kanarya" uygulamaları ile ölçümleri toplamak ve günlükleri analiz etmek için kullanılacak doğru sistemi seçme gibi konuları ele almayacağız.
Bu makale, doğru ham ölçüm verilerini üretmeleri için uygulamalarımıza izleme özelliği ekleme ihtiyacına odaklanmaktadır. Amazon ekiplerinin uygulamalarına izleme özelliği eklerken dahil etmeye (veya kaçınmaya) çalıştığı durumları açıklayacağız.
İstek günlüğüne ilişkin en i̇yi uygulamalar
Bu bölümde, yapılandırılmış "iş birimi başına" verilerimizi günlüğe kaydetme konusunda Amazon'da zamanla öğrenmiş olduğumuz iyi alışkanlıkları anlatacağım. Bu kriterleri karşılayan bir günlükte; ne sıklıkta olay gerçekleştiğini gösteren sayaçlar, gerçekleşen olayların ne kadar sürdüğünü gösteren zamanlayıcılar ve her iş biriminin meta verilerini içeren özellikler bulunur.
• Her iş birimi için bir istek kaydı girdisi gönderin. Bir iş birimi, genelde hizmetimizin aldığı bir istek veya kuyruktan çektiği bir mesajdır. Hizmetimizin aldığı her istek için bir hizmet günlüğü girdisi oluştururuz. Birden fazla iş birimini bir araya getirmeyiz. Bu sayede, hata veren bir istekteki sorunları giderirken bakmamız gereken tek bir günlük girdisi olur. Bu girdi; ne yapmaya çalıştığını görmek için istek hakkındaki konuyla ilgili girdi parametrelerini, arayanın kim olduğu hakkındaki bilgileri ve tüm zamanlama ile sayaç bilgilerini tek bir yerde toplar.
• Belirli bir istek için birden fazla istek günlük girdisi oluşturmayın. Engelleyici olmayan bir hizmet uygulamasında, bir işleme hattındaki her aşama için ayrı bir günlük girdisi oluşturmak uygun görünebilir. Bunun yerine, hat içerisindeki aşamalar arasında tek bir "ölçüm nesnesine" işaret yerleştirip ardından tüm aşamalar tamamlandıktan sonra ölçümleri bir birim olarak serileştirerek bu sistemlerde sorun giderme konusunda daha başarılı oluruz. İş birimi başına birden fazla günlük girdisi bulunması, günlük analizini daha da zorlaştırır ve halihazırda maliyetli olan günlüğe kaydetme yükünü bir kat daha artırır. Engelleyici olmayan bir hizmet yazıyorsak, daha sonradan yeniden düzenlemek ve onarmak oldukça zorlaşacağından yaşam döngüsünü kaydetme işlemini önceden planlamaya çalışırız.
• Uzun süren işleri birden fazla günlük girdisine bölün. Önceki tavsiyenin aksine uzun süren, birkaç dakikalık veya birkaç saatlik bir iş akışı benzeri işimiz varsa, düzenli olarak ayrı bir günlük girdisi oluşturmaya karar verebilir, böylece ilerleme olup olmadığını veya nerede yavaşlama olduğunu tespit edebiliriz.
• Doğrulama gibi işlemler yapmadan önce istekle ilgili ayrıntıları kaydedin. Amacının ne olduğunu bilmemiz için istekle ilgili yeterli bilgiyi günlüğe kaydetmenin sorun giderme ve denetim günlüğü için önemli olduğunu düşünüyoruz. Ayrıca isteğin doğrulama, kimlik doğrulaması veya kısıtlama mantığı tarafından reddedilme ihtimalinden önce bu bilgilerin günlüğe mümkün olduğunca erken kaydedilmesinin önemli olduğunu belirledik. Gelen istekten elde edilen bilgileri günlüğe kaydedeceksek, kaydetmeden önce girdi temizleme işlemlerini (kodlama, kaçma ve kesme) yaptığımızdan emin oluruz. Örneğin arayan, hizmet günlüğü girdimiz için 1 MB büyüklüğünde dizeler gönderdiğinde bunları eklemek istemeyiz. Bunu yapmamız halinde disklerimizin kapasitesinin dolma ve günlük depolamanın beklenenden daha maliyetli olma riski ortaya çıkar. Temizleme işleminin bir başka örneği, ASCII denetim karakterlerini filtrelemek veya günlük formatıyla ilgili kaçış sıralarıdır. Arayan, kendi hizmet günlüğü girdisini gönderip bunu günlüklerimize yerleştirebiliyorsa, bu durum kafa karıştırıcı olabilir! Ayrıca bkz.: https://xkcd.com/327/
• Artan ayrıntı düzeyinde günlüğe kaydetmek için bir yöntem planlayın. Bazı sorun türlerini ortadan kaldırmak için günlük içerisinde neden hata verdiklerini anlamak için sorunlu istekler hakkında yeterince ayrıntı bulunmayacaktır. Bu bilgi hizmette mevcut olabilir ancak bilgi hacmi, sürekli olarak günlüğe kaydetme işleminin yapılması için fazla büyük olabilir. Bir sorunu araştırırken günlüklerin ayrıntı düzeyini geçici olarak artırmak için basabileceğiniz bir yapılandırma düğmesinin olması yardımcı olabilir. Bu özelliği tek bir sunucuda veya istemcide ya da filo genelinde örnekleme hızında kullanabilirsiniz. İşlem tamamlandığında kapatmak için düğmeye tekrar basmayı unutmamak önemlidir.
• Ölçüm adlarını (çok kısa olmamak kaydıyla) kısa tutun. Amazon, 15 yıldan uzun bir süredir aynı hizmet günlüğü serileştirmesini kullanmaktadır. Bu serileştirme işleminde, her bir sayaç ve zamanlayıcı adı her hizmet günlüğü girdisinde düz metin olarak tekrarlanır. Günlüğe kaydetme yükünü en aza indirmeye yardımcı olması için zamanlayıcılara kısa ancak açıklayıcı adlar veririz. Amazon, Amazon Ion olarak bilinen ve ikili bir serileştirme protokolünü temel alan yeni serileştirme biçimlerini benimsemeye başlamıştır. Sonuç olarak araçların anlayabileceği ve ayrıca mümkün olduğunca verimli bir şekilde serileştireceği, serileştirmeden çıkarılabileceği ve depolayacağı günlük analizi araçlarının seçilmesi önem arz eder.
• Günlük hacimlerinin, maksimum aktarım hızında günlük kaydı yapmak için yeterince büyük olduğundan emin olun. Sürekli en yüksek yükte (hatta aşırı yükte) hizmetlerimize saatlerce yük testi uyguluyoruz. Hizmetimiz aşırı trafik yönetirken, hizmetin elindeki günlükleri yeni günlük girdileri üretme oranında gönderecek kaynaklara sahip olduğundan emin olmamız gerekir, aksi halde disk kapasitesinin dolması kaçınılmazdır. Ayrıca, günlük kaydını kök bölümden farklı bir dosya sistemi bölümünde yazılacak şekilde yapılandırabilirsiniz, böylece sistem aşırı günlük kaydı durumunda hata vermez. Aktarım hızı ile orantılı olan dinamik örneklemeyi kullanmak gibi buna yönelik etki azalma yöntemlerini daha sonra ele alacağız ancak strateji ne olursa olsun test etmek çok önemlidir.
• Disk kapasitesinin dolması durumunda sistemin vereceği tepkiyi göz önünde bulundurun. Bir sunucunun diski dolduğunda, diske günlük kaydı yapamaz. Bu durum söz konusu olduğunda bir hizmet istek kabul etmeyi durdurmalı mı, yoksa günlük kaydı yapmayı bırakıp izlemeden çalışmaya devam mı etmelidir? Günlük kaydı olmadan çalışmak risklidir, bu nedenle diskleri dolmak üzere olan sunucuların tespit edilmesini sağlamak için sistemleri test ederiz.
• Saatleri eşitleyin. Dağıtılmış sistemlerde "zaman", herkesçe bilinen karmaşık bir kavramdır. Dağıtılmış algoritmalarda saat eşitlemesine güvenemeyiz ancak günlüklerin anlamlı olması için gereklidir. Saat eşitlemesi için Chrony veya ntpd gibi daemon'lar kullanırız ve sunucularda saat sapması olup olmadığını takip ederiz. Bu işlemi kolaylaştırmak için Amazon Time Sync Service'a göz atın.
• Erişilebilirlik ölçümleri için sayım yapmayın. Hata sayımları yararlıdır ancak hata yüzdeleri de yararlı olabilir. "Erişilebilirlik yüzdesi" ölçümünü izlemek için faydalı bulduğumuz bir strateji, istek başarılı olduğunda 1 değeri ve istek başarısız olduğunda 0 değeri bildirmektir. Ardından, elde edilen ölçümün "ortalama" istatistiği erişilebilirlik oranıdır. Kasıtlı olarak 0 veri noktası bildirmek, diğer durumlarda da yardımcı olabilir. Örneğin bir uygulama lider seçimi gerçekleştiriyorsa, bir işlem lider olduğunda belirli aralıklarla 1 veya işlem lider olmadığında 0 değerini bildirmek takipçilerin durumunun izlenmesinde yardımcı olabilir. Bu şekilde, bir işlem 0 değeri bildirmeyi durdurursa, içerisindeki bir şeyin hata verip vermediğini anlamak daha kolaydır ve lidere bir şey olması durumunda yerini devralamaz.
• Tüm bağımlılıkların erişilebilirlik ve gecikme süresi verilerini günlüğe kaydedin. Bunun özellikle "İstek neden yavaş yanıtlandı?" ya da "İstek neden hata verdi?" gibi soruları yanıtlamada faydalı olduğunu belirledik. Bu günlük olmadan, sadece bağımlılık grafiklerini bir hizmetin grafikleriyle karşılaştırabilir ve bağımlı bir hizmetin gecikme süresindeki ani bir artışın araştırdığımız isteğin hata vermesine yol açıp açmadığını tahmin edebiliriz. Birçok hizmet ve istemci çerçevesi, ölçümleri otomatik olarak yapmaktadır ancak diğer çerçeveler için (AWS SDK gibi) manuel izleme gereklidir.
• Çağrı, kaynak, durum kodu vb. başına bağımlılık ölçümleri çıkarın. Aynı iş birimindeki aynı bağımlılıkla birden çok kez etkileşime geçersek, her çağrıya ilişkin ölçümleri ayrı ayrı toplar ve her bir isteğin hangi kaynakla etkileşime geçtiğini belirleriz. Örneğin, Amazon DynamoDB'ye çağrı yaparken bazı ekipler tablo başına, ayrıca hata kodu başına ve hatta yeniden deneme sayısına göre zamanlama ve gecikme süresi ölçümlerini eklemenin yararlı olduğunu belirlemiştir. Böylece, koşullu denetim hataları nedeniyle hizmetin yeniden denemelerden dolayı yavaş olduğu durumlarda sorun giderme kolaylaşır. Ayrıca bu ölçümler, istemci tarafından algılanan gecikme süresi artışlarının aslında yeniden deneme sayısı kısıtlamasına veya bir sonuç kümesini ayrıştırmaya bağlı olduğu ve paket kaybı ya da ağ gecikmesinden kaynaklanmadığı durumlar bulunduğunu ortaya çıkarmıştır.
• Bellek kuyruk derinliklerine eriştiğiniz sırada bunları kaydedin. Bir istek, kuyruk ile etkileşime geçerse ve içerisinden bir nesne çeker veya içerisine bir şey eklersek, işlem sırasında mevcut kuyruk derinliğini ölçümler nesnesine kaydederiz. Bellek içi kuyruklar için bu bilgiyi elde etmenin maliyeti düşüktür. Dağıtılmış kuyruklar için bu meta veriler API çağrılarına verilen yanıtlarda ücretsiz olarak kullanılabilir. Bu günlük kaydı, gelecekteki biriktirme listelerini ve gecikme kaynaklarını bulmaya yardımcı olacaktır. Ek olarak, mesajları kuyruktan aldığımızda, mesajların kuyrukta bulunduğu süreyi ölçeriz. Bu, mesajı kuyruğa almadan önce mesaja kendi "kuyruğa alınma zamanı" ölçümümüzü eklememiz gerektiği anlamına gelir.
• Her hata nedeni için ek bir sayaç ekleyin. Her başarısız istek için belirli bir hata nedenini sayan bir kod eklemeyi düşünebilirsiniz. Uygulama günlüğünde, hataya neden olan bilgiler ve ayrıntılı bir özel durum mesajı bulunacaktır. Ancak, uygulama günlüğündeki bu bilgileri araştırıp bulmak zorunda kalmadan, zaman geçtikçe ölçümlerdeki hata nedenlerinde bulunan eğilimleri incelemenin de yardımcı olduğunu belirledik. Her bir hata özel durum kategorisi için ayrı bir ölçümle başlamak yararlıdır.
• Hataları nedenlerine göre düzenleyin. Tüm hatalar aynı ölçümde toplanırsa, ölçümde aşırı çeşitlilik olur ve kullanılamaz hale gelir. En azından, "istemci hatası" olan hataları "sunucu hatası" olan hatalardan ayırmanın önemli olduğunu ortaya çıkardık. Bunun ötesinde, daha fazla ayrıntıya inmek yardımcı olabilir. Örneğin DynamoDB'de istemciler, değişiklik yaptıkları öğenin istekte belirtilen ön koşullarla eşleşmemesi durumunda hata döndüren koşullu yazma isteklerinde bulunabilir. Bu hatalar tahmin edilebilirdir ve zaman zaman gerçekleşmelerini bekleriz. İstemcilerden gelen "geçersiz istek" hataları büyük olasılıkla düzeltmemiz gereken hatalardır.
• İş birimiyle ilgili önemli meta verileri günlüğe kaydedin. Yapılandırılmış bir ölçüm günlüğünde, istekle ilgili yeterli meta verileri de ekleriz, böylece daha sonra isteğin amacını ve kimden geldiğini belirleyebiliriz. Bu, müşteriler sorun bildirdiğinde bu sorunların günlüğümüzde bulunduğunu düşündükleri meta verileri kapsar. Örneğin DynamoDB, bir isteğin etkileşime geçtiği tablonun adını ve okuma işleminin tutarlı bir okuma olup olmadığı gibi meta verileri günlüğe kaydeder. Ancak, veritabanında depolanan veya buradan alınan verileri günlüğe kaydetmez.
• Günlükleri erişim kontrolü ve şifreleme ile koruyun. Günlükler belirli düzeyde hassas bilgi içerdiği için bu verileri korumak ve güvenliğini sağlamak için önlemler alırız. Bu önlemler arasında günlükleri şifreleme, erişimi sorunları gideren operatörlerle sınırlama ve düzenli olarak bu erişime temel oluşturmayı içerir.
• Günlüklere aşırı hassas bilgiler kaydetmeyin. Günlüklerin yararlı olması için bazı hassas bilgiler içermesi gerekir. Amazon olarak günlüklerde belirli bir isteğin kimden geldiğini anlayacak kadar bilgi bulunmasının önemli olduğunu düşünüyoruz ancak yönlendirmeyi ve istek işleme davranışını etkilemeyen istek parametreleri gibi aşırı hassas bilgileri günlüklere dahil etmeyiz. Örneğin kod, bir müşteri mesajını çözümlüyor ve bu çözümleme hata veriyorsa, daha sonra sorun giderme işlemini zorlaştırsa da müşteri gizliliğini korumak amacıyla yükün günlüğe kaydedilmemesi önemlidir. Sonradan eklenen yeni bir hassas parametrenin günlüğe kaydedilmesini engellemek için reddetme yöntemi yerine kabul etme yöntemiyle nelerin günlüğe kaydedileceğiyle ilgili kararlar vermek için araçlar kullanırız. Amazon API Gateway gibi hizmetler, erişim günlüğüne hangi verilerin kaydedileceğini yapılandırmaya olanak sağlar ve iyi bir kabul mekanizması işlevi görür.
• Günlüğe bir izleme kimliği kaydedin ve arka uç çağrılarına aktarın. Belirli bir müşteri isteği için muhtemelen iş birliği içinde çalışan birçok hizmet devreye girecektir. Bu hizmetlerin sayısı, birçok AWS isteği için iki ya da üç kadar, amazon.com istekleri içinse çok daha fazla olabilir. Dağıtılmış bir sistemde sorun giderirken ne olduğunu anlamak için hataların nerede meydana geldiğini görmek üzere çeşitli sistemlerdeki günlükleri sıralayabilmemiz için bu sistemlere aynı izleme kimliğini aktarırız. İzleme kimliği, iş biriminin başlangıç noktası olan "ön kapı" hizmeti tarafından dağıtılmış bir iş birimine bağlanan bir tür meta istek kimliğidir. AWS X-Ray, bu aktarımın bir kısmını sağlayarak yardımcı olan bir hizmettir. İzleri bağımlılığımızla paylaşmanın önemli olduğunu belirledik. Birden fazla iş parçacıklı bir ortamda, çerçevenin bu aktarımı bizim adımıza yapması oldukça zor ve hataya açıktır, bu nedenle yöntem imzalarımızda izleme kimliklerini ve diğer istek içeriğini (ölçüm nesnesi gibi!) paylaşma alışkanlığı edindik. Ayrıca yöntem imzalarımızda bir Bağlam nesnesi paylaşmanın faydalı olduğu sonucuna vardık, böylece gelecekte paylaşmak için benzer bir model bulduğumuzda yeniden düzenlememize gerek kalmayacaktır. AWS ekipleri için konu sadece sistemlerimizde sorun giderme ile ilgili değil, aynı zamanda müşterilerin kendi sorunlarını gidermesiyle ilgilidir. Müşteriler, müşteri adına birbirleriyle iletişim kurduklarında AWS hizmetleri arasında paylaşılan AWS X-Ray izlerine güvenirler. İzleme verilerini eksiksiz alabilmeleri için müşterinin AWS X-Ray izleme kimliklerini hizmetler arasında aktarmamız gereklidir.
• Durum koduna ve boyutuna bağlı olarak farklı gecikme süresi ölçümlerini günlüğe kaydedin. Hatalar genellikle erişim reddedildi, kısıtlama ve doğrulama hata yanıtları gibi hızlı gerçekleşir. İstemciler yüksek oranda kısıtlama hatası almaya başlarsa, gecikme süresinin iyi görünmesi aldatıcı olabilir. Bu ölçüm kirliliğini önlemek amacıyla başarılı yanıtlar için günlüğe ayrı bir zamanlayıcı kaydeder ve genel bir Zaman ölçümü kullanmak yerine panolarımız ve alarmlarımızdaki bu ölçüme odaklanırız. Benzer şekilde, girdi veya yanıt boyutuna bağlı olarak daha yavaş gerçekleşebilen bir işlem varsa, SmallRequestLatency ve LargeRequestLatency gibi sınıflandırılmış bir gecikme süresi ölçümü yayımlayabiliriz. Ayrıca, isteğimizin ve yanıtlarımızın karmaşık kesinti ve hata modlarından kaçınacak şekilde sınırlandırılmasını sağlarız ancak bu ölçüm klasörleme tekniği, özenle tasarlanmış bir hizmette bile müşteri davranışını ayırabilir ve aşırı çeşitliliği panolardan uzak tutabilir.
Uygulama günlüğüne ilişkin en i̇yi uygulamalar
Bu bölümde, yapılandırılmamış hata ayıklama günlüğü verilerinin günlüğe kaydedilmesi konusunda Amazon'da öğrendiğimiz iyi alışkanlıklar açıklanmaktadır.
• Uygulama günlüğüne gereksiz veriler kaydetmeyin. Test ortamlarında geliştirme ve hata ayıklama işlemlerine yardımcı olması için istek yolunda INFO ve DEBUG düzeyinde günlük dökümleri olsa da, üretim adımında bu günlük düzeylerini devre dışı bırakabiliriz. İstek izleme bilgileri için uygulama günlüğüne güvenmek yerine, hizmet günlüğünü izleme bilgileri için kolayca ölçümler yapabileceğimiz ve zaman içinde toplu eğilimleri görebileceğimiz bir konum olarak görürüz. Ancak burada her şey siyah ve beyaz değildir. Uyguladığımız yaklaşım, günlüklerimizde aşırı çeşitlilik (ya da yeterli çeşitlilik) bulunup bulunmadığını belirlemek ve zaman içinde günlük düzeylerini düzenlemektir. Örneğin, günlükleri kapsamlı bir şekilde incelediğimizde, genellikle aşırı çeşitliliğe sahip günlük dökümleri veya elimizde olmasını istediğimiz ölçümleri buluruz. Neyse ki bu iyileştirmelerin yapılması kolaydır, bu nedenle günlüklerimizi temiz tutmak için takip biriktirme listesi öğelerini hızlı bir şekilde dosyalama alışkanlığı edindik.
• İlgili istek kimliğini ekleyin. Uygulama günlüğündeki bir hatayı giderirken, genellikle hatayı tetikleyen istek veya arayan hakkındaki ayrıntıları görmek isteriz. Her iki günlükte de aynı istek kimliği bulunuyorsa, bir günlükten diğerine kolayca geçebiliriz. Uygulama günlük kaydı kitaplıkları, uygun şekilde yapılandırılmışsa ilgili istek kimliğini yazar ve istek kimliği ThreadLocal olarak ayarlanır. Bir uygulama birden fazla iş parçacığına sahipse, bir iş parçacığı yeni bir istek üzerinde çalışmaya başladığında doğru istek kimliğini belirlemeye özen gösterin.
• Bir uygulama günlüğündeki gereksiz hata verilerini sınırlayın. Genellikle bir hizmet, uygulama günlüğüne çok fazla veri iletmez ancak aniden yüksek miktarda hata vermeye başlarsa, birdenbire yığın izlemelerinin bulunduğu çok büyük günlük girdileri yazmaya başlayabilir. Bundan korunmak için bulduğumuz bir yöntem, belirli bir günlük kaydedicinin ne sıklıkta günlüğe kayıt yapacağına ilişkin sınırlama koymaktır.
• Dize#biçim veya biçim birleştirme yerine biçim dizelerini tercih edin. Eski uygulama günlüğü API işlemleri, log4j2'nin varargs biçim dizesi api'si yerine tek bir dize mesajı kabul eder. Kod, DEBUG dökümleriyle donatılmış ancak üretim ERROR düzeyinde yapılandırılmışsa, dikkate alınmayan DEBUG mesaj dizelerini biçimlendirmeye boşuna zaman harcanabilir. Bazı günlüğe kaydetme API işlemleri, yalnızca günlük girdisi dışarı yazılacağı zaman çağrılan toString() yöntemlerine sahip rastgele nesneler paylaşmayı destekler.
• Hata veren hizmet çağrılarından gelen istek kimliklerini günlüğe kaydedin. Bir hizmete çağrı yapılır ve hata verirse, hizmet muhtemelen bir istek kimliği döndürmüştür. İstek kimliğini günlüğümüze kaydetmenin yararlı olduğunu belirledik, böylece hizmetin sahipleriyle iletişime geçmemiz gerektiğinde, ilgili hizmet günlüğü girdilerini kolayca bulabilmeleri için bir yöntem sunabiliyoruz. Zaman aşımı hataları, hizmetin henüz bir istek kimliği döndürmemiş ya da bir istemci kitaplığının kimliği ayrıştırmamış olması nedeniyle bu işlemi zorlaştırmaktadır. Fakat, hizmetten bir istek kimliği gelirse, bunu günlüğe kaydederiz.
Yüksek aktarım hızlı hizmetlere ilişkin en iyi uygulamalar
Amazon'daki hizmetlerin büyük çoğunluğu için her isteği günlüğe kaydetmek, aşırı bir maliyet yükü getirmez. Yüksek aktarım hızlı hizmetler daha gri bir alanda bulunur ancak çoğu zaman her isteği günlüğe kaydederiz. Örneğin, yalnızca Amazon iç trafiğinin saniyede 20 milyondan fazla isteğine tam kapasite hizmet veren DynamoDB'nin çok fazla günlük kaydı yapamayacağını varsaymak normaldir ancak sorun giderme, denetim ve uygunluk nedeniyle her isteği günlüğe kaydeder. Amazon olarak, günlüğe kaydetme işlemini ana bilgisayar başına daha yüksek aktarım hızında daha verimli hale getirmek için kullandığımız bazı üst düzey ipuçları şunlardır:
• Günlük örneklemesi. Her girdiyi tek tek yazmak yerine, her N girdide bir yazmayı deneyebilirsiniz. Ayrıca her girdide, kaç girdinin atlandığı belirtilir, böylece ölçüm toplama sistemleri işlediği ölçümlerdeki gerçek günlük hacmini tahmin edebilir. Rezervuar örneklemesi gibi diğer örnekleme algoritmaları daha iyi temsil örnekleri sunar. Diğer algoritmalar, başarılı ve hızlı istekler yerine günlük kaydı hatalarını veya yavaş istekleri önceliklendirir. Ancak örneklemede, müşterilere yardım etmek ve belirli hataları gidermek için bu özellik bulunmaz. Bazı uygunluk gereksinimleri bunu tamamen engeller.
• Serileştirme yükünü boşaltın ve ayrı bir iş parçacığına günlük kaydı yapın. Bu kolay bir değişikliktir ve yaygın olarak kullanılır.
• Günlük döndürmeyi sıklaştırın. Günlük dosyalarını saatte bir döndürmek uygun görünebilir, bu sayede ilgilenilmesi gereken dosya sayısı azalır ancak her dakika döndürdüğünüzde birçok şey iyileştir. Örneğin, günlük dosyasını okuyan ve sıkıştıran aracı, dosyayı disk yerine sayfa önbelleğinden okuyacak ve CPU ile sıkıştırma ve gönderim günlüklerindeki G/Ç, her zaman saat başında tetiklenmek yerine bir saate yayılacaktır.
• Günlükleri önceden sıkıştırılmış olarak yazın. Bir günlük taşıma aracısı, arşivleme hizmetine göndermeden önce günlükleri sıkıştırırsa, sistemde CPU ve disk kullanımı düzenli aralıklarla yükselir. Sıkıştırılmış günlükleri diske aktararak bu maliyeti sıfırlamak ve disk G/Ç'sini yarı yarıya azaltmak mümkündür. Bu işlem, bazı riskleri beraberinde getirir. Bir uygulamanın kilitlenmesi durumunda, kesilmiş dosyaları işleyebilecek bir sıkıştırma algoritması kullanmanın yararlı olduğunu belirledik.
• Bir ramdisk/tmpfs'ye yazın. Bir hizmetin, günlükleri diske yazmak yerine sunucudan gönderilinceye kadar belleğe yazması daha kolay olabilir. Deneyimlerimize göre bu yöntem, saatte bir günlük döndürme yerine her dakika günlük döndürüldüğünde en iyi sonucu verir.
• Bellek içi toplamalar. Tek bir makinede saniyede yüz binlerce işlem gerçekleştirilmesi gerekiyorsa, istek başına tek bir günlük girdisi yazmak çok maliyetli olabilir. Ancak bu işlemi yapmamanız halinde gözlemlenebilirlik düzeyi oldukça düşer, bu nedenle erken optimize etmemek yararlıdır.
• Kaynak kullanımını izleyin. Bazı ölçeklendirme sınırlamalarına ulaşmaya ne kadar yakın olduğumuza dikkat ediyoruz. Sunucu başına G/Ç ile CPU'muzu ve bu kaynakların ne kadarının günlük kaydı aracıları tarafından kullanıldığını ölçeriz. Yük testleri yaptığımızda, günlük taşıma aracılarımızın aktarım hızına yetişebildiğini gösterebilmek için testleri yeterince uzun yaparız.
Doğru günlük analizi araçlarını hazırda bulundurun
Amazon olarak kendi yazdığımız hizmetleri yönetiyoruz, bu nedenle hepimizin sorun giderme konusunda uzman olması gereklidir. Bu, kolaylıkla günlük analizi yapabilmeyi de kapsar. Nispeten az sayıda günlüğü incelemek için yerel günlük analizinden çok sayıda günlük arasından eleme yapmak ve sonuçları toplamak için dağıtılmış günlük analizine kadar elimizde birçok araç var.
Günlük analizi için ekiplerin araçlarına ve işletim kılavuzlarına yatırım yapmanın önemli olduğunu belirledik. Günlükler mevcut durumda küçük ancak bir hizmetin zaman içinde büyüyeceği düşünülüyorsa, mevcut araçlarımızın ölçeklendirmeyi ne zaman durdurduğuna dikkat ederiz. Böylece, dağıtılmış bir günlük analizi çözümü benimsemek için yatırım yapabiliriz.
Günlük analizi süreci, çeşitli Linux komut satırı yardımcı programlarında deneyimli olmayı gerektirebilir. Örneğin, yaygın "en çok konuşan IP adreslerini günlükte bulma" işlemi temelde şudur:
cat log | grep -P "^RemoteIp=" | cut -d= -f2 | sort | uniq -c | sort -nr | head -n20
Ancak, günlüklerimizi kullanarak daha karmaşık soruları yanıtlamaya yardımcı olan başka araçlar da vardır:
• jq: https://stedolan.github.io/jq/
• RecordStream: https://github.com/benbernard/RecordStream
Herhangi bir büyük veri analizi hizmeti, dağıtılmış günlük analizi yapmak için kullanılabilir (Amazon EMR, Amazon Athena, Amazon Aurora ve Amazon Redshift gibi). Ancak Amazon CloudWatch Logs gibi bazı hizmetler, günlük kaydı sistemleriyle donatılmış olarak gelir.
• CloudWatch Logs Insights
• AWS X-Ray: https://aws.amazon.com/xray/
• Amazon Athena: https://aws.amazon.com/athena/
Sonuç
Bir hizmet sahibi ve bir yazılım geliştiricisi olarak, zamanımın büyük bir kısmını panolardaki grafikler ve tekil günlük dosyaları gibi izleme özelliği çıktılarını inceleyerek ve CloudWatch Logs Insights gibi dağıtılmış günlük analizi araçlarını kullanarak geçiriyorum. Bunlar yapmayı en çok sevdiğim şeylerden bazıları. Zorlu bir işi tamamladıktan sonra mola vermem gerektiğinde, iyice dinlenip kendimi kapsamlı günlük incelemesiyle ödüllendiriyorum. "Neden bu ölçümde yükselme oldu?" veya "Bu işlemin gecikme süresi daha az olabilir mi?" gibi sorularla başlıyorum. Sorularım çıkmaza girdiğinde, genellikle kodda yardımcı olabilecek bazı ölçümler bulup izleme özelliği ekler, test eder ve ekip arkadaşlarıma bir kod incelemesi gönderirim.
Kullandığımız yönetilen hizmetlerle birlikte birçok ölçüm gelmesine rağmen, bu hizmetleri etkin bir şekilde kullanmak için gereken görünürlüğü elde etmek amacıyla kendi hizmetlerimize izleme özelliği ekleme konusunda fazlaca düşünmemiz gereklidir. Operasyonel olaylar sırasında, yaşadığımız sorunun kaynağını ve bu sorunun etkisini azaltmak için ne yapabileceğimizi hızlıca belirlememiz gereklidir. Panolarımızda doğru ölçümleri görmek çok önemlidir, bu sayede tanıyı hızlı bir şekilde koyabiliriz. Ayrıca hizmetlerimizi sürekli değiştirdiğimiz, yeni özellikler eklediğimiz ve bağımlılıklarıyla etkileşime geçme biçimlerini farklı hale getirdiğimiz için güncelleme yapma ve doğru izleme özelliklerini ekleme çalışmaları daima devam etmektedir.
Bağlantılar
• Eski Amazon çalışanı John Rauser tarafından "Look at your data": https://www.youtube.com/watch?v=coNDCIMH8bk (13:22'de günlükleri daha yakından incelemek için yazdırdığı bölüm dahil)
• Eski Amazon çalışanı John Rauser tarafından "Investigating anomalies": https://www.youtube.com/watch?v=-3dw09N5_Aw
• Eski Amazon çalışanı John Rauser tarafından "How humans see data": https://www.youtube.com/watch?v=fSgEeI2Xpdc
• https://www.akamai.com/uk/en/about/news/press/2017-press/akamai-releases-spring-2017-state-of-online-retail-performance-report.jsp
Yazar hakkında
David Yanacek, AWS Lambda üzerinde çalışan bir Kıdemli Baş Mühendistir. David, 2006'dan bu yana Amazon'da çalışan bir yazılım geliştiricisidir. Daha önce Amazon DynamoDB ve AWS IoT'de, dâhili web hizmeti çerçevelerinde ve filo operasyonları otomasyon sistemlerinde çalışmıştır. David'in iş yerinde en sevdiği aktivitelerden birisi, sistemlerin zaman içinde daha hatasız çalışması için operasyonel ölçümler yoluyla günlük analizi ve elemeler yapmaktır.