أغلب التطبيقات التي تستضيفها تطلب منك في ملف Docker Compose خدمة Redis بجانب قاعدة البيانات، لحفظ الجلسات أو طوابير المهام أو نتائج الاستعلامات المكلفة، وأغلب من يضيفها يتركها بالإعدادات الافتراضية ولا يفكر فيها مرة أخرى حتى يوم تمتلئ الذاكرة ويخرج المستخدمون من حساباتهم جميعاً، أو حتى يقرأ أن رخصة Redis تغيرت ويتساءل هل ما زال يحق له استخدامه. وفي هذا المقال سوف نجيب عن السؤالين بتجربة عملية على Redis وبديله المفتوح Valkey جنباً إلى جنب.
وسوف نناقش في هذا المقال ما يلي:
- ما هو Redis، وهياكل البيانات التي تجعله أكثر من مخزن مفاتيح وقيم Key-Value.
- الاستخدامات اليومية: الجلسات Sessions والعدادات Counters ولوحات الترتيب Leaderboards.
- الحفظ على القرص Persistence بطريقتي RDB وAOF.
- سياسات الإخراج Eviction Policies عندما تمتلئ الذاكرة، بأرقام حقيقية.
- النسخ المتماثل Replication وSentinel باختصار.
- قصة الرخصة: من BSD إلى RSAL وSSPL ثم خيار AGPL في Redis 8، وولادة Valkey تحت Linux Foundation.
- هل Valkey بديل مباشر Drop-in Replacement فعلاً؟ وأين يختلف اليوم.
أما استراتيجيات التخزين المؤقت نفسها، مثل Cache-Aside وWrite-Through وإبطال البيانات القديمة Invalidation، فشرحناها في مقال التخزين المؤقت، وهنا نركز على الأداة.
ما هو Redis؟
Redis قاعدة بيانات تحفظ كل بياناتها في الذاكرة RAM، وتستقبل الأوامر عبر الشبكة على المنفذ 6379، وتنفذها واحداً بعد الآخر في خيط رئيسي واحد، ولذلك كل أمر ذري Atomic بطبيعته، فلا يمكن أن يتداخل أمران على نفس المفتاح. والسرعة تأتي من أن القراءة من الذاكرة لا تنتظر القرص، والثمن أن حجم البيانات محدود بحجم الذاكرة، وأن ما في الذاكرة يضيع عند إعادة التشغيل إلا إذا طلبت حفظه على القرص كما سوف نرى.
والذي يجعله أكثر من مخزن مفاتيح وقيم أن القيمة ليست نصاً فقط، وإنما هياكل بيانات يعرفها السيرفر ويعدلها بأمر واحد، وهي نفس الهياكل التي شرحناها في مقال هياكل البيانات:
| النوع | الأوامر | الاستخدام المعتاد |
|---|---|---|
| النص String | SET وGET وINCR | نتيجة مخزنة مؤقتاً، وعداد |
| الجدول Hash | HSET وHGETALL | جلسة مستخدم بحقولها |
| القائمة List | LPUSH وBRPOP | طابور مهام بسيط |
| المجموعة Set | SADD وSISMEMBER | من شاهد هذا المنشور |
| المجموعة المرتبة Sorted Set | ZADD وZREVRANGE | لوحة الترتيب، وتحديد معدل الطلبات |
| التدفق Stream | XADD وXREADGROUP | سجل أحداث مع مجموعات مستهلكين |
ولاحظ أن كل مفتاح يمكن أن يكون له عمر TTL بالثواني، وعندما ينتهي يحذفه السيرفر وحده، وهذه الخاصية هي أساس الجلسات والتخزين المؤقت معاً.
الاستخدامات اليومية: الجلسات والعدادات ولوحات الترتيب
شرحنا في مقال الجلسات لماذا تحتاج مخزناً مشتركاً للجلسات عندما يعمل التطبيق على أكثر من نسخة، وRedis هو الخيار الأشهر لهذا. والسكربت التالي يبين الاستخدامات الثلاثة الأكثر شيوعاً، وسوف نشغله على Redis وValkey في التجربة:
# Sessions, counters and a leaderboard: the three everyday uses (ArabRoot lab).
# docker exec lab-redis-app python /lab/sessions.py redis
import sys, time, json, secrets, redis
r = redis.Redis(host=sys.argv[1], decode_responses=True)
print(r.info('server').get('valkey_version') and 'valkey ' + r.info('server')['valkey_version'] or 'redis ' + r.info('server')['redis_version'])
# 1) a session: a hash with a TTL, extended on every request (sliding expiry)
sid = secrets.token_urlsafe(24)
r.hset(f'sess:{sid}', mapping={'user_id': 7, 'name': 'Sara', 'role': 'editor', 'csrf': secrets.token_hex(16)})
r.expire(f'sess:{sid}', 1800)
print('session', r.hgetall(f'sess:{sid}')['name'], 'ttl', r.ttl(f'sess:{sid}'))
r.delete(f'sess:{sid}') # logout = delete the key
print('after logout exists:', r.exists(f'sess:{sid}'))
# 2) a counter: INCR is atomic, 10 workers never lose an update
r.delete('views:post:42')
pipe = r.pipeline()
for _ in range(10_000): pipe.incr('views:post:42')
pipe.execute()
print('views', r.get('views:post:42'))
# 3) a leaderboard: a sorted set keeps the order for you
r.delete('lb:week')
r.zadd('lb:week', {'sara': 3120, 'ahmed': 2980, 'omar': 3350, 'lina': 3010})
r.zincrby('lb:week', 200, 'ahmed')
print('top3', r.zrevrange('lb:week', 0, 2, withscores=True), 'rank of lina', r.zrevrank('lb:week', 'lina') + 1)في الكود أعلاه لاحظ التالي:
- الجلسة Hash عمره 1800 ثانية، والتطبيق يمدد العمر مع كل طلب بالأمر
EXPIRE، وتسجيل الخروج هو حذف المفتاح، فتنتهي الجلسة فوراً على كل نسخ التطبيق. - العداد بالأمر
INCRلا يحتاج قراءة ثم كتابة، فالسيرفر يزيد القيمة بنفسه، ولذلك لا تضيع زيادة حتى لو كتب عشرة Workers في نفس اللحظة، وهذا هو الخطأ الذي يقع فيه من يقرأ القيمة في التطبيق ثم يكتبها. - لوحة الترتيب Sorted Set يرتبها السيرفر عند كل إضافة، فأعلى ثلاثة أو ترتيب لاعب معين أمر واحد سريع مهما كبر العدد.
الحفظ على القرص: RDB أم AOF؟
بما أن البيانات في الذاكرة، فالسؤال الأول: ماذا يحدث إذا أعيد تشغيل السيرفر؟ وتوثيق Redis Persistence يذكر طريقتين، والصورة التالية تبين الفرق:

- RDB: صورة كاملة للبيانات في ملف
dump.rdbكل فترة تحددها، مثلsave 60 1000(كل 60 ثانية إذا تغير 1000 مفتاح على الأقل). الملف صغير ومناسب للنسخ الاحتياطي ويعيد التشغيل بسرعة، ولكنك تخسر كل ما كتب بعد آخر صورة، والتوثيق يقول إن الصورة تكون عادة كل خمس دقائق أو أكثر. - AOF: ملف يسجل كل أمر يغير البيانات، ويحفظه على القرص كل ثانية بالإعداد الافتراضي
appendfsync everysec، فتخسر ثانية واحدة على الأكثر، والملف أكبر ويعاد كتابته في الخلفية عندما يكبر.
والتوصية في التوثيق أن تستخدم الاثنين إذا كنت تريد أماناً قريباً من PostgreSQL، وRDB وحده إذا كنت تقبل خسارة دقائق، وبدون حفظ إطلاقاً إذا كان Redis مجرد Cache تستطيع أن تبنيه من جديد. وقد يتساءل البعض: هل الجلسات تحتاج حفظاً على القرص؟ والإجابة نعم في الغالب، فبدونها كل إعادة تشغيل لل Container تخرج كل المستخدمين من حساباتهم، وهذا ما سوف نختبره.
عندما تمتلئ الذاكرة: سياسات الإخراج Eviction
القيمة الافتراضية لـ maxmemory هي صفر على الأنظمة 64 بت، أي بلا حد، وهذا يعني أن Redis يكبر حتى يأخذ ذاكرة السيرفر كلها، ثم يقتله نظام التشغيل OOM Killer أو يقتل شيئاً آخر بجانبه. لذلك أول إعداد تغيره دائماً هو maxmemory، ومعه السياسة maxmemory-policy التي تحدد ماذا يفعل عندما يصل إلى الحد، وأهمها بحسب توثيق الإخراج:
noeviction: لا يحذف شيئاً، ويرفض كل أمر يضيف بيانات بخطأ، والقراءة تستمر. وهي الافتراضية.allkeys-lru: يحذف المفاتيح الأقل استخداماً مؤخراً Least Recently Used من كل المفاتيح، والتوثيق يعتبرها الاختيار الافتراضي الجيد لل Cache.allkeys-lfu: يحذف الأقل استخداماً من حيث عدد المرات Least Frequently Used.volatile-lruوأخواتها: تحذف فقط من المفاتيح التي لها TTL، وإذا لم يوجد مفتاح له TTL تتصرف مثلnoeviction.
ولاحظ أن LRU في Redis تقريبي، فهو يأخذ عينة صغيرة من المفاتيح (5 افتراضياً بالإعداد maxmemory-samples) ويحذف الأقدم بينها، ولهذا سوف ترى في التجربة أن بعض المفاتيح القديمة بقيت. والصورة التالية تلخص ما خرج من التجربة:

النسخ المتماثل وSentinel
شرحنا Sentinel وانتقال الرئيسي تلقائياً بتجربة كاملة على Valkey في مقال عناقيد قواعد البيانات، والخلاصة هنا: نسخة رئيسية تكتب، ونسخ تتبعها بالأمر REPLICAOF، والنسخ غير متزامن Asynchronous، فقد تضيع آخر كتابات قليلة عند الانتقال. وSentinel ثلاث عمليات صغيرة أو أكثر تراقب الرئيسي وتتفق على أنه توقف، ثم ترقي نسخة وتخبر التطبيق بعنوانها الجديد كما في توثيق Sentinel. وأما Cluster فهو لتوزيع البيانات على عدة سيرفرات عندما لا تكفيها ذاكرة سيرفر واحد، وأغلب الاستضافات الذاتية لا تحتاجه. والنسخ المتماثل هو أيضاً الطريق الطبيعي للانتقال من Redis إلى Valkey دون توقف، ولكن بشرط سوف نراه في التجربة.
قصة الرخصة: لماذا ظهر Valkey؟
كان Redis منذ بدايته تحت رخصة BSD-3 المتساهلة، ثم في 20 مارس 2024 أعلنت شركة Redis أن كل إصدار بدءاً من 7.4 سوف يكون تحت رخصتين يختار المستخدم إحداهما: RSALv2 أو SSPLv1، وكلاهما ليست رخصة مفتوحة المصدر بتعريف OSI كما يعترف الإعلان نفسه، والهدف المعلن منع الشركات السحابية من بيع Redis كخدمة دون اتفاق مع الشركة. وبعد ثمانية أيام، في 28 مارس 2024، أطلقت Linux Foundation مشروع Valkey، وهو نسخة Fork من Redis 7.2.4 تحت BSD-3، بدعم من AWS وGoogle Cloud وOracle وEricsson وSnap، وقاده عدد من مطوري Redis السابقين. ثم في 1 مايو 2025 أضافت Redis رخصة AGPLv3 خياراً ثالثاً بدءاً من Redis 8، ودمجت فيه ما كان في Redis Stack مثل JSON والسلاسل الزمنية ومحرك البحث. والصورة التالية تبين ذلك:

فماذا يعني هذا لك إذا كنت تستضيف تطبيقاتك بنفسك؟ بحسب أسئلة الإعلان، استخدام Redis داخل شركتك أو خلف تطبيقك مسموح تحت RSALv2 وSSPLv1، والممنوع أن تقدم Redis نفسه خدمة منافسة لمنتجات الشركة. وتحت AGPLv3 تستطيع أن تفعل أي شيء بشرط أنك إذا عدلت كود Redis وقدمته للمستخدمين عبر الشبكة تنشر تعديلاتك، وشرحنا معنى هذا في قسم Copyleft في مقال الرخص. وبالتالي أغلب من يستضيف تطبيقاته لن يتأثر بالرخصة، ولكن من يريد رخصة متساهلة تماماً لا تتغير بقرار شركة واحدة، أو يبني منتجاً يضم قاعدة البيانات، فValkey هو الخيار الأوضح.
تجربة عملية: الجلسات والإخراج وValkey بدل Redis
سوف نشغل Redis 8.10.2 وValkey 9.1.2 جنباً إلى جنب، بنفس الإعدادات: حد ذاكرة 64 MB، والسياسة noeviction في البداية، وAOF مفعل، ومعهما Container صغير فيه Python ومكتبة redis-py 6.4.0 لتشغيل السكربتات على الاثنين. والتجربة على Docker Engine 29.8.0.
ملف التشغيل
# Redis and Valkey side by side, with a small Python client (ArabRoot lab).
# docker compose -p lab-redis up -d
name: lab-redis
services:
redis:
image: redis:8.10.2
container_name: lab-redis-redis
command: ["redis-server", "--maxmemory", "64mb", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
ports: ["127.0.0.1:16379:6379"]
volumes: ["redis-data:/data"]
valkey:
image: valkey/valkey:9.1.2
container_name: lab-redis-valkey
command: ["valkey-server", "--maxmemory", "64mb", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
ports: ["127.0.0.1:16380:6379"]
volumes: ["valkey-data:/data"]
app:
image: python:3.13.7-slim
container_name: lab-redis-app
command: ["sh", "-c", "pip install --quiet redis==6.4.0 && sleep infinity"]
volumes: ["./:/lab:ro"]
volumes:
redis-data:
valkey-data:docker compose -p lab-redis up -d
docker exec lab-redis-app python /lab/sessions.py redis
docker exec lab-redis-app python /lab/sessions.py valkeyوالمخرج سوف يكون كما يلي:
redis 8.10.2
session Sara ttl 1800
after logout exists: 0
views 10000
top3 [('omar', 3350.0), ('ahmed', 3180.0), ('sara', 3120.0)] rank of lina 4
---
valkey 9.1.2
session Sara ttl 1800
after logout exists: 0
views 10000
top3 [('omar', 3350.0), ('ahmed', 3180.0), ('sara', 3120.0)] rank of lina 4نفس السكربت ونفس المكتبة ونفس النتيجة على الاثنين، والتغيير الوحيد هو اسم السيرفر.
الجلسات بعد إعادة التشغيل
نكتب جلسة وعداداً، ثم نعيد تشغيل ال Container:
docker exec lab-redis-redis redis-cli set sess:abc '{"user_id":7}' EX 1800
docker exec lab-redis-redis redis-cli info persistence | grep -E "aof_enabled|aof_last_write_status"
docker restart lab-redis-redis
docker exec lab-redis-redis redis-cli dbsize
docker exec lab-redis-redis redis-cli get views:post:42
docker exec lab-redis-redis redis-cli ttl sess:abcوالمخرج:
aof_enabled:1
aof_last_write_status:ok
3
10000
1784كل المفاتيح الثلاثة عادت، والعداد بقيمته، والجلسة بعمرها المتبقي، والسبب أن AOF مفعل في ال Compose بالخيار --appendonly yes. ولاحظ أن ال Docker Image الرسمي لا يفعل AOF افتراضياً، فإذا شغلت Redis دون هذا الخيار ودون Volume فكل إعادة تشغيل تعني أن كل المستخدمين يخرجون من حساباتهم.
نكسرها: 120 ألف جلسة في 64 MB
الآن نملأ السيرفر عن قصد. السكربت eviction.py يكتب 120 ألف جلسة بحجم 1 KB لكل منها TTL، أي قرابة ضعف الذاكرة المتاحة، ويقرأ أثناء ذلك ألفي جلسة نشطة باستمرار كأنهم مستخدمون يتصفحون الآن، ويضع مفتاحاً مهماً للإعدادات دون TTL، ثم يحسب من بقي:
# Break it: fill a 64 MB server with 1 KB sessions under different maxmemory policies (ArabRoot lab).
# docker exec lab-redis-app python /lab/eviction.py redis noeviction
import sys, random, redis
host, policy = sys.argv[1], sys.argv[2]
r = redis.Redis(host=host)
r.flushall(); r.config_resetstat()
r.config_set('maxmemory-policy', policy)
r.set('config:feature-flags', 'x' * 200) # an important key with no TTL
payload = b'x' * 1000
hot = [f'sess:{i}' for i in range(2000)] # 2,000 users who keep clicking
written, errors = 0, None
for i in range(120_000): # about 120 MB of sessions for a 64 MB server
try:
r.set(f'sess:{i}', payload, ex=1800)
written += 1
except redis.exceptions.ResponseError as e:
errors = str(e); break
if i % 50 == 0: # the hot users are read all the time
for k in random.sample(hot, 50): r.get(k)
mem, stats = r.info('memory'), r.info('stats')
alive = lambda keys: sum(1 for k in keys if r.exists(k))
print(f'policy={policy} written={written} keys={r.dbsize()} used={mem["used_memory_human"]} evicted={stats["evicted_keys"]}')
print(f' hot sessions alive: {alive(hot)}/2000, cold sample alive: {alive([f"sess:{i}" for i in range(50_000, 52_000)])}/2000, feature-flags alive: {r.exists("config:feature-flags")}')
if errors: print(' error:', errors)for p in noeviction allkeys-lru volatile-lru allkeys-lfu; do docker exec lab-redis-app python /lab/eviction.py redis $p; doneوالمخرج على Redis سوف يكون كما يلي:
policy=noeviction written=60072 keys=60073 used=64.00M evicted=0
hot sessions alive: 2000/2000, cold sample alive: 2000/2000, feature-flags alive: 1
error: command not allowed when used memory > 'maxmemory'.
policy=allkeys-lru written=120000 keys=59655 used=64.00M evicted=60346
hot sessions alive: 2000/2000, cold sample alive: 341/2000, feature-flags alive: 0
policy=volatile-lru written=120000 keys=59647 used=64.00M evicted=60354
hot sessions alive: 2000/2000, cold sample alive: 321/2000, feature-flags alive: 1
policy=allkeys-lfu written=120000 keys=59663 used=64.00M evicted=60337
hot sessions alive: 2000/2000, cold sample alive: 164/2000, feature-flags alive: 0وعلى Valkey كانت الأرقام قريبة جداً:
policy=noeviction written=60095 keys=60096 used=64.00M evicted=0
error: command not allowed when used memory > 'maxmemory'.
policy=allkeys-lru written=120000 keys=60030 used=64.00M evicted=59971
hot sessions alive: 2000/2000, cold sample alive: 342/2000, feature-flags alive: 0
policy=volatile-lru written=120000 keys=60028 used=64.00M evicted=59973
hot sessions alive: 2000/2000, cold sample alive: 318/2000, feature-flags alive: 1
policy=allkeys-lfu written=120000 keys=60013 used=64.00M evicted=59988
hot sessions alive: 2000/2000, cold sample alive: 228/2000, feature-flags alive: 0في المخرج أعلاه لاحظ التالي:
- مع
noeviction، وهي الافتراضية، توقفت الكتابة عند قرابة 60 ألف جلسة، وكل تسجيل دخول جديد بعد ذلك يفشل بالخطأcommand not allowed when used memory > 'maxmemory'، أي أن الموقع يتوقف عن قبول المستخدمين الجدد بينما القدامى يعملون، وهذا عطل غريب يصعب فهمه إذا لم تعرف السبب. - مع
allkeys-lruوallkeys-lfuبقيت كل الجلسات النشطة الألفين، وخرجت أغلب الجلسات التي لم تستخدم منذ مدة، ولكن مفتاح الإعدادات المهم خرج أيضاً لأنه لم يقرأ أثناء التجربة، فإذا كان التطبيق يفترض أنه موجود دائماً فسوف ينكسر. - مع
volatile-lruبقي مفتاح الإعدادات لأنه بلا TTL، وخرجت الجلسات القديمة فقط، وهذا هو الخيار المناسب عندما تخلط بيانات دائمة وبيانات مؤقتة في نفس السيرفر، والتوثيق ينصح بأن تفصلها في سيرفرين إذا استطعت. - بقي بعض الجلسات القديمة (341 من 2000) لأن الخوارزمية تقريبية بالعينات، وليس خطأ.
إذن القاعدة: حدد maxmemory دائماً، واختر السياسة بحسب ما تخزنه، فلل Cache الخالص allkeys-lru، وللجلسات مع بيانات دائمة volatile-lru، ولا تترك noeviction إلا إذا كان Redis يحفظ بيانات لا يجوز أن تخرج، مثل طابور مهام، وعندها راقب الذاكرة وتنبه قبل أن تمتلئ.
هل Valkey بديل مباشر؟
رأينا أن نفس الكود ونفس المكتبة عملا على الاثنين، ولكن لنحاول الآن الطريقة الطبيعية للانتقال دون توقف: أن يكون Valkey نسخة Replica من Redis 8.10 ثم نرقيه:
docker exec lab-redis-valkey valkey-cli replicaof redis 6379
docker exec lab-redis-valkey valkey-cli info replication | grep -E "role|master_link_status"
docker logs lab-redis-valkey 2>&1 | grep -i rdbوالمخرج:
role:slave
master_link_status:down
# Can't handle RDB format version 15
# Failed to load RDBRedis 8.10 يرسل البيانات بصيغة RDB رقم 15، وValkey 9.1 لا يقرأ هذه الصيغة، والسبب أن المشروعين افترقا منذ 2024 وكل واحد يطور صيغة ملفاته. ونفس المحاولة من Redis 7.2.16، وهو آخر خط تحت BSD، نجحت مباشرة:
role:slave
master_link_status:up
10000
omar
3350
ahmed
3180وهناك فرقان آخران ظهرا في التجربة:
redis-cli config set maxmemory-policy allkeys-lrm → OK
valkey-cli config set maxmemory-policy allkeys-lrm → ERR CONFIG SET failed ... must be one of the following: volatile-lru, volatile-lfu, volatile-random, volatile-ttl, allkeys-lru, allkeys-lfu, allkeys-random, noeviction
redis-cli JSON.SET cart:7 $ '{"items":2}' → OK
valkey-cli JSON.SET cart:7 $ '{"items":2}' → ERR unknown command 'JSON.SET'سياسة allkeys-lrm أضيفت في Redis 8.6، وأوامر JSON أصبحت جزءاً من Redis 8، أما في Valkey فهي في وحدة منفصلة valkey-json تأتي مع ال Docker Image المسمى valkey-bundle. والخلاصة أن Valkey بديل مباشر لـ Redis 7.2 ولكل تطبيق يستخدم الأوامر الأساسية، وليس بديلاً مباشراً لكل ما أضيف في Redis 8، فإذا كنت على Redis 8 وتريد الانتقال فلا تعتمد على ملف RDB أو النسخ المتماثل، وانقل البيانات من التطبيق نفسه، أو اترك ال Cache والجلسات تبنى من جديد في Valkey إذا كان خروج المستخدمين مرة واحدة مقبولاً.
حذف المختبر
docker compose -p lab-redis down -v
docker rm -f lab-redis-oldRedis أم Valkey؟
Redis
نقاط القوة: الأصل الذي تختبر عليه أغلب المكتبات، وRedis 8 فيه JSON والسلاسل الزمنية ومحرك البحث والمتجهات Vector Sets في الحزمة نفسها، وخيار AGPLv3 رخصة مفتوحة معترف بها، وميزات جديدة مثل سياسة LRM وأوامر BACKUP.
نقاط الضعف: شركة واحدة تملك الكود وغيرت رخصته مرتين في سنة، والرخص الأخرى ليست مفتوحة، وAGPL قد لا تقبلها سياسة بعض الشركات، وصيغة ملفاته لم تعد تقرأ في Valkey.
Valkey
نقاط القوة: BSD-3 تحت Linux Foundation ولا تملكه شركة واحدة، وبديل مباشر لكل ما كان في Redis 7.2، ومدعوم من مزودي السحابة الكبار، ومتوفر في مستودعات التوزيعات مثل حزمة valkey-server في Debian 13.
نقاط الضعف: ميزات Redis 8 الجديدة ليست فيه أو في وحدات منفصلة، ولا يقرأ ملفات RDB الحديثة من Redis، وبعض التطبيقات الجاهزة توثق Redis فقط فتختبر أنت التوافق.
- تطبيق جاهز يحتاج Cache أو جلسات أو طابور: Valkey يكفي ويعمل بنفس الإعداد، كما فعلنا في مقالات سابقة مثل مقال العناقيد.
- تحتاج JSON أو البحث أو المتجهات داخل نفس السيرفر: Redis 8، أو valkey-bundle بعد أن تختبر الأوامر التي تحتاجها.
- تبني منتجاً تبيعه ويضم قاعدة البيانات: Valkey لتجنب أي سؤال عن الرخصة.
- تريد كل شيء في قاعدة واحدة دون سيرفر إضافي: اقرأ قسم Cache في مقال PostgreSQL لكل شيء قبل أن تضيف Redis أصلاً.
أخطاء شائعة
- ترك
maxmemoryبلا حد: يكبر حتى يقتله نظام التشغيل، أو يقتل قاعدة البيانات بجانبه. - ترك
noevictionلسيرفر يخزن Cache: عند الامتلاء يرفض كل كتابة جديدة بدل أن يحذف القديم. - خلط بيانات دائمة مع Cache مع
allkeys-lru: في التجربة خرج مفتاح الإعدادات المهم. - جلسات بلا AOF ولا Volume: كل إعادة تشغيل تخرج كل المستخدمين.
- قراءة القيمة ثم كتابتها في التطبيق بدل
INCR: تضيع الزيادات عند التزامن. - المنفذ 6379 مفتوح بلا كلمة مرور: كل الجلسات مكشوفة.
- اعتبار النسخة Replica نسخة احتياطية:
FLUSHALLينتقل إليها فوراً، فخذ نسخاً من ملف RDB خارج السيرفر.
الخلاصة
- Redis يحفظ هياكل بيانات في الذاكرة، وكل أمر ذري، والجلسات Hash بعمر TTL، والعدادات
INCR، ولوحات الترتيب Sorted Set. - AOF يحفظ كل أمر ويخسر ثانية على الأكثر، وفي التجربة عادت كل المفاتيح بعد إعادة التشغيل، وRDB أصغر وأنسب للنسخ الاحتياطي.
- في 64 MB توقفت الكتابة عند 60 ألف جلسة مع
noeviction، وبقيت كل الجلسات النشطة مع LRU وLFU، وحمتvolatile-lruالمفتاح الذي بلا TTL. - Redis انتقل في 2024 إلى RSAL وSSPL ثم أضاف AGPLv3 في Redis 8، وValkey خرج من Redis 7.2.4 تحت Linux Foundation برخصة BSD-3.
- Valkey بديل مباشر في الأوامر الأساسية، ولكنه لم يقرأ ملف RDB من Redis 8.10 ولا يملك أوامر JSON وسياسة LRM دون وحدات إضافية.
دليلالتخزين المؤقت Caching بالتفصيل: الاستراتيجيات والإبطالكيف تختار نمط التخزين المؤقت المناسب، ومتى تبطل القيمة، وكيف تمنع انهيار قاعدة البيانات عندما ينتهي مفتاح مشهور.
دليلكيف يتذكرك الموقع بعد تسجيل الدخول؟ الجلسات وJWTبروتوكول HTTP لا يتذكر أحداً، فكيف يبقى المستخدم مسجلاً بين الصفحات، ومتى تختار الجلسة على السيرفر ومتى تختار JWT.
دليلعناقيد قواعد البيانات Database Clustering ومتى تحتاجهاماذا تعني كلمة Cluster في كل قاعدة بيانات، ومتى تحتاج نسخاً أو انتقالاً تلقائياً، ومتى يكفيك سيرفر واحد مع نسخ احتياطية جيدة.
دليلPostgreSQL لكل شيء: متى يكفيك ومتى تحتاج غيره؟كم عملاً يستطيع PostgreSQL واحد أن يقوم به في شركتك الناشئة قبل أن تحتاج Redis أو Elasticsearch، وما الإشارة التي تقول لك إن الوقت قد حان.
دليلهياكل البيانات Data Structures للمبتدئينلماذا تكون نفس العملية سريعة في هيكل بيانات وبطيئة في آخر، وأين تقابل كل هيكل في السيرفرات وقواعد البيانات.سجل التحديثات
- أكتوبر 2026: كتابة المقال، والتجربة على Redis 8.10.2 وRedis 7.2.16 وValkey 9.1.2 مع redis-py 6.4.0 في Docker Engine 29.8.0، والمعلومات من توثيق Redis وValkey وإعلانات الرخص كما قرأناها في 11 أكتوبر 2026.