تحسين أداء Redis
تحسين أداء 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)
# تساعد مساحات الأسماء في التنظيم ومطابقة الأنماط
# مفاتيح أقصر = استخدام أقل للذاكرة
SCAN مقابل KEYS - فرق أداء حرج
لا تستخدم أبدًا KEYS في الإنتاج - فهو يحظر 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
تحسين خط الأنابيب
يقلل خط الأنابيب من رحلات الشبكة عن طريق تجميع أوامر متعددة:
# 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 إجمالي
$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();
تجميع الاتصالات
إعادة استخدام الاتصالات بدلاً من إنشاء اتصالات جديدة لكل طلب:
# 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, # تمكين الاتصالات المستمرة
],
],
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
# الإخراج:
# 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
# إحصائيات تفصيلية لتخصيص الذاكرة
# تثبيت RMA
pip install rma
# إنشاء تقرير الذاكرة
rma --host 127.0.0.1 --port 6379 --types all
# الإخراج: توزيع تفصيلي للذاكرة حسب نمط المفتاح
سياسات الإخلاء
قم بتكوين Redis لإزالة المفاتيح تلقائيًا عند الوصول إلى حد الذاكرة:
# تعيين الحد الأقصى للذاكرة
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
مقايضات الاستمرارية
وازن بين المتانة والأداء عن طريق اختيار استراتيجية الاستمرارية الصحيحة:
# لا استمرارية (الأسرع، لا متانة)
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 للمتانة