Yazılım Geliştirme

Mikroservis Mimarisi ile Ölçeklenebilir Uygulama Geliştirme

Fatih Algül
13.03.2026 259 görüntülenme

Mikroservis Mimarisi Nedir?

Mikroservis mimarisi, bir uygulamayı küçük, bağımsız ve gevşek bağlı (loosely coupled) servisler koleksiyonu olarak tasarlama yaklaşımıdır. Her bir mikroservis, belirli bir iş kapasitesine odaklanır, kendi veritabanına sahip olabilir ve diğer servislerle iyi tanımlanmış API'ler aracılığıyla iletişim kurar. Geleneksel monolitik mimarilerin aksine, mikroservisler bağımsız olarak geliştirilebilir, dağıtılabilir ve ölçeklendirilebilir.

Günümüzde Netflix, Amazon, Spotify ve Uber gibi teknoloji devleri, milyonlarca kullanıcıya hizmet verebilmek için mikroservis mimarisini benimsemiştir. Peki bu mimariyi kendi projelerinizde nasıl uygulayabilirsiniz? Bu yazıda, mikroservis mimarisinin temel prensiplerinden pratik uygulamasına kadar kapsamlı bir yol haritası çizeceğiz.

Monolitik Mimari vs. Mikroservis Mimarisi

Mikroservislerin avantajlarını anlamak için önce monolitik mimarinin sınırlamalarına bakmak gerekir.

Monolitik Mimarinin Sorunları

  • Tek hata noktası: Uygulamanın herhangi bir bileşenindeki bir hata, tüm sistemi çökertebilir.
  • Ölçeklendirme zorluğu: Sadece yoğun trafik alan bir modülü ölçeklendirmek yerine, tüm uygulamayı ölçeklendirmek zorunda kalırsınız.
  • Teknoloji kilidi: Tüm uygulama tek bir teknoloji yığınına bağımlıdır; yeni teknolojilere geçiş son derece maliyetlidir.
  • Yavaş dağıtım döngüleri: Küçük bir değişiklik bile tüm uygulamanın yeniden derlenmesini ve dağıtılmasını gerektirir.
  • Ekip koordinasyonu: Büyüyen ekiplerde kod çakışmaları ve bağımlılık sorunları artar.

Mikroservis Mimarisinin Avantajları

  • Bağımsız dağıtım: Her servis, diğerlerini etkilemeden güncellenebilir ve dağıtılabilir.
  • Teknoloji çeşitliliği: Her servis, probleme en uygun programlama dili ve veritabanı ile geliştirilebilir.
  • Granüler ölçeklendirme: Sadece darboğaz oluşturan servisler yatay olarak ölçeklendirilebilir.
  • Hata izolasyonu: Bir servisin çökmesi, diğer servislerin çalışmasını doğrudan engellemez.
  • Ekip özerkliği: Küçük ekipler, kendi servislerinin tam sahipliğini üstlenebilir.

Mikroservis Mimarisinin Temel Bileşenleri

1. API Gateway

API Gateway, istemcilerden gelen tüm isteklerin tek bir giriş noktasından geçmesini sağlar. Yönlendirme, kimlik doğrulama, hız sınırlama ve yük dengeleme gibi çapraz kesim endişelerini (cross-cutting concerns) merkezi olarak yönetir. Popüler API Gateway çözümleri arasında Kong, NGINX, AWS API Gateway ve Spring Cloud Gateway yer alır.

# Basit bir NGINX API Gateway yapılandırması
upstream kullanici_servisi {
    server kullanici-servis-1:8081;
    server kullanici-servis-2:8081;
}

upstream siparis_servisi {
    server siparis-servis-1:8082;
    server siparis-servis-2:8082;
}

server {
    listen 80;

    location /api/kullanicilar {
        proxy_pass http://kullanici_servisi;
    }

    location /api/siparisler {
        proxy_pass http://siparis_servisi;
    }
}

2. Servis Keşfi (Service Discovery)

Dinamik ortamlarda servis örnekleri sürekli oluşturulup kaldırılır. Servis keşfi mekanizması, servislerin birbirlerini otomatik olarak bulmasını sağlar. Consul, Eureka ve etcd bu alanda yaygın kullanılan araçlardır. Kubernetes kullanıyorsanız, yerleşik DNS tabanlı servis keşfi zaten mevcuttur.

3. Servisler Arası İletişim

Mikroservisler arasındaki iletişim iki temel modelde gerçekleşir:

  • Senkron iletişim: REST API veya gRPC üzerinden doğrudan istek-yanıt modeli. Anlık yanıt gerektiren senaryolar için uygundur.
  • Asenkron iletişim: Mesaj kuyrukları (RabbitMQ, Apache Kafka) aracılığıyla olay tabanlı (event-driven) iletişim. Gevşek bağlılık sağlar ve sistem dayanıklılığını artırır.

4. Merkezi Olmayan Veri Yönetimi

Her mikroservis kendi veritabanına sahip olmalıdır (Database per Service pattern). Bu yaklaşım servisler arasındaki bağımlılığı azaltır ancak veri tutarlılığı konusunda ek çözümler gerektirir. Saga Pattern ve Event Sourcing, dağıtık işlem (distributed transaction) sorunlarını çözmek için kullanılan yaygın desenlerdir.

Pratik Uygulama: Node.js ile Mikroservis Örneği

Aşağıda, basit bir e-ticaret sisteminin kullanıcı servisini Node.js ve Express ile nasıl oluşturabileceğinizi görebilirsiniz:

// kullanici-servisi/index.js
const express = require('express');
const mongoose = require('mongoose');
const app = express();

app.use(express.json());

// MongoDB bağlantısı - her servisin kendi veritabanı
mongoose.connect('mongodb://kullanici-db:27017/kullanicilar');

const KullaniciSemasi = new mongoose.Schema({
  ad: { type: String, required: true },
  eposta: { type: String, required: true, unique: true },
  olusturmaTarihi: { type: Date, default: Date.now }
});

const Kullanici = mongoose.model('Kullanici', KullaniciSemasi);

// Kullanıcı oluşturma
app.post('/api/kullanicilar', async (req, res) => {
  try {
    const kullanici = new Kullanici(req.body);
    await kullanici.save();
    res.status(201).json(kullanici);
  } catch (hata) {
    res.status(400).json({ mesaj: hata.message });
  }
});

// Kullanıcı sorgulama
app.get('/api/kullanicilar/:id', async (req, res) => {
  try {
    const kullanici = await Kullanici.findById(req.params.id);
    if (!kullanici) {
      return res.status(404).json({ mesaj: 'Kullanıcı bulunamadı' });
    }
    res.json(kullanici);
  } catch (hata) {
    res.status(500).json({ mesaj: 'Sunucu hatası' });
  }
});

// Sağlık kontrolü uç noktası
app.get('/health', (req, res) => {
  res.json({ durum: 'aktif', servis: 'kullanici-servisi' });
});

const PORT = process.env.PORT || 8081;
app.listen(PORT, () => {
  console.log(`Kullanıcı servisi ${PORT} portunda çalışıyor`);
});

Docker ile Konteynerleştirme

Her mikroservisin bağımsız olarak çalışabilmesi için konteynerleştirme kritik öneme sahiptir. İşte kullanıcı servisi için bir Dockerfile örneği:

FROM node:20-alpine

WORKDIR /app

COPY package*.json ./
RUN npm ci --only=production

COPY . .

EXPOSE 8081

HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://localhost:8081/health || exit 1

CMD ["node", "index.js"]

Docker Compose ile Orkestrasyon

Geliştirme ortamında tüm servisleri bir arada ayağa kaldırmak için Docker Compose kullanabilirsiniz:

version: '3.8'

services:
  api-gateway:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - kullanici-servisi
      - siparis-servisi

  kullanici-servisi:
    build: ./kullanici-servisi
    environment:
      - PORT=8081
      - MONGO_URI=mongodb://kullanici-db:27017/kullanicilar
    depends_on:
      - kullanici-db

  siparis-servisi:
    build: ./siparis-servisi
    environment:
      - PORT=8082
      - MONGO_URI=mongodb://siparis-db:27017/siparisler
    depends_on:
      - siparis-db

  kullanici-db:
    image: mongo:7
    volumes:
      - kullanici-veri:/data/db

  siparis-db:
    image: mongo:7
    volumes:
      - siparis-veri:/data/db

volumes:
  kullanici-veri:
  siparis-veri:

Ölçeklendirme Stratejileri

Yatay Ölçeklendirme

Mikroservis mimarisinin en büyük gücü yatay ölçeklendirme kapasitesidir. Kubernetes gibi bir orkestrasyon aracı ile belirli servislerin kopya sayısını trafik yoğunluğuna göre otomatik olarak artırabilir veya azaltabilirsiniz:

# kubernetes/kullanici-servisi-hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: kullanici-servisi-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: kullanici-servisi
  minReplicas: 2
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Önbellekleme (Caching)

Sık erişilen verileri Redis veya Memcached gibi bellek içi (in-memory) veri depoları ile önbelleğe almak, veritabanı yükünü önemli ölçüde azaltır ve yanıt sürelerini iyileştirir.

Mesaj Kuyrukları ile Yük Dengeleme

Yoğun işlem gerektiren görevleri mesaj kuyruklarına yönlendirerek, arka plan işçileri (background workers) arasında yükü dağıtabilirsiniz. Bu yaklaşım, anlık trafik artışlarında sistemin kararlı kalmasını sağlar.

Gözlemlenebilirlik ve İzleme

Dağıtık sistemlerde gözlemlenebilirlik (observability) üç temel sütun üzerine kuruludur:

  1. Günlükler (Logs): Yapılandırılmış günlükleme ile her servisin davranışını kayıt altına alın. ELK Stack (Elasticsearch, Logstash, Kibana) veya Grafana Loki merkezi günlük toplama için idealdir.
  2. Metrikler (Metrics): Prometheus ve Grafana ile CPU, bellek, istek sayısı ve yanıt süreleri gibi metrikleri izleyin.
  3. Dağıtık İzleme (Distributed Tracing): Jaeger veya Zipkin ile bir isteğin servisler arasındaki yolculuğunu uçtan uca izleyin. Bu, performans darboğazlarını tespit etmek için vazgeçilmezdir.

Dayanıklılık Desenleri

Dağıtık sistemlerde hatalar kaçınılmazdır. Sisteminizi dayanıklı kılmak için şu desenleri uygulamalısınız:

  • Devre Kesici (Circuit Breaker): Sürekli hata veren bir servise yapılan çağrıları geçici olarak durdurarak, hatanın yayılmasını engeller.
  • Yeniden Deneme (Retry) ve Üstel Geri Çekilme (Exponential Backoff): Geçici hatalarda akıllı yeniden deneme stratejileri uygular.
  • Zaman Aşımı (Timeout): Her dış çağrıya uygun zaman aşımı süreleri tanımlayarak, kaynakların tükenmesini önler.
  • Bölme Perdesi (Bulkhead): Servis kaynaklarını izole ederek, bir bileşendeki aşırı yükün diğerlerini etkilemesini önler.

Dikkat Edilmesi Gereken Zorluklar

Mikroservis mimarisi güçlü bir yaklaşım olsa da her proje için uygun olmayabilir. Karar vermeden önce şu zorlukları göz önünde bulundurun:

  • Operasyonel karmaşıklık: Düzinelerce servisi yönetmek, izlemek ve hata ayıklamak ciddi DevOps olgunluğu gerektirir.
  • Ağ gecikmesi: Servisler arası her çağrı ağ üzerinden geçtiğinden, monolitik uygulamalara kıyasla ek gecikme oluşur.
  • Veri tutarlılığı: Dağıtık işlemler ve nihai tutarlılık (eventual consistency) modelleri, iş mantığını karmaşıklaştırabilir.
  • Test karmaşıklığı: Entegrasyon ve uçtan uca testler, birden fazla servisin koordinasyonunu gerektirir.

Sonuç ve Öneriler

Mikroservis mimarisi, doğru uygulandığında ölçeklenebilirlik, esneklik ve geliştirme hızı açısından büyük avantajlar sunar. Ancak bu mimariye geçiş, bilinçli ve kademeli bir süreç olmalıdır. İşte başlangıç için bazı öneriler:

  1. Küçük başlayın: Mevcut monolitik uygulamanızı bir anda parçalamaya çalışmayın. Strangler Fig Pattern ile kademeli geçiş yapın.
  2. Sınırları doğru çizin: Domain-Driven Design (DDD) prensiplerini kullanarak, sınırlı bağlamları (bounded contexts) belirleyin.
  3. Otomasyon yatırımı yapın: CI/CD pipeline'ları, altyapı kodu (Infrastructure as Code) ve otomatik testler olmadan mikroservis yönetimi sürdürülebilir değildir.
  4. Gözlemlenebilirliği baştan planlayın: Merkezi günlükleme, metrik toplama ve dağıtık izleme altyapısını ilk günden kurun.
  5. Ekip yapısını uyumlandırın: Conway Yasası gereği, sistem mimariniz organizasyon yapınızı yansıtacaktır. Her servise sahip olacak küçük, özerk ekipler oluşturun.

Mikroservis mimarisi bir hedef değil, bir yolculuktur. Sisteminizin ihtiyaçlarını iyi analiz edin, doğru araçları seçin ve her adımda ölçümleme yaparak ilerlemeye devam edin.

Yazar Hakkında
Fatih Algül
TechSoft Solutions
Proje mi var?

Yazılım, IoT veya otomasyon konularında destek almak ister misiniz?

İletişime Geç