Redis والتخزين المؤقت المتقدم

تحسين أداء Redis

20 دقيقة الدرس 23 من 30

تحسين أداء Redis

تم تصميم Redis للأداء العالي، ولكن التكوين الصحيح وأفضل الممارسات ضرورية لتعظيم الإنتاجية وتقليل الكمون وتحسين استخدام الذاكرة في بيئات الإنتاج.

استراتيجيات تحسين الذاكرة

الذاكرة هي المورد الأكثر أهمية في Redis. يؤثر الاستخدام الفعال للذاكرة بشكل مباشر على الأداء والتكلفة:

تقنيات تحسين الذاكرة:
  • استخدام هياكل البيانات المناسبة: Hashes للكائنات، Sets للعناصر الفريدة، Sorted Sets مع النقاط
  • تمكين الضغط: استخدام الترميز المدمج في Redis للمجموعات الصغيرة
  • تعيين أوقات الانتهاء: منع تسربات الذاكرة باستخدام TTL
  • استخدام ترميزات موفرة للذاكرة: ziplist، intset، listpack
  • تجنب المفاتيح الكبيرة: تقسيم القيم الكبيرة إلى أجزاء أصغر
  • مراقبة تجزئة الذاكرة: إعادة تشغيل Redis إذا كانت التجزئة > 1.5
التحقق من استخدام الذاكرة:
# إجمالي استخدام الذاكرة
INFO memory

# استخدام الذاكرة حسب المفتاح
MEMORY USAGE mykey

# إحصائيات الذاكرة
used_memory_human: 2.50M
used_memory_peak_human: 3.12M
mem_fragmentation_ratio: 1.23

# العثور على أكبر المفاتيح
redis-cli --bigkeys

# تحليل مفصل للذاكرة
redis-cli --memkeys --memkeys-samples 1000

اصطلاحات تسمية المفاتيح

تسمية المفاتيح المتسقة تحسن التنظيم والأداء وكفاءة الذاكرة:

النمط الموصى به:
# التنسيق: object:id:field أو namespace:object:id
user:1000:name
user:1000:email
user:1000:settings

session:abc123:data
cache:homepage:html
rate_limit:api:user:1000

# استخدم النقطتين كفواصل (اصطلاح Redis)
# تساعد مساحات الأسماء في التنظيم ومطابقة الأنماط
# مفاتيح أقصر = استخدام أقل للذاكرة
نصيحة الذاكرة: أسماء المفاتيح تستهلك الذاكرة. المفتاح المسمى "u:1000:n" يستخدم ذاكرة أقل من "user:1000:name". وازن بين سهولة القراءة وكفاءة الذاكرة.

SCAN مقابل KEYS - فرق أداء حرج

لا تستخدم أبدًا KEYS في الإنتاج - فهو يحظر Redis أثناء فحص جميع المفاتيح:

❌ سيء - يحظر Redis:
KEYS user:*
# يحظر الخادم بأكمله حتى يكتمل
# تعقيد O(N) حيث N = إجمالي المفاتيح

✅ جيد - غير محظور:
SCAN 0 MATCH user:* COUNT 100
# يعيد المؤشر + دفعة من المفاتيح
# غير محظور، يمكن ترقيمه
# O(1) لكل استدعاء

# مثال تكرار SCAN
cursor="0"
while true; do
result=$(redis-cli SCAN $cursor MATCH user:* COUNT 100)
cursor=$(echo "$result" | head -1)
keys=$(echo "$result" | tail -n +2)
echo "$keys"
[ "$cursor" = "0" ] && break
done
تحذير حرج: يمكن أن يحظر أمر KEYS Redis لثوانٍ على قواعد البيانات التي تحتوي على ملايين المفاتيح. استخدم دائمًا SCAN أو SSCAN أو HSCAN أو ZSCAN بدلاً من ذلك.

تحسين خط الأنابيب

يقلل خط الأنابيب من رحلات الشبكة عن طريق تجميع أوامر متعددة:

بدون خط الأنابيب (بطيء):
# 1000 أمر = 1000 رحلة
for i in range(1000):
redis.set(f"key:{i}", f"value{i}")
# ~500ms مع 0.5ms كمون لكل أمر

مع خط الأنابيب (سريع):
# 1000 أمر = 1 رحلة
pipe = redis.pipeline()
for i in range(1000):
pipe.set(f"key:{i}", f"value{i}")
pipe.execute()
# ~10ms إجمالي
مثال خط الأنابيب PHP:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$pipe = $redis->multi(Redis::PIPELINE);
for ($i = 0; $i < 1000; $i++) {
$pipe->set("key:$i", "value$i");
}
$pipe->exec();

مثال خط الأنابيب Node.js:
const pipeline = redis.pipeline();
for (let i = 0; i < 1000; i++) {
pipeline.set(`key:${i}`, `value${i}`);
}
await pipeline.exec();
أداء خط الأنابيب: يمكن أن يحسن خط الأنابيب الإنتاجية بمقدار 5-10 أضعاف للعمليات الكبيرة. استخدمه للإدراج الجماعي أو القراءة الجماعية أو أي سيناريو به أوامر متسلسلة متعددة.

تجميع الاتصالات

إعادة استخدام الاتصالات بدلاً من إنشاء اتصالات جديدة لكل طلب:

تجميع الاتصالات PHP (Laravel):
# config/database.php
'redis' => [
'client' => 'predis',
'options' => [
'cluster' => env('REDIS_CLUSTER', 'redis'),
'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
],
'default' => [
'host' => env('REDIS_HOST', '127.0.0.1'),
'password' => env('REDIS_PASSWORD'),
'port' => env('REDIS_PORT', 6379),
'database' => env('REDIS_DB', 0),
'persistent' => true, # تمكين الاتصالات المستمرة
],
],
تجميع الاتصالات Node.js:
const Redis = require('ioredis');

const redis = new Redis({
host: '127.0.0.1',
port: 6379,
maxRetriesPerRequest: 3,
enableReadyCheck: true,
lazyConnect: false,
keepAlive: 30000 // الحفاظ على الاتصالات حية
});

# إعادة استخدام هذا الاتصال في جميع أنحاء التطبيق

أدوات تحليل الذاكرة

حدد عنق الزجاجة في الذاكرة وقم بتحسين التخزين:

redis-cli --bigkeys:
redis-cli --bigkeys
# الإخراج:
# Biggest string found: "cache:homepage" has 2048576 bytes
# Biggest list found: "queue:jobs" has 50000 items
# Biggest hash found: "user:1000" has 1000 fields

MEMORY DOCTOR:
MEMORY DOCTOR
# يوفر اقتراحات لتحسين الذاكرة

MEMORY STATS:
MEMORY STATS
# إحصائيات تفصيلية لتخصيص الذاكرة
محلل ذاكرة Redis (RMA):
# تثبيت RMA
pip install rma

# إنشاء تقرير الذاكرة
rma --host 127.0.0.1 --port 6379 --types all

# الإخراج: توزيع تفصيلي للذاكرة حسب نمط المفتاح

سياسات الإخلاء

قم بتكوين Redis لإزالة المفاتيح تلقائيًا عند الوصول إلى حد الذاكرة:

redis.conf:
# تعيين الحد الأقصى للذاكرة
maxmemory 2gb

# خيارات سياسة الإخلاء:
maxmemory-policy allkeys-lru

# السياسات:
# noeviction: إرجاع خطأ عند الوصول إلى حد الذاكرة
# allkeys-lru: إزالة المفاتيح الأقل استخدامًا مؤخرًا
# allkeys-lfu: إزالة المفاتيح الأقل استخدامًا بشكل متكرر
# allkeys-random: إزالة مفاتيح عشوائية
# volatile-lru: إزالة مفاتيح LRU مع تعيين TTL
# volatile-lfu: إزالة مفاتيح LFU مع تعيين TTL
# volatile-random: إزالة مفاتيح عشوائية مع TTL
# volatile-ttl: إزالة المفاتيح بأقصر TTL
اختيار السياسة: استخدم allkeys-lru للذاكرة المؤقتة حيث تكون جميع المفاتيح مرشحة للإخلاء. استخدم volatile-lru إذا كان يجب إخلاء المفاتيح ذات TTL فقط.

مقايضات الاستمرارية

وازن بين المتانة والأداء عن طريق اختيار استراتيجية الاستمرارية الصحيحة:

مقارنة الأداء:
# لا استمرارية (الأسرع، لا متانة)
save ""
appendonly no
# الأفضل لـ: ذاكرة تخزين مؤقت نقية، بيانات مؤقتة

# RDB فقط (أداء جيد، بعض فقدان البيانات)
save 900 1
save 300 10
save 60 10000
appendonly no
# الأفضل لـ: فقدان البيانات المحتمل (دقائق)

# AOF مع fsync everysec (متوازن)
appendonly yes
appendfsync everysec
# الأفضل لـ: الإنتاج مع الحد الأدنى من فقدان البيانات

# AOF مع fsync always (الأبطأ، الأكثر متانة)
appendonly yes
appendfsync always
# الأفضل لـ: بيانات حرجة لا تتطلب فقدان

سجل الاستعلام البطيء

حدد وقم بتحسين الأوامر البطيئة:

تكوين السجل البطيء:
# redis.conf
# تسجيل الاستعلامات الأبطأ من 10ms
slowlog-log-slower-than 10000

# الاحتفاظ بآخر 128 استعلام بطيء
slowlog-max-len 128

عرض السجل البطيء:
# الحصول على آخر 10 استعلامات بطيئة
SLOWLOG GET 10

# مثال الإخراج:
1) 1) (integer) 12
2) (integer) 1634567890
3) (integer) 15234
4) 1) "KEYS"
2) "user:*"

# إعادة تعيين السجل البطيء
SLOWLOG RESET

مراقبة الكمون

تتبع وتشخيص ارتفاعات الكمون:

تمكين مراقبة الكمون:
# مراقبة الأحداث التي تستغرق >100ms
CONFIG SET latency-monitor-threshold 100

# عرض أحداث الكمون
LATENCY LATEST
LATENCY HISTORY command
LATENCY DOCTOR

# رسم بياني للكمون
LATENCY GRAPH command

ضبط التكوين

قم بتحسين تكوين Redis لعبء العمل الخاص بك:

ضبط الأداء:
# redis.conf

# تعطيل الصفحات الضخمة الشفافة (Linux)
# echo never > /sys/kernel/mm/transparent_hugepage/enabled

# TCP backlog
tcp-backlog 511

# الحد الأقصى للعملاء
maxclients 10000

# مهلة الاتصالات الخاملة
timeout 300

# TCP keepalive
tcp-keepalive 300

# نسخ متماثل أسرع
repl-diskless-sync yes
repl-diskless-sync-delay 5

# تحرير كسول (حذف غير محظور)
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
التحرير الكسول: يتيح الحذف غير المحظور للمفاتيح في مؤشرات الترابط في الخلفية، مما يمنع الحظر عند حذف المفاتيح الكبيرة (القوائم الكبيرة، الهاشات، المجموعات).

ملخص أفضل الممارسات

قائمة التحقق من الأداء:
  • ✅ استخدام خطوط الأنابيب للعمليات الكبيرة
  • ✅ استخدام SCAN بدلاً من KEYS
  • ✅ تمكين تجميع الاتصالات
  • ✅ تعيين TTLs مناسبة لمنع تسربات الذاكرة
  • ✅ استخدام هياكل بيانات فعالة (Hashes > Strings للكائنات)
  • ✅ مراقبة الذاكرة باستخدام --bigkeys
  • ✅ تكوين maxmemory وسياسة الإخلاء
  • ✅ تمكين التحرير الكسول للحذف غير المحظور
  • ✅ مراقبة السجل البطيء وتحسين الاستعلامات البطيئة
  • ✅ استخدام أسماء مفاتيح أقصر لتوفير الذاكرة
  • ✅ تعطيل الاستمرارية لأحمال العمل في ذاكرة التخزين المؤقت النقية
  • ✅ استخدام AOF مع everysec للمتانة
تمرين: حلل مثيل Redis: 1) قم بتشغيل redis-cli --bigkeys للعثور على أكبر المفاتيح، 2) تحقق من SLOWLOG للاستعلامات البطيئة، 3) تحقق من mem_fragmentation_ratio باستخدام INFO memory، 4) اختبر أداء خط الأنابيب مقابل الأوامر المتسلسلة مع 10,000 عملية SET وقياس الفرق في الوقت.