> ## Content Index
> Fetch the complete content index at: https://arabroot.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Redis وبديله المفتوح Valkey: التخزين المؤقت والجلسات
- URL: https://arabroot.io/articles/redis-و-valkey-التخزين-المؤقت-والجلسات/
- Published: 2026-10-12T10:30:00.000Z
- Updated: 2026-10-11T11:18:18.000Z
- Description: كيف تستخدم Redis للجلسات والعدادات دون أن تمتلئ الذاكرة، وماذا تعني رخصته الجديدة، ومتى يكفيك Valkey بدلاً منه.
- Author: فريق عرب رووت
- Tags: الأدلة التقنية, هندسة البرمجيات وتصميم الأنظمة, قواعد البيانات, الاستضافة الذاتية

أغلب التطبيقات التي تستضيفها تطلب منك في ملف 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، فشرحناها في [مقال التخزين المؤقت](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%85%D8%A4%D9%82%D8%AA-caching-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B1%D8%A7%D8%AA%D9%8A%D8%AC%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A7%D8%A8%D8%B7%D8%A7%D9%84/)، وهنا نركز على الأداة.

## ما هو Redis؟

Redis قاعدة بيانات تحفظ كل بياناتها في الذاكرة RAM، وتستقبل الأوامر عبر الشبكة على المنفذ 6379، وتنفذها واحداً بعد الآخر في خيط رئيسي واحد، ولذلك كل أمر ذري Atomic بطبيعته، فلا يمكن أن يتداخل أمران على نفس المفتاح. والسرعة تأتي من أن القراءة من الذاكرة لا تنتظر القرص، والثمن أن حجم البيانات محدود بحجم الذاكرة، وأن ما في الذاكرة يضيع عند إعادة التشغيل إلا إذا طلبت حفظه على القرص كما سوف نرى.

والذي يجعله أكثر من مخزن مفاتيح وقيم أن القيمة ليست نصاً فقط، وإنما هياكل بيانات يعرفها السيرفر ويعدلها بأمر واحد، وهي نفس الهياكل التي شرحناها في [مقال هياكل البيانات](https://arabroot.io/articles/%D9%87%D9%8A%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/):

| النوع                       | الأوامر          | الاستخدام المعتاد                 |
| --------------------------- | ---------------- | --------------------------------- |
| النص String                 | SET وGET وINCR   | نتيجة مخزنة مؤقتاً، وعداد         |
| الجدول Hash                 | HSET وHGETALL    | جلسة مستخدم بحقولها               |
| القائمة List                | LPUSH وBRPOP     | طابور مهام بسيط                   |
| المجموعة Set                | SADD وSISMEMBER  | من شاهد هذا المنشور               |
| المجموعة المرتبة Sorted Set | ZADD وZREVRANGE  | لوحة الترتيب، وتحديد معدل الطلبات |
| التدفق Stream               | XADD وXREADGROUP | سجل أحداث مع مجموعات مستهلكين     |

ولاحظ أن كل مفتاح يمكن أن يكون له عمر TTL بالثواني، وعندما ينتهي يحذفه السيرفر وحده، وهذه الخاصية هي أساس الجلسات والتخزين المؤقت معاً.

## الاستخدامات اليومية: الجلسات والعدادات ولوحات الترتيب

شرحنا في [مقال الجلسات](https://arabroot.io/articles/%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-%D9%88%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%88-jwt-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#session-scaling) لماذا تحتاج مخزناً مشتركاً للجلسات عندما يعمل التطبيق على أكثر من نسخة، وRedis هو الخيار الأشهر لهذا. والسكربت التالي يبين الاستخدامات الثلاثة الأكثر شيوعاً، وسوف نشغله على Redis وValkey في التجربة:

```python
# 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](https://redis.io/docs/latest/operate/oss%5Fand%5Fstack/management/persistence/?ref=arabroot.io) يذكر طريقتين، والصورة التالية تبين الفرق:

![لوحتان: في الأولى RDB snapshot حيث يأخذ Redis بعملية fork نسخة كاملة من الذاكرة إلى ملف dump الساعة 10:00 ثم 10:05، ثم يتعطل الساعة 10:09 فتضيع الكتابات بعد 10:05، والملف صغير والتشغيل سريع، وفي الثانية AOF حيث يكتب كل أمر SET وINCR وZINCRBY وEXPIRE في ملف ويحفظه على القرص كل ثانية، فيضيع ثانية واحدة على الأكثر، وفي التجربة عادت كل المفاتيح بعد إعادة التشغيل](https://arabroot.io/content/images/2026/10/redis-valkey-03-persistence.webp)

RDB يأخذ صورة كاملة كل فترة، وAOF يسجل كل أمر ويحفظه كل ثانية

- **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` التي تحدد ماذا يفعل عندما يصل إلى الحد، وأهمها بحسب [توثيق الإخراج](https://redis.io/docs/latest/develop/reference/eviction/?ref=arabroot.io):

- **`noeviction`:** لا يحذف شيئاً، ويرفض كل أمر يضيف بيانات بخطأ، والقراءة تستمر. وهي الافتراضية.
- **`allkeys-lru`:** يحذف المفاتيح الأقل استخداماً مؤخراً Least Recently Used من كل المفاتيح، والتوثيق يعتبرها الاختيار الافتراضي الجيد لل Cache.
- **`allkeys-lfu`:** يحذف الأقل استخداماً من حيث عدد المرات Least Frequently Used.
- **`volatile-lru` وأخواتها:** تحذف فقط من المفاتيح التي لها TTL، وإذا لم يوجد مفتاح له TTL تتصرف مثل `noeviction`.

ولاحظ أن LRU في Redis تقريبي، فهو يأخذ عينة صغيرة من المفاتيح (5 افتراضياً بالإعداد `maxmemory-samples`) ويحذف الأقدم بينها، ولهذا سوف ترى في التجربة أن بعض المفاتيح القديمة بقيت. والصورة التالية تلخص ما خرج من التجربة:

![أربع بطاقات لسياسات الإخراج على Redis بحد 64 MB: noeviction توقفت الكتابة عند 60072 جلسة بخطأ used memory أكبر من maxmemory ولم يحذف شيء وبقي مفتاح الإعدادات، وallkeys-lru كتب كل 120000 وحذف 60346 مفتاحاً وبقيت كل الجلسات النشطة 2000 من 2000 وبقي 341 من 2000 من الجلسات القديمة وحذف مفتاح الإعدادات، وvolatile-lru حذف فقط المفاتيح التي لها TTL وبقيت النشطة وبقي 321 من القديمة وبقي مفتاح الإعدادات، وallkeys-lfu حذف 60337 وبقيت النشطة و164 من القديمة وحذف مفتاح الإعدادات](https://arabroot.io/content/images/2026/10/redis-valkey-02-eviction.webp)

نفس 120 ألف جلسة على ذاكرة 64 MB: سياسة الإخراج تقرر من يبقى ومن يخرج، ومن يحصل على خطأ

## النسخ المتماثل وSentinel

شرحنا Sentinel وانتقال الرئيسي تلقائياً بتجربة كاملة على Valkey في [مقال عناقيد قواعد البيانات](https://arabroot.io/articles/%D8%B9%D9%86%D8%A7%D9%82%D9%8A%D8%AF-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/#lab-sentinel)، والخلاصة هنا: نسخة رئيسية تكتب، ونسخ تتبعها بالأمر `REPLICAOF`، والنسخ غير متزامن Asynchronous، فقد تضيع آخر كتابات قليلة عند الانتقال. وSentinel ثلاث عمليات صغيرة أو أكثر تراقب الرئيسي وتتفق على أنه توقف، ثم ترقي نسخة وتخبر التطبيق بعنوانها الجديد كما في [توثيق Sentinel](https://valkey.io/topics/sentinel/?ref=arabroot.io). وأما Cluster فهو لتوزيع البيانات على عدة سيرفرات عندما لا تكفيها ذاكرة سيرفر واحد، وأغلب الاستضافات الذاتية لا تحتاجه. والنسخ المتماثل هو أيضاً الطريق الطبيعي للانتقال من Redis إلى Valkey دون توقف، ولكن بشرط سوف نراه في التجربة.

## قصة الرخصة: لماذا ظهر Valkey؟

كان Redis منذ بدايته تحت رخصة BSD-3 المتساهلة، ثم في 20 مارس 2024 [أعلنت شركة Redis](https://redis.io/blog/redis-adopts-dual-source-available-licensing/?ref=arabroot.io) أن كل إصدار بدءاً من 7.4 سوف يكون تحت رخصتين يختار المستخدم إحداهما: RSALv2 أو SSPLv1، وكلاهما ليست رخصة مفتوحة المصدر بتعريف OSI كما يعترف الإعلان نفسه، والهدف المعلن منع الشركات السحابية من بيع Redis كخدمة دون اتفاق مع الشركة. وبعد ثمانية أيام، في 28 مارس 2024، [أطلقت Linux Foundation مشروع Valkey](https://www.linuxfoundation.org/press/linux-foundation-launches-open-source-valkey-community?ref=arabroot.io)، وهو نسخة Fork من Redis 7.2.4 تحت BSD-3، بدعم من AWS وGoogle Cloud وOracle وEricsson وSnap، وقاده عدد من مطوري Redis السابقين. ثم في 1 مايو 2025 [أضافت Redis رخصة AGPLv3](https://redis.io/blog/agplv3/?ref=arabroot.io) خياراً ثالثاً بدءاً من Redis 8، ودمجت فيه ما كان في Redis Stack مثل JSON والسلاسل الزمنية ومحرك البحث. والصورة التالية تبين ذلك:

![محور زمني بخطين: خط Redis بثلاث نقاط، حتى 7.2 تحت BSD-3، ثم 7.4 في مارس 2024 تحت RSALv2 أو SSPLv1، ثم 8.0 في مايو 2025 تحت RSALv2 أو SSPLv1 أو AGPLv3، وخط Valkey يتفرع من 7.2.4 تحت Linux Foundation في 28 مارس 2024 تحت BSD-3، ثم 8.0 و8.1 في 2024 و2025، ثم 9.0 و9.1 وما زال تحت BSD-3](https://arabroot.io/content/images/2026/10/redis-valkey-01-license.webp)

Redis انتقل من BSD إلى رخص المصدر المتاح ثم أضاف AGPL، وValkey بقي على BSD من نقطة التفرع

فماذا يعني هذا لك إذا كنت تستضيف تطبيقاتك بنفسك؟ بحسب أسئلة الإعلان، استخدام Redis داخل شركتك أو خلف تطبيقك مسموح تحت RSALv2 وSSPLv1، والممنوع أن تقدم Redis نفسه خدمة منافسة لمنتجات الشركة. وتحت AGPLv3 تستطيع أن تفعل أي شيء بشرط أنك إذا عدلت كود Redis وقدمته للمستخدمين عبر الشبكة تنشر تعديلاتك، وشرحنا معنى هذا في [قسم Copyleft في مقال الرخص](https://arabroot.io/articles/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7%D8%AA-%D9%85%D9%81%D8%AA%D9%88%D8%AD%D8%A9-%D8%A7%D9%84%D9%85%D8%B5%D8%AF%D8%B1-%D9%88%D8%AA%D8%B1%D8%A7%D8%AE%D9%8A%D8%B5%D9%87%D8%A7/#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.

### ملف التشغيل

```yaml
# 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:
```

⚠️

لا توجد كلمة مرور في هذا الإعداد لأنه مختبر على 127.0.0.1\. في الإنتاج لا تقم بنشر المنفذ 6379 على الإنترنت أبداً، وأنشئ مستخدمين بصلاحيات محدودة عبر [ACL](https://valkey.io/topics/acl/?ref=arabroot.io)، والسبب أن من يصل إلى Redis بلا كلمة مرور يقرأ كل الجلسات، ويستطيع بأوامر الإعداد أن يكتب ملفات على السيرفر كما يحذر [توثيق الأمان](https://redis.io/docs/latest/operate/oss%5Fand%5Fstack/management/security/?ref=arabroot.io).

```bash
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
```

والمخرج سوف يكون كما يلي:

```text
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:

```bash
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
```

والمخرج:

```text
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، ثم يحسب من بقي:

```python
# 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)
```

```bash
for p in noeviction allkeys-lru volatile-lru allkeys-lfu; do docker exec lab-redis-app python /lab/eviction.py redis $p; done
```

والمخرج على Redis سوف يكون كما يلي:

```text
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 كانت الأرقام قريبة جداً:

```text
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 ثم نرقيه:

```bash
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
```

والمخرج:

```text
role:slave
master_link_status:down
# Can't handle RDB format version 15
# Failed to load RDB
```

Redis 8.10 يرسل البيانات بصيغة RDB رقم 15، وValkey 9.1 لا يقرأ هذه الصيغة، والسبب أن المشروعين افترقا منذ 2024 وكل واحد يطور صيغة ملفاته. ونفس المحاولة من Redis 7.2.16، وهو آخر خط تحت BSD، نجحت مباشرة:

```text
role:slave
master_link_status:up
10000
omar
3350
ahmed
3180
```

وهناك فرقان آخران ظهرا في التجربة:

```text
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](https://github.com/valkey-io/valkey-json?ref=arabroot.io) تأتي مع ال Docker Image المسمى [valkey-bundle](https://valkey.io/topics/valkey-bundle/?ref=arabroot.io). والخلاصة أن Valkey بديل مباشر لـ Redis 7.2 ولكل تطبيق يستخدم الأوامر الأساسية، وليس بديلاً مباشراً لكل ما أضيف في Redis 8، فإذا كنت على Redis 8 وتريد الانتقال فلا تعتمد على ملف RDB أو النسخ المتماثل، وانقل البيانات من التطبيق نفسه، أو اترك ال Cache والجلسات تبنى من جديد في Valkey إذا كان خروج المستخدمين مرة واحدة مقبولاً.

### حذف المختبر

```bash
docker compose -p lab-redis down -v
docker rm -f lab-redis-old
```

## Redis أم Valkey؟

### Redis

**نقاط القوة:** الأصل الذي تختبر عليه أغلب المكتبات، وRedis 8 فيه JSON والسلاسل الزمنية ومحرك البحث والمتجهات Vector Sets في الحزمة نفسها، وخيار AGPLv3 رخصة مفتوحة معترف بها، وميزات جديدة مثل سياسة LRM وأوامر BACKUP.

**نقاط الضعف:** شركة واحدة تملك الكود وغيرت رخصته مرتين في سنة، والرخص الأخرى ليست مفتوحة، وAGPL قد لا تقبلها سياسة بعض الشركات، وصيغة ملفاته لم تعد تقرأ في Valkey.

### Valkey

**نقاط القوة:** BSD-3 تحت Linux Foundation ولا تملكه شركة واحدة، وبديل مباشر لكل ما كان في Redis 7.2، ومدعوم من مزودي السحابة الكبار، ومتوفر في مستودعات التوزيعات مثل [حزمة valkey-server في Debian 13](https://packages.debian.org/trixie/valkey-server?ref=arabroot.io).

**نقاط الضعف:** ميزات Redis 8 الجديدة ليست فيه أو في وحدات منفصلة، ولا يقرأ ملفات RDB الحديثة من Redis، وبعض التطبيقات الجاهزة توثق Redis فقط فتختبر أنت التوافق.

- **تطبيق جاهز يحتاج Cache أو جلسات أو طابور:** Valkey يكفي ويعمل بنفس الإعداد، كما فعلنا في مقالات سابقة مثل [مقال العناقيد](https://arabroot.io/articles/%D8%B9%D9%86%D8%A7%D9%82%D9%8A%D8%AF-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/).
- **تحتاج JSON أو البحث أو المتجهات داخل نفس السيرفر:** Redis 8، أو valkey-bundle بعد أن تختبر الأوامر التي تحتاجها.
- **تبني منتجاً تبيعه ويضم قاعدة البيانات:** Valkey لتجنب أي سؤال عن الرخصة.
- **تريد كل شيء في قاعدة واحدة دون سيرفر إضافي:** اقرأ [قسم Cache في مقال PostgreSQL لكل شيء](https://arabroot.io/articles/postgresql-%D9%84%D9%83%D9%84-%D8%B4%D9%8A%D8%A1-%D9%85%D8%AA%D9%89-%D8%AA%D9%83%D9%81%D9%8A%D9%83-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%AD%D8%AF%D8%A9/#cache) قبل أن تضيف 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 دون وحدات إضافية.

[![](https://arabroot.io/content/images/2026/10/caching-strategies-cover-cover.webp)دليلالتخزين المؤقت Caching بالتفصيل: الاستراتيجيات والإبطالكيف تختار نمط التخزين المؤقت المناسب، ومتى تبطل القيمة، وكيف تمنع انهيار قاعدة البيانات عندما ينتهي مفتاح مشهور.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%85%D8%A4%D9%82%D8%AA-caching-%D8%A7%D9%84%D8%A7%D8%B3%D8%AA%D8%B1%D8%A7%D8%AA%D9%8A%D8%AC%D9%8A%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A7%D8%A8%D8%B7%D8%A7%D9%84/)[![](https://arabroot.io/content/images/2026/10/sessions-cookies-jwt-cover-cover.webp)دليلكيف يتذكرك الموقع بعد تسجيل الدخول؟ الجلسات وJWTبروتوكول HTTP لا يتذكر أحداً، فكيف يبقى المستخدم مسجلاً بين الصفحات، ومتى تختار الجلسة على السيرفر ومتى تختار JWT.](https://arabroot.io/articles/%D8%A7%D9%84%D8%AC%D9%84%D8%B3%D8%A7%D8%AA-%D9%88%D9%85%D9%84%D9%81%D8%A7%D8%AA-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-%D8%A7%D9%84%D8%A7%D8%B1%D8%AA%D8%A8%D8%A7%D8%B7-%D9%88-jwt-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/db-clustering-cover-cover.webp)دليلعناقيد قواعد البيانات Database Clustering ومتى تحتاجهاماذا تعني كلمة Cluster في كل قاعدة بيانات، ومتى تحتاج نسخاً أو انتقالاً تلقائياً، ومتى يكفيك سيرفر واحد مع نسخ احتياطية جيدة.](https://arabroot.io/articles/%D8%B9%D9%86%D8%A7%D9%82%D9%8A%D8%AF-%D9%82%D9%88%D8%A7%D8%B9%D8%AF-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)[![](https://arabroot.io/content/images/2026/10/postgres-for-everything-cover-cover.webp)دليلPostgreSQL لكل شيء: متى يكفيك ومتى تحتاج غيره؟كم عملاً يستطيع PostgreSQL واحد أن يقوم به في شركتك الناشئة قبل أن تحتاج Redis أو Elasticsearch، وما الإشارة التي تقول لك إن الوقت قد حان.](https://arabroot.io/articles/postgresql-%D9%84%D9%83%D9%84-%D8%B4%D9%8A%D8%A1-%D9%85%D8%AA%D9%89-%D8%AA%D9%83%D9%81%D9%8A%D9%83-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%88%D8%A7%D8%AD%D8%AF%D8%A9/)[![](https://arabroot.io/content/images/2026/10/data-structures-cover-cover.webp)دليلهياكل البيانات Data Structures للمبتدئينلماذا تكون نفس العملية سريعة في هيكل بيانات وبطيئة في آخر، وأين تقابل كل هيكل في السيرفرات وقواعد البيانات.](https://arabroot.io/articles/%D9%87%D9%8A%D8%A7%D9%83%D9%84-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D9%84%D9%84%D9%85%D8%A8%D8%AA%D8%AF%D8%A6%D9%8A%D9%86/)

## سجل التحديثات

- أكتوبر 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.