Hizmetler, her türlü yerleşik güvenilirlik ve dayanıklılık ile tasarlanabilir ancak pratikte güvenilir olmaları için öngörülebilir hatalar ortaya çıktığında bunları çözmeleri gerekir. Donanımlar er ya da geç bozulacağından, Amazon olarak yatay bir biçimde ölçeklenebilen ve yedekli hizmetler oluşturuyoruz. Tüm sabit sürücülerin maksimum bir kullanım ömrü vardır ve herhangi bir yazılım parçasının bir noktada çökmesi muhtemeldir. Bir sunucunun durumu iki seçenekten ibaret gibi görünebilir; ya çalışır ya da hiç çalışmaz ve devreden çıkar. Ancak durum bu şekilde değildir. Hata veren sunucuların kapanmak yerine sisteme öngörülemeyen ve bazen de ölçülemeyecek zararlar verebileceğini düşünüyoruz. Durum denetimleri bu tür sorunları otomatik olarak algılar ve müdahale eder.

Bu makale, tekil sunucu hatalarını tespit etme ve bunlara çözüm üretmede durum denetimlerini nasıl kullandığımızı, bu denetimler yapılmadığında ortaya çıkan durumları ve durum denetimleri hatalarına beklenmedik tepki gösteren sistemlerin küçük sorunları nasıl geniş çaplı kesintilere dönüştürebildiğini açıklamaktadır. Ayrıca, Amazon'daki deneyimlerimize dayanarak çeşitli durum denetimi uygulamaları arasındaki ödünlerin dengelenmesi konusunda öngörüler sağlıyoruz.

Büyük etkiye sahip küçük hatalar

Amazon'da yeni bir yazılım geliştiricisiyken, Amazon.com'un arkasındaki web sitesi işleme filosu üzerinde çalıştım. Bazı izleme özellikleri eklemek ve yazılımın ne kadar iyi çalıştığını görmek için değişiklik yapmaya çalışırken, hatalı kod yazdım. Hatalı kod nadiren tetikleniyor ancak meydana geldiğinde belirli bir web sunucusunun tüm isteklere boş hata sayfaları vermesine neden oluyordu. Yalnızca web sunucusu işlemini yeniden başlatmak sorunu çözmüştü. Hatalı kodu tespit ettik ve yaptığımız değişikliği hemen geri aldık. Ayrıca, ileride bu gibi durumları tespit edebilmek için birçok test ve gelişmiş işlemler ekledik. Hatalı kod üretim adımında olmasına rağmen büyük filodaki birkaç sunucu da bu hatayı verdi.
 
Hatalı kodu bulmayı özellikle zorlaştıran durum ise sunucunun kendisini iyi durumda olduğunu zannetmesiydi. Ayrıca sunucu; durumunu izleme sistemlerine bildirme özelliğini kaybetti, bu nedenle otomatik olarak hizmet dışı bırakılmadı ve normal alarmlarını tetiklemedi. Daha da kötüsü sunucu, çok hızlandı ve sorunsuz web sayfaları işleyen "iyi durumdaki eş sunuculardan" çok daha hızlı bir şekilde boş hata sayfaları üretmeye başladı. O zaman kullandığımız yük dengeleme teknolojisi, yavaş sunucular yerine hızlı sunucuları tercih ediyordu. Bu nedenle, iyi durumda olmayan sunuculara orantısız miktarda trafik yönlendirdi ve sorunun etki alanını genişletti.

İzleme işleminde sistemdeki birçok noktadan gelen hata oranları ve gecikme süreleri ölçüldüğünden, diğer alarmlar tetiklendi. Bu tür izleme sistemleri ve operasyonel işlemler, sorunu çözmek için bir dayanak noktası işlevi görse de doğru durum denetimleri, hataları hızlı bir şekilde tespit edip müdahale ederek bu tür sorunların etkisini önemli ölçüde azaltabilir.

Durum denetimi ödünleri

Durum denetimleri, belirli bir sunucudaki bir hizmetin işi başarıyla yapıp yapamayacağını sormanın bir yoludur. Yük dengeleyiciler, trafiği hangi sunucuya yönlendirmenin güvenli olduğunu belirlemek için düzenli aralıklarla her sunucuya bu soruyu sorar. Bir kuyruktaki mesajları yoklayan bir hizmet, kuyruktan daha fazla iş yoklamaya karar vermeden önce kendinin iyi durumda olup olmadığını sorgulayabilir. Her sunucuda veya harici bir izleme filosunda çalışan izleme aracıları, sunuculara iyi durumda olup olmadıklarını sorarak alarm verebilir veya hata veren sunucularla otomatik olarak ilgilenebilir.

Web sitesinde hatalı kod örneğimde görüldüğü üzere, iyi durumda olmayan bir sunucu hizmet vermeye devam ettiğinde, hizmet genelinde erişilebilirliği orantısız şekilde azaltabilir. On sunucudan oluşan bir filoda iyi durumda olmayan bir sunucu bulunması, filonun erişilebilirliğinin %90 veya daha az olacağı anlamına gelir. Daha da kötüsü, "en az sayıda istek" gibi bazı yük dengeleme algoritmaları, en hızlı sunucuya daha fazla iş vermektedir. Bir sunucu hata verdiğinde, genellikle hızlı bir şekilde istek hataları vermeye başlar ve iyi durumdaki sunuculardan daha fazla istek alarak hizmet filosunda bir "kara delik" oluşturur. Bazı durumlarda, hata veren istekleri başarılı isteklerin ortalama gecikme süresiyle uyumlu olacak şekilde yavaşlatarak kara deliklerin önlenmesi için ek koruma ekleriz. Ancak, kuyruk yoklayıcılarında olduğu gibi bu sorunun çözülmesinin daha zor olduğu başka senaryolar da vardır. Örneğin, bir kuyruk yoklayıcısı mesajları alabildiği kadar hızlı bir şekilde yoklayabiliyorsa, hata veren sunucu da bir kara delik haline gelecektir. İşlerin bu kadar çeşitli ortamlarda dağıtılacak olması nedeniyle, kısmen hata vermiş bir sunucuyu koruma yöntemimiz sistemden sisteme değişir.

Sunucuların; yazılamaz hale gelen ve isteklerin anında hata vermesine neden olan diskler, saatlerin aniden değişmesi ve buna bağlı olarak bağımlılıklara yapılan çağrıların kimlik denetiminden geçememesi, güncellenmiş şifre materyallerini alamayan ve şifre çözme ile şifrelemenin yapılamamasına neden olan sunucular, işlemenin donmasına neden olan kendi hataları, bellek sızıntıları ve kilitlenmeleri nedeniyle çöken kritik destek işlemleri dahil olmak üzere birçok nedene bağlı olarak bağımsız bir şekilde hata verdiklerini tespit ettik.

Sunucular, bir filodaki sunucuların birçoğunun veya tamamının hata vermesine sebep olan birbiriyle bağlantılı nedenlerden dolayı da hata verir. Bağlantılı nedenler arasında paylaşılan bir bağımlılığın kesilmesi ve büyük ölçekli ağ sorunları yer almaktadır. İdeal durum denetimi, sunucu ve uygulama durumunu her açıdan test eder, hatta kritik olmayan destek işlemlerinin çalışıp çalışmadığını da doğrular. Ancak, durum denetimi kritik olmayan bir nedenden dolayı yapılamadığında ve bu hata tüm sunucularda bağlantılı olduğunda sorun çıkmaktadır. Otomasyon, hâlâ faydalı işler yapabilecek sunucuları hizmetten çekerse, yarardan çok zarar vermiş olur.

Durum denetimlerinde yaşanan zorluk, bir yandan kapsamlı durum denetimlerinin faydaları ile tekil sunucu hatalarının etkilerinin hızla hafifletilmesi ve diğer yandan filo genelindeki yanlış pozitif bir hatanın verdiği zararlar arasındaki gerilimdir. Bu nedenle, iyi bir durum denetimi oluşturmanın zorluklarından biri yanlış pozitiflere karşı dikkatli bir şekilde korunmaktır. Genel olarak bu durum, durum denetimlerini çevreleyen otomasyonun trafiği kötü durumdaki tek bir sunucuya yönlendirmeyi bırakması ancak filonun tamamında sorun yaşanıyor gibi görünüyorsa trafiğin devam etmesi gerektiği anlamına gelir.

Durum ölçme yöntemleri

Bir sunucuda hata verebilecek birçok şey vardır ve sistemlerimizde sunucu durumunu ölçtüğümüz birçok yer bulunmaktadır. Bazı durum denetimleri, belirli bir sunucunun bağımsız olarak hata verdiğini kesin olarak bildirebilir, diğer denetimler ise daha karmaşıktır ve birbiriyle bağlantılı hatalar meydana gelmesi durumunda yanlış pozitif sonuçlar verebilir. Bazı durum denetimlerini uygulamak zordur. Diğer denetimler ise Amazon Elastic Compute Cloud (Amazon EC2) ve Elastic Load Balancing gibi hizmetlerde kurulum sırasında uygulanmaktadır. Her durum denetiminin güçlü yanları bulunur.

Canlılık denetimleri

Canlılık denetimleri bir hizmete giden temel bağlantıyı ve bir sunucu işleminin varlığını test eder. Bu denetimler genellikle bir yük dengeleyici veya harici izleme aracısı tarafından gerçekleştirilir ve bir uygulamanın nasıl çalıştığıyla ilgili ayrıntıları dikkate almazlar. Canlılık denetimleri, hizmete dahil olma eğilimindedir ve uygulama yazarının herhangi bir işlem yapmasını gerektirmez. Amazon'da kullandığımız bazı canlılık denetimi örnekleri şunlardır:

• Bir sunucunun beklenen bağlantı noktasında trafik beklediğini ve yeni TCP bağlantılarını kabul ettiğini doğrulayan testler.
• Temel HTTP istekleri gerçekleştiren ve sunucunun 200 durum koduyla yanıt verdiğinden emin olan testler.
• Ağ erişilebilirliği gibi herhangi bir sistemin çalışması için gerekli olan temel şeyleri test eden Amazon EC2 Durum Denetimleri.

Yerel durum denetimleri

Yerel durum denetimleri, uygulamanın işlevsel olma olasılığını doğrulamada canlılık denetimlerine göre daha fazlasını yapmaktadır. Bu durum denetimleri, sunucunun eşleriyle paylaşılmayan test kaynaklarını test eder. Bu nedenle, filodaki birçok sunucuda aynı anda hata verme ihtimalleri düşüktür. Bu durum denetimleri şunları test eder:

• Diske yazamama veya diskten okuma yapamama. Durumsuz bir hizmetin yazılabilir bir disk gerektirmediğine inanmak cazip gelebilir. Ancak Amazon olarak hizmetlerimiz, disklerini zaman uyumsuz ölçüm verilerini izleme, günlüğe kaydetme ve yayımlama gibi işlemler için kullanma eğilimindedir.
• Kritik işlemlerin çökmesi veya yarıda kesilmesi. Bazı hizmetler, sunucu üzerinde bir proxy (NGINX'e benzer) kullanarak istekleri alır ve iş mantığını başka bir sunucu işleminde gerçekleştirir. Canlılık denetimi, yalnızca proxy işleminin çalışıp çalışmadığını test edebilir. Yerel bir durum denetimi işlemi, her ikisinin de çalıştığından ve istekleri doğru yanıtladığından emin olmak için proxy'den uygulamaya geçebilir. İlginç bir şekilde, makalenin başındaki web sitesi örneğinde mevcut durum denetimi, işleme sürecinin çalıştığından ve yanıt verdiğinden emin olmak için yeteri kadar kapsamlı olmakla beraber, doğru şekilde yanıt verdiğinden emin olacak kadar kapsamlı değildi.
• Eksik destek işlemleri. İzleme aracılarının bulunmadığı ana bilgisayarlar, operatörlerin "karanlıkta hareket etmelerine" ve hizmetlerinin durumundan habersiz olmalarına neden olabilir. Diğer destek işlemleri, ölçme ve faturalandırma kullanımı kayıtlarını aktarır veya kimlik bilgileri güncellemelerini alır. Hatalı destek işlemlerine sahip sunucular, işlevselliği anlaşılması ve algılanması zor yöntemlerle riske atar.

Bağımlılık durum denetimleri

Bağımlılık durum denetimleri, bir uygulamanın yakınındaki sistemlerle etkileşime geçebilme özelliğini kapsamlı bir şekilde inceler. Bu denetimler ideal olarak, süresi dolmuş kimlik bilgileri gibi sunucunun bir bağımlılıkla etkileşime geçmesini önleyen yerel sunucu sorunlarını tespit eder. Ancak bağımlılığın kendisiyle ilgili sorunlar meydana geldiğinde yanlış pozitif sonuçlar verebilirler. Bu yanlış pozitif sonuçlar nedeniyle, bağımlılık durum denetimi hatalarına nasıl müdahale ettiğimize dikkat etmeliyiz. Bağımlılık durum denetimleri şunlara yönelik testler gerçekleştirebilir:

• Kötü yapılandırma veya eski meta veriler. Bir işlem zaman uyumsuz olarak meta veri veya yapılandırma güncellemelerini denetler ancak güncelleme mekanizması bir sunucuda hata verirse sunucu, eşlerinin oldukça gerisinde kalıp öngörülemeyen ve test edilmemiş bir davranış sergileyebilir. Ancak sunucu bir süreliğine güncelleme görmediğinde, güncelleme mekanizmasının bozulup bozulmadığını veya merkezi güncelleme sisteminin güncellemeleri tüm sunuculara yayımlamayı bırakıp bırakmadığını bilmez.
• Eş sunucularla veya bağımlılıklarla iletişim kurulamaması. Bir filodaki sunucu alt kümesinin bağımlılıklarla konuşma özelliğinin, tuhaf ağ davranışından etkilendiği ancak bu davranışların ilgili sunuculara trafik gönderilmesini etkilemediği bilinmektedir. Bağlantı havuzlarındaki kilitlenmeler veya hatalar gibi yazılım sorunları da ağ iletişimini engelleyebilir.
• İşlem geri almayı gerektiren diğer olağan dışı yazılım hataları. Kilitlenmeler, bellek sızıntıları veya durum bozulması hataları bir sunucunun çok sayıda hata vermesine neden olabilir. 

Anormallik algılama

Anormallik algılama, herhangi bir sunucunun eşlerine göre tuhaf davranıp davranmadığını belirlemek için bir filodaki tüm sunuculara göz atar. Sunucu başına izleme verilerini toplayarak, anormal sunucuları bulmak ve bunları otomatik olarak hizmet dışı bırakmak için hata oranlarını, gecikme süresi verilerini veya diğer özellikleri sürekli olarak karşılaştırabiliriz. Anormallik algılama, filodaki bir sunucunun kendisinin tespit edemediği şunlar gibi farklılıkları bulabilir:

• Saat değişmesi. Sunucular özellikle de fazla yük altındayken, saatlerinin aniden ve önemli ölçüde değiştiği bilinmektedir. AWS'ye yapılan imzalı istekleri değerlendirmek için kullanılanlar gibi güvenlik önlemleri, istemcinin saatindeki zamanın gerçek zamandan en fazla beş dakika farklı olmasını gerektirir. Bu şekilde değilse, istekler AWS hizmetlerine ulaşmaz.
• Eski kod. Bir sunucunun ağ bağlantısı kesilirse veya uzun süre kapalı kalır ve ardından tekrar çevrimiçi olursa, filonun geri kalanıyla uyumlu olmayan, tehlikeli bir eski kod çalıştırıyor olabilir.
• Beklenmeyen herhangi bir hata modu. Sunucular bazen kendi hatalarını istemcinin hatası olarak tanımladıkları hataları döndürerek hata verirler (HTTP 500 yerine 400). Sunucular hata vermek yerine yavaşlayabilir veya arayanlarına eşlerinden daha hızlı yanıt verebilirler. Bu durum ise arayanlarına yanlış yanıtlar verdiklerine dair bir işarettir. Anormallik algılama, beklenmeyen hata modları için inanılmaz bir kapsamlı çözümdür.

Anormallik algılamanın pratikte çalışması için doğru olması gereken birkaç şey bulunmaktadır:

• Sunucular yaklaşık olarak aynı şeyi yapmalıdır. Farklı trafik türlerini farklı türden sunuculara yönlendirdiğimiz durumlarda, sunucular aykırılıkları algılayacak kadar benzer şekilde çalışmayabilir. Ancak, trafiği sunuculara yönlendirmek için yük dengeleyicileri kullandığımız durumlarda, benzer şekilde yanıt vermeleri olasıdır.
• Filolar nispeten homojen olmalıdır. Farklı bulut sunucusu tipleri içeren filolarda, bazı bulut sunucuları diğerlerinden yavaş olabilir ve bu durum yanlışlıkla pasif ve kötü durumdaki sunucu algılamasını tetikleyebilir. Bu senaryoya çözüm bulmak için ölçümleri bulut sunucusu tipine göre derliyoruz.
• İşleyişteki hatalar veya farklılıklar rapor edilmelidir. Hataları bildirmede sunuculara güvendiğimiz için izleme sistemleri de hata verdiğinde ne olacak? Neyse ki hizmet istemcisi, izleme özelliği eklemek için harika bir alan sunuyor. Application Load Balancer gibi yük dengeleyiciler; her istekte hangi arka uç sunucusuyla bağlantı kurulduğu, yanıt süresi ve isteğin başarılı olup olmadığını gösteren erişim günlükleri yayımlar. 

Durum denetimi hatalarına güvenli bir şeklide müdahale etme

Bir sunucu iyi durumda olmadığını belirlediğinde, gerçekleştirebileceği iki tür eylem vardır. En uç durumda, herhangi bir iş almaması gerektiğine yerel olarak karar verebilir ve yük dengeleyici durum denetiminden geçmeden veya kuyruk yoklamasını durdurarak kendisini hizmet dışı bırakabilir. Sunucunun izleyebileceği diğer bir yol ise merkezi bir otoriteye sorunla karşılaştığını bildirmek ve merkezi sistemin sorunun nasıl çözüleceğine karar vermesini sağlamaktır. Merkezi sistem, otomasyonun tüm filoyu etkisiz hale getirmesini engelleyerek sorunu güvenli bir şekilde çözebilir.

Durum denetimlerini uygulamanın ve bunlara müdahale etmenin birçok yolu vardır. Bu bölümde Amazon'da kullandığımız birkaç yöntem açıklanmaktadır.

Hata durumunda çalışma gerçekleştirme

Bazı yük dengeleyiciler, akıllı bir merkezi otorite gibi davranabilir. Tek bir sunucu durum denetiminden geçemezse, yük dengeleyici sunucuya trafik göndermeyi durdurur. Ancak tüm sunucular aynı anda durum denetimlerinden geçemezse, yük dengeleyici hata durumunda çalışma gerçekleştirir ve tüm sunuculara trafik yönlendirilmesine izin verir. Bir bağımlılık durum denetiminin güvenli bir şekilde uygulanmasını desteklemek için kendi veritabanını sorgulayan ve kritik olmayan destek işlemlerinin çalıştığından emin olmak için denetleyen yük dengeleyicilerden kullanabiliriz.

Örneğin, hiçbir sunucu iyi durumda olduğunu bildirmiyorsa AWS Network Load Balancer, hata durumunda çalışma gerçekleştirir. Bir Erişilebilirlik Alanındaki tüm sunucular iyi durumda olmadıklarını bildirirse, iyi durumda olmayan Erişilebilirlik Alanına trafik yönlendirilmez. (Durum denetimleri için Network Load Balancer'ları kullanma hakkında daha fazla bilgi için Elastic Load Balancing belgelerine göz atın.) Application Load Balancer hizmetimiz de Amazon Route 53'te olduğu gibi hata durumunda çalışma gerçekleştirmeyi destekler. (Route 53 ile durum denetimlerinin yapılandırılması hakkında daha fazla bilgi için Route 53 belgelerine göz atın.)

Hata durumunda çalışma işlevini kullandığımızda, bağımlılık durum denetiminin hata modlarını test ettiğinizden emin oluruz. Örneğin, sunucuların paylaşılan veri deposuna bağlandığı bir hizmet düşünün. Bu veri deposu yavaşlar veya düşük bir hata oranıyla yanıt verirse, sunucular zaman zaman bağımlılık durum denetimlerinde hata verebilir. Bu durum, sunucuların hizmet dışı kalıp ardından hizmete geçmelerine neden olur ancak hata durumunda çalışma eşiğini tetiklemez. Bu durum denetimleriyle bağımlılıkların kısmi hatalarını değerlendirmek ve test etmek, kapsamlı durum denetimlerinin işlerin daha da kötüleşmesine neden olabileceği bir hata durumundan kaçınmak için önemlidir.

Hata durumunda çalışma gerçekleştirme yararlı bir işlev olsa da Amazon olarak tüm durumlarda nedenini bütünüyle açıklayamadığımız veya test edemediğimiz şeylere kuşkuyla bakarız. Bir sistemdeki veya bu sistemin bağımlılıklarındaki her türlü aşırı yüklenme, kısmi hatalar veya gri hatalar için hata durumunda çalışmanın beklediğimiz gibi tetikleneceğine dair genel kanıtlar henüz elimizde bulunmamaktadır. Bu sınırlama nedeniyle Amazon ekipleri, hızlı müdahale edebilen yük dengeleyici durum denetimlerini yerel durum denetimleriyle sınırlama eğilimindedir ve daha kapsamlı bağımlılık durum denetimlerine dikkatli bir şekilde müdahale etmek için merkezi sistemlere güvenmektedir. Bu durum, hata durumunda çalışma işlevini kullanmadığımızı veya belirli durumlarda işe yaradığını belirtmez. Ancak mantık, çok sayıda sunucuyu hızlı bir şekilde etkileyecekse, bu mantığa oldukça temkinli yaklaşırız.

Devre kesici olmadan durum denetimleri

Sunucuların kendi sorunlarına müdahale etmelerine izin vermek, kurtarmanın en hızlı ve en basit yöntemi gibi görünebilir. Ancak sunucu, durumu konusunda yanılıyorsa veya filo genelinde neler olup bittiğini tam olarak göremiyorsa, bu yöntem en riskli olandır. Tüm filodaki sunucular aynı anda aynı yanlış kararı verirse, bitişik hizmetlerde peş peşe hatalar oluşmasına neden olabilir. Bu risk bizi bir ödünle karşı karşıya bırakır. Durum denetimi ile izleme arasında bir boşluk varsa, bir sunucu sorun tespit edilinceye kadar bir hizmetin erişilebilirliğini azaltabilir. Ancak bu senaryoda, bütün bir filoda beklenmeyen durum denetimi davranışından dolayı hizmetin tamamen kesinti yaşaması önlenir.

Yerleşik bir devre kesiciye sahip olmadığımızda, durum denetimleri gerçekleştirmek için kullandığımız en iyi uygulamalar şunlardır:

• İş üreticisini (yük dengeleyici, kuyruk yoklama iş parçacığı) canlılık ve yerel durum denetimleri yapacak şekilde yapılandırma. Bozuk bir disk gibi sunucu sorununun yerel olduğu kesinse, yük dengeleyici sadece bu durumda sunucuyu otomatik olarak hizmet dışı bırakır.
• Bağımlılık durum denetimleri ve anormallik algılama gerçekleştirmek için diğer harici izleme sistemlerini yapılandırma. Bu sistemler, bulut sunucularını otomatik olarak sonlandırmayı veya bir operatörü uyarmayı ya da operatörle iletişime geçmeyi deneyebilir.

Bağımlılık durum denetimi hatalarına otomatik olarak müdahale edecek sistemler oluştururken, otomatik sistemin beklenmedik bir şekilde geniş kapsamlı eylemler gerçekleştirmesini önlemek için doğru seviyede bir eşik belirlemeliyiz. Amazon DynamoDB, Amazon S3 ve Amazon Relational Database Service (Amazon RDS) gibi durum bilgisi olan sunucuları yöneten Amazon ekiplerinin sunucu değişimi hakkında önemli dayanıklılık gereksinimleri bulunmaktadır. Ayrıca ekipler, otomasyonun belirlenen eşikler geçildiğinde durması ve personelle iletişime geçmesi için dikkatli hız sınırlaması ve kontrol geri bildirim döngüleri oluşturmuştur. Bu tür bir otomasyon oluştururken, bir sunucunun bağımlılık durum denetiminden geçemediğini fark ettiğimizden emin olmalıyız. Bazı ölçümler için sunucuların kendi durumlarını merkezi bir izleme sistemine bildirmelerine güveniyoruz. Sunucunun kendi durumunu rapor edemeyecek kadar hata verdiği durumları çözmek için durumlarını denetlemek üzere aktif olarak sunuculara ulaşıyoruz. 

Sunucu durumunu önceliklendirme

Özellikle aşırı yük bulunduğu durumlarda, sunucuların normal işlere göre durum denetimlerine öncelik vermeleri önemlidir. Bu durumda, durum denetimlerini geçememek veya denetimlere yavaş tepki vermek, kesinti durumunun çok daha kötüleşmesine neden olabilir. 

Bir sunucu, yük dengeleyici durum denetiminden geçemediğinde, bu yük dengeleyiciden derhal ve belirsiz bir süre boyunca hizmet dışı bırakılmasını istemektedir. Tek bir sunucu hata verdiğinde sorun olmaz ancak hizmette meydana gelen trafik dalgalanmasında istediğimiz son şey hizmetin hacmini küçültmektir. Sunucuları aşırı yüklenme sırasında hizmet dışı bırakmak, aşağı yönlü sarmal oluşmasına neden olabilir. Kalan sunuculara daha fazla trafik yönlendirmek, aşırı yüklenme olasılığını artırmakla beraber durum denetiminden geçememelerine ve filonun daha da küçülmesine neden olabilir.

Sorun, aşırı yüklenen sunucuların bu durumda hata döndürmesi değildir. Asıl sorun, sunucuların yük dengeleyici ping isteğine zamanında yanıt vermemesidir. Sonuçta yük dengeleyici durum denetimleri, diğer tüm uzaktan hizmet çağrıları gibi zaman aşımları ile yapılandırılmıştır. Kesinti yaşayan sunucular; yüksek CPU çekişmesi, uzun çöp toplama döngüleri veya çalışan iş parçacıklarının bitmesi gibi birçok nedenden dolayı yavaş yanıt verir. Hizmetlerin, aşırı ek istek almak yerine durum denetimlerine zamanında yanıt vermeleri için kaynak ayırmak üzere yapılandırılması gerekir.

Neyse ki, bu tür aşağı yönlü sarmalların oluşmasını önlemeye yardımcı olmak için takip ettiğimiz bazı basit yapılandırma en iyi uygulamaları bulunmaktadır. Iptables ve hatta bazı yük dengeleyiciler gibi araçlar, "en fazla bağlantı" fikrini desteklemektedir. Bu durumda, sunucu işleminin yavaşlamaya neden olabilecek eş zamanlı isteklerle dolmaması için işletim sistemi (ya da yük dengeleyici), sunucuya giden bağlantı sayısını sınırlar.

Bir hizmet, proxy veya maksimum bağlantıyı destekleyen bir yük dengeleyici arkasında yer alıyorsa, HTTP sunucusundaki çalışan iş parçacığı sayısının proxy'deki maksimum bağlantı sayısıyla eşleşmesini sağlamak mantıklı görünmektedir. Ancak bu yapılandırma, kesinti sırasında hizmette aşağı yönlü bir sarmal oluşturabilir. Proxy durum denetimleri de bağlantılara ihtiyaç duyar ve bu nedenle bir sunucunun çalışan havuzunu, ek durum denetimi taleplerini karşılayacak kadar büyütmek önemlidir. Kullanılmayan çalışanlar düşük maliyetli olduğu için birkaç fazla çalışandan yapılandırılmış en fazla proxy bağlantı sayısını iki katına çıkarmaya kadar ek çalışan yapılandırma eğilimindeyiz.

Durum denetimlerini önceliklendirmek için kullandığımız bir diğer strateji ise sunucuların kendi en fazla eş zamanlı isteklerini uygulamasını sağlamaktır. Bu durumda, yük dengeleyici durum denetimlerine her zaman izin verilir ancak sunucu halihazırda belirli bir eşik üzerinde çalışıyorsa normal istekler reddedilir. Amazon'daki uygulamalar, Java'daki basit bir semafordan CPU kullanımındaki eğilimlerin daha karmaşık bir analizine kadar uzanmaktadır.

Hizmetlerin bir durum denetimi ping isteğine zamanında yanıt vermesini sağlamanın bir başka yolu ise bağımlılık durum denetimi mantığını arka plandaki bir iş parçacığında gerçekleştirmek ve ping mantığının denetlediği bir "isHealthy" bayrağını güncellemektir. Bu durumda, sunucular durum denetimlerine zamanında yanıt verir ve bağımlılık durum denetimi, etkileşime geçtiği harici sistem üzerinde öngörülebilir bir yük oluşturur. Ekipler bu işlemi yaparken, durum denetimi iş parçacığı hatasını algılama konusunda oldukça temkinlidirler. Bu arka plan iş parçacığı mevcutsa, sunucu gelecekteki bir sunucu hatasını (veya kurtarmasını) algılamaz.

Etki kapsamı ile bağımlılık durum denetimlerinin dengelenmesi

Bir sunucunun durumuna yönelik kapsamlı bir test işlevi gördükleri için bağımlılık durum denetimleri cazip görünür. Ancak bir bağımlılık, tüm sistemde peş peşe hatalar oluşmasına neden olabileceği için bu denetimler tehlikeli olabilir.

Amazon'daki hizmet odaklı mimarimize göz atarak durum denetimi bağımlılıklarını yönetme konusunda bazı öngörüler edinebiliriz. Amazon'un sunduğu hizmetler, birkaç işlem yapacak şekilde tasarlanmıştır. Tüm işlemleri yapan tek parçalı bir sistem bulunmaz. Küçük ekiplerle daha hızlı inovasyon gerçekleştirme ve bir hizmetle ilgili sorun yaşanırsa etki kapsamının azaltılması gibi birçok nedenden dolayı hizmetleri bu şekilde oluşturmaktayız. Bu mimari tasarım, durum denetimleri için de geçerli olabilir.

Bir hizmet başka bir hizmeti aradığında, bu hizmetten bir bağımlılık almış olur. Bir hizmet sadece bazen bağımlılığı arıyorsa, bağımlılıkla konuşamasa bile yine de bazı iş türlerini yapabildiği için bağımlılığı "zayıf bir bağımlılık" olarak düşünebiliriz. Hata durumunda çalışma koruması olmadan bir bağımlılığı test eden durum denetimi gerçekleştirmek, bu bağımlılığı "güçlü bir bağımlılığa" dönüştürür. Bağımlılık çökerse hizmet de çöker ve peş peşe hatalar oluşturarak etki kapsamının artmasına neden olur.

İşlevselliği farklı hizmetlere ayırsak da, her hizmet birden fazla API sunabilir. Bazen, hizmet içerisindeki API'lerin kendi bağımlılıkları olabilir. Bir API zarar görürse hizmetin, diğer API'leri sunmaya devam etmesini tercih ediyoruz. Örneğin bir hizmet, hem bir denetim düzlemi (diğer adıyla uzun süre bitmeyen kaynaklar üzerinde CRUD API'ler gibi) hem de bir veri düzlemi (yüksek aktarım hızına sahip iş için son derece önemli API'ler) olabilir. Denetim düzlemi API'leri, bağımlılıklarıyla konuşmakta sorun yaşasa bile, veri düzlemi API'lerinin çalışmaya devam etmesini isteriz.

Benzer şekilde, tek bir API bile verilerin girdilerine ya da durumuna bağlı olarak farklı davranışlar gösterebilir. Yaygın bir model, veritabanını sorgulayan ancak yanıtları yerel olarak bir süre için önbelleğe alan Okuma API'sidir. Veritabanının çökmesi durumunda hizmet, veritabanı çevrimiçi oluncaya kadar önbelleğe alınmış okumaları sunabilir. Yalnızca bir kod yolunun iyi durumda olmaması halinde durum denetimlerinin hata vermesi, bir bağımlılıkla konuşmaya ilişkin sorunun etki kapsamını artırır.

Hangi bağımlılığa durum denetimi yapılacağı konusu, mikro hizmetler ile nispeten tek parçalı hizmetler arasındaki ödünler hakkında ilginç bir soruyu gün yüzüne çıkarıyor. Bir hizmetin kaç dağıtılabilir birime veya uç noktaya bölünebileceğiyle ilgili kesin bir kural bulunmasa da "hangi bağımlılıklara durum denetimi yapılacağı" ve "bir hatanın daha sonra etki kapsamını artırıp artırmadığı" soruları, bir hizmetin ne kadar mikro veya makro olacağını belirlemede ilginç bakış açılarıdır. 

Durum denetimlerinde yanlış giden asıl şeyler

Tüm bunlar teoride anlamlı olabilir ancak durum denetimlerini doğru gerçekleştirmeyen sistemlere pratikte ne olur? Büyük resmi göstermeye yardımcı olması için AWS müşterilerinden ve Amazon'dan dinlediğimiz hikayelerde ortak noktalar aradık. Ayrıca ekiplerin, durum denetimindeki bir zayıflığın geniş çaplı bir soruna yol açmaması için uyguladığı "kemer ve askı" çeşitlerinden oluşan dengeleyici faktörleri araştırdık.

Dağıtımlar

Durum denetimi sorunlarının bir türü dağıtımları kapsar. AWS CodeDeploy gibi dağıtım sistemleri, yeni kodu her seferinde filodaki bir alt kümeye aktararak sonraki dağıtım dalgasına geçmeden önce devam eden dalganın tamamlanmasını bekler. Bu işlem, sunucuların yeni kodla sorunsuz çalıştıklarını dağıtım sistemine geri bildirmesine dayanır. Sunucular durumlarını bildirmezse, dağıtım sistemi yeni kodda bir sorun olduğunu anlar ve dağıtımı geri alır.

En temel hizmet başlatma dağıtım kodu, sunucu işlemini ayrıştırır ve derhal dağıtım sistemine "dağıtım tamamlandı" yanıtını gönderir. Ancak başlatmadan hemen sonra kilitlenebilmesi, kapatılıp sunucu yuvasında trafiği beklemeye başlayamaması, istekleri başarıyla işlemek için gereken yapılandırmanın yüklenememesi veya bir hatayla karşılaşması gibi birçok sorun yeni kodda meydana gelebileceği için bu işlem tehlikelidir. Bir dağıtım sistemi, bağımlılık durum denetimine karşı test edilmek üzere yapılandırılmadığında, sorunlu bir dağıtımı aktardığını fark etmez. Bir sunucudan diğerine geçerek sunucuların hata vermesine neden olur.

Neyse ki Amazon ekipleri, bu senaryonun pratikte tüm filolarını devre dışı bırakmasını önlemek için etki azaltıcı çeşitli sistemler uygular. Etki azaltıcı bu tür bir sisteme örnek, toplam filo boyutunun çok küçük olması ya da filo fazla yük altında çalışırken veya fazla gecikme süresi ya da hata oranı olduğunda tetiklenen alarmlar yapılandırmaktır. Bu alarmlardan herhangi biri tetiklenirse, dağıtım sistemi dağıtımı durdurup geri alır.

Diğer bir etki azaltma şekli, aşamalı dağıtımlar uygulamaktır. Tüm filoya tek bir dağıtımda dağıtmak yerine hizmet, Erişilebilirlik Alanı gibi bir alt kümeye dağıtım yapmak için yapılandırılabilir. Bu dağıtımı, dağıtıma ara verip söz konusu alanda entegrasyon testlerinin tamamını gerçekleştirmeden yapabilir. Hizmetler, tek bir Erişilebilirlik Alanında sorun yaşandığında çalışmaya devam edecek şekilde tasarlandığı için Erişilebilirlik Alanı başına dağıtım eşleşmesi oldukça kullanışlıdır.

Amazon ekipleri, üretim adımına dağıtım yapmadan önce elbette bu değişiklikleri test ortamları aracılığıyla aktarır ve bu tür bir hatayı algılayacak otomatik entegrasyon testlerini gerçekleştirir. Ancak, üretim ve test ortamları arasında algılanması zor ve kaçınılmaz farklılıklar bulunabilir. Bu nedenle, üretimde bir sıkıntıya yol açmadan önce her tür sorunu algılayabilecek birçok dağıtım güvenliği katmanını bir araya getirmek önemlidir. Durum denetimleri, hizmetleri sorunlu dağıtımlara karşı korumada önemli olsa da bunlarla yetinmiyoruz. Filoları bu ve diğer hatalardan korumak için dayanak noktası işlevi gören "kemer ve askı" yaklaşımlarını göz önünde bulunduruyoruz.

Zaman uyumsuz işlemciler

Diğer bir hata türü ise bir SQS Kuyruğu veya Amazon Kinesis Akışını yoklayarak iş alan bir hizmet gibi zaman uyumsuz mesaj işlemeyle ilgilidir. Yük dengeleyiciden istek alan sistemlerin aksine, sunucuları hizmet dışı bırakmak için otomatik olarak durum denetimi gerçekleştiren bir süreç yoktur.

Hizmetlerde yeterince kapsamlı durum denetimleri bulunmadığında, bağımsız kuyruk çalışanı sunucuları, disk kapasitesinin dolması veya dosya tanımlayıcılarının bitmesi gibi hatalar verebilir. Bu sorun, sunucunun kuyruktan iş almasını engellemez ancak sunucunun mesajları başarıyla işlemesini engelleyecektir. Bu sorun, kötü durumdaki sunucunun kuyruktan hızlıca iş alıp bunlarla başa çıkamadığı durumda gecikmiş mesaj işlemesiyle sonuçlanır.

Bu tür durumlarda, genellikle etkiyi azaltmaya yardımcı olacak birkaç dengeleyici faktör bulunur. Örneğin bir sunucu, SQS'den çektiği mesajı işleyemezse SQS, yapılandırılmış bir mesaj görünürlük zaman aşımından sonra bu mesajı başka bir sunucuya yeniden gönderir. Uçtan uca gecikme süresi artsa da mesajlar işlenir. Diğer bir dengeleyici faktör ise mesaj işleme sırasında çok fazla hata olduğunda tetiklenen ve bir operatörü durumu incelemek üzere uyaran bir alarmdır.

Disklerin dolması

Karşılaştığımız bir diğer hata sınıfı, sunuculardaki disklerin dolması ve hem işlemenin hem de günlüğe kaydetmenin başarısız olmasına neden olmasıdır. Sunucu, hatalarını izleme sistemine bildiremeyebileceği için bu hata, izleme görünürlüğünde bir boşluğa yol açmaktadır.

Çeşitli etki azaltıcı denetimler burada da hizmetlerin "karanlıkta hareket etmesini" engeller ve etkiyi hızla azaltır. Application Load Balancer veya API Gateway gibi bir proxy arkasında yer alan sistemlerde, bu proxy kaynaklı hata oranı ve gecikme süresi ölçümleri bulunacaktır. Bu durumda, sunucu hata bildirmese bile alarmlar tetiklenir. Amazon Simple Queue Service (Amazon SQS) gibi hizmetler, kuyruğa dayalı sistemler için bazı mesajların işlenmesinin geciktiğini belirten ölçümleri rapor eder.

Bu çözümlerin ortak noktası, birçok izleme katmanı bulunmasıdır. Sunucunun kendisi hataları bildirir ancak harici bir sistem de bunu yapabilir. Aynı ilke durum denetimleri için de önemlidir. Harici bir sistem, belirli bir sistemin durumunu sistemin kendi yapacağı testten daha doğru bir şekilde test edebilir. Bu nedenle ekipler, AWS Auto Scaling ile harici ping durum denetimleri yapması için bir yük dengeleyici yapılandırır.

Ayrıca ekipler, her sunucuya iyi durumda olup olmadığını düzenli olarak sorması ve bir sunucu iyi durumda olmadığında bunu AWS Auto Scaling'e bildirmesi için kendi özel durum denetimi sistemlerini oluşturmaktadır. Bu sistemin yaygın bir uygulamasında, dakika başı çalışarak her sunucunun durumunu test eden bir Lambda işlevi bulunur. Bu durum denetimleri, DynamoDB gibi bir hizmette her çalıştırma arasındaki durumlarını kaydedebilir ve böylece bir seferde çok fazla sunucuyu yanlışlıkla kötü durumda olarak işaretlemeleri önlenmiş olur.

Zombiler

Başka bir sorun türünde ise zombi sunucular bulunmaktadır. Sunucular, ağ bağlantısı belirli bir süre boyunca kesilse de çalışmaya devam edebilir ya da uzun süre kapalı kalıp daha sonra yeniden başlatılabilir.

Zombi sunucular yeniden canlandığında, filonun geri kalanıyla önemli ölçüde eşitlenmemiş olabilir ve bu durum ciddi sorunlar doğurabilir. Örneğin bir zombi sunucu, eski ve uyumsuz bir yazılım sürümü çalıştırırsa, farklı şemalara sahip bir veritabanıyla etkileşime geçmeye çalıştığında hatalara neden olabilir ya da yanlış yapılandırma kullanabilir.

Zombi sorununu çözmek için sistemler genellikle durum denetimlerine güncel yazılım sürümleriyle cevap verir. Ardından merkezi bir izleme aracısı, beklenmedik bir şekilde eski sürümle çalışan bir sunucu olup olmadığını kontrol etmek için filodaki yanıtları karşılaştırır ve bu sunucuların hizmet vermeye başlamasını önler.

Sonuç

Sunucular ve sunucuda çalıştırılan yazılımlar her türlü tuhaf nedenden dolayı hata vermektedir. Donanım er ya da geç bozulur. Yazılım geliştiricileri olarak, yazılımın bozulmasına neden olan yukarıda açıkladığım gibi hatalı bir kod yazmamız kaçınılmazdır. Tüm beklenmedik hata modu türlerini algılamak için hafif canlılık denetimlerinden sunucu başına ölçümlerin pasif izlenmesine kadar birçok denetim katmanına ihtiyaç vardır.

Bu hatalar meydana geldiğinde, bunları algılamak ve etkilenen sunucuları hızlı bir şekilde hizmet dışı bırakmak önemlidir. Ancak tüm filo otomasyonlarında olduğu gibi, otomasyonu devre dışı bırakan ve belirsizlik durumlarında ya da uç durumlarda insanları sürece dahil eden hız sınırlayıcılar, eşikler ve devre kesiciler ekliyoruz. Hata durumunda çalışma gerçekleştirme ve merkezi aktörler oluşturma, hız sınırlayıcılı otomasyonun sağladığı güvenlikle yapılan kapsamlı durum denetiminin avantajlarından yararlanmak için geliştirilen stratejilerdir.

Uygulamalı laboratuvar

Burada öğrendiğiniz prensiplerin bazılarını uygulamalı laboratuvar ile deneyin.


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.

Zaman aşımları, yeniden denemeler ve sapmalı geri çekilme