Node.js Mimari Tasarımı: Mobil Backend İçin Ölçeklenebilir Rehber
Yazar: Burak Balkı | Kategori: Mobile Development | Okuma Süresi: 9 dk
Bu rehberde, Node.js kullanarak mobil uygulamalar için nasıl ölçeklenebilir ve yüksek performanslı backend mimarileri tasarlanacağı, katmanlı mimari, güvenli...
## Node.js ve Mobil Backend Mimarisine Giriş
**Node.js**, modern mobil uygulama geliştirme süreçlerinde backend (sunucu tarafı) mimarisinin vazgeçilmez bir parçası haline gelmiştir. Özellikle asenkron yapısı ve olay döngüsü (event loop) mekanizması sayesinde, binlerce eşzamanlı bağlantıyı düşük gecikme süreleriyle yönetebilir. Mobil uygulamaların değişken ağ koşulları ve anlık veri talepleri göz önüne alındığında, Node.js mimari tasarımı projenin başarısında kritik bir rol oynar.
Bu rehberde, bir mobil uygulama backend'inin nasıl tasarlanması gerektiğini, sistem mimarisi kararlarını ve ölçeklenebilirlik stratejilerini derinlemesine inceleyeceğiz.
## Node.js Mimarisinin Temel Bileşenleri: Event Loop ve Non-blocking I/O
Node.js'in kalbinde **Chrome V8 motoru** ve **Libuv** kütüphanesi yer alır. Geleneksel sunucu mimarilerinin aksine (her istek için yeni bir thread), Node.js tek bir thread üzerinden çalışır.
- **Event Loop:** Giriş/çıkış işlemlerini yöneten ve callback fonksiyonlarını sıraya koyan mekanizmadır.
- **Non-blocking I/O:** Bir dosya okuma veya veritabanı sorgusu sırasında işlemcinin yanıt beklemeden diğer işlemlere devam etmesidir.
| Özellik | Geleneksel Mimari (Thread-per-request) | Node.js (Event-driven) |
| :--- | :--- | :--- |
| Kaynak Kullanımı | Yüksek (Her thread RAM tüketir) | Düşük (Tek thread) |
| Ölçeklenebilirlik | Dikey ölçekleme zordur | Yatay ölçekleme için idealdir |
| I/O İşlemleri | Bloklayıcı (Blocking) | Bloklamayan (Non-blocking) |
## Katmanlı Mimari (Layered Architecture) Yaklaşımı
Mobil backend projelerinde kodun sürdürülebilirliği için **Layered Architecture** (Katmanlı Mimari) kullanılmalıdır. Bu yaklaşım, sorumlulukları birbirinden ayırarak test edilebilirliği artırır.
### 1. Controller Katmanı
İstekleri karşılar ve yanıtları döner. İş mantığı (business logic) içermemelidir.
```javascript
// controllers/userController.js
const userService = require('../services/userService');
exports.getUserProfile = async (req, res, next) => {
try {
const userId = req.params.id;
const user = await userService.fetchUserById(userId);
res.status(200).json({ status: 'success', data: user });
} catch (error) {
next(error);
}
};
```
### 2. Service Katmanı
Tüm iş mantığının bulunduğu katmandır. Veritabanı modelleriyle etkileşime girer.
```javascript
// services/userService.js
const User = require('../models/userModel');
exports.fetchUserById = async (id) => {
const user = await User.findById(id);
if (!user) throw new Error('Kullanıcı bulunamadı');
return user;
};
```
## Veri Tabanı Tasarımı ve Entegrasyonu
Mobil uygulamalarda veri tutarlılığı ve hızı için doğru veritabanı seçimi ve bağlantı yönetimi hayati önem taşır. Genellikle **MongoDB** (NoSQL) veya **PostgreSQL** (Relational) tercih edilir.
```javascript
// config/database.js
const mongoose = require('mongoose');
const connectDB = async () => {
try {
await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
console.log('MongoDB bağlantısı başarılı.');
} catch (err) {
console.error('Bağlantı hatası:', err.message);
process.exit(1);
}
};
module.exports = connectDB;
```
## Kimlik Doğrulama ve Yetkilendirme Stratejileri
Mobil cihazlarda oturum yönetimi için en yaygın yöntem **JWT (JSON Web Token)** kullanımıdır. Stateless (durumsuz) yapısı sayesinde sunucu tarafında session saklama zorunluluğunu ortadan kaldırır.
```javascript
// middleware/auth.js
const jwt = require('jsonwebtoken');
module.exports = (req, res, next) => {
const token = req.header('Authorization')?.split(' ')[1];
if (!token) return res.status(401).json({ message: 'Yetkisiz erişim' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (ex) {
res.status(400).json({ message: 'Geçersiz token' });
}
};
```
## Microservices vs. Monolith: Mobil Backend Seçimi
Projenin büyüklüğüne göre mimari karar verilmelidir:
- **Monolith:** Küçük ve orta ölçekli uygulamalar için hızlı geliştirme ve kolay deployment sağlar.
- **Microservices:** Büyük ölçekli, farklı ekiplerin çalıştığı ve her modülün ayrı ölçeklenmesi gereken sistemler içindir.
> **Not:** Mobil uygulamalarda microservices kullanılıyorsa, istemcinin (mobil cihaz) tüm servislerle ayrı ayrı konuşması yerine bir **API Gateway** üzerinden geçmesi önerilir.
## API Gateway ve Reverse Proxy Kullanımı
**Nginx** veya **Kong** gibi araçlar, gelen istekleri karşılayıp ilgili servislere yönlendirir. Ayrıca SSL sonlandırma ve rate limiting (istek sınırlama) görevlerini üstlenir.
```nginx
# Örnek Nginx Konfigürasyonu
server {
listen 80;
server_name api.mobiluygulama.com;
location /users {
proxy_pass http://localhost:3001;
}
location /orders {
proxy_pass http://localhost:3002;
}
}
```
## Gerçek Zamanlı İletişim: WebSocket ve Socket.io
Sohbet uygulamaları veya canlı takip sistemleri için HTTP protokolü yetersiz kalır. **Socket.io** ile çift yönlü iletişim sağlanır.
```javascript
// server.js - Socket.io Entegrasyonu
const http = require('http');
const socketIo = require('socket.io');
const server = http.createServer(app);
const io = socketIo(server);
io.on('connection', (socket) => {
console.log('Yeni bir cihaz bağlandı');
socket.on('sendMessage', (data) => {
io.emit('message', data);
});
});
```
## Hata Yönetimi ve Loglama Mekanizmaları
Hataların merkezi bir noktadan yönetilmesi, mobil uygulamanın çökmesini engeller ve hata ayıklamayı kolaylaştırır. **Winston** veya **Morgan** kütüphaneleri loglama için standarttır.
```javascript
// middleware/errorMiddleware.js
module.exports = (err, req, res, next) => {
const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
res.status(statusCode).json({
message: err.message,
stack: process.env.NODE_ENV === 'production' ? null : err.stack,
});
};
```
## Performans Optimizasyonu ve Caching Stratejileri
Mobil kullanıcılar için hız her şeydir. Sık erişilen veriler için **Redis** gibi in-memory veritabanları kullanılmalıdır.
```javascript
// services/cacheService.js
const redis = require('redis');
const client = redis.createClient();
exports.getCachedData = async (key) => {
return new Promise((resolve, reject) => {
client.get(key, (err, data) => {
if (err) reject(err);
resolve(data ? JSON.parse(data) : null);
});
});
};
```
## Güvenlik Önlemleri ve Best Practices
1. **Input Validation:** Kullanıcıdan gelen her veriyi doğrulayın (Joi veya Zod kullanın).
2. **Helmet:** HTTP başlıklarını güvenli hale getirmek için `helmet` middleware kullanın.
3. **Rate Limiting:** Kötü niyetli botlara karşı istek sayısını sınırlayın.
4. **Environment Variables:** Hassas verileri asla kodun içine yazmayın, `.env` dosyalarını kullanın.
```javascript
// validation/userValidation.js
const Joi = require('joi');
const userSchema = Joi.object({
email: Joi.string().email().required(),
password: Joi.string().min(8).required()
});
module.exports = userSchema;
```
## Node.js Backend Dağıtım (Deployment) Süreçleri
Uygulamanın sürekliliği için **PM2** gibi process manager'lar ve **Docker** konteynerizasyon teknolojisi tercih edilmelidir. PM2, sunucu çöktüğünde uygulamayı otomatik olarak yeniden başlatır.
```bash
# PM2 ile uygulamayı başlatma ve cluster modu
pm2 start server.js -i max
```
## Sık Sorulan Sorular
1. **Node.js mobil uygulama geliştirmek için uygun mu?**
Evet, özellikle JSON tabanlı API'ler ve gerçek zamanlı özellikler için en performanslı dillerden biridir.
2. **TypeScript kullanmalı mıyım?**
Kesinlikle. Büyük projelerde tip güvenliği sağladığı için hata payını minimize eder ve kodun okunabilirliğini artırır.
3. **Node.js CPU yoğunluklu işler için uygun mu?**
Hayır. Video işleme veya ağır matematiksel hesaplamalar Node.js'in tek thread yapısını bloklayabilir. Bu tür işler için Worker Threads kullanılmalıdır.
4. **Hangi veritabanı Node.js ile daha iyi çalışır?**
JSON benzeri yapısı nedeniyle MongoDB çok popülerdir, ancak ilişkisel veriler için PostgreSQL ve Sequelize/Prisma ikilisi daha sağlıklıdır.
5. **Güvenlik için en önemli adım nedir?**
Her zaman güncel kütüphaneler kullanmak (npm audit) ve kullanıcı girdilerini (input) asla güvenilir kabul etmemektir.
## Özet ve Sonuç
Node.js mimari tasarımı, bir mobil uygulamanın ölçeklenebilirliği ve performansı için temel taşıdır. Doğru katmanlı mimari, güvenli kimlik doğrulama yöntemleri ve etkili caching stratejileriyle, milyonlarca kullanıcıya hizmet verebilecek sağlam bir backend altyapısı kurabilirsiniz. Unutmayın, iyi bir mimari sadece çalışan kod değil, aynı zamanda kolayca genişletilebilen ve test edilebilen bir yapıdır.