Redis عبر VPN يبدو بطيئًا: تقليل رحلات الذهاب والعودة لكل طلب
لا يحوّل VPN نداء Redis البعيد إلى محلي. احسب رحلات الذهاب والعودة لكل طلب، وأعد استخدام الاتصالات، وأبقِ خطوط الأنابيب بعيدًا عن المعاملات.
صفحة تستجيب في 200 مللي ثانية مقابل Redis محلي تستغرق أربع ثوانٍ بمجرد أن يجلس العميل خلف VPN، بينما تبقى عدادات الخادم خاملة. لا يُظهر السجل البطيء شيئًا يتجاوز ميلي ثانية واحدة، ومخطط المعالج مسطح، والخادم يخدم عملاء آخرين دون شكوى. الذي تغيّر هو المسافة، والشيء الذي يضاعف المسافة هو عدد المرات التي يتوقف فيها كودك وينتظر. تتبَّع مسار الطلب من العميل إلى الخارج وستجد أن الحل دائمًا تقريبًا هو انتظارات متتالية أقل بدلًا من خادم أسرع.
ابدأ من العميل، لا من مقاييس الخادم
راقب عملية العميل بين الأمر الأول والأمر الأخير. إذا أظهر التتبع ردًا ثم توقفًا ثم الأمر التالي، فأنت تدفع رحلة كاملة لكل أمر ولن يغيّر أي قدر من ضبط الخادم ذلك. السجل البطيء أداة خاطئة هنا، لأنه يسجل زمن التنفيذ ويستبعد عمدًا إدخال/إخراج الاتصال. سجل بطيء نظيف بجانب نقطة نهاية بطيئة هو بصمة مشكلة رحلات ذهاب وعودة.
قِس المسار نفسه قبل لمس الكود. يرسل redis-cli -h redis.example.internal --latency طلبات PING متكررة ويطبع متوسط زمن الطلب والرد، وهو تكلفتك لكل تبادل. اضرب ذلك في عدد الأوامر المتتالية في إجراء مستخدم واحد وستحصل على حد أدنى لنقطة النهاية.
احسب الرحلات التي يحتاجها إجراء مستخدم واحد فعليًا
خذ نقطة نهاية واحدة واكتب كل نداء Redis بالترتيب، بما في ذلك النداءات المخفية داخل ORM أو وسيط جلسة أو بحث عن علامة ميزة. تتضح أن معظم نقاط النهاية البطيئة تقوم بعشرين أو ثلاثين نداءً حيث تكفي ثلاثة، وأن المخفية هي الغالبية عادةً.
لا يمكن طيّ سلسلة التبعية: إذا كان الأمر الثاني يحتاج المفتاح الذي يعيده الأول، فالانتظار حقيقي والخيارات الوحيدة هي نموذج بيانات مختلف أو عملية على الخادم تعبّر عن الخطوة كاملة دفعة واحدة. القراءات المستقلة حالة مختلفة، لأن لا شيء يجبرك على انتظار الرد الأول قبل إرسال الثاني. صنّف كل نداء كتبعية أو مستقل قبل أن تعدّل أي شيء، وسيبدو شكل الحل واضحًا.
الرقم المهم هو الانتظارات المتتالية، لا مجموع الأوامر. ثلاثون أمرًا في دفعة واحدة تكلّف انتظارًا واحدًا.
جمّع فقط الأوامر التي لا تعتمد على بعضها
يضع خط الأنابيب الأوامر المستقلة في قائمة انتظار ويجمع الردود بالترتيب، محوّلًا N انتظارًا إلى واحد. تعرضه معظم العملاء ككتلة أو دالة رد نداء أو مدير سياق بدلًا من وضع اتصال منفصل، لذا تحقق من واجهة API التي توفرها النسخة المثبّتة لديك. يكبر المكسب مع زمن الرحلة، وهذا بالضبط سبب أهميته على VPN وعدم ظهوره تقريبًا على localhost.
import redis
r = redis.Redis(host="redis.example.internal", port=6379, socket_timeout=2)
pipe = r.pipeline(transaction=False)
for key in ("user:1001", "user:1002", "user:1003"):
pipe.get(key)
print(pipe.execute())
مرّر transaction=False عندما تريد التجميع فقط. مع الإعداد الافتراضي يلفّ العميل الدفعة في MULTI وEXEC، مما يجعلها ذرية ويغيّر ما يمكن للعملاء الآخرين ملاحظته أثناء التنفيذ. الذرية قرار صحة لا مفتاح أداء، وخط الأنابيب ليس معاملة لمجرد أن كليهما يقلل الرحلات.
اقرأ كل رد بدلًا من إرسال الدفعة فقط. يمكن أن يعيد أمر ما خطأ بينما تكتمل الدفعة ككل، والعميل الذي يتخلص من قائمة الردود يحوّل كتابة فاشلة إلى كتابة صامتة. قارن طول قائمة الردود بعدد الأوامر التي أدرجتها.
أبقِ الاتصال حيًا بين الإجراءات
كل اتصال جديد يدفع ثمن تحليل الاسم ومصافحة TCP ومصافحة TLS وAUTH، وعبر VPN كل واحد من هذه رحلة لا يمكنك تجميعها بعيدًا. أنشئ العميل مرة واحدة لكل عملية وأعد استخدامه، أو استخدم التجمع الذي توفره مكتبتك بحجم محدود. إعادة الاتصال لكل طلب هي ثاني أكثر الأسباب شيوعًا لهذه العَرَض بعد الانتظار لكل أمر.
أبقِ اسم المضيف الخاص في الإعدادات بدلًا من عنوان حرفي. التحقق من الشهادة وهوية الخدمة لا يزالان ساريين على شبكة خاصة، وتثبيت عنوان IP ينكسر في اللحظة التي يعيد فيها المزود ترقيم شبكة فرعية. إذا كان تحليل الاسم هو الجزء البطيء، فأصلح مسار المحلل بدلًا من سلسلة الاتصال.
اضبط مهلة مقبس صريحة حتى تفشل النفق المتعطل بسرعة بدلًا من تعليق عامل. ثم تأكد من أن التجمع يُعاد استخدامه فعلًا بتسجيل إنشاء الاتصالات في العميل.
قدّر حجم الدفعة قبل أن تصبح مشكلة ذاكرة
يحتفظ Redis بالردود المدرجة طوال مدة الدفعة، ويحتفظ العميل بالنتيجة المحللة بعدها. خط أنابيب من عشرة آلاف قيمة كبيرة يقايض انتظارات الشبكة بارتفاعات في الذاكرة وتوقفات طويلة على الطرفين.
اختر حجم الدفعة وفق حجم الاستجابة لا عدد الأوامر. بضع مئات من الأوامر الصغيرة في دفعة واحدة مريحة عادةً، بينما مئة حمولة بحجم عدة كيلوبايت ليست كذلك. قسّم بالبايتات وكذلك بالعدد، وأبقِ كل دفعة داخل ميزانية زمن الاستجابة التي تملكها نقطة النهاية فعليًا.
قِس من الطرف إلى الطرف بعد التغيير: يُظهر redis-cli -h redis.example.internal --latency-history ما إذا كان المسار نفسه مستقرًا، ويُظهر مؤقت الطلب الخاص بك ما إذا كانت نقطة النهاية قد تحسنت. إذا بقيت نقطة النهاية بطيئة بينما تاريخ زمن الاستجابة مسطح، فالتكلفة المتبقية هي عمل على الخادم أو تسلسلك الخاص، والخطوة التالية هي أخذ ملف تعريف للمعالج بدلًا من تغيير آخر في التجميع.