تطوير الويب

Redis Sentinel وCluster: الإتاحة العالية في الإنتاج

5 دقائق للقراءة

📌 المقال الرئيسي: Redis 8: caching، queues، pub/sub، streams

Redis ذو instance وحيد نقطة فشل وحيدة: أيّ crash للعملية أو الآلة يُسَبِّب توقّفًا كاملًا وفقدانًا محتملًا للبيانات. لتطبيقات الإنتاج، آليّتان رسميتان تُلغيان هذه المخاطرة: Redis Sentinel للـ failover التلقائي على نشرات معتدلة، وRedis Cluster للـ sharding الأفقي على مجموعات بيانات ضخمة. يُهَيِّئ هذا الدليل الاثنين خطوة بخطوة.

المتطلّبات

  • ثلاثة VPS Linux Ubuntu 24.04 أو Debian 12 مع توصيل شبكة خاصّة.
  • Redis 8 مثبَّت على كلّ منها.
  • أساسيات إدارة systemd وشبكة Linux.
  • الوقت: 90 دقيقة.

الخطوة 1 — معمارية Sentinel بثلاث عقد

النشر الأدنى الموصى به: ثلاث آلات: Redis maître، replica أو اثنين، وثلاث عمليات Sentinel مُوَزَّعة. quorum بثلاث Sentinels يُتيح تحمّل فقدان عقدة كاملة دون انقطاع.

Machine A (10.0.0.1): Redis maître  + Sentinel-A
Machine B (10.0.0.2): Redis replica + Sentinel-B
Machine C (10.0.0.3): Redis replica + Sentinel-C

عند سقوط الآلة A، Sentinels B وC يكشفون عدم التوفّر، يصوّتون (quorum 2/3) وينتخبون أحد الـ replicas كـ maître جديد. الـ failover يستغرق نمطيًّا 5 إلى 30 ثانية.

الخطوة 2 — تهيئة نسخ Redis

# على الآلة B (10.0.0.2)
sudo nano /etc/redis/redis.conf

# أضف:
replicaof 10.0.0.1 6379
masterauth motdepasse-replication
replica-read-only yes

# أعد التشغيل
sudo systemctl restart redis-server

replicaof IP PORT يُخبر هذا الـ instance أنّه replica للـ maître. masterauth يُوَفِّر كلمة سرّ التوثيق. replica-read-only yes يمنع الكتابات العرضية.

# على الآلة A (maître)
redis-cli --user appuser --askpass INFO replication

# على الآلة B (replica)
redis-cli --user appuser --askpass INFO replication

على الـ maître ترى role:master وconnected_slaves:2. على الـ replicas، role:slave، master_host:10.0.0.1، master_link_status:up. إن كان down، افحص التوصيل الشبكي وكلمة السرّ.

الخطوة 3 — اختبار النسخ

# على الـ maître (10.0.0.1)
redis-cli --user appuser --askpass SET test:replication "hello"

# على replica (10.0.0.2)
redis-cli --user appuser --askpass GET test:replication
"hello"

# محاولة كتابة على replica (يجب أن تفشل)
redis-cli --user appuser --askpass SET test:write "foo"
(error) READONLY You can't write against a read only replica.

الخطوة 4 — تهيئة Sentinel على الآلات الثلاث

sudo nano /etc/redis/sentinel.conf

port 26379
sentinel announce-ip MA_IP_PUBLIQUE
sentinel monitor mymaster 10.0.0.1 6379 2
sentinel auth-pass mymaster motdepasse-replication
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1

quorum مُحَدَّد بـ 2: Sentinels يجب أن يتفقا قبل تشغيل failover. down-after-milliseconds 5000 يقول إنّ maître يُعتَبَر down بعد 5 ثوانٍ بلا ردّ. parallel-syncs 1 يحدّ بـ replica واحد يُعاد تزامنه بالتوازي.

sudo systemctl enable redis-sentinel
sudo systemctl start redis-sentinel
sudo systemctl status redis-sentinel
redis-cli -p 26379 SENTINEL master mymaster
redis-cli -p 26379 SENTINEL replicas mymaster
redis-cli -p 26379 SENTINEL sentinels mymaster

الأمر الأخير يجب إدراج Sentinels الاثنين الآخرين. إن لم ترَ سوى واحد، فجدار حماية يحجب المنفذ 26379.

الخطوة 5 — اختبار الـ failover

# من الآلة A (maître)، أوقف Redis
sudo systemctl stop redis-server

# من أيّ آلة أخرى، راقب سجلّات Sentinel
sudo journalctl -u redis-sentinel -f

سترى السلسلة: +sdown master mymaster (Sentinel يكتشف العطل محلّيًّا)، +odown master mymaster #quorum 2/2 (quorum)، +vote-for-leader (انتخاب)، +failover-state-select-slave، +failover-state-send-slaveof-noone، وأخيرًا +switch-master mymaster 10.0.0.1 6379 10.0.0.2 6379. المجموع: 10 إلى 30 ثانية.

redis-cli -p 26379 SENTINEL master mymaster
redis-cli -h 10.0.0.2 --user appuser --askpass SET test:apres-failover "ok"

الآلة B الآن هي الـ maître. حين تُعيد تشغيل Redis على A، سيُعَاد ضبطه تلقائيًّا كـ replica.

الخطوة 6 — اتّصال العميل بـ Sentinel

// client-sentinel.js
import Redis from 'ioredis';

const redis = new Redis({
  sentinels: [
    { host: '10.0.0.1', port: 26379 },
    { host: '10.0.0.2', port: 26379 },
    { host: '10.0.0.3', port: 26379 }
  ],
  name:             'mymaster',
  username:         'appuser',
  password:         process.env.REDIS_PASSWORD,
  sentinelPassword: process.env.REDIS_PASSWORD
});

await redis.set('cle', 'valeur');
const v = await redis.get('cle');

عند failover، ioredis يستقبل إشعار Sentinel +switch-master ويُعيد الاتّصال بالـ maître الجديد تلقائيًّا. لا تغيير كود تطبيقي ضروري.

الخطوة 7 — معمارية Redis Cluster للـ sharding

حين يتجاوز dataset ذاكرة آلة واحدة (نمطيًّا 100+ جيغا)، Sentinel لا يكفي — Redis Cluster يُوَزِّع المفاتيح على عدّة maîtres. الحدّ الأدنى الموصى به: 3 maîtres + 3 replicas.

Master-1 (10.0.0.1:7000) -- Replica-1 (10.0.0.4:7000)
Master-2 (10.0.0.2:7000) -- Replica-2 (10.0.0.5:7000)
Master-3 (10.0.0.3:7000) -- Replica-3 (10.0.0.6:7000)

كلّ مفتاح يُربَط بـ slot عبر CRC16(key) mod 16384. الـ 16,384 slots مُوَزَّعة بين maîtres. حين يكتب عميل على عقدة لا تملك الـ slot، العقدة تردّ MOVED. ioredis يُدير هذا تلقائيًّا.

الخطوة 8 — تهيئة Redis Cluster

port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes
requirepass motdepasse-cluster
masterauth motdepasse-cluster
redis-cli --user appuser -a "$REDIS_PASSWORD" --cluster create \
  10.0.0.1:7000 10.0.0.2:7000 10.0.0.3:7000 \
  10.0.0.4:7000 10.0.0.5:7000 10.0.0.6:7000 \
  --cluster-replicas 1

--cluster-replicas 1 يُنشئ replica تلقائيًّا لكلّ maître.

redis-cli -h 10.0.0.1 -p 7000 --user appuser --askpass CLUSTER INFO
redis-cli -h 10.0.0.1 -p 7000 --user appuser --askpass CLUSTER NODES

CLUSTER INFO يجب إظهار cluster_state:ok، cluster_slots_ok:16384، cluster_known_nodes:6.

الخطوة 9 — عميل Cluster بـ ioredis

// client-cluster.js
import { Cluster } from 'ioredis';

const cluster = new Cluster([
  { host: '10.0.0.1', port: 7000 },
  { host: '10.0.0.2', port: 7000 },
  { host: '10.0.0.3', port: 7000 }
], {
  redisOptions: {
    password: process.env.REDIS_PASSWORD,
    username: 'appuser'
  }
});

await cluster.set('user:1', JSON.stringify({ nom: 'Salim' }));
await cluster.set('user:2', JSON.stringify({ nom: 'Mariam' }));
const u = JSON.parse(await cluster.get('user:1'));

seeds (العقد الأوّلية) تخدم فقط لاكتشاف الطوبولوجيا. العمليات متعدّدة المفاتيح (معاملات، Lua، MSET) تعمل فقط داخل نفس slot — استعمل hash tags {...} لفرض ذلك: {user1}:profile و{user1}:settings على نفس العقدة.

الخطوة 10 — Resharding وrebalancing

redis-cli --cluster add-node 10.0.0.7:7000 10.0.0.1:7000 --user appuser -a "$PWD"
redis-cli --cluster reshard 10.0.0.1:7000 --user appuser -a "$PWD"
# الأداة تطلب عدد slots المراد ترحيلها وإلى أيّ عقدة

Resharding يُهَجِّر slots ومفاتيحها بشفافية. للإزالة، هَجِّر كلّ slots أوّلًا ثم cluster forget. هذه العمليات يجب تخطيطها في ساعات خفيفة.

أخطاء شائعة

الخطأ السبب الحلّ
Failover مُشَغَّل خطأً (flapping) down-after-milliseconds قصير جدًّا زد إلى 10000-15000 ms وحسِّن المراقبة
Sentinel لا يرى Sentinels الأخرى جدار حماية يحجب 26379 افتح 26379 TCP في mesh بين الآلات
Cluster state failing دائمًا instance غير قابل للوصول، slots غير مُسَنَدة CLUSTER NODES للتشخيص، CLUSTER FORGET + إعادة إنشاء
زمن استجابة مفاجئ بعد failover replicas غير محدَّثة، إعادة تزامن كامل هَيِّئ repl-backlog-size 256mb
MOVED في حلقة لا نهائية طوبولوجيا محلّية قديمة بعد resharding افرض CLUSTER RESET وأعد تشغيل العميل

العودة للدليل الرئيسي

🔝 Redis 8: caching، queues، pub/sub، streams

FAQ

Sentinel أم Cluster؟ Sentinel لـ datasets دون 100 جيغا مع failover تلقائي دون sharding. Cluster فور الحاجة إلى sharding أفقي أو تجاوز قدرات maître وحيد.

كم replica لكلّ maître؟ واحد يكفي للـ failover. اثنان يُتيحان load balancing على القراءة (replicas تخدم GET للقراءة فقط). ثلاثة وما فوق دون مكسب متناسب.

كيف نُهَجِّر من Sentinel إلى Cluster؟ هجرة يدوية: (1) توفير cluster بالتوازي، (2) كتابة مزدوجة في التطبيق، (3) نسخ البيانات عبر --cluster import، (4) تبديل القراءة على cluster، (5) إيقاف Sentinel.

Cluster يدعم معاملات MULTI/EXEC؟ فقط إن كانت كلّ المفاتيح على نفس slot. استعمل hash tags {...} لفرض التجميع.

مراجع

  • Redis Sentinel — التوثيق الرسمي
  • Redis Cluster — التوثيق الرسمي
  • Replication Redis
مشاركة