ویرگول
ورودثبت نام
ابوالفضل وکیلی
ابوالفضل وکیلیinstagram : @a_vakily7
ابوالفضل وکیلی
ابوالفضل وکیلی
خواندن ۶ دقیقه·۵ ماه پیش

الگوهای غلط در استفاده از Redis

توسعه‌دهندگان فقط از Redis استفاده نمی‌کنند؛ آن را واقعاً دوست دارند. طبق نظرسنجی سالانه Stack Overflow در سال ۲۰۲۱، Redis برای پنجمین سال پیاپی به عنوان «محبوب‌ترین پلتفرم پایگاه‌داده» شناخته شده است.
با این حال، مهم است در نظر داشته باشیم که تنظیمات پیش‌فرض Redis لزوماً برای همه مناسب نیست. میلیون‌ها توسعه‌دهنده Redis را به خاطر سرعت و کارایی‌اش انتخاب می‌کنند، اما نکته حیاتی این است که اطمینان پیدا کنیم استفاده‌مان از آن درست و اصولی است.

«الگوی اشتباه» یا Antipattern در واقع به روش‌ها و راه‌حل‌هایی گفته می‌شود که در نگاه اول مناسب به نظر می‌رسند، اما در مرحله اجرا باعث پیچیدگی بیشتر کد و کاهش کارایی می‌شوند. در ادامه به مهم‌ترین الگوهای غلط در استفاده از Redis می‌پردازیم:


۱. اجرای پایگاه‌داده‌های بزرگ روی یک شارد یا یک نمونه Redis
وقتی یک پایگاه‌داده بزرگ را روی یک شارد یا یک نمونه از Redis اجرا می‌کنید، عملیات‌هایی مانند failover (تغییر خودکار سرور در صورت خرابی)، پشتیبان‌گیری و بازیابی، همگی زمان بیشتری خواهند برد.
بنابراین، همیشه توصیه می‌شود حجم هر شارد را در محدوده استاندارد نگه دارید. قاعده محافظه‌کارانه و رایج این است:

  • حداکثر ۲۵ گیگابایت داده

  • یا ۲۵ هزار عملیات بر ثانیه

در Redis Cloud اگر داده‌های شما بیش از ۲۵ گیگابایت باشد و تعداد عملیات نیز بالا باشد، شارد کردن می‌تواند کارایی را افزایش دهد. حتی با حجم کمتر عملیات، Redis می‌تواند تا ۵۰ گیگابایت داده را نیز مدیریت کند.

۱. استفاده از redis-py
کتابخانه redis-py از یک connection pool برای مدیریت اتصال‌ها به سرور Redis استفاده می‌کند. به‌طور پیش‌فرض، هر نمونه Redis که ایجاد کنید، یک connection pool اختصاصی خواهد داشت.
شما می‌توانید این رفتار را تغییر دهید و از یک connection pool موجود استفاده کنید. این کار با ارسال نمونه connection pool به پارامتر connection_pool کلاس Redis انجام می‌شود. این روش زمانی کاربرد دارد که بخواهید شاردینگ سمت کلاینت پیاده‌سازی کنید یا کنترل دقیق‌تری روی مدیریت اتصال‌ها داشته باشید:

pool = redis.ConnectionPool(host='localhost', port=6379, db=0) r = redis.Redis(connection_pool=pool)

۲. اتصال مستقیم به نمونه‌های Redis
وقتی تعداد زیادی کلاینت دارید، موجی از تلاش‌ها برای اتصال مجدد (Reconnect Flood) می‌تواند یک پردازش single threaded را از کار بیندازد و باعث failover شود.

برای جلوگیری از این مشکل، باید از ابزاری مناسب برای کاهش تعداد اتصال‌های باز به سرور Redis استفاده کنید.

به‌عنوان نمونه:

  • Redis Enterprise DMC Proxy می‌تواند با نقش پروکسی، تعداد اتصال‌ها به سرور کش شما را کاهش دهد.

  • Twemproxy یک پروکسی سبک و سریع است که با هدف کاهش تعداد اتصال‌های باز به سرورهای کش ساخته شده است. این ابزار همراه با ویژگی‌هایی مانند Protocol Pipelining و Sharding به شما کمک می‌کند معماری کش توزیع‌شده خود را به‌صورت افقی (Horizontal) مقیاس‌دهی کنید.


۳. بیش از یک شارد ثانویه (Redis OSS)
در Redis نسخه متن‌باز (Redis OSS) برای اجماع داده‌ها (Quorum) از مدل شاردبندی استفاده می‌شود. توصیه می‌شود حداقل ۳ نسخه از داده‌ها (دو شارد Replica برای هر شارد Master) داشته باشید تا از مشکل Split-Brain جلوگیری شود.
به‌طور خلاصه، Redis OSS با داشتن تعداد فردی از شاردها (یک Primary + دو Replica) این چالش را حل می‌کند.

در Redis Cloud این مشکل با تعداد فردی از نودها (Nodes) برطرف می‌شود و حتی با داشتن تنها دو نسخه از داده‌ها نیز از Split-Brain جلوگیری می‌کند که این کار از نظر هزینه به‌صرفه‌تر است. در صورت نیاز می‌توان از «Quorum-Only Node» استفاده کرد تا تعداد نودها فرد شود، بدون این که نود داده اضافه و پرهزینه‌ای ایجاد کنیم.


۴. اجرای عملیات‌ها به‌صورت تک‌به‌تک
اجرای چندین عملیات به‌صورت سری باعث افزایش سربار ارتباطی می‌شود. راه‌حل بهتر Pipelining است؛ یعنی ارسال چندین دستور پشت سر هم، بدون صبر کردن برای پاسخ هرکدام، و پردازش پاسخ‌ها در انتها.

Pipelining کاملاً سمت کلاینت پیاده‌سازی می‌شود و برای کاهش تأخیر پاسخ در شبکه‌های با Latency بالا استفاده می‌گردد. این روش با Buffering زمان رفت‌و‌برگشت داده در شبکه را کاهش می‌دهد. در اتصال به localhost این روش می‌تواند سرعت را تا ۵ برابر افزایش دهد و در ارتباطات اینترنتی کند حتی بیش از ۱۰۰ برابر بهبود ایجاد کند.


۵. کش‌کردن کلیدها بدون TTL
Redis در اصل یک ذخیره‌ساز کلید-مقدار است و می‌توان برای هر کلید زمان انقضا (TTL) تعیین کرد. با رسیدن این زمان، کلید به‌طور خودکار حذف می‌شود. بدون TTL، کلیدها انباشته شده و در نهایت منجر به Eviction خواهند شد.
پیشنهاد می‌شود برای تمام کلیدهای کش، TTL مشخص کنید. دستور TTL مدت زمان باقی‌مانده عمر یک کلید را برحسب ثانیه بازمی‌گرداند و به شما اجازه می‌دهد نظارت دقیقی روی چرخه عمر داده‌ها داشته باشید.


۶. حلقه بی‌پایان Redis Replication
اگر بخواهید یک پایگاه‌داده فعال و بسیار بزرگ را روی یک لینک کند یا اشباع‌شده replicate کنید، فرآیند Replication هیچ‌وقت تمام نمی‌شود، چون داده‌ها دائماً در حال تغییرند.
برای حل این مشکل باید بافرهای Slave و Client را برای replication کندتر بهینه‌سازی کنید.


۷. کلیدهای داغ (Hot Keys)
وقتی حجم زیادی از درخواست‌ها روی یک کلید خاص متمرکز می‌شود، همان نود یا شارد مسئول آن کلید زیر فشار شدیدی قرار می‌گیرد. به‌عنوان مثال، اگر خوشه Redis شما ۹۹ نود داشته باشد و یک کلید خاص در هر ثانیه یک میلیون بار درخواست شود، همه این یک میلیون درخواست به یک نود خواهند رفت، نه بین ۹۸ نود دیگر پخش شوند.

Redis ابزاری برای شناسایی کلیدهای داغ دارد:

redis-cli --hotkeys

بهترین راه‌حل، طراحی مناسب است تا این وضعیت اصلاً ایجاد نشود. می‌توانید داده را با کلیدهای مختلف و در شاردهای متفاوت ذخیره کنید یا از الگوریتم‌های هش برای توزیع درخواست‌ها استفاده کنید.


۸. استفاده از دستور KEYS
دستور KEYS تمام کلیدهای ذخیره‌شده را با یک الگو جستجو می‌کند و در پایگاه‌داده‌های بزرگ این کار بسیار کند و پرهزینه است (O(N) با N تعداد کلیدها). معادل این کار در SQL، اجرای SELECT * FROM ... بدون WHERE است.
به‌جای آن از دستور SCAN استفاده کنید که جستجو را در چند مرحله انجام می‌دهد و کل سرور را متوقف نمی‌کند. برای جستجو بر اساس محتوا نیز می‌توانید از Redis Search استفاده کنید.


۹. استفاده از Redis گذرا (Ephemeral Redis) به‌عنوان پایگاه‌داده اصلی
وقتی Redis را به‌عنوان پایگاه‌داده اصلی استفاده می‌کنید (نه فقط کش)، باید دسترس‌پذیری بالا (High Availability) و دوام داده (Durability) را تضمین کنید. در نسخه متن‌باز این کار با Redis Sentinel انجام می‌شود. در Redis Cloud این قابلیت به‌صورت پیش‌فرض وجود دارد. همچنین برای دوام، می‌توانید از AOF یا Snapshotting استفاده کنید.


۱۰. ذخیره JSON به‌صورت رشته (String)
ذخیره JSON به‌صورت رشته باعث مشکلاتی در هماهنگی بین سرویس‌ها و افزایش هزینه پردازش می‌شود. به‌جای آن از ساختار داده HASH یا ماژول Redis JSON استفاده کنید.


۱۱. نگاشت جدول یا JSON به HASH بدون توجه به الگوی کوئری
اگر تنها روش پرس‌وجو SCAN باشد، فیلترگذاری محدودی خواهید داشت. بهتر است داده را به‌صورت رشته ذخیره کنید و ایندکس‌های معکوس را با SET یا SORTED SET بسازید و به کلید اصلی ارجاع دهید.
همچنین استفاده از چند پایگاه‌داده در یک نمونه Redis (با دستور SELECT) یک ضدالگو است و بهتر است برای هر نیاز یک نمونه Redis اختصاصی داشته باشید.

برای داده‌های سری زمانی (Time Series) اگر تنها بر اساس ترتیب کوئری دارید، استفاده از ماژول Redis Time Series پیچیدگی اضافی است؛ به‌جای آن از SORTED SET با امتیاز (Score) زمان استفاده کنید.

با افتخار ترجمه شده از

https://redis.io/learn/howtos/antipatterns

redis
۱
۰
ابوالفضل وکیلی
ابوالفضل وکیلی
instagram : @a_vakily7
شاید از این پست‌ها خوشتان بیاید