Redis از طریق VPN کند به نظر میرسد: کاهش رفتوبرگشت بهازای هر درخواست
VPN یک فراخوانی راهدور Redis را محلی نمیکند. رفتوبرگشتها را بهازای هر درخواست بودجهبندی کنید، اتصالها را دوباره به کار بگیرید و خطوط لوله را از تراکنشها دور نگه دارید.
صفحهای که در برابر یک Redis محلی در 200 میلیثانیه پاسخ میدهد، وقتی مشتری پشت VPN مینشیند چهار ثانیه طول میکشد، در حالی که شمارندههای سرور بیکار میمانند. گزارش کند چیزی بالاتر از یک میلیثانیه نشان نمیدهد، نمودار CPU صاف است و نمونه بدون شکایتی به مشتریان دیگر خدمت میدهد. چیزی که تغییر کرده فاصله است، و آنچه فاصله را چند برابر میکند تعداد دفعاتی است که کد شما متوقف میشود و منتظر میماند. مسیر درخواست را از مشتری به بیرون طی کنید و راهحل تقریباً همیشه انتظارهای متوالی کمتر است، نه سرور سریعتر.
از مشتری شروع کنید، نه از سنجههای سرور
فرایند مشتری را بین اولین فرمان و آخرین فرمان تماشا کنید. اگر ردیابی یک پاسخ، یک مکث و سپس فرمان بعدی را نشان دهد، برای هر فرمان یک رفتوبرگشت کامل میپردازید و هیچ میزان از تنظیم سرور آن را تغییر نمیدهد. گزارش کند اینجا ابزار اشتباهی است، چون زمان اجرا را ثبت میکند و ورودی/خروجی ارتباطی را عمداً کنار میگذارد. گزارش کند پاک در کنار یک نقطه پایانی کند، امضای یک مشکل رفتوبرگشت است.
پیش از دست زدن به کد، خود مسیر را اندازه بگیرید. redis-cli -h redis.example.internal --latency پینگهای مکرر میفرستد و میانگین زمان درخواست و پاسخ را چاپ میکند که هزینه هر تبادل شماست. آن را در تعداد فرمانهای متوالی در یک اقدام کاربر ضرب کنید و یک کف برای نقطه پایانی دارید.
رفتوبرگشتهایی را بشمارید که یک اقدام کاربر واقعاً نیاز دارد
یک نقطه پایانی را بگیرید و هر فراخوانی Redis را به ترتیب بنویسید، از جمله آنهایی که درون یک ORM، میانافزار نشست یا جستجوی پرچم ویژگی پنهان شدهاند. بیشتر نقاط پایانی کند معلوم میشود بیست یا سی فراخوانی انجام میدهند جایی که سه فراخوانی کافی بود، و پنهانها معمولاً اکثریت هستند.
زنجیره وابستگی را نمیتوان جمع کرد: اگر فرمان دوم به کلیدی نیاز داشته باشد که اولی برمیگرداند، انتظار واقعی است و تنها گزینهها مدل داده متفاوت یا عملیاتی سمت سرور است که کل گام را یکجا بیان کند. خواندنهای مستقل مورد دیگری هستند، چون هیچ چیز شما را مجبور نمیکند پیش از فرستادن دومی منتظر پاسخ اول بمانید. پیش از هر ویرایشی هر فراخوانی را وابسته یا مستقل علامت بزنید و شکل راهحل آشکار میشود.
عددی که اهمیت دارد انتظارهای متوالی است، نه مجموع فرمانها. سی فرمان در یک دسته هنوز یک انتظار هزینه دارد.
فقط فرمانهایی را دسته کنید که به یکدیگر وابسته نیستند
خط لوله فرمانهای مستقل را در صف میگذارد و پاسخها را به ترتیب جمع میکند و N انتظار را به یکی تبدیل میکند. بیشتر کلاینتها آن را بهصورت بلوک، callback یا مدیر زمینه ارائه میدهند نه حالت اتصال جداگانه، پس 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 نشان میدهد آیا خود مسیر پایدار است، و زمانسنج درخواست خودتان نشان میدهد آیا نقطه پایانی بهتر شده است. اگر نقطه پایانی هنوز کند است در حالی که تاریخچه تأخیر صاف است، هزینه باقیمانده کار سمت سرور یا سریالسازی خودتان است، و گام بعدی نمایهای از هندلر است نه یک تغییر دستهبندی دیگر.