YAZILIM MİMARLIĞINDA İLKELER VE TEKNİKLER

Durumsuz Mimarilere Giriş

Durumsuz Mimariler — 1. Bölümde Ölçeklenebilirlik ve Ulaşılabilirlik için Durum (ing. State) ile başa çıkmayı öğrenin!

Ersin Er
Bilgisayımcı

--

Hepimiz ölçeklenebilir (ing. scalable) bir sisteme sahip olmanın yolunun durumsuz (ing. stateless) bir mimarî tasarımdan (ing. architectural design) geçtiğini biliriz, en azından bu konuda sağdan soldan bir şeyler duymuşluğumuz ve bilinçli-bilinçsiz bazı teknikler uygulamışlığımız vardır. Bu yazı dizisinde durumsuz mimariler (ing. stateless architectures) tasarlama konusunu —daha çok modern web mimarisi bağlamında— derinlemesine ve alışılagelmiş kalıpların dışında etraflıca ele alacağız. Ölçeklenebilirliğe odaklanmış olsak da ulaşılabilirlik (ing. availability) ve yeri geldikçe diğer kalite öznitelikleri bağlamında da durumsuzluğu ele alacağız.

Bu dizinin tüm yazılarına aşağıdaki listeden ulaşabilirsiniz.1. Durumsuz Mimarilere Giriş
Durumsuz Mimariler — 1. Bölümde Ölçeklenebilirlik ve Ulaşılabilirlik için Durum (ing. State) ile başa çıkmayı öğrenin!
2. Durumsuz Mimariler Tasarlamak için bir Genelleme ve Modelleme Yaklaşımı
Durumsuz Mimariler — 2. Bölümde Durum (ing. State) ve ilişkili diğer kavramlara daha soyut ve geniş bir açıdan bakın!
3. Çift Yönlü İletişim Gerektiren Sistemlerde Durumsuzluk Tasarımı
Durumsuz Mimariler — 3. Bölümde en çetrefilli ölçeklenebilirlik/ulaşılabilirlik problemlerinden birisinin çözümünü keşfedin!

Başlamadan önce…

Yazma Üslubum ve Okuyucuya Beklenen-Olası Yansımaları HakkındaTamamen terketmemin mümkün olmadığı akademik üslubum bazen ön plana geçebiliyor. Ama anlaşılırlığı bu tarz için feda etmiyorum.Bazen kuramsal da kaçabilecek, biraz da işin felsefesine dönük, yoğun ve soyut açıklamalarım olacak. Bunlarla ilk karşılaştığınızda hemen pes etmeyin; zamanla taşlar yerine oturacaktır. Teknik konuların günlük işinize —belki de farkında olmadığınız— yansımaları üzerinden ayrıntılı sorun-çözüm örnekleri vereceğim ve böylece konu ile yakınlık kurmanızı ve yazıdan azami ölçüde faydalanmanızı temin etmeye çalışacağım.Teknik yazılarımdan, ilgili konu alanında muhakemenizi güçlendirecek bir kavramlar ağını zihninize örmüş olarak ve aynı zamanda doğrudan kullanabileceğiniz araçlarla ayrılmanızı hedefliyorum.Yazılarımın tarzı sohbet havasında; biraz uzun ve dolambaçlı da olabilir. Bu yazıları vitamin hapı gibi tüketilsin diye değil, yazarının emek harcadığı kadar okuru da emek harcayıp sindire sindire okusun ve kesinlikle yararlansın diye yazıyorum. Yazdığım konularda okurlara doyurucu bilgiler sağlamayı özellikle amaçlıyorum. Bu bilgilerin, zaman içerisinde elde edilmiş ya da edilecek deneyimlerle perçinlenerek okuru daha üst bir kavrayış ve yetkinlik düzeyine sıçratacak bir altyapının gelişmesine katkıda bulunmasını umuyorum.Dil şimdiye kadar anlaşılmış olduğu üzere Türkçe :-) Dilimizi seviyorum, hakkını vermeye çalışıyorum... Yazı dilinde Türkilizce sözcükleri özensizce, gerekli-gereksiz kullanmaktan sakınıyorum (açıkçası, bunun için çok da zorlanmıyorum). Bu yaklaşım alışık olmayanları başta zorlasa da terimlere ve üsluba aşinalık oluştukça sorun olmaktan çıkar, hatta kavrayışı zamanla geliştirir diye düşünüyorum. Kullandığım Türkçe terimlerin İngilizce karşılıklarını genelde ilk kez kullandığım noktada (ya da bazen unutulmasın, pekişsin diye defaatle) parantez içinde veriyorum, ör. mimarlık (ing. architecture) gibi. Diğer yandan, anlamı ortaya çıkaracak tasvirleri metne yedirmeye çalışıyorum.Bu açıklamalardan sonra şimdi işimize bakalım...

Nedir “durum”? “Durumlu” ya da “durumsuz” nitelemeleri bize nasıl bir sistemi tarif eder?

Öncelikle herkesin hemfikir olabileceği basit bir tanımla başlayalım:

A istemcisi S servisinden hizmet almak istiyor olsun. A’dan S’ye art arda aktarılan isteklerden, önceki birinin işlenmesi sonucu oluşan ve sonraki bir isteğin işlenmesinde girdi (ing. input) olarak kullanılmak üzere S’de saklanan (“duran”) bilgiyi durum” (ing. state) olarak adlandırırız. Bu bilgiyi gerekli kılan bir sistemi durumlu” (ing. stateful), gerektirmeyenini de durumsuz” (ing. stateless) olarak nitelendiririz.

Bu tanım doğrultusunda durumsuz sistemlere basit bir örnek verelim:

Durumsuz Sistem örneği

3+4, 6/3 gibi aritmetik ifadelerin hesaplanması için istekleri (ing. request) istemciden (ing. client) art arda alıp gerekli aritmetik işlemleri yaparak her birinin sonucunu (7, 2) istemciye döndüren bir web servisimiz olsun. Herhangi bir istek sıklığı (ing. request rate) ya da istemci kimliği (ing. client identity) kısıtlamasının olmadığını varsaydığımız böyle bir web servisi görüp görebileceğiniz en durumsuz sistemdir!

Durumsuz Sistem için istek-yanıt akışı örneği

Örnek sistemimizi durumlu bir hâle dönüştürmek istersek kurgumuzu şöyle değiştirebiliriz:

Durumlu Sistem örneği

İstemciden +3, +4, C, +6, /3 gibi ifadeleri art arda istekler olarak alıp, her seferinde bir önceki işlemin saklanan sonucunu hesaba katarak, gerekli aritmetik işlemi yapan ve hem sonucu saklayarak yeni bir durum geçişi (ing. state transition) yapan hem de istemciye bu sonucu döndüren bir web servisi, hedeflediğimiz türden tam anlamıyla durumlu bir sistemdir! Bu sistemin belirlenen bir ilk durum (ing. initial state) — ki bu örnekte makul olanı 0— üzerinden çalışmaya başlaması gerektiğini gözden kaçırmayın.

Durumlu Sistem istek-yanıt akışı örneği
Her ne kadar sürekli olarak açıktan anmasak da her durum, bir bilgi ile sistemde karşılık bulur. O yüzden durum bilgisinden (ing. state information) bahsederiz. Durum ve durum bilgisi terimlerinin hem Türkçede hem de İngilizcede nöbetleştikleri sık görülür. Durumu daha çok kavramsal, durum bilgisini ise daha çok onun fiziksel karşılığı olarak düşünebilirsiniz. Diğer yandan, birbirlerini anlam olarak karşılamasalar da, üretilmiş, yüklenmiş ve işlenmeye aday her veri bir durum olarak algılanabilir. Ancak en azından bu yazı dizisinde referans alacağımız terminolojiye göre her durum veridir diyemeyiz. Bunu sonraki yazılarda uzunca irdeleyeceğiz.

Her iki örnek sistem kurgusundaki istek dizilerinin birbirine denk olduğu dikkatinizi çekmiştir. İlk örnekteki isteklerin aktarım ve dolayısıyla işlenme sırası önemsizken, ikinci örnekteki isteklerin yazıldığı sırada (en azından C temizle komutu (ing. clear command) isteğinin her iki tarafındaki ifade dizileri kendi içlerinde sıralı olarak) işlenmesinin gerekli olduğu açıktır. Çünkü her bir işlem sonrasında oluşan yeni durumun bir sonraki işleme girdi olarak kullanılmasıyla birlikte istekler birbirini ardışık olarak bağlar hâle gelmiştir.

Şunu da gözden kaçırmayalım: Açıkça belirtmemiş olsak da her iki sistem kurgusunda da istekleri teker teker kabul ederek işleyen tek bir servis biriminin olduğunu varsaydık. [Burada biraz gelişigüzel ve genel anlamda kullandığımız servis ya da servis birimi ifadesinden kastım, yerine göre bir sunucu (ing. server), yerine göre bir süreç (ing. process) ya da yerine göre bir uçnokta (ing. endpoint) olarak algılanabilir; bu yazı için aksi belirtilmediği sürece çok ciddi bir ayrım yok.] Diğer yandan, istekleri teker teker gönderen de tek bir istemcinin olduğunu da varsaydık.

Derdimiz ölçeklenebilirlik olmadığı sürece sistemin durumlu ya da durumsuz olmasının pek de bir önemi yoktur. Oysa ki bizim asıl amacımız ölçeklenebilir bir mimarî tasarıma ulaşmak. O yüzden anlatımımızı ve örneklerimizi aradaki farkı ortaya çıkaracak doğrultuda geliştirmeye devam edeceğiz.

Örnek Kurgumuz Üzerine Bir DeğerlendirmeHesap makinesi işlevselliği (ing. functionality) sunan bu servisi durumlu hale getirmekle ne kadar yarar sağladığımız tartışılabilir, ancak gerçek dünyadaki hemen hemen tüm anlamlı yazılım sistemleri durum üzerine inşa edilmiştir ve buradaki örneği de bu anlamlı servislerden birisi olarak saymanızı rica edeceğim.Ayrıca, istersek senaryoyu genişleterek bu örneği daha da amacımıza hizmet edecek şekilde geliştirebiliriz: Hesap makinalarında genelde M1, M2 gibi tuşlarla temsil edilen ve herhangi bir işlemin sonucunu belirli bir hafıza alanına yeniden kullanmak üzere kaydetme gibi işlevsellikler durumun gerekliliğini pekiştirmekte kullanılabilir.

Duruma teslim olmak: Çoklu Kullanıcı Desteği, Kullanıcı Oturumu ve Kişiselleştirme (ing. Multi-user Support, User Session and Personalization)

Eğer harcıalem bir DNS servisi sunmaya hazırlanmıyorsanız geliştirdiğiniz servisi “tanımadığınız insanların” yolgeçen hanı gibi ve hoyratça kullanmasını istemezsiniz. Ayrıca servisin kişiselleştirilebilmesi kullanışlılığı oldukça artıran bir etmen olmakla birlikte yokluğu neredeyse tamamen anlamsızdır. Bu bağlamda hepimizin kullandığı GitHub’dan Gmail’a, LinkedIn’den Slack’e, herhangi bir servis tabanlı ürünü örnek olarak göz önüne alabiliriz.

Örnek olarak saydığımız servisler gibi bizim servisimizin de, kullanıcılarını en azından işe yaradığı ölçüde tanımasını [ki bu “modellemek” (ing. “modelling”) ile olur] ve ona göre de sunulan hizmeti kişiselleştirmek —ya da genel manada özelleştirmek— istiyoruz (değil mi?). Hem de kötü niyetli kullanıcılara karşı sistemimizin güvenilirliğine dönük önlemler de almayı amaçlıyoruz. Demem o ki, artık servisimiz için “herhangi bir istek sıklığı ya da istemci kimliği kısıtlamasının olmadığını” varsaymıyoruz.

Çok İstemcili, Durumlu Sistem örneği
Web Mimarisinde Oturum Yönetimi: Kısa bir Genel BakışBildiğiniz üzere herhangi bir sistem için en temel kullanıcı modeli bir kullanıcı adı (ing. user name) ve bir parola (ing. password) içerir. Bu iki bilgi —özellikle de parola— kullanıcı ile servis arasında gizli bir kontrattır. Kullanıcı bu bilgilerle servise kaydolur. Servisi kullanmak istediğinde (servisin “başına oturacağında”) ise bir “oturum” (ing. session) açmak için kullanıcı adının yanında parolasını da şifreli (ing. encrypted) bir kanaldan servise aktarır ve kimlik  doğrulamasına (ing. identity authentication) tabi tutulur.HTTP iletişim modelini düşündüğümüzde bu oturumun birden çok istek boyunca (ing. across multiple requests) yaşamasını temin edecek olan nedir? Belki akla gelebilecek en kolay çözüm her istekle birlikte kullanıcı adı ve parolanın servise aktarılmasıdır —böylece her istek için kullanıcının kimliği doğrulanmış olur. Ne yazık ki bu yaklaşım başta güvenlik olmak üzere çeşitli nedenlerle tercih edilebilirlikten uzaktır. Kullanıcı-etkileşimli (ing. user-interactive) bir istemci söz konusu olsun ya da olmasın parolayı her seferinde kullanıcıya sormak pratik değildir. Alınan parolanın ise itinasızca saklanıp tekrar tekrar kullanılması da bir güvenlik riski oluşturur.Parolanın sürekli olarak her bir istekle birlikte kimlik doğrulama için servise aktarımının uygun olmadığı hallerde (yani genelde) kullanıcının doğrulanmış kimliğine ilişkin bir jeton (ing. token), bir çereze (ing. cookie) zarflanarak web tarayıcıda (ya da geniş anlamda HTTP istemcisinde) tutulur. Bu sefer, çerez her istekle birlikte karşı servise aktarılır —adeta oturum açma esnasında elde ettiğimiz bu jetonlar her seferinde servisin bozukluk gözüne atılır ve bir kere daha servisi kullanım hakkı elde ederiz. Böylece servis hangi kullanıcının istek yaptığını çerez içeriğindeki jetona karşılık olarak kendi bünyesinde tuttuğu bir eşleştirim (ing. mapping) ile bilir ve ona göre de kişiselleştirilmiş hizmetini sunar.Oturum, çerez zaman aşımına (ing. timeout/expiration) uğrayana kadar (evet, bir de zaman aşımı bilgisi eklenir ki sonsuza kadar bu kimlik doğrulanmış olarak kalmasın) ya da kullanıcı tarafında bile isteye silinene kadar geçerliğini korur. Her iki senaryoda  da oturum sonlanmış olur. Artık istemci, herhangi bir kullanıcı adına servisten istekte bulunamaz, ta ki yeniden bir oturum açılana değin. Kullanıcı ve oturum yönetimi harfiyen böyle olmak zorunda değildir elbette. Günümüz modern web mimarisinde bu yaklaşımı temel alan farklı teknikler uygulanmaktadır. Konumuzla kesiştikçe onlardan da bahsedeceğiz.

Sözünü ettiğimiz, oturum çerezi (ing. session cookie) istemci için de bir durum teşkil etmekle birlikte, kullanıcı bilgileri ve bunların çerez ile eşleştirimi de servis tarafında mutlaka ilişkili bir durum bilgisi tutulmasını gerektirir. Görüldüğü üzere en basit bir sistem kurgusunda bile durum kaçınılmazdır. Çözüme geleceğiz ama önce konuyu biraz daha irdeleyip toparlayalım.

Aradan istek sıklığı denetimi konusunu da çıkaralım: İstemci-başına (ing. per-client) tutulacak bir sayaç (ing. counter) ve doğru algoritma ile istekler için sıklık sınırlaması (ing. rate limiting) yapılabilir. Söz konusu algoritma, her bir kaynaktan gelen isteklerin sayısının belli bir zaman aralığında öntanımlı bir sınırını aşmamasını garanti eden standart yaklaşımlardan birini kullanır. Bu sayaç, tahmin edeceğiniz gibi, servis tarafında istemci-başına yeni bir durum bilgisi anlamına gelecektir.

Kullanıcı yönetimi ve istek sıklığı denetimi haricinde servisimizin verdiği hizmet mantığından ötürü durumu gerektiren başka hangi gereksinim olabilir? Servisimizin yapabildiği aritmetik işlemleri hatırlayalım. Her işlemin sonucu serviste yeni bir durum oluşturuyordu. Bunun, durumu elzem kıldığından bahsetmiştik. Artık bu durum bilgisini kullanıcı bağlamında tutacağız ki her kullanıcı kendi servis durumunu referans alarak isteklerini niyet ettiği hesaplamayı yaptırabilecek şekilde art arda aktarabilsin. Tersi durumda (yani kullanıcılar aynı durum bilgisini paylaşırsa) farklı kullanıcıların istekleri birbirine karışarak işlemlerin mantıksal bütünlükleri bozulabilir ve ortaya tam bir kargaşa çıkardı. Fark ettiğiniz gibi artık birden çok kullanıcıdan ve dolayısı ile birden çok istemciden söz ediyoruz.

Peki ya tek bir kullanıcının farklı cihazları ve oturumları? Malum, günümüzde kullanıcılar servislere farklı cihazlardan ve hatta aynı anda erişebilmekteler. Her şeyden önce bir mobil cihaz gerçeğimiz var. Aritmetik hesaplamalar yapan web servisimizde sizce işlem sonuçlarına ilişkin durum bilgisi kullanıcı-başına (ing. per-user) mı, yoksa cihaz-başına (ing. per-device) mı, yoksa oturum-başına (ing. per-session) mı tutulmalı? Bununla paralel diğer bir soru da şu: durum bilgisi servis tarafında mı istemci tarafında mı tutulmalı? (Kafanız karıştı mı? Güzel.) Burada servisin sunduğu hizmetin iş mantığına (ing. business logic) göre seçeneklerimizin olduğunun farkına vardık mı? Kullanıcı farklı cihazlardan servise erişse bile belirli senaryolar için durum bilgisinin kullanıcı-başına saklanması anlamlı olabilir. Diğer taraftan, her cihaz üzerinden yaptığı (servise yaptırdığı) işlemlerin ilgili cihaz (ya da oturum) bağlamında yürümesini istemesi de son derece doğal olabilir; ki bu seçenek örnek aritmetik işlem servisi senaryomuz için daha akla yatkın görüyor.

Biraz Derin DüşünceYazının ilk bölümünde irdelediğimiz Durumlu ve Durumsuz örnek sistemler bağlamında kullanıcı-başına, cihaz-başına, ve oturum-başına durum bilgisinin saklanmasının servis ya da istemci tarafında nasıl yapılabileceğini, genel olarak bu bilginin yönetimin nasıl yapılabileceğini biraz düşünmeye ne dersiniz? Burada dikkatinizi çekmek istediğim husus, durum bilgisinin <servis ya da istemci tarafında tutulması> ile <kullanıcı-başına, cihaz-başına, ya da oturum-başına tutulmasının> çözüm uzayının iki farklı boyutunu oluşturması!

Örneğimizdeki aritmetik hesaplama servisi için durum bilgisinin cihaz/oturum-başına yönetilmesinin, yerine göre anlamlı olduğunu söyledik. Ne var ki, bir alışveriş sitesinin sepet özelliği için pek de böyle değildir! Bu konu bağlamındaki en büyük derdimiz alışveriş siteleri olmasa da herkesin deneyimlediği bir uygulama alanı olduğundan biraz üzerinde duralım:

Günümüzde hâlâ bazı alışveriş siteleri kullanıcı deneyimini (ing. user experience) baltalama pahasına sepet bilgilerini oturum-başına tutmaya devam ediyor. Masaüstü bilgisayarınızın başından kalkıp (oradaki oturumunuzu terkedip) mobil cihazınız üzerinden alışverişe devam etmek istediğinizde bir de bakmışsınız sepetiniz boş ya da daha önce bu mobil cihazı kullanırken bıraktığınız durumda. Bu modası geçmiş bir yaklaşım. Peki neden uygulanıyor(du)? Belli ki durumsuzluk ilkesi gereği… Bir de tabii ki iş bilmezlikten… (Bir de yukarıdaki beyin jimnastiğini yapmadıklarından…)

Mimar olarak görevlerimizden biri de tüm kalite özniteliklerinin birbiri arasında bir ödünleşim (ing. tradeoff) dengesi sağlamanın yanında her birinin işlevsellik ve kullanıcı deneyimi ile de benzeri dengesini kurabilmektir.

İstemci tarafı durum yönetimi, gereksinimler doğrultusunda tercih edilmeli, körü körüne sırf durumsuz bir tasarım yapmış olmak için tercih edilmemelidir. Veri odaklı senaryolarda kullanıcı verisinin kaybı anlamına gelebilecek bu yaklaşımı dikkatli kullanmalısınız. Tabii bu yaklaşımın son derece anlamlı olduğu senaryolar da var —her şey kullanıcı verisinden ibaret değil yazılım sistemlerinde. Mesela mı? Özellikle ölçeklenebilir mikroservis (ing. microservice) mimarilerinde öne çıkan “İstemci Tarafı Yük Dengeleme” (ing. “Client Side Load Balancing”) başka yazılarımızda değineceğimiz iyi bir örnek olabilir.

Genel geçer bir ilke şudur: Tüm tasarım kararlarımız bilinçli olarak verilmelidir. Tercihler, başkaları öyle yapıyor ya da şu teknoloji öntanımlı olarak şöyle çalışıyor diye değil de sistemin bir gereksinimine karşılık yapılmalıdır.

Pekala, durumsuz bir sistem tasarımı nasıl olur? Ya da neden olsun?

Belli ki bu durum denen şeyden kaçış yok ve bir şekilde tutmamız gerekiyor ki en azından kullanıcılarımızı tanıyalım, kimlik doğrulaması yapabilelim ve iş mantığımıza göre veri olarak işleyebilelim (ki bu herhangi bir yazılımı anlamlı kılan sınırsız bir kullanım senaryosu). Peki ne zaman durum gerçekten sorun olur ve bu sorunla nasıl başa çıkılır?

Şimdiye kadar örneklediğimiz durum bilgisi çeşitleri oldu. Bunların servis ve istemci tarafında olası ele alınışlarının artılarından-eksilerinden kısmen bahsettik. İyi de, servis tarafındaki durum neden bir sorun olarak ortaya konuyor? Durum kaçınılmaz, anladık da, pek de bir sorun göremedik şimdiye kadar, değil mi?

Gelelim ölçeklenebilirliğe. Haydi yine biraz dolanarak gidelim... Servis tarafındaki durum nerede tutulabilir ve hangi yaklaşım gerçekten de ölçeklenebilirlik bağlamında sorun yaratır? (Bu sorular hep düşünmeyi tetiklemek için… “Anlatacaksan anlat, soru sorup durma” demeyin!)

İşte 42 puanlık çoktan seçmeli bir uzmanlık sorusu:

Servis sürecimizin koştuğu bir sunucuda aşağıdakilerin hangisinde durum bilgisini tutabiliriz?

  • A) Süreç belleğinde (ing. Process memory) (dolayısıyla sunucu ana belleğinde)
  • B) Dosya sisteminde
  • C) Aynı sunucuda kurulu ilişkisel veri tabanı sisteminde (ör. MySQL)
  • D) Aynı sunucuda kurulu önbellekleme sisteminde (ing. caching system) (ör. Redis)

Cevap?

Fotoğrafı çeken: Jules Bss / Unsplash

Tabii ki “E) Hiçbiri”. Böyle denk gelmesinden çok keyif aldım… :-D

Bunların seçeneklerin hepsinde durum bilgisi tutulabilir ama tutmamalıyız. Nedenini birazdan irdeleyeceğiz.

Dananın kuyruğunun koptuğu yer: Yatayda Ölçeklenebilirlik (ing. Horizontal Scalability)

Ölçeklenebilirlik, artan istek miktarı ve dolayısıyla yük ile orantılı olarak altyapı büyüklüğünün ve hizmet kapasitesinin de artabilmesidir.

Peki bir servis yazılımının kapasitesi nasıl artırılır? İlk akla gelen yöntem servis uygulama yazılımının çalıştığı sunucu kapasitesini artırmak olabilir. Ne var ki bu yöntem, başta güvenilirlik (ing. reliability) ve ulaşılabilirlik (ing. availability) olmak üzere, diğer birçok mimarî kalite özniteliğini ve çeşitli tasarım ilkelerini hiçe sayar. Bu arada bu yaklaşıma dikeyde ölçeklendirme (ing. vertical scaling) denir ve kendine göre anlamlı ya da elzem olduğu koşullar olabilir, vardır da (ör. yüksek işlem gücü gerektiren uygulamalar). Bizim tercih edeceğimiz taktik ise yatayda ölçeklendirme olmalıdır, yani yeni sunucular ekleyerek sistem kapasitesini artırma. Kalite öznitelikleri perspektifinden bakarsak da mimarimiz, diğer bir deyişle, yatayda ölçeklenebilir (ing. horizontally scalable) olmalıdır.

Bir önceki kısımdaki soruya ilişkin dört cevap şıkkını da değerlendirdiğimizde yatayda ölçeklenebilirliğe ket vuran ortak özellik olsa olsa nedir? Elbette hepsinin servis uygulama yazılımı ile aynı sunucu üzerinde olmasıdır.

Durumluluğun, ölçeklenebilirliği neredeyse imkânsız kılan yönü durum bilgisinin uygulama yazılımı ile aynı sunucuda tutulmasındandır. Bundan ötürü, kapasite artırımı için yeni eklenecek sunucuların, halihazırda oluşmuş olan durumların bilgisine doğrudan erişiminin olmaması ve dolayısıyla belirli istemcilerin ancak belirli sunucularla iş görmeye mahkum edilmesi sorunun temel kaynağıdır.

Böyle bi mimaride sunucular bir havuz gibi yük dengeleme (ing. load balancing) ve yedeklilik (ing. redundancy) amacıyla esnekçe kullanılamaz. Belli bir durum bilgisini tutan sunucu olası bir çökme ya da yazılım yükleme gibi planlı bir operasyon sırasında bile kendisine bağımlı hale getirdiği istemcilere cevap veremeyeceğinden, sistemin ulaşılabilirliği, güvenilirliği ve hatta durum bilgisinin dayanıklılığı (ing. durability) hiçe sayılmış olur.

Tüm bu olumsuzluklara rağmen kapasite idamesi için birden çok görevdeş sunucunun olduğu bazı sistemlerde bir istemci her oturum açtığında o defalık yük dengeleme algoritması ile seçilen belirli bir sunucu ile geçici olarak (oturum sonuna kadar) ilişkilendirilir. Bu ilişkilendirme sunucularla istemci arasındaki yük dengeleyicinin mahareti ile, örneğin istemci IP’sinin sunucu kimliğiyle yazılımsal olarak birbirine eşleştirilmesi ile sağlanır. Bu eşleştirme sonrasında, belirli bir istemciden gelen tüm istekler hep aynı belirlenmiş sunucuya yönlendirilir. Zaman aşımına uğrama ya da kasten sonlandırılma sonrasında oturum yeniden başlatıldığında bahsettiğimiz süreç baştan çalışır. Bu tekniğe oturum benzeşimi (ing. session affinity) ya da daha salaş bir ifade ile oturum yapışkanlığı (ing. session stickiness) denir. Bir de günümüzde başat erişim ortamı olan mobil cihazlarda koşan yazılımlarda oturumların hemen hemen hiç sonlanmadığını düşünün… Elbette kullanıcıdan habersizce tazeleme jetonu (ing. refresh token) kullanılarak oturumlar yenileniyor olabilir — ve yapılmaktadır da — ama bu işlenen suçu hafifletmez. Kaş yapayım derken göz çıkaran bu yaklaşımın yatayda ölçeklenebilirliğe hizmet etmediği açıktır; olsa olsa verimsiz bir kapasite yönetim yöntemi olarak addedilebilir.

Bu durum bilgisini sunuculasak da mı saklasak, sunuculamasak da mı saklasak?

Hâl böyle olunca durum bilgisini kullanmaya öyle ya da böyle ihtiyaç duyan sunucuları, yatayda ölçeklenebilirliği (ve daha başka kalite özniteliklerini) sağlayabilmek için her ne nedenle olursa olsun istediğimiz zaman, istediğimiz sıklıkta ve miktarda açıp kapatabilmek isteriz. Böyle bir mimarî tasarımı her daim (maliyeti de gözeterek) hedefleriz. Bunun yolu da yazının en başında dediğimiz gibi öncelikle durum bilgisini sunucu dışına çıkarmaktan ve sunucularda koşan uygulama yazılımı süreçleri için sürekli bulunur kılmaktan geçer.

Çok İstemcili, Yatayda Ölçeklenebilir, Durumsuz (Harici Durumlu) Sistem örneği

Döndük dolaştık aynı yere geldik. Bitti mi peki? Hayır, sadece meseleye biraz bol örnekli ve fazlaca izahatlı dolambaçlı bir giriş yapmış olduk. Eğer bu konuda daha önceden pek bir bilginiz yoktuysa o zaman iyi bir temel aldınız demektir. Eğer bir uzmansanız buraya kadar olan hikayeyi zaten biliyor olmalısınız — yine de etraflıca tartıştığımızdan, konuyu zihninizde biraz daha pekiştirdiğinizi umuyorum.

Son olarak yarım kalan bir işimizi tamamlayalım ve sorumuzu yineleyelim, ama bu sefer cevap şıklarını değiştirerek ve soruyu da ona göre yeniden ifadelendirerek:

Servis sürecimizin koştuğu bir sunucudan erişilebilmesi için aşağıdakilerin hangisinde durum bilgisini tutabiliriz?

  • A) Bellek-içi dağıtık önbellekleme sisteminde (ing. In-memory distributed caching system) (ör. Hazelcast)
  • B) Dağıtık dosya sisteminde (ör. NFS)
  • C) Ağ üzerinden erişilebilen merkezi ya da dağıtık bir veri tabanı sisteminde (ör. MySQL)
  • D) Ağ üzerinden erişilebilen merkezi ya da dağıtık önbellekleme sisteminde (ör. Redis)

Cevap?

Tabii ki “E) Hepsi”. ;-)

Her iki sorunun cevap şıklarını iyice irdelemenizi öneririm. İkinci sorunun şıklarındaki sistemlerin ilk sorudakindekilerden farklı olarak hep ağ üzerinden farklı modellerle veri erişimi sağlayan, herhangi bir uygulama yazılımı sunucusunun yokluğunda (A seçeneğindeki bir incelikle birlikte) müstakil olarak çalışmalarına devam edebilecek sistemler olduğu dikkat çekmeli. Buradan, odağımızda sadece dağıtık veri yönetimi varmış gibi bir izlenim edinebilirsiniz ama o kadarla sınırlı değil bu konu…

Bir sonraki yazımızda anlatımımızı, kullanıcı, istemci, oturum, sunucu, servis, veri ve hatta durum terimlerinden sıyırıp konuyu hem daha elverişli soyut bir düzeyde hem de daha geniş bir bakış açısı ile ele alacağız. Henüz meseleye yalnızca giriş yapabildik…

Umarım keyifli ve verimli bir okuma olmuştur. Beğeni, eleştiri ve öneri yorumlarınızı merakla bekliyorum. Bunun için yazının altındaki tartışma alanını kullanabilirsiniz. Ayrıca bana kişisel Twitter hesabımdan, bu yazının yayımlandığı Medium yayınına özel Twitter hesabımdan ya da LinkedIn üzerinden de ulaşabilirsiniz.

Bir başka yazıda görüşene dek esen kalın!..

--

--

Ersin Er
Bilgisayımcı

Teknoloji Stratejisi, Mühendislik Yönetimi, Liderlik, Yazılım-Sistem & Ürün Mimarisi, Organizasyon Tasarımı, Akış & Ölçeklenme, Sistemlerle & Karmaşıkla Düşünme