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

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!

Ersin Er
Bilgisayımcı

--

Fotoğrafın kaynağı: The Matrix (1999)

Durumsuz Mimariler (ing. Stateless Architectures) başlıklı yazı dizimizin ikinci bölümünde birlikteyiz!

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!
Not: "Yazma Üslubum ve Okuyucuya Beklenen-Olası Yansımaları Hakkında" bilgilere dizinin ilk yazısının giriş kısmından ulaşabilirsiniz.

Önceki bölümde ölçeklenebilirlik bağlamında durumun yarattığı soruna değinmiş ve ekseriyetle veri biçiminde karşımıza çıkan durumun, servisin koştuğu sunucudan uzaklaştırılmasıyla ölçeklenebilirliğin ve ulaşılabilirliğin yolunun nasıl açıldığını açıklamıştık.

İşin aslı şu ki ilk yazıdaki tartışmamızı biraz dar bir bakış açısıyla ve yetersiz bir soyutlama düzeyinde yaptık; biraz da kavramlar birbirine karıştı. Aslında ölçeklenebilirlik için sisteme yansıtılması gereken ilke, gelen isteklerle sunucuda veri biçiminde oluşan durumdan kurtulmanın ötesinde çok daha genellenebilir türdendir. Derdimiz ne sadece istek, ne sadece veri, ne de sadece sunucu

Bu genelleme ve soyutlama (ing. generalization and abstraction) işine girişmeden önce ilk yazıdaki yargılarımızı özetleyelim:

  • Ölçeklenebilir (ing. scalable) bir sisteme sahip olmanın yolu durumsuz (ing. stateless) bir mimarî tasarımdan (ing. architectural design) geçer.
  • Bir istemciden bir servise 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 serviste 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. Durum daha çok kavramın adıyken, durum bilgisi (ing. state information) ise fiziksel karşılığıdır.
  • Ölçeklenebilirlik, bir sistemin, artan istek (ing. request) miktarı ve dolayısıyla yüküyle (ing. load) orantılı olarak altyapı büyüklüğünün ve hizmet kapasitesinin de artabilmesini ifade eder. Bunun sağlanabilmesi için de sistemdeki uygulama yazılımı sunucularının herhangi bir veri —dolayısı ile durum— yönetmiyor olması ve böylece kapasite artırımına engel teşkil edecek bu bağımlılıktan kurtulunmuş olması gerekir.
  • Durumsuz sunucuların esnek bir biçimde açılıp kapatılabilmesi ulaşılabilirliğe (ing. availability) de katkı sağlar.
  • Sunucu dışına çıkarılan durum bilgisi ağ üzerinden erişilebilen ve kendi yaşam döngüleri olan —ölçeklenebilirik, ulaşılabilirlik gibi çeşitli kalite özniteliklerini kendi bünyesinde karşılaması beklenen— dosya, önbellekleme ve veri tabanı sistemleri üzerinde tutulabilir.

Bu özetten sonra şimdi işe koyulalım…

Sunuculamasak da mı saklasaydık acaba? — Bir Genelleme

Belirli bir iş mantığına karşılık gelen bir servis (ing. service), bir sunucu makinede (ing. server machine), bir programın (ing. program) işletim sistemi tarafından bir süreç (ing. process) biçiminde çalıştırılması ve istemci’deki bir süreç ile süreçler arası iletişim (SAİ) [ing. inter-process communication (IPC)] yöntemiyle iletişim kurarak hizmetini verir.

Burada sunucu diye adlandırdığımız şey aslında genelgeçer algılanışıyla belirli nitelikleri hâiz bir makinedir. Bu algıya ve şimdiye kadar anlattıklarımıza göre sunucu, yatayda ölçeklenebilir ve ulaşılabilir bir sistemden düşebilecek, sisteme eklenebilecek birimin adıdır. Nitekim günümüz modern sistem mimarisinde sunucular sanallaştığı gibi konteynerler de aynı muameleye tâbi bilgiişlem (ing. compute/computing) birimleri olarak karşımıza çıkmakta. Yani sistemden çıkarılan/düşen ya da sisteme eklenen (provizyonlanan [ing. provisioned]) yapının cinsi ne ise bizim derdimiz de onunladır —durumu o yapının sınırları dışında tutmaya çalışacağız. Bu yapılar iç içe olabilir ve her katman kendi içinde ölçeklenebilir ama biz sürecin koştuğu iç yapı ile ilgileniyoruz. Yani konteynerler sanal sunucular üzerinde, sanal sunucular gerçek makineler üzerinde ölçekleniyor olabilir ama bizim uygulama yazılımımız eğer konteyner içinde çalışıyorsa bizim için eklenen/çıkarılan ve ona göre pozisyon alacağımız yapı konteynerdir.

Bu değerlendirmeler ışığında ilk genellememizi yapalım: İster fiziksel ya da sanal bir sunucu, ister konteyner olsun, ölçeklenirken eklenen (ya da planlı/plansız sistemden çıkarılan/düşen) ve servis yazılımının konuşlandırılarak doğrudan temas ettiği yapılara bilgiişlem kapasitesi provizyonlama birimi (BKPB) [ing. compute capacity provisioning unit (CCPU)] diyeceğiz —bazen de basitçe bilgiişlem birimi. Bu noktada önemli olan, bir adlandırma yapmamızın ötesinde konuyu soyutlayarak irdelemiş ve üzerine yenilerini inşa edebileceğimiz bir model ortaya koymuş olmamızdır…

Bilgiişlem Kapasitesi Provizyonlama Birimi Seçenekleri

“CCPU da neymiş, hiç duymadım.” deyip de hiç boşuna Google’a sormayın; doğrudan böyle bir kavram yok zaten literatürde. Ama bu bizim kavram üretmemize mâni değil. Aslına bakarsanız, bu yazı dizisindeki kavram ve tekniklerin çoğu ne sektörde ne de literatürde buradaki perspektiften ele alınmış değil bildiğim kadarıyla. İcat çıkarmaya devam edeceğiz.

Fazladan bir perspektif: KonuşlandırmaFarklı bir açıdan konuya bakarsak bu yapıları servis yazılımımızın konuşlandırma hedefi (ing. deployment target) olarak da görebiliriz. Bu durumda servis yazılımımızı da konuşlandırma birimi (ing. deployment unit) olarak anabiliriz. Bir servisi devreye alabilmek için önce altyapısını (ing. infrastructure) provizyonlamak, sonra da yazılımı konuşlandırmak gerekir. Ne var ki binyılın başından beri konuşlandırma hedeflerinin (yani altyapının) sanallaş[tırıl]ması (ing. virtualization) ve birer yazılımsal yapıya dönüşmeleri neticesinde aradaki makas daralmıştır.Şunu demek istiyorum: donanıma yakın BKPB’lerin provizyonlanması ile uygulama yazılımının konuşlandırılması tamamen ayrık ve ardışık süreçlerken, sanallaştırmanın arttığı bilgiişlem modellerinde iki süreç bir arada işletilmeye ve hatta aynı işlem olmaya kadar evrilmişlerdir. Konteynerlerin içlerindeki servis uygulama yazılımı ile birlikte paketlenip (ing. packaging) provizyonlandıklarını ve dolayısıyla konuşlandırıldıklarını söyleyebiliriz.Burada bir tekniği daha anmadan olmaz —kafalar karışacak yine kavram binişmesi yüzünden: sunucusuz [bilgiişlem] (ing. serverless [computing]) ya da servis olarak işlev (ing. function as a service). Tekniğin ayrıntısına şimdi girmeyeceğim ama sunucusuz bilgiişlemde —evet, sunucu lafı yine çıkageldi— BKPB ile konuşlandırma biriminin tamamen birbirine geçip yekpare bir yapı oldukları, dolayısıyla provizyonlama ve konuşlandırmanın aynı süreç oldukları söylenebilir. Konteylerler için de aynı şey söylenebilirdi, ancak o modelde bu örtüşmeyi zorlayan aslî bir etmen söz konusu değil —konteynere bağlanıp hâlâ bir sanal makine gibi müdahale edebiliyoruz…

Durumu neyin dışında tutacağımızı anladığımıza ve kapsayıcı bir tanıma bağladığımıza göre şimdi de durumun altından girip üstünden çıkabiliriz!

Durum Ötesi Durumlar

Her veri durumdur ama her durum veri olmak zorunda değil demiştik. Bu başlıktan itibaren doğrudan veri olarak değerlendirilemeyecek, ya da daha doğrusu kullanıcı verisi olarak değerlendirilemeyecek durum bilgileri ile farklı sulara yelken açmaya başlıyoruz. Burada yer yer sunucu-istemci modelinden de çıkacağız.

Gizli Kalmaması Gereken Günlükler

Durum gözlüğümüzü takıp BKPB’lere eğilecek olursak, sistem ve uygulama günlüklerinin (ing. system and application logs) hem kayıtların dayanıklılığı (ing. durability) hem de yine sistemin ölçeklebilirliği açısından ilgili BKPB’nin sınırları içerisinde kalmasının sakıncalı olduğunu görürüz. Olası bir çökmede kayıtların yitirileceği aşikar.

Peki, retorik bir soru gelsin: Özellikle uygulama günlüklerini dikkate aldığımızda, belli bir istemciden gelen istekleri kayıt devamlılığı açısından hep aynı bilgiişlem birimine mi yönlendirelim yoksa yük dengeleme için farklı birimlere yönlendirilmeleri durumunda kayıtların bağdaşımı (ing. coherence) mı bozulsun? İkisi de olmasın elbette!..

Fotoğrafı çeken: Petri R / Unsplash

Günlüklerin de ölçeklenebilirlik yanında birçok nedenle bilgiişlem birimi dışına taşınması [genellikle] olmazsa olmaz bir uygulamadır. Bunun için merkezi günlük yönetimi sistemleri kullanılabilir (ör. ELK Stack).

Bilgiişlem Birimine Hapsolunamayacak Durumsal Boyut: Zaman

Bu başlıklardan çok fazla anlam çıkarmaya çalışmayın, sadece dikkatinizi çekmeye çalışıyorum… ;-)

Geliştirdiğimiz bir yazılımda çeşitli görevleri zamanlandırarak (ing. scheduling) ileri bir tarihte ya da saatte çalıştırmak istediğimizi varsayalım. Bunun içinde kullandığımız programlama dilinin kütüphanesinden zamanlayıcı (ing. timer) benzeri bir modülden yararlanmayı tercih edebiliriz. Bu oldukça sık karşılaşılan bir gereksinimdir. Örneğin belirli zaman aralıkları ile rapor üretilmek istendiğinde doğrudan böyle bir gerçekleştirime (ing. implementation) gidilir. Bu yolla düzenli olarak belirli zaman aralıklar ile ya da düzen izlemeden bir kere çalışacak rutinler (ing. routines) zamanlandırılmış işler olarak yönetilebilir.

Aynı gereksinim ya da bunun uygulama yazılımından öte, daha sistem düzeyinde olan benzer gereksinimler —örneğin, belirli zaman aralıklarıyla yedekleme işlemi yapılması işi gibi — ilgili işletim sisteminde ya da çalışma ortamında bulunabilecek bir servis aracılığıyla da karşılabilir. Linux ve türevi sistemlerde cron isimli sistem servisi bunun çok meşhur bir örneğidir. Bu servis crontab isimli bir dosyaya tanımları kaydedilen zamanlandırılmış işleri zamanı gelince çalıştırmakla yükümlüdür ve diğer sistem servisleri ile aynı düzenekle (systemd, upstart vb.) çalışır.

Yukarıda bahsettiğimiz zamanlandırılmış işlerin yönetimi için her iki yöntemin de sorununu farkettiniz mi?

Her iki yaklaşımda da aslında sistemde (bellekte ya da dosya sisteminde) bir durum bilgisi oluşturmuş oluruz! Programlama dilinin ya da işletim sisteminin güçlü bir şekilde sağladığı bu düzenekleri kullanmak işten bile değildir! O yüzden de çok tartılıp biçilmeden öylesine kullanılıverirler. Ama siz artık işleri zamanlandırmayı da, zamanı gelince o işleri tetiklemeyi de halledilmek üzere bilgiişlem biriminin dışına taşıyıp ehil ellere teslim etmeniz gerektiğini biliyorsunuz.

Bu iş için defakto sistem —biraz eskimiş olmakla birlikte— Quartz’dır. Bulut sağlayıcılarının bu işe adanmış servisleri ya da konteyner orkestrasyon sistemlerinin işleri konteyner kümesinde dağıtık çalışacak şekilde zamanlayan düzenekleri de değerlendirilebilir burada. Örneğin, AWS CloudWatch Events ve AWS ECS Scheduled Tasks gibi.

İyi de işleri zamanlandırmayı bilgiişlem birimi dışına çıkarmazsak ne olur? Bir durum bilgisi söz konu dedik ama pek de irdelemedik bu bilginin doğasını… Açıklayalım.

Belirli bir bilgiişlem biriminde çalışmak üzere zamanlandırılmış bir iş, bilgiişlem birimi çökerse — ulaşılabilirliğin zaten sağlanamamasının yanında— işlevsellik kaybı olacaktır. Bu işi tekrar hangi düzenek nasıl zamanlayacak ve çalıştıracak?

Ölçeklenebilirlik ve yük dengeleme açısından bakalım bir de. Sisteme yeni bilgiişlem birimleri eklenmiş olsun. Belirli bir bilgiişlem biriminde çalışmak üzere zamanlanmış bir iş zamanı geldiğinde o an için daha uygun olan başka bir birimde nasıl çalışabilir? Bu çakılı yapıda çalışamaz, çünkü bilgiişlem biriminin içinde mahsur kalan işler yük dengeleyiciye uğramaz —tabii bu durumu ele alacak özel bir tasarımınız yoksa…

Zamanlandırılmış işler konusunu güvenilir bir biçimde çözmek kolay değildir. Bu görev için özelleşmiş bir sisteme devredilmesi en doğru çözüm olacaktır.

Durum v2

Son iki örnekten de anlaşılacağı üzere durum sadece son kullanıcı kontrolündeki bir istemciden art arda gelen isteklerle oluşan ve sonraki istekleri bağlayan bir bilgiden fazlasıdır.

  • Durum geçişine neden olan işlemler, son kullanıcıya ait bir istemciden ya da bir servis odaklı mimaride (ing. service-oriented architecture) diğer servislerden gelecek istekler ve güncellemelerle de tetiklenebilir.
  • Durum, bilgiişlem birimi dışından gelenlerin yanında içinden gelişen olaylar ile de oluşabilir (ör. sistemde oluşan bir sorunun günlüğe kaydedilmesi).

Hız kesmeden Durum v3'e bakalım isterseniz? Daha neler, değil mi? Ama bu işin verinin ötesinde bir iş olduğunu anlatmak ve sonradan anlatacağım son derece kritik konulara altyapı hazırlamak için böyle zıpçıktılık yapıyorum!

Dizinin bir sonraki yazısında — ki bence asıl aktarmak istediğim mesajı içeren en önemli bölüm olacak — işleyeceğimiz konuya bir teğet geçiş yapalım ve durumu bir derece daha genelleyelim.

Ağ İletişimi Duruma Karşı

İlk başlarda örneğini verdigimiz türden durumsuz bir servisimiz olsun. Buradaki durumsuzluk tanımı sadece şimdiye kadar bildiklerimizle sınırlı olarak geçerli. Bu servisi kullanan istemcilerde servisin hizmet verdiği tek bir sunucunun IP’sinin gömülü kodlanmış (ing. hard-coded) olduğunu varsayalım. (Hiç mi başınıza gelmedi? Ben çok sistem gördüm böyle. Güvenlik amaçlı sabit IP kullanımı alışılageldik bir uygulamadır.) Sözde durumsuz bir kurguya sahip olan servisimiz istemciler açısından hep aynı sunucuya isteklerin akacağı gayet durumlu bir sistemdir aslında. Sisteme yeni bir sunucu eklerseniz istekler DNS mahareti ile yeni sunucuya yönlendirilemez.

Ha bire sorun… Bu sefer ne yapmak lazım? Çok kolay: bilgiişlem birimini durum olarak addettiğimiz yüklerinden kurtaracağız. Sunucuya atanmış sabit bir IP’den nasıl kurtulunur ki? Elbette sabit olmayan bir IP ile… Ama sabit olmayan derken farklı manada: IP adresi sabit olmak zorunda olabilir (ki bu senaryoda öyle varsaydık) ama yeri sabit olmak zorunda değil, yani sunucuya doğrudan atanmak zorunda değil.

2 olası çözüm var.

Birincisi, IP’yi sunucu yerine yük dengeleyiciye vermek. Böylece yük dengeleyici arkasında özel IP’leri ile birden çok sunucu açılabilir ve hem ölçeklenebilirlik hem de ulaşılabilirik sağlanabilir.

İkinci çözüm ise bir taşınabilir ya da daha motamot karşılığı ile yüzen IP (ing. floating IP) kullanmak. Hem veri merkezleri hem de bulut sağlayıcıları bu özelliğe karşılık gelen düzenekler sunuyorlar genelde (ör. AWS Elastic IP). Bu düzeneklerde aslında birinci çözümümüzdeki yapı gizli bir biçimde bizim için kurulmuş oluyor. Ama bir yük dengeleme işlemi söz edilemese de yüzen IP’yi gerektiğinde başka bir sunucuyu gösterecek şekilde yönlendirmek mümkün. Bu çözümde ölçeklenebilirlik adreslenmiş olmaz ama ulaşılabilirlik sağlanabilir.

Bu senaryoda durum servis uygulama yazılımı ile ilgili değil bilgiişlem altyapısı ile ilgili olarak önümüze geldi. Provizyonlama işlemi ile oluşmuş bir durum sonraki iletişim akışını bağlayıcılık oluşturmuştu. Bu durumu bilgiişlem birimi dışına çıkararak çözüme ulaşmış olduk. Tabii burada altyapının da desteğini aldık.

Her ne nedenle ve biçimde oluşmuş olursa olsun ölçeklenebilirliğe ve ulaşılabilirliğe engel teşkil edecek herhangi bir durum bilgiişlem biriminin dışına taşınmalıdır.

Yazılım mühendisliğinde bir ilke vardır: Değişeni sarmala (ing. encapsulate what varies). Biz de yeni bir ilke öne sürebiliriz: Duranı dışarıda bırak (ing. externalize what stays).

Durum algınızı belli bir yere getirdiğimizi umuyorum.

Bu yazıyı sonlandırmadan önce servis yazılımına ilişkin bir mimari model önerisinde bulunacağım. Şimdiye kadar anlattıklarımız aslında kulağımıza bir başka mimarî ilkeyi fısıldıyor.

İstek mi Olay mı? Bir Model Teklifi

Servisimize, konuşlandığı bilgiişlem birimi içinden ya da dışından, ister bir istek gelsin, ister bir güncelleme; isterse de bir olaydan haber edilsin servis; her durumda bir olay olmuştur ve bu olaya tepki vermek gerekir. Durumlu sistemlerin işleme (ing. processing) modeli durum makinesi (ing. state machine) olarak kabul edilebilir. Her ne kadar bu mantığa göre soyut ve üzerinden çözümleme yapılabilecek kıvamda bir modelleme bakış açısı ile kurgulanmasalar da tâbî oldukları model durum makinesidir. Sisteme yeni girdiler geldikçe sistem durum geçişi yaşar.

Durumsuz sistemler için ise referans model olay işlemedir (ing. event processing). Buradan hareket edilerek olay güdümlü mimarilere (ing. event-driven architectures) geçiş yapılabilir. Bir başka yazı dizinin konusu olabilecek bu başlık duruma ilişkin çözümlerin ötesinde birçok avantajlı tasarım örüntüsünü (ing. design pattern) beraberinde getirir.

Bu yazıda bazı genellemeler, soyutlamalar ve modellemelere yer verdik. Durum artık durum olmaktan çıktı belki de, fakat amaca odaklanalım! Bir sonraki bölümde ağ iletişimine odaklanıp yine konuyu genişleterek devam edeceğiz. Sözünü edeceğimiz durumlu mimariler birçok sektörde geliştirilen yazılım sistemlerinin mecbur kaldığı (ya da kaldığını düşündüğü ya da bilinçsizce etrafından dolandığı) sorunlu bir alana karşılık gelecek.

Unutmayın:

Neo gibi gör!

Durumu farket!

Duranı dışarıda bırak!

Bir sonraki yazıda görüşmek dileğiyle…

--

--

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