Kritik hatalar, bir hizmetin verimli sonuçlar vermesini engeller. Örneğin, bir e-ticaret web sitesinde ürün bilgisi için bir veritabanı sorgusu başarısız olduğunda, web sitesi ürün sayfasını başarılı bir şekilde görüntüleyemez. Amazon hizmetleri, güvenilir olmak için kritik hatalarının büyük çoğunluğuyla başa çıkmalıdır. Kritik hatalarla başa çıkmada, dört büyük strateji kategorisi bulunmaktadır:

Yeniden deneme: başarısız olan eylemi hemen veya biraz bekledikten sonra tekrar deneme.
Proaktif yeniden deneme: eylemi birden fazla kez paralel olarak deneme ve tamamlanan ilk denemeden yararlanma.
Yük devretme: eylemi uç noktanın farklı bir kopyasına karşı deneme veya tercihen denemelerden en az birinin başarılı olma olasılığını artırmak için eylemin birden fazla, paralel kopyasını deneme.
Geri dönüş: aynı sonucu almak için farklı bir mekanizma kullanma.

Bu makale, geri dönüş stratejilerini ve bunları Amazon'da neredeyse hiç kullanmama nedenlerimizi kapsamaktadır. Bunu ilginç bulabilirsiniz. Sonuçta mühendisler, tasarımları için başlangıç noktası olarak gerçek dünyayı kullanır. Gerçek dünyada da geri dönüş stratejileri önceden planlanmalı ve gerektiğinde kullanılmalıdır. Örneğin, bir havaalanındaki elektronik panonun bozulduğunu düşünelim. Yolcuların kullanacakları kapıları bulmaları gerektiği için böyle bir durumla başa çıkmada bir beklenmedik durum planı (insanların beyaz tahtalara uçuş bilgilerini yazmaları gibi) hazır olmalıdır. Ancak bu beklenmedik durum planının ne kadar kötü olduğunu göz önünde bulundurun: beyaz tahtaları okuma zorluğu, bilgileri güncel tutma zorluğu ve insanların yanlış bilgi ekleme riski. Beyaz tahta geri dönüş stratejisi gerekli ancak sorunlarla doludur.

Dağıtılmış sistemler dünyasında geri dönüş stratejileri, özellikle zaman hassasiyeti olan hizmetler için başa çıkılması en zor görevlerdir. Bu zorluğu oluşturan, geri dönüş stratejilerinin geri tepmeden kurtulmasının uzun zaman (hatta yıllar) alabilmesi ve iyi strateji ile kötü strateji arasındaki farkın kolay göze çarpmamasıdır. Bu makalede, geri dönüş stratejilerinin düzelttiğinden daha fazla soruna yol açabileceğine odaklanacağız. Geri dönüş stratejilerinin Amazon'da yol açmış olduğu sorunlarla ilgili örnekler vereceğiz. Son olarak, Amazon'da geri dönüş yerine kullandığımız alternatiflerden bahsedeceğiz.

Hizmetler için geri dönüş stratejilerini analiz etmek sezgisel değildir ve dağıtılmış sistemlerde bunların dalga etkilerini önceden görmek zordur. Bu nedenle, tek makine uygulaması için geri dönüş stratejilerine göz atarak işe başlayalım.

Tek makine geri dönüşü

Pek çok uygulamada bellek ayırma hatalarıyla başa çıkmak için genel bir modeli gösteren aşağıdaki C kod parçacığını inceleyin. Bu kod, malloc() işlevini kullanarak bellek ayırır ve ardından bir tür dönüşüm gerçekleştirirken bir görüntü arabelleğini bu belleğe kopyalar:
pixel_ranges = malloc(image_size); // allocates memory
if (pixel_ranges == NULL) {
  // On error, malloc returns NULL
  exit(1);
}
for (i = 0; i < image_size; i++) {
  pixel_ranges[i] = xform(original_image[i]);
}

Bu kod, malloc'un başarısız olduğu durumdan incelikli bir şekilde kurtulmaz. Pratikte, malloc çağrıları nadiren başarısız olur ve bu nedenle geliştiriciler genellikle koddaki hatayı yoksayarlar. Bu strateji neden bu kadar olağan bir şeydir? Bunun sebebi, tek makinede malloc başarısız olduğunda, muhtemelen makinede belleğin yetersiz kalmasıdır. Dolayısıyla makinenin kilitlenmesi gibi, malloc çağrısının başarısız olmasından daha büyük sorunlar vardır. Bunun tek makinede meydana gelmesi ise çoğu zaman anlaşılır bir durumdur. Çoğu uygulama, böyle zahmetli bir sorunun çözümüne değecek kadar kritik değildir. Peki ya bu hatayla başa çıkmak istiyorsanız? Bu durumda işe yarar bir şeyler yapmak beceri ister. Diyelim ki belleği farklı bir şekilde ayıracak olan malloc2 adında ikinci bir yöntem uyguladık ve varsayılan malloc uygulaması başarısız olduğunda malloc2'yi çağırdık:

pixel_ranges = malloc(image_size);
if (pixel_ranges == NULL) {
  pixel_ranges = malloc2(image_size);
}

İlk bakışta bu kod çalışabilir gibi görünüyor ancak bazıları belirgin olmayan sorunlar var. Öncelikle, geri dönüş mantığını test etmek zordur. Malloc çağırma işlemine müdahale edebilir ve bir hata ekleyebiliriz ancak bu, üretim ortamında gerçekleşebilecekleri doğru olarak simüle etmeyebilir. Üretimde malloc başarısız olduğunda, büyük olasılıkla makinenin belleği yetersiz veya çok düşük düzeydedir. Bu tür büyük bellek sorunlarını nasıl simüle edersiniz? Bu testi, düşük bellekli bir ortamda (örneğin bir Docker container'da) gerçekleştirebilseniz bile, malloc2 geri dönüş kodunun yürütmesiyle çakışacak şekilde düşük bellek durumunun zamanlamasını nasıl yapardınız?

Diğer bir sorun da geri dönüşün kendisinin başarısız olabileceğidir. Önceki geri dönüş kodu, malloc2 hatasıyla başa çıkamaz, bu nedenle de program düşündüğünüz kadar yarar sağlamaz. Geri dönüş stratejisi, tamamen hatayı daha olası hale getirse de bu imkansız değildir. Amazon olarak, temel kodu daha güvenilir yapmak için mühendislik kaynaklarını harcamanın, sık kullanılmayan geri dönüş stratejisine yatırım yapmaktan daha fazla başarı şansı getirdiğini gördük.

Dahası, en yüksek önceliğimiz erişilebilirlikse, geri dönüş stratejisi, oluşacak riske değmeyecektir. Malloc2'nin başarı şansı daha yüksekse, neden malloc ile oyalanıyoruz? Mantıken, malloc2'nin sahip olduğu yüksek erişilebilirliğe karşı bir ödün vermesi gerekir. Daha yüksek gecikme sürelerinde bellek ancak daha büyük SSD tabanlı depolama alanı ayırıyor olabilir. Ancak bu, neden malloc2'nin ödün vermesinin kabul edilir olduğu sorusunu ortaya çıkarıyor. Bu geri dönüş stratejisiyle ortaya çıkabilecek potansiyel olaylar sıralamasını düşünelim. İlk olarak müşteri uygulamayı kullanır. Bir anda malloc başarısız olduğundan, malloc2 devreye girer ve uygulama yavaşlar. Bu kötüdür: Yavaşlaması kabul edilebilir bir şey midir? Ve sorun burada kalmaz. Makinenin büyük olasılıkla belleğinin yetersiz kalması veya çok düşük düzeylere inmesi ihtimalini düşünün. Müşteri, artık bir yerine iki sorunla (yavaşlamış uygulama ve yavaşlamış makine) karşı karşıya. Malloc2'ye geçiş yapmanın yan etkileri, sorunu genel olarak daha da kötüleştirebilir. Örneğin, diğer alt sistemler de aynı SSD tabanlı depolama alanıyla çakışma yaratıyor olabilir.

Geri dönüş mantığı, sistemde beklenmeyen yüke de sebep olabilir. Bir hata mesajını yığın izlemesiyle bir günlüğe kaydetmek gibi basit mantıklar bile görünüşte zararsızdır ancak bir şey aniden değişir ve bu hatanın daha yüksek oranda meydana gelmesine neden olursa, CPU'ya bağlı bir uygulama birden G/Ç'ye bağlı hale gelebilir. Ve disk de bu oranda yazma işlemiyle başa çıkmak veya bu miktarda veriyi depolamak için tedarik edilmemişse, uygulamayı yavaşlatır veya kilitler.

Geri dönüş stratejisi, sorunu kötüleştirmekle kalmaz, ayrıca görünmez bir hata olarak ortaya çıkma olasılığına sebep olur. Üretimde nadiren tetiklenen geri dönüş stratejileri geliştirmek kolaydır. Bir müşterinin makinesinin gerçekten de daha önce gösterilen malloc2 geri dönüşlü belirli bir kod satırını tetikleyecek doğru zamanda bellek yetersizliği yaşaması yıllar alabilir. Geri dönüş mantığında sorunu daha da kötüleştirecek bir hata veya bir çeşit yan etki ortaya çıkarsa, kodu yazan mühendisler bu kodun ilk başta nasıl çalıştığını muhtemelen unutmuş olacaktır ve kodu düzeltmek daha da zorlaşacaktır. Tek makine uygulamasında bu, iş için kabul edilebilir bir ödün olabilir ancak dağıtılmış sistemlerde sonuçlar daha belirgindir. Bu sonuçlardan daha sonra bahsedeceğiz.

Tüm bu sorunlar zahmetli olmasına rağmen deneyimimize göre çoğu zaman tek makine uygulamalarında güvenli bir şekilde yoksayılabilir. En genel çözümden daha önce bahsetmiştik: Bellek ayırma hatalarının, uygulamayı kilitlemesine izin verin. Bellek ayırmayı sağlayan kod, makinenin geri kalanıyla aynı kaderi paylaşır ve böyle bir durumda makinenin geri kalanı da büyük olasılıkla hata verecektir. Aynı kaderi paylaşmasa bile, uygulama artık beklenmeyen bir durumdadır ve bir an önce hata vermesi iyi bir stratejidir. İşten ödün verme kabul edilebilir.

Bellek ayırma hataları durumlarında çalışması gereken kritik tek makine uygulamalarında, çözümlerden biri tüm yığın belleği başlangıçta önceden ayırma ve hata durumlarında bile bir daha malloc'a asla güvenmemektir. Amazon bu stratejiyi defalarca uygulamıştır. Örneğin, üretim sunucularında çalışan daemon'ları ve müşterilerin ani CPU artışlarını izleyen Amazon Elastic Compute Cloud (Amazon EC2) daemon'larını takip etmek için kullanmıştır.

Dağıtılmış geri dönüş

Amazon olarak, özellikle gerçek zamanlı yanıt vermeleri için oluşturulmuş dağıtılmış sistemlerin, tek makine uygulamalarıyla aynı ödünleri vermesine fırsat tanımayız. Sebeplerimizden biri, müşteriyle aynı kader paylaşımının eksik olmasıdır. Uygulamaların, müşterinin önünde duran makinede çalıştığını varsayabiliriz. Uygulamanın belleği yetersiz kaldığında, büyük olasılıkla müşteri, makinenin çalışmaya devam etmesini beklemeyecektir. Hizmetler, müşterilerin doğrudan kullandığı makinelerde çalışmadığı için beklenti farklıdır. Bunun da ötesinde, müşterilerin hizmetleri asıl kullanma nedeni, tek bir sunucuda uygulama çalıştırmaya kıyasla hizmetlerin daha erişilebilir olmasıdır ve biz de hizmetleri daha erişilebilir hale getirmek için çalışıyoruz. Teorik olarak bu, bizi hizmeti daha güvenilir yapmak için geri dönüş uygulamaya itiyor. Ne yazık ki, kritik sistem hataları konusunda, dağıtılmış geri dönüş için de aynı sorunlar ve daha fazlası meydana gelmektedir.

Dağıtılmış geri dönüş stratejilerini test etmek daha zordur. Hizmet geri dönüşü, tek makine uygulaması durumundan daha karışıktır çünkü hatalarda birden fazla makine ve aşağı akış hizmetleri rol oynar. Birden fazla makinede test düzenlemesini hazırlamak kolay olsa da aşırı yük senaryoları gibi hata modlarının testte tekrarlanması zordur. Kombinasyoncular da test edilecek durumların sayısını oldukça artırdığı için kurulumu daha zor olan daha fazla teste ihtiyacınız vardır.

Dağıtılmış geri dönüş stratejilerinin kendisi hata verebilir. Geri dönüş stratejilerinin başarıyı garanti ettiği düşünülse de bizim deneyimimize göre genellikle yalnızca başarı olasılığını artırıyorlar.

Dağıtılmış geri dönüş stratejileri, çoğu zaman kesintileri daha da kötüleştirir. Bizim deneyimimize göre geri dönüş stratejileri kurtarma süresini artırmanın yanı sıra hataların etki alanını da artırır.

Dağıtılmış geri dönüş stratejileri, genellikle alınan riske değmez. Malloc2'de olduğu gibi, geri dönüş stratejisi genelde bir çeşit ödün verir. Aksi takdirde, her zaman kullanırdık. Zaten bir sorun varken, bunu kötüleştirecek bir geri dönüşü neden kullanalım?

Dağıtılmış geri dönüş stratejilerinde genelde görünmez hatalar vardır ve beklenmeyen rastlantısal durumlar gerçekleştiğinde, kullanılmaya başlanma tarihinden potansiyel olarak aylar veya yıllar sonra ortaya çıkarlar.
Amazon perakende satış web sitesindeki bir geri dönüş mekanizması tarafından tetiklenen gerçek bir büyük kesinti, tüm bu sorunları göstermektedir. Kesinti 2001 civarından gerçekleşti ve buna, web sitesinde gösterilen tüm ürünler için güncel kargo hızını sağlayan yeni bir özellik sebep oldu. Yeni özellik şu şekildeydi:

O zamanlar web sitesi mimarisinde sadece iki katman bulunuyordu ve bu veriler bir tedarik zinciri veritabanında depolandığı için web sunucularının veritabanını doğrudan sorgulaması gerekiyordu. Ancak veritabanı, web sitesinden gelen istek miktarını kaldıramadı. Web sitesinde yüksek hacimde bir trafik vardı ve bazı sayfalar, her ürün için yanlarında kargo hızının bulunduğu 25 veya daha fazla ürünü gösteriyordu. Bu nedenle her web sunucusunda ayrı bir işlem olarak çalışan önbelleğe alma katmanı (Memcached benzeri) ekledik:

Bu işe yaradı ancak ekip, önbelleğin (ayrı bir işlem) bir şekilde başarısız olduğu durumla başa çıkmayı da denedi. Bu senaryoda web sunucuları, veritabanını doğrudan sorgulamaya yöneltildi. Sözde kodda buna benzer bir şey yazdık:

if (cache_healthy) {
  shipping_speed = get_speed_via_cache(sku);
} else {
  shipping_speed = get_speed_from_database(sku);
}

Doğrudan veritabanı sorgularına geri dönüş, birkaç ay işe yarayan sezgisel bir çözümdü. Ancak, er ya da geç tüm önbellekler birbirlerine yakın zamanlarda hata verdi ve bu da tüm web sunucularının veritabanını doğrudan sorgulaması demekti. Bu, veritabanının kilitlenmesine yetecek kadar yük oluşturdu. Tüm web sunucusu işlemleri veritabanında engellendiği için web sitesinin tamamı çöktü. Bu tedarik zinciri veritabanı, depolar için de çok önemliydi. Bu nedenle, kesinti daha fazla yayıldı ve dünya çapındaki tüm depolar, sorun çözülene kadar çalışmayı durdurdu.

Tek makine örneğinde gördüğümüz tüm sorunlar, çok daha ciddi sonuçlarla birlikte dağıtılmış örnekte gözlemlendi. Dağıtılmış geri dönüş örneğini test etmek zordu. Önbellek hatasını simüle etsek bile, tetiklenmesi için birden fazla makinede hataların oluşmasını gerektiren sorunu bulamazdık. Ve bu örnekte, geri dönüş stratejisinin kendisi sorunu büyüttü ve hiçbir geri dönüş stratejisinin olmaması durumundan daha kötü bir durum yarattı. Geri dönüş stratejisi, kısmi web sitesi kesintisini (kargo hızını gösterememe), tüm siteyi kapsayan bir kesintiye (hiçbir sayfanın yüklenmemesi) dönüştürdü ve arka uçta Amazon depo ağının tamamını çökertti.

Bu örnekteki geri dönüş stratejimiz arkasındaki fikir mantıksızdı. Veritabanını doğrudan sorgulamak, önbellek üzerinden ilerlemekten daha güvenilirse, neden en başta önbellekle uğraşalım? Önbellek kullanmamanın veritabanı üzerinde aşırı yük oluşturacağından korktuk ancak bu, potansiyel olarak çok zararlıysa neden geri dönüş koduyla uğraşalım? Hatamızı önceden fark edebilirdik ancak hata gizli bir hataydı ve kesintiye neden olan durum, stratejiyi kullanmaya başlamamızdan aylar sonra ortaya çıkmıştı.

Amazon, geri dönüşlerden nasıl kaçınır?

Dağıtılmış geri dönüşte karşılaştığımız olumsuzluklardan sonra artık neredeyse her zaman geri dönüşe alternatif olan şeyleri tercih ediyoruz. Bunlar, burada açıklanmaktadır.

Geri dönüş dışındaki örneklerin güvenilirliğini artırma

Daha önce de bahsedildiği gibi, geri dönüş stratejileri yalnızca tüm sistemde hata meydana gelme olasılığını azaltır. Ana (geri dönüş dışında) kod daha dayanıklı yapıldığında, hizmetin erişilebilirliği çok daha fazla olabilir. Örneğin ekip, iki farklı veri deposu arasına geri dönüş mantığı uygulamak yerine Amazon DynamoDB gibi daha fazla yerleşik erişilebilirliğe sahip bir veritabanı kullanmaya yatırım yapabilir. Bu strateji, Amazon içerisinde başarıyla sık sık kullanılmaktadır. Örneğin, bu konuşma Prime Day 2017'de amazon.com'u desteklemek için DynamoDB'nin kullanılmasını açıklamaktadır.

Arayanın hatalarla başa çıkmasına izin verin

Kritik sistem hataları için kullanılabilecek bir çözüm, geri dönüşten ziyade çağıran sistemin hatayla başa çıkmasına izin vermektir (örneğin, yeniden deneyerek). Bu, CLI ve SDK'larımızın zaten yerleşik yeniden deneme mantığına sahip olduğu AWS hizmetleri için tercih edilen bir stratejidir. Mümkün olan yerlerde, özellikle aynı kaderi paylaşma ve ana örnek hatasının meydana gelme olasılığını azaltma (ve geri dönüş mantığının erişilebilirliği biraz olsun artırması çok düşük ihtimaldir) için yeterli çabanın gösterildiği durumlarda bu stratejiyi tercih ederiz. 

Proaktif olarak veri gönderin

Geri dönüş ihtiyacını önlemede kullandığımız bir başka yöntem de isteklere yanıt verirken hareketli parçaların sayısını azaltmaktır. Örneğin, bir hizmetin bir isteği yerine getirmesi için veri gerekiyorsa ve bu veri zaten yerel olarak mevcutsa (getirilmesine gerek yoksa), bir yük devretme stratejisine gerek yoktur. Bunun başarılı bir örneği, Amazon EC2 için AWS Identity and Access Management (IAM) görevlerinin uygulanmasıdır. IAM hizmetinin, EC2 bulut sunucularında çalışan kodlara imzalı ve döndürülmüş kimlik bilgilerini sağlaması gerekir. Geri dönüş ihtiyacını önlemek için kimlik bilgileri her bulut sunucusuna proaktif olarak gönderilir ve saatlerce geçerliliğini korur. Bu, IAM göreviyle ilgili isteklerin, gönderim mekanizmasındaki olasılık dışı bir kesintide çalışmaya devam etmesi anlamına gelir. 

Geri dönüşü yük devretmeye dönüştürün

Geri dönüşle ilgili en kötü şeylerden biri; düzenli olarak uygulanmaması, hata verme olasılığının bulunması ve kesinti sırasında tetiklendiğinde etki alanını artırmasıdır. Geri dönüşü tetikleyen şartlar, aylar veya yıllar boyunca doğal olarak gerçekleşmeyebilir! Geri dönüş stratejisinin gizli hataları sorununu çözmek için bu stratejiyle üretimde düzenli olarak alıştırma yapılması önemlidir. Bir hizmet hem geri dönüş hem de geri dönüş dışındaki mantığı sürekli çalıştırmalıdır. Geri dönüş örneğini çalıştırmanın yanı sıra, geçerli bir veri kaynağı olarak bu örneği eşit şekilde değerlendirmesi gerekir. Örneğin, bir hizmet geri dönüş ve geri dönüş dışındaki yanıtlar arasında (her ikisi de döndüğünde) ikisinin de çalıştığından emin olmak için rastgele seçim yapabilir. Ancak bu noktada strateji, geri dönüş olarak değerlendirilmez ve tamamen yük devretme kategorisine girer.

Yeniden denemelerin ve zaman aşımlarının geri dönüş olmamasından emin olun

Yeniden denemeler ve zaman aşımları, Sapma ile Zaman Aşımları, Yeniden Denemeler ve Geri Çekilmeler makalesinde anlatılmıştır. Bu makale, yeniden denemelerin geçici ve rastgele hatalar karşısında yüksek erişilebilirlik sağlamak için güçlü mekanizmalar olduğundan bahseder. Diğer bir deyişle, yeniden denemeler ve zaman aşımları; sahte paket kaybı, bağlantısız tek makine hatası gibi küçük sorunlardan doğan nadir hatalara karşı güvence sağlar. Ancak yeniden denemelerde ve zaman aşımlarında hata yapmak kolaydır. Hizmetler genellikle fazla yeniden deneme yapmadan aylar veya daha uzun bir süre boyunca çalışır ve bunlar, ekibinizin hiç test etmediği senaryolar sırasında devreye girebilir. Bu nedenle, yeniden denemeler sıklaştığında genel yeniden deneme oranlarını ve ekiplerinizi uyaracak alarmları izleyen ölçümler yapıyoruz.

Yeniden denemelerin geri dönüşlere dönüşmesinden kaçınmanın bir diğer yolu ise hepsini sürekli proaktif yeniden denemeyle yürütmektir (riskten korunma ve paralel istek olarak da bilinir). Bu teknik, bir sistemin yanıt vermesi için üç sunucunun ikisinden bir cevap gerektirdiği yerlerde, çekirdek okuma veya yazmalarının uygulandığı sistemlerde yerleşik olarak bulunur. Proaktif yeniden deneme, sürekli çalışma tasarım modelini takip eder. Yedekli istekler her zaman yapıldığından, yedekli isteklere olan ihtiyaç arttıkça yeniden denemeler tarafından sisteme fazladan yük eklenmez.

Sonuç

Kanıtlamanın zor ve etkisini test etmenin güç olmasından dolayı Amazon olarak sistemlerimizde geri dönüşlerden kaçınırız. Geri dönüş stratejileri, sistemlerin yalnızca sorunların ortaya çıkmaya başladığı en karışık anlarda geçiş yaptığı bir operasyon modu sunar ve bu moda geçiş yapmak karışıklığı daha da artırır. Geri dönüş stratejisinin uygulanmaya başlandığı zaman ile üretim ortamında bu stratejiyle karşılaşıldığı zaman arasında genellikle büyük bir gecikme vardır.

Bunun yerine, üretimde arada sırada değil, sürekli olarak kullanılan kod yollarını tercih ediyoruz. Veri alıp kritik bir zamanda uzaktan çağrının başarılı olmasını riske atma yerine sistemlere veri gönderme gibi modeller kullanarak ana sistemlerimizin erişilebilirliğini iyileştirmeye odaklanıyoruz. Son olarak, çok fazla yeniden deneme gerçekleştirme gibi kodumuzu geri dönüş benzeri bir operasyon moduna alabilecek hemen göze çarpmayan davranışlara karşı gözlem yapıyoruz.

Bir sistemde geri dönüş şartsa, ana çalışma modu kadar güvenilir ve tahmin edilebilir davranması için üretimde mümkün olduğunca sık geri dönüş alıştırması yaparız.


Yazar hakkında

Jacob Gabrielson, Amazon Web Services'ta Kıdemli Baş Mühendistir. Başta dahili mikro hizmet platformları olmak üzere 17 yıldır Amazon'da çalışmaktadır. Son 8 yıldır; yazılım dağıtım sistemleri, denetim düzlemi hizmetleri, Spot market, Lightsail ve son zamanlarda container'lar dahil olmak üzere EC2 ve ECS üzerinde çalışmaktadır. Jacob'ın tutkuları; sistem programlama, programlama dilleri ve dağıtılmış bilişim üzerinedir. En sevmediği şey, özellikle hata durumları altında çift modlu sistem davranışıdır. Seattle'daki Washington Üniversitesi'nden Bilgisayar Bilimi lisans derecesine sahiptir.

Zaman aşımları, yeniden denemeler ve sapmalı geri çekilme Önbelleğe alma zorlukları ve stratejileri