Node.js ve Redis ile Pub/Sub Mimarisi: Ölçeklenebilir Chat Uygulaması
Bu rehberde ne öğreneceksiniz?
Bu rehberde, gerçek zamanlı uygulamaların temel yapı taşlarından biri olan Publish/Subscribe (Pub/Sub) mimarisini öğreneceksiniz.
Node.js ve WebSocket ile çalışan bir sohbet uygulaması geliştirecek, ardından Redis’i mesaj aracısı olarak ekleyerek uygulamayı çoklu sunucu ortamına uygun hale getireceksiniz.
Teknik Özet
Bu rehber, Node.js tabanlı bir WebSocket uygulamasının nasıl ölçeklendirileceğini anlatır.
Problem, tek sunucuda çalışan chat uygulamalarının farklı sunucularla haberleşememesidir.
Çözüm ise Redis Pub/Sub mekanizması ile sunucular arası mesaj paylaşımı sağlamaktır.
Ön Hazırlıklar
Başlamadan önce aşağıdaki gereksinimlerin hazır olması gerekir:
- Node.js (v12 ve üzeri)
- VS Code veya benzeri bir kod editörü
- Redis (yerel veya uzak sunucu)
- JavaScript, HTML ve WebSocket hakkında temel bilgi
1. Sunucu Tarafı Kurulumu
1.1 Projeyi Başlatma
npm init -y
npm install ws ioredis
- Bu komutlar, Node.js projesini oluşturur ve WebSocket ile Redis bağımlılıklarını kurar.
1.2 Basit HTTP Sunucusu Oluşturma
const http = require("http");
const server = http.createServer((req, res) => {
res.end("Merhaba Chat Uygulaması");
});
const PORT = process.argv[2] || 3459;
server.listen(PORT, () => {
console.log(`Sunucu ${PORT} portunda çalışıyor`);
});
- Bu kod, Node.js’in yerleşik HTTP modülüyle temel bir web sunucusu başlatır.
2. HTML Arayüzünü Hazırlama
2.1 index.html Dosyası
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8" />
<title>Pub/Sub Chat</title>
</head>
<body>
<h2>Pub/Sub Chat Uygulaması</h2>
<div id="mesajKutusu"
style="border:1px solid #ddd;height:300px;overflow-y:auto;padding:10px;">
</div>
<form id="mesajFormu" style="margin-top:10px;">
<input type="text" id="mesajMetni" placeholder="Mesajınızı yazın..." />
<button type="submit">Gönder</button>
</form>
<script>
const socket = new WebSocket(`ws://${location.host}`);
const mesajKutusu = document.getElementById("mesajKutusu");
socket.onmessage = (event) => {
if (event.data instanceof Blob) {
event.data.text().then(yaz);
} else {
yaz(event.data);
}
};
function yaz(text) {
const p = document.createElement("p");
p.textContent = text;
mesajKutusu.appendChild(p);
}
document.getElementById("mesajFormu").addEventListener("submit", (e) => {
e.preventDefault();
const input = document.getElementById("mesajMetni");
socket.send(input.value);
input.value = "";
});
</script>
</body>
</html>
- Bu dosya, WebSocket bağlantısı kurar ve mesajları kullanıcı arayüzünde gösterir.
2.2 HTML Dosyasını Sunucudan Yayınlama
const fs = require("fs");
const path = require("path");
const server = http.createServer((req, res) => {
const filePath = path.join(__dirname, "index.html");
fs.readFile(filePath, (err, data) => {
if (err) {
res.writeHead(500);
return res.end("Dosya okunamadı");
}
res.writeHead(200, { "Content-Type": "text/html" });
res.end(data);
});
});
- Bu kod, tarayıcıdan gelen isteklere HTML arayüzü döndürür.
3. WebSocket Entegrasyonu
const WebSocket = require("ws");
const wss = new WebSocket.Server({ server });
wss.on("connection", (client) => {
client.on("message", (mesaj) => {
wss.clients.forEach((c) => {
if (c.readyState === WebSocket.OPEN) {
c.send(mesaj);
}
});
});
});
- Bu yapı, gelen mesajları aynı sunucuya bağlı tüm istemcilere dağıtır.
4. Ölçekleme Problemi
- Tek sunucu çalışırken mesajlaşma sorunsuzdur.
- Ancak uygulama büyüdüğünde birden fazla sunucu gerekir.
- Bu noktada, farklı sunucular birbirlerinden haberdar değildir.
5. Redis ile Pub/Sub Mimarisi
- Redis burada bir mesaj aracısı görevi görür.
- Bir sunucu mesajı Redis’e yayınlar, diğer sunucular bu mesaja abone olur.
5.1 Redis Entegrasyonu
const Redis = require("ioredis");
const redisPublisher = new Redis();
const redisSubscriber = new Redis();
redisSubscriber.subscribe("genel_sohbet");
wss.on("connection", (client) => {
client.on("message", (mesaj) => {
redisPublisher.publish("genel_sohbet", mesaj);
});
});
redisSubscriber.on("message", (kanal, mesaj) => {
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(mesaj);
}
});
});
- Bu kod, mesajların tüm sunucular arasında paylaşılmasını sağlar.
5.2 Çoklu Sunucu Testi
node app.js 3459
node app.js 3460
- Farklı portlarda çalışan sunucular, Redis üzerinden mesajları paylaşır.
Sıkça Sorulan Sorular
-
Pub/Sub mimarisi ne zaman tercih edilir? Gerçek zamanlı ve gevşek bağlı sistemlerde kullanılır.
-
Redis yerine veritabanı olur mu? Teknik olarak mümkündür, ancak performans düşer.
-
Bu yapı kaç kullanıcıyı destekler? Redis ve sunucu kapasitesine bağlıdır.
-
Tek nokta hatası var mı? Redis tek başına çalışıyorsa vardır.
-
Alternatif mesaj aracısı var mı? RabbitMQ ve Kafka yaygın alternatiflerdir.
Sonuç
Bu rehberde, Node.js ile basit bir chat uygulamasını Rabisu Bulut mimarisiyle ölçeklenebilir hale getirdik. Redis sayesinde farklı sunucular arasında gerçek zamanlı mesajlaşma sağladık. Bu yaklaşım, modern ve yüksek trafikli uygulamaların temelini oluşturur.