Monolitik Mimari
A Monolithic application puts all its functionality into a single process and scales by replicating the monolith on multiple servers — Martin Fowler
Service Oriented Architecture (SOA) ve Mikroservisler mimarilerinden önce projeler çoğunlukla Monolitik mimari ile geliştiriliyordu. Fakat uygulamanın büyümesi, daha fazla end-user tarafından kullanılması, client’tan gelen isteklerin artması, database kontrolünün zorlaşması, geliştirme sürecinde sabit teknolojilere bağımlı kalınması, test süreçlerinin büyümekte olan projelerde sağlıklı olmaması gibi durumlar ile sektör içerisinde farklı mimariler geliştirilmeye ve kullanılmaya başlandı. Peki Monolitik mimari neden bahsettiğim bu sorunlara sebep oluyor? Bu sorunlara karşılık hangi alternatifler tercih edilmeye başlandı? Hangi durumlar için Monolitik mimari’yi tercih etmek avantajlı olabilir?
Herkese merhaba, bu yazımda Monolitik mimarinin ne olduğundan bahsedip, uygulama geliştirme sürecinde nasıl kullanıldığını açıklamaya çalışacağım. En sonda ise bu yapının yerine hangi mimarilerin son yıllarda daha sık tercih edildiğine değineceğim. Keyifli okumalar :)
Konular:
- Monolitik Mimari
- Vertical / Horizontal Scaling
- Monolitik Mimarinin Dezavantajları
- Monolitik Mimari Hangi Durumlar İçin Avantajlı Olabilir?
- Hangi Mimariler Daha Sık Tercih Edilmeye Başlandı?
Monolithic Architecture (Monolitik Mimari)
Kişisel projelerimizde pek çoğumuz Monolitik Mimariyi kullanmışızdır. Günümüzdeki popüler uygulamaların bazıları da ilk ortaya çıktığı zaman bu mimari ile geliştiriliyordu. Monolitik mimari yazılımın self-contained olarak tasarlandığı, tek bir birim (single unit) olarak geliştirilip deploy edildiği yazılım geliştirme yaklaşımıdır.
Monolitik Mimari Katman Yapısı
Monolitik mimari genellikle üç katmanlı bir yapıya sahiptir:
- Presentation Layer: Bu katman, kullanıcı arayüzünü oluşturur ve uygulama verilerini kullanıcıya sunar. Web uygulamalarında, Presentation (sunum) katmanı HTML, CSS ve JavaScript gibi teknolojiler kullanır.
- Bussiness (Application) Layer: Bu katman, bussiness logic’in yani uygulama içerisindeki mantıksal işlemlerin yapıldığı, geliştirildiği kısımdır. Kullanıcıların taleplerini işleyerek, uygulamanın çalışmasını sağlar. Ayrıca, uygulama verilerinin yönetiminden sorumludur.
- Data Access Layer: Bu katman, uygulama verilerinin depolandığı yerdir. Veri katmanı, genellikle bir veritabanı yönetim sistemi (Relational -RDBMS veya Non Relational DB Management System) kullanır ve verilerin saklanmasını, yedeklenmesini, geri yüklenmesini ve erişimini yönetir.
Bu üç katman, birbirleriyle bağlantılıdır ve uygulamanın tüm fonksiyonlarını barındırır.
Bu mimariyi bir örnek üzerinden açıklamak istiyorum. Monolitik yapıda bir online alışveriş uygulaması geliştirdiğimizi varsayalım. Projeye ait kısımları şu şekilde belirtebiliriz;
- User-authantication
- Product
- Shopping-cart
- Checkout
- Payment
- Search
- Notification
Monolitik mimari ile geliştirdiğimiz uygulamamızda bütün bölümler single unit (tek birim) olarak geliştirilir. Projeye ait tek bir codebase vardır ve bütün kısımlarda aynı programlama dili, teknolojisi kullanılır. Proje büyüdükçe bu kısımları geliştiren ayrı takımlar oluşturduğumuzu düşünelim. Bu durumda her bir takımın geliştirme sürecinde diğer bölümleri etkilememek, bozmamak için düzenli olarak diğer takımlarla koordine şekilde çalışması gerekir. Bu da çoğu zaman yazılımcı için ekstra efor harcamaya neden olabilir :(
Bir diğer durum için şu örneği verebilirim. Payment kısmında değişiklik yaptık, yeni özellik getirdik. Bu durumda bütün uygulamanın single package (tek bir paket) olarak deploy edilmesi gerekir. Monolitik mimari ile geliştirdiğimiz projemizde, o sırada tek güncelleme yapılan bölüm olan Payment kısmını tek olarak deploy etme gibi bir şansımız olmaz. Bu da zaman ve performans açısından maliyetli olur :(
Client — Server — Database İlişkisi
Bu yapıyı bir de uygulama akışı örneğiyle açıklamak istiyorum. Kullanıcı uygulamaya girdi ve ürünlerin listelendiği sayfaya gitmek istedi. Bu durumda client’tan server’a şu şekilde istek atılır:
- Ürünlerin listelendiği sayfa için = /products
- Ürün detay sayfası için = /products/1234
Aynı şekilde kullanıcı ürünler için satıcıların listelendiği sayfayı görmek istediğinde client’tan server’a yine bu şekilde istek atılacaktır.
- Satıcıların listelendiği sayfa için = /sellers
- Satıcı detay sayfası için = /sellers/1234
Bu durumda server gelen isteğe göre database’e gider, oradan data’yı alır ve ilgili sayfanın ekranında kullanıcıya ürünleri / satıcıları gösterir.
Bu yapı ile çalışan uygulamada, client’tan gelen istekler arttıkça endpointler üzerindeki trafik de sıkışmaya başlar. Örneğin alışveriş için büyük indirimlerin yapıldığı haftayı düşünelim. O hafta uygulama ortalamaya göre çok daha fazla end-user tarafından ziyaret edilir. Bu durumda üyelik bilgilerim, şifre güncelleme gibi kısımlar üzerindeki trafik çok yoğun olmazken; ana sayfa, ürün detay sayfası, sepetim gibi bölümlere yoğun istek gelir ve database server’dan gelen istekler için sorgulara yetişememeye başlar. Sunucu kaynaklarının yetersiz olması, uygulamanın zaman zaman kilitlenmesine, yanıt vermemesine yol açabilir. Bu sorunu çözmek için sunucu üzerinde ölçeklendirme (scaling) yöntemine başvururuz.
Vertical Scaling — Horizontal Scaling (Dikey — Yatay Ölçeklendirme)
Dikey ve yatay ölçeklendirme, bir yazılım sistemini büyütmek için kullanılan iki farklı yöntemdir.
Dikey ölçeklendirme (vertical scaling), mevcut bir sunucunun donanımını veya kaynaklarını (CPU, RAM, deoplama vb.) yükseltmek yoluyla bir uygulamanın kapasitesini artırmaya çalışır. Örneğin, bir sunucunun RAM kapasitesini artırarak veya daha fazla bellek kullanarak uygulama için daha fazla işlemci gücü sağlanabilir.
Yatay ölçeklendirme (horizontal scaling), mevcut donanım kaynaklarının artırılması yerine, daha fazla sunucu veya bilgisayar ekleyerek sistem kapasitesini artırmayı hedefler. Bu yöntem, her sunucunun yükü paylaşmasına izin verir.
Endpoint’ler üzerindeki trafiğin arttığı, server kaynaklarının yetersiz kaldığı, database’in sorgulara yetişemediği senaryoya geri dönelim. Burada sunucu kaynaklarını arttırmamız gerekli ve biz de sunucuyu ölçeklendiririz, yani sunucunun kopyasını alırız (duplicating servers).
- Server:9000
- Server:9001
- Server:9002
- Server:9003
Load Balancer: Bir uygulamayı yatay olarak ölçeklendirmek için, sunucuların load balancer (yük dengeleyici) aracılığıyla koordine edilmesi gerekir. Load balancer, gelen istekleri alır ve bu istekleri arka plandaki sunuculara yönlendirir. Bu sayede, sunucular arasındaki yük eşit olarak dağıtılır ve her sunucu gereksinim duyulan iş yüküne göre hareket eder. Yani load balancer, çoklanan sunucuların (duplicated servers) hangilerinin kullanıcılara hangi kısımlarda destek vereceğini belirleyen sistemdir.
Endpointler üzerindeki trafiğin arttığı durumlarda scaling yöntemlerine başvurulur. Ürün ve ürün detay sayfası için endpoint’ler üzerindeki trafiğin yoğunlaştığı, hatta database’in sorgulara yetişemediği senaryoyu örnek vermiştim. İşte tam bu durumda scaling ile load balancer aracılığıyla bahsettiğim şekilde çözüm üretiriz.
Monolitik Mimarinin Dezavantajları
Yazılımın single unit (tek parça) olarak geliştirilmesi ve deploy edilmesi süreç içerisinde özellikle büyük veya büyümekte olan projelerde birçok probleme neden olabilir. Burada monolitik mimarinin dezavantajlarına örnekler vermek istiyorum.
- Single unit olmasından dolayı farklı özellikleri geliştiren takımlar arasındaki koordinasyonun çok iyi sağlanması gerekir. Bir yazılımcı geliştirme yaptığı sırada farklı bölümü bozabilir. Bir bölümün bozulması bütün uygulamanın çalışmamasına neden olur.
- Uygulama güncelleneceği zaman tüm uygulamayı yeniden deploy etmek gerekir. Sadece Payment kısmı için yaptığımız değişiklikten dolayı tüm projenin yeniden deploy edilmesi zaman ve performans kaybına neden olur.
- Projede bütün kısımlarda aynı programlama dili / teknolojisi kullanılır. Online alışveriş uygulaması örneği vermiştim. Onun üzerinden devam edelim. Örneğin uygulamaya kullanıcıların ürünler veya sipariş durumu ile ilgili anlık soru sorup sorup cevap alabildiği bir chatbot sistemi entegre etmek istiyoruz. Bu durumda uygulamada kullandığımız programlama dili ve teknolojilerle bu sistemi geliştirmemiz gerekir. Eğer kullandığımız programlama dili bu iş için pek elverişli değilse, hem harcadığımız efor artacak hem de belki ciddi performans sorunları yaşayacağız.
- Ölçeklendirme tüm proje genelinde yapılır. Bu da higher infrastructure cost & less flexibility şeklinde adlandırılan yüksek altyapı ve sistem maliyetine neden olur.
- Bir diğer örnek için şu durumu söyleyebilirim. Uygulamada Payment kısmı için versiyonu 2.4 olan açık kaynak bir paket kullandık. Aynı paketi Notification için de kullanmamız gerekli. Fakat orada herhangi bir sebeten dolayı o paketin daha eski versiyonun kullanmaya ihtiyaç duyabiliriz. Fakat bu mimari single application yapıda olduğu için her yerde bir paketin aynı versiyonunu kullanmak durumunda kalırız ve farklı bir çözüm aramamız gerekir.
- Örneklerle açıkladığım bu durumlardan dolayı kodun bakımı (maintanance) ve sürdürülebilirliği (sustainability) proje büyüdükçe zorlaşır.
Şu anda hepimizin bildiği, kullandığı uygulamaların da birçoğu başlangıçta Monolitik mimari ile geliştiriliyordu. Fakat bu mimari, proje büyüdükçe ciddi anlamda zaman, performans ve maliyet kaybına sebep olabileceği için bu uygulamalarda ve büyümekte olan diğer uygulamalarda Service Oriented Architecture (SOA) ve SOA’nın bir yorumu olan Mikroservisler mimarisi daha sık olarak tercih edilmeye başlandı.
Mevcut Monolith uygulamanın Mikroservis Mimari’ye dönüşümünün teknik anlamda nasıl olduğunu detaylı bir şekilde incelemek için bu yazıyı okuyabilirsiniz.
Monolitik Mimari Hangi Durumlar İçin Avantajlı Olabilir?
Monolitik mimarinin, projenin tek bir codebase ile, sabit teknolojiler kullanılarak geliştirildiği single unit bir yaklaşım olduğunu şimdiye kadar açıkladım. Şimdi de bu yaklaşımın avantajlı olabileceği durumları belirtmek istiyorum.
- Monolitik mimari küçük projelerde kolayca kullanılabilir. Küçük bir proje için tek bir codebase’in olması, geliştirme sürecini hızlandırır.
- Tek bir server’ın yeterli olduğu durumda kullanılması oldukça mantıklıdır. Bu durumda yönetim (management), bakım (maintanance) ve yedekleme (back-up) maliyetleri en aza iner.
- Tek bir projenin deploy edilmesi, uygulama gereğinden fazla büyük değilse ve sürekli güncellenmiyorsa oldukça kolaydır.
- Tek bir merkezde geliştirildiği için unit-test, end-to-end test gibi test işlemleri distributed application olarak adlandırılan polyrepo uygulamalara göre daha kolay gerçekleştirilir.
Hangi Mimariler Daha Sık Tercih Edilmeye Başlandı?
Şimdiye kadar Monolitik mimarinin yapısını, kullanılma şeklini, avantajlı ve dezavantajlı olduğu durumları örneklerle açıkladım. Özellikle büyük ve büyümekte olan projeler için çeşitli sorunlara sebep olabileceğinden bahsettim. Bu gibi durumlar için bu yaklaşım yerine, servislerin birbirinden bağımsız geliştirilip deploy edildiği Service Oriented Architecture ve Mikroservisler gibi mimariler tercih edilmeye başlandı.
Bir sonraki yazımda da bu mimarilerin neler olduğunu, son zamanlarda neden oldukça popüler hale geldiklerini ele alacağım. Gelecek yazıda görüşmek üzere :)
Referanslar:
Kablosuz Kedi: https://www.youtube.com/watch?v=IGUJKGskaOE&t=430s