Mikroservisler — Genel Bakış
Mikroservis mimarileri son yıllarda pek çok yazılım projesinde yaygınlaşırken yazılımcıların bu mimaride geliştirme yaparken daha önce tecrübe ettiği yöntemleri veya alışkanlıkları değiştirmelerine neden olmuştur. Bu yazıda mikroservis nedir? Nasıl bir mimari önerir? Sorularına yanıtlar verilmeye çalışılarak konuya yeni giriş yapan yazılımcılara temel bilgiler verilmeye çalışılacaktır.
Bulut teknolojisi yaygınlaştıkça yazılım geliştirme alanında da buna entegre çözümler ve sunduğu imkanları kullanan mimariler hızla gelişmeye başladı. Böylece yüksek altyapı yatırımları gerektirmeden daha hızlı, ölçeklenebilir, çevik, güvenilir ve kullanıma göre esneyebilen çözümler yaygınlaştı. Bulut hizmetlerinde sunulan imkanların yazılım projelerine etkisi kaçınılmaz bir sonuçtu.
Container mimarilerinin ve açık kaynaklı sistemlerin giderek yaygınlaşmasıyla beraber geliştirilen uygulamaların dağıtılması, yayınlanması ve ölçeklenmesi gibi konularda mikroservis mimarilerine geçiş hızlandı. Agile yazılım geliştirme süreçlerinde hedeflenen özetle, değişen uygulamanın kullanıcıya sürekli ulaştırılabilmesi ve alınan dönüşlere göre aksiyon alınabilmesidir. Mikroservis mimarisinin getirdiği çözüm ile bu hedef pek çok alanda örtüşmektedir. Mikroservis mimarilerinin artan kullanımlarının nedenleri çeşitlendirilebilir. Ama önce bu noktaya gelirken hangi aşamalardan geçtik onu kısaca inceleyelim.
Buraya Nereden Geldik?
Mikroservis konusunu anlayabilmek için öncelikle hangi ihtiyaçtan doğduğunu ve hangi aşamalardan geçip bugünlere geldiğini bilmek önemli. Olabildiğince kısa şekilde Neydi? Ne oldu? Şimdi buna bakalım.
Monolitik Mimari
Bu mimari, temelde User Interface Layer, Business Layer ve Data Layer katmanlarında oluşmaktaydı. Business Layer’ı kendi için de N-katmana ayırmak ve modüler bir yapı oluşturmak mümkün. Sonuçta tüm iş modellerimiz ve geliştirmelerimiz tek bir blok yapı içerisinde bulunmakta. Uygulama geliştikçe ve detaylandıkça bu blok büyümekte ve gittikçe karmaşık hale gelmekteydi.
Farklı alanlarda kullanılmaya devam edilen bir mimaridir ve her mimaride olduğu gibi bazı avantaj/dezavantajları mevcuttur. Avantajlarına örnek olarak; Başlangıçta kolay ve hızlı geliştirilebilmesi, dağıtım, test ve yayınlamanın basit olması, loglama ve takip süreçlerinin kolay yapılabilmesi vs. çoğaltılabilir. Fakat zamanla bu yapılardaki kod yükünün artması nedeniyle uygulamanın karmaşıklaşması sorunu ile karşılaşılmaya başlandı. Yani uygulama geliştikçe ve detaylandıkça gittikçe daha komplike hale gelmeye başladı. Uygulama içerisinde yapılacak bir değişiklik tüm uygulamanın çalışamaz duruma gelmesine neden olabiliyordu, kırılgandı. Bir modülün yanıt veremez olması tüm uygulamanın yanıt verememesine neden oluyordu. Modüllerden herhangi birinde küçük bir değişiklik yapıp yayınlamak isteseniz de sadece o değişikliği değil tüm uygulamayı olduğu gibi yayınlamanız gerekiyordu.
Küçük ölçekli uygulamalar için ideal görünen bu mimari, büyük ölçekli ve kapsamlı uygulamalarda giderek zor yönetilen ve projede yeterli tecrübesi olan ekiplerin yönetebileceği süreçler haline geldi.
Yine çok önemli bir konu olan teknolojik yeniliklere kapalı bir mimari olmasını da eklemek gerekir. Eğer kullanılan teknolojiyi güncellemeyi planlıyorsanız muhtemelen tüm yapıyı yeniden yazmanız gerekiyordu.
Örneğin .Net 2.0 ile gelişitirdiğiniz bir monolitik uygulamanızı .Net 4.8 versiyonuna yükseltmek istiyorsunuz, bunu yapabilmek için monolitik içindeki projeleri ve bağlılıklar yığınını yeni versiyona geçirmeniz gerekir bu da ciddi emek ve zaman alacaktır.
Eksiler içermesi veya popüler bir mimari olmaması kötü bir mimari olduğu anlamına gelmez, küçük ölçekteki uygulamalar için zaman kazandıran ve yönetimi kolay olduğundan daha az geliştiriciyle daha çok işin yapılabildiği bir mimari olduğunu da not düşelim.
Service Oriented Mimari
Bu mimari, birbirinden farklı işler yapan servislerin birlikte kullanılarak farklı uygulamalar oluşturulabilmesine imkan sağlar. Elde edinilen kazanım geliştirilen uygulama modüllerinin tekrar kullanılabilmesi ve kolay bakımı olarak özetlenebilir. SOA mimarilerinde geliştirdiğimiz Business Service’leri başka bir uygulamada da kullanabilme imkanı bulunmaktadır, servislerin tekrar kullanılabilmesi önemli bir gelişmedir. Ayrıca bir servis üzerinde çalışan bir ekip ile başka bir servis üzerinde çalışan ekibin birbirini bekleme gibi bir zorunluluğun olmaması da olumlu yönlerinden biridir.
Ölçekleme konusundaki esneklik, monolitik mimariye göre daha iyi bir aşamadadır, fakat ölçekleme hala tüm mimariye uygulanamamaktadır. Mikroservislere gidilen yolda önemli bir çözüm olarak görülebilir.
Bu mimarinin eksi yönlerine ise yönetim ve operasyonel maliyetlerin yüksek olmasını ekleyebiliriz. Enterprise Service Bus yapılarının kurulması ve yönetilmesi maliyetli süreçlerdir. Ayrıca monolitik mimarilerde belirttiğim single point of failure bu mimaride de karşımıza çıkar. Her ne kadar servis tarafındaki sorunlara çözüm bulunabilse de diğer katmanlardaki(ör: ESB) olası sorunlarda tüm yapının hataya düşmesi kaçınılmazdır.
Mikroservis Mimarisi
Önceki mimarilerdeki eksi ve artı yönler değerlendirilerek veya dersler çıkarılarak bir adım daha atıldı ve mikroservis mimarileri yaygınlaşmaya başladı. Daha iyi bir mimari olarak nitelendirebileceğimiz bir mimariden isteklerimiz nedir? Bu isteklere ne oranda yanıt verebiliyor inceleyelim.
Geniş kapsamlı uygulamalar geliştirirken kodların giderek içinden çıkılmaz olmasına veya karmaşıklığına neden olan kod alanlarının bölünebilmesini istiyoruz. Büyük ekiplerle çalışırken ekiplerin yaptığı geliştirmelerin test ve yayınlama süreçlerinin hızlı ve çevik olmasını istiyoruz, yani agile süreçlerine uygun entegrasyon ve yayınlama yapabilmeyi istiyoruz. Teknolojik altyapılarımızı çeşitlendirebilmeyi ve daha kolay güncelleyebilmeyi istiyoruz. Ölçeklenebilir sistemler geliştirmeyi istiyoruz. Birbirine sıkı bağlı yapılar değil daha esnek bağlı yapılar kurgulamak istiyoruz. Tek hata noktası sorununa çözüm üretebilmek istiyoruz.
Bunlar çoğaltılabilir. Peki çözüm nasıl olmalı?
Aslında farkedileceği üzere bu isteklere yanıt verebilecek çözümün dağıtık yapılardan geçtiği görülebilir. Ulaşılmak istenen nokta, öyle bir mimarimiz olsun ki bu mimariyi oluşturan parçalar alternatifli olabilsin, birbirine bağımlı olmasın, taşınabilir olsun, izlenebilir olsun ve kendi içinde bir çözüm içerir olsun. Böylece ölçekleyebilirim yani gerekirse o bileşenden istediğim kadar yaratırım, gerekmezse silerim, sorun yaşarsam yerine benzerini koyabilirim, Yeni versiyonunu geliştirdiğimde devreye alabilirim ve diğer bileşenlerle ilişkisi sıkı bağlı olmadığı için bunu hızla yapabilirim. Bileşen dediğim bu parçaları da birbirinden bağımsız ekiplerle ve teknolojilerle geliştirebilirim. Yazının devamında bu cümlenin detayını inceleyeceğiz.
Tanımı soyut olarak yukarıdaki paragrafta yapmış olduk. Ama bence aşağıdaki tanımlar konuyu çok güzel özetlemekte.
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
Veya,
Microservices are an architectural and organizational approach to software development where software is composed of small independent services that communicate over well-defined APIs. These services are owned by small, self-contained teams.
Microservices architectures make applications easier to scale and faster to develop, enabling innovation and accelerating time-to-market for new features.
Mikroservislere giden gelişim sürecinde açık kaynaklı yazılımların yaygınlaşması, docker container ve orkestrasyon teknolojilerinin kullanımı ve SDI(Software Defined Infrastructure) gibi teknolojiler sürecin çok hızlı ilerlemesine katkı sağladı.
Mikroservis mimarilerinin, yukarıdaki maddelerde özetlendiği üzere yazılım geliştirme süreçlerine önemli etkisi olmuştur. Büyük uygulamalardaki küçük parçaların değiştirilip test edilmesi, yayınlanması ve bunların otonom olarak sağlanabilmesi Agile yazılım geliştirme yaklaşımlarının ve Continuous Integration / Continuous Delivery (CI/CD) metodlarının daha geniş kapsamda kullanılmasını sağlamıştır.
CI/CD süreçleriyle birlikte yazılım geliştirme ekiplerinin geliştirdikleri ürünleri sürekli olarak ve hızla yayınlayabilmesinde container yapılarının sunduğu imkanlar bu noktada itici güç olmuş ve bence gelinen noktada büyük pay sahibidir.
Mikroservisler için docker veya diğer container teknolojilerinin kullanılması gibi bir zorunluluk yoktur, bunlar olmadan da mikroservis mimarisi oluşturmak mümkün. Ürettiği çözümde, container’ları kullanmayan mikroservis mimarileri olabilir. Veya ürettiği çözümde container kullanan projelerin sırf container kullanmaları nedeniyle de mikroservis mimarisine sahip olmasını iddia etmek de yanılmak olacaktır.
Elbette her mimaride olduğu gibi mikroservis mimarisinin de artı/eksi yönleri mevcut.
Eksileri
- İdeal olarak uygulandığında her mikroservisin bir ekip tarafından sahiplenilmesi gerektiğinden ekip sayısının artmasına neden olmakta.
- Unit testler açısından sorun bulunmasa da integration testler daha karmaşık. Geliştiriciler kendi makinalarından tüm sistemi daha zor test edebiliyor.
- Debug etmek, tracing, trafik izleme ve loglama diğer mimariler kadar kolay değil, ekstra efor gerekiyor.
- Monolitik mimarilerle kıyaslandığında çok bileşen içermesi ve sistem içi iletişimin yönetilmesi gibi konular nedeniyle karmaşıklık düzeyi daha yüksek bir mimaridir.
- Birbirine sıkı bağlı olmayan yapılar kurgulamak gerekmekte, doğal olarak bu da geliştirme ekiplerine bir maliyet getiriyor.
- Her servis kendi veritabanını kullanırken bunu paylaşmaması gerekiyor. Haliyle data consistency konusu gündeme geliyor ve bunun uygulanması yine ekiplerin yüklendiği bir sorumluluk oluyor.
Artıları
- Daha iyi ölçekleme sunuyor. Birbirine sıkı bağlı olmayan yapılar çok daha kolay ölçeklenebiliyor.
- Modüler yapılar geliştirildiğinden daha esnek bir mimari sunuyor.
- Geliştirme, test ve yayınlama süreçleri çevik. Üründeki değişiklikler hızla yayınlanabiliyor. Diyelim ki bir bug tespit edildi, tüm yapıyı tekrar yayınlama yapmaya gerek olmadan sadece ilgili servisin yayınlanması mümkün oluyor.
- Mikroservislerin farklı codebase ve ekiplerinin olması karmaşıklıkların azalmasına katkı sağlıyor. Büyük bir codebase yerine kendi işine odaklı küçük parçaların olması yazılımcılar açısından da daha okunabilir veya müdahalesi daha kolay sistemler geliştirmeyi sağlıyor.
- Farklı teknolojiler ve diller kullanabiliyoruz. Her mikroservis, kendi içerisinde bağımsız bir bölüm olduğundan teknolojik olarak da farklılaşabilme avantajı sağlıyor. Örneğin bir mikroservis içinde .Net ile birşeyler yapılırken başka bir mikroservis içerisinde Python kullanılabiliyor.
- Sistemde single point of failure olmaması adına daha kolay çözümler üretebiliyoruz. Fault tolerance yapıları daha kolay kurabiliyoruz. Örneğin bir servis hata verdi ve sorun mevcut. Tasarım gereği diğer servisler bu tip durumlar düşünülerek yazıldığından tüm uygulamanın hataya düşmesi önlenmiş oluyor.
- Veri izolasyonu sağladığından veritabanında bir düzenleme yapmak daha az risk içeriyor. Her mikroservis kendi veri sorumluluğuna sahip olduğundan yapılmak istenen düzenleme o mikroservis ile sınırlı oluyor.
Bu dönüşümde en önemli konulardan biri de Devops konusu. Prensipleri listelediğim sonraki başlıkta buna değineceğim.
Genel olarak mikroservis nedir? Neye çözüm üretir? Gibi sorulara cevap bulmaya çalıştık. Yazının devamında mikroservis mimarisinde hangi prensiplere dikkat etmeliyiz? Neler önerilir/önerilmez? Bu konulara bakalım.
Mikroservis Mimarisinde Uygulanacak Prensipler
Mikroservis mimarilerinin doğru ve etkin kurulmasında edinilen tecrübeler ve bu alandaki teorisyenlerin yönlendirmeleriyle dikkat edilmesi gereken önemli noktalar bulunmakta. Bunlarla devam edelim. Bir mikroservis:
- Çözüm ürettikleri business domain modeli çerçevesinde geliştirilmelidir. Her mikroservis spesifik bir problemin çözümüne odaklanmalıdır. Domain merkezli, işe odaklı olmalıdır. Mikroservisler büyüklüklerine göre değil çözüm ürettikleri domain problemlerine göre ayrılmalıdır. Eğer zaman içerisinde karmaşık bir hal alırsa daha küçük parçalara ayrılmalıdır.
- Her mikroservis bağımsız olarak geliştirilebilmeli, test edilebilmeli, deploy edilebilmeli, uygulamanın tamamının baştan aşağı publish edilmesi vs. gibi zorunluluklar olmamalı.
- Çevik olmalı, geliştirme sürecinden sonraki test ve yayınlama süreçlerinin otonom olarak yürütülebilmesi sağlanabilmeli. Yapılan değişikliklerin son kullanıcıya sunulabilmesi sürekli ve sık sık yapılabilmeli.
- Devops ve otomasyon süreçleri uygulanmalı. Eğer mikroservis mimarisi ile çözüm üretecekseniz Devops uygulamanız gerekiyor. Daha doğrusu öncelikle Devops ile başlayıp yeterli birikime ulaşmak önemli. Devops uygulamayan ve otomasyon süreçleri kurulmayan ortamlarda sıkıntı yaşanacağını tahmin etmek zor olmaz. Öncelikle bu süreçlerin sağlıklı kurulması öneriliyor.
- Ölçeklenebilmeli.(scalability)
- Sürekli ulaşılabilmeli(availability) veya bu modele uygun tasarımlanmalı.
- Diğer servislere bağımlılıkları olmamalı. Mikroservis içindeki tüm data ve business logic diğer mikroservislerden izole olmalıdır. Mikroservisler kendi veritabanlarını barındırmalı ve birbirleriyle paylaşmamalı.
- Konfigürasyonlarını dışarıdan alabilmeli. Mikroservisler, ihtiyaç dudukları konfigürasyonları kendi içlerinde barındırmamalı, dışarıdan bir hizmet olarak alabilmeliler.
- Mikroservisler eğer diğer mikroservislerle haberleşeceklerse protokoller kullanarak haberleşmeli, bu protokollerin uyarlamaları mikroservislerin kendi içlerinde yapılmalı. Servis haberleşmesinde akıllı olmamalı. “smart endpoints and dumb pipes” yani diğer servislerle haberleşirken o servislerin business domain’lerinde ne yaptığını bilmemeli.
- Mikroservisler arası iletişim mimarisi servis sayısının artması ve yüksek trafik durumları düşünülerek esnek tasarımlanmalı(resilient communication).
- Mikroservisler teknoloji olarak birbiriyle aynı içerikte olmak zorunda olmamalı. Kütüphanelerini veya geliştirme platformlarını paylaşmak durumunda olmamalı. Bazı servisler gerekiyorsa farklı programlama dilleriyle de geliştirilebilmeli.
- Hata izolasyonu yapabilmeli, toleransı yüksek olmalı. Mikroservislerden bir veya daha fazlasının erişilemez olduğu durumlara karşı bu servisi kullanan diğer servislerde yeterli önlemler alınmalı.
- Gözlemlenebilir olmalı. İzlenebilmeli, sürekli takip sistemlerine entegre olabilmeli.
- Infrastructure as code (IaC), otonom olarak gereken sistem kaynağı üretilebilmeli ve deploy edilebilmeli.
- Her mikroservisin mümkünse farklı bir codebase’i olmalı ve ekipleri de farklı olmalı. Proje değil ürün odaklı geliştirme yapılmalıdır.
Yukarıdaki maddelerin bazıları geliştiricilerin mikroservis içerisinde uygulamaları gereken tasarım kalıpları ile ilgili olmakla birlikte bazı maddeler de hazırda kullanılabilir araçlarla sağlanmaktadır.
Yazıda anlatmaya çalıştığım üzere uygulamaların sadece küçük parçalara ayrılması mikroservis mimarisine göre yazıldığı anlamına gelmiyor. Eğer mikroservis mimarisi uygulanacaksa öncelikle devops adımlarının atılması, gereken tecrübe ve bilgi seviyesine ulaşılması öneriliyor. Devamında yazılım ekiplerinin bu mimarinin prensiplerine ve süreçlere hazır duruma getirilmesi öneriliyor.
Teşekkürler.
Engin ÜNAL