Redis یک پایگاه‌داده‌ی کلید-مقدار است که داده را در حافظه‌ی RAM نگه می‌دارد، نه روی دیسک. به همین دلیل خواندن و نوشتن در آن معمولاً زیر یک میلی‌ثانیه طول می‌کشد. کاربرد اصلی‌اش جایی است که سرعت مهم‌تر از نگهداری بلندمدت است: کش کردن نتیجه‌ی کوئری‌های سنگین، نگهداری سشن کاربران، صف کارهای پس‌زمینه، شمارنده‌ها و محدود کردن تعداد درخواست.

Redis معمولاً جایگزین MySQL یا PostgreSQL نیست؛ کنار آن‌ها می‌نشیند. پایگاه‌داده‌ی اصلی منبع حقیقت است و Redis لایه‌ای سریع برای چیزهایی که یا موقتی‌اند یا می‌شود دوباره ساختشان. در ادامه می‌بینیم Redis دقیقاً به چه دردی می‌خورد، چطور با Docker اجرایش کنیم، چطور امنش کنیم و کی اصلاً لازمش نداریم.

Redis چطور کار می‌کند

هر چیزی در Redis یک کلید دارد، مثل user:42:profile، و یک مقدار. تفاوتش با یک دیکشنری ساده در این است که مقدار می‌تواند ساختار داده‌ی کامل باشد (لیست، مجموعه، هش و...) و Redis برای هر کدام دستورهای اتمی دارد. «اتمی» یعنی اگر صد درخواست هم‌زمان یک شمارنده را زیاد کنند، نتیجه دقیقاً صد واحد بیشتر است.

دو ویژگی دیگر هم مهم است:

  • TTL: هر کلید می‌تواند تاریخ انقضا داشته باشد و خودش پاک شود. برای کش و سشن عالی است.
  • تک‌نخی بودن اجرای دستورها: دستورها یکی‌یکی اجرا می‌شوند، پس مسئله‌ی هم‌زمانی ساده می‌شود. در عوض، یک دستور سنگین مثل KEYS * روی میلیون‌ها کلید همه را معطل می‌کند.

کاربردهای اصلی Redis

کش

رایج‌ترین کاربرد. نتیجه‌ی یک کوئری یا محاسبه‌ی سنگین را برای مدتی در Redis می‌گذارید و درخواست‌های بعدی از آنجا می‌خوانند. اینکه چه چیزی را و چقدر کش کنید، موضوع مقاله‌ی کش در لاراول؛ کجا و تا کی است.

سشن

وقتی برنامه روی بیش از یک سرور اجرا می‌شود، سشن‌های فایلی جواب نمی‌دهند، چون هر سرور فایل‌های خودش را دارد. Redis یک محل مشترک و سریع برای سشن همه‌ی سرورهاست.

صف

لیست‌های Redis پایه‌ی خوبی برای صف کارهای پس‌زمینه‌اند. Laravel، Sidekiq در Ruby و Celery و RQ در Python همه از Redis به عنوان صف پشتیبانی می‌کنند. جزئیات صف در Laravel را در این مقاله نوشته‌ایم.

محدود کردن نرخ درخواست

«هر IP حداکثر ۶۰ درخواست در دقیقه». با INCR و EXPIRE این کار چند خط است و بین همه‌ی سرورها یکسان کار می‌کند.

Pub/Sub

یک بخش پیام منتشر می‌کند و هر کس مشترک آن کانال است، فوراً دریافتش می‌کند. برای اعلان‌های لحظه‌ای مناسب است، با این قید که اگر مشترکی در آن لحظه وصل نباشد، پیام را از دست می‌دهد. برای پیام‌هایی که نباید گم شوند، Redis Streams گزینه‌ی بهتری است.

انواع داده با مثال redis-cli

این دستورها را می‌شود مستقیم در شل اجرا کرد؛ اگر وارد محیط تعاملی redis-cli شده‌اید، خود کلمه‌ی redis-cli و توضیح بعد از # را ننویسید.

String؛ ساده‌ترین نوع، برای کش و شمارنده:

bash
redis-cli SET page:home "<html>...</html>" EX 300   # با انقضای ۳۰۰ ثانیه
redis-cli GET page:home
redis-cli TTL page:home                             # چند ثانیه مانده
redis-cli INCR stats:visits                         # شمارنده‌ی اتمی

Hash؛ مثل یک رکورد با چند فیلد:

bash
redis-cli HSET user:42 name "Sara" plan "pro"
redis-cli HGET user:42 plan
redis-cli HGETALL user:42

List؛ صف یا آخرین موارد:

bash
redis-cli LPUSH jobs "send-invoice:1001"
redis-cli RPOP jobs
redis-cli LRANGE recent:posts 0 9                   # ده مورد اول

Set؛ مجموعه‌ی بدون تکرار:

bash
redis-cli SADD online:users 42 57 91
redis-cli SISMEMBER online:users 42
redis-cli SCARD online:users

Sorted Set؛ مجموعه با امتیاز، برای جدول رده‌بندی:

bash
redis-cli ZADD leaderboard 1500 "ali" 2100 "sara" 1800 "reza"
redis-cli ZRANGE leaderboard 0 2 REV WITHSCORES     # سه نفر اول

و الگوی محدود کردن نرخ:

bash
redis-cli INCR rate:203.0.113.5
redis-cli EXPIRE rate:203.0.113.5 60 NX             # فقط اگر انقضا نداشت

اگر مقدار برگشتی INCR از ۶۰ بیشتر شد، درخواست را رد می‌کنید. گزینه‌ی NX در EXPIRE از Redis 7 به بعد وجود دارد.

ماندگاری: RDB و AOF

داده در RAM است، پس با ری‌استارت چه می‌شود؟ Redis دو روش برای نوشتن روی دیسک دارد:

روش چطور کار می‌کند مزیت عیب
RDB هر چند وقت یک عکس کامل از داده در فایل dump.rdb فایل فشرده، بالا آمدن سریع تغییرات بعد از آخرین عکس از دست می‌رود
AOF هر دستور نوشتن به انتهای یک فایل اضافه می‌شود با appendfsync everysec حداکثر حدود یک ثانیه داده از دست می‌رود فایل بزرگ‌تر، بازسازی کندتر

برای صف و سشن، AOF را روشن کنید. برای کش خالص، حتی می‌شود ماندگاری را کامل خاموش کرد؛ کش خالی فقط یعنی چند درخواست اول کندتر است.

چرا Redis پایگاه‌داده‌ی اصلی شما نیست

  • حجم داده محدود به RAM است و RAM گران‌تر از دیسک است.
  • کوئری‌گیری ندارد: نمی‌شود پرسید «سفارش‌های ماه گذشته‌ی کاربران تهران». فقط با کلید دسترسی دارید.
  • روابط، قیود و تراکنش به معنای SQL ندارد.
  • حتی با AOF، تضمین‌های ماندگاری‌اش به پای یک پایگاه‌داده‌ی رابطه‌ای نمی‌رسد.

قاعده‌ی ساده: اگر کلیدی از Redis پاک شود، باید بتوانید از پایگاه‌داده‌ی اصلی دوباره بسازیدش. برای انتخاب پایگاه‌داده‌ی اصلی، این مقاله را ببینید.

اجرای Redis با Docker

اگر Docker ندارید، اول Docker را روی Ubuntu 24.04 نصب کنید. بعد:

bash
docker run -d --name redis \
  --restart unless-stopped \
  -p 127.0.0.1:6379:6379 \
  -v redis-data:/data \
  redis:8-alpine \
  redis-server --appendonly yes --requirepass "$REDIS_PASSWORD"

دقت کنید که پورت به 127.0.0.1 بسته شده است. اگر فقط -p 6379:6379 بنویسید، Docker پورت را روی همه‌ی کارت‌های شبکه باز می‌کند و قانون‌های ufw را هم دور می‌زند.

برای تست:

bash
docker exec -it redis redis-cli
AUTH <your-password>
PING

در یک پروژه با Docker Compose، بهتر است Redis اصلاً پورتی به بیرون منتشر نکند و برنامه از طریق شبکه‌ی داخلی Compose با نام سرویس به آن وصل شود:

compose.yaml
services:
  redis:
    image: redis:8-alpine
    command: ["redis-server", "--appendonly", "yes", "--requirepass", "${REDIS_PASSWORD}"]
    volumes:
      - redis-data:/data
    restart: unless-stopped

volumes:
  redis-data:

جزئیات Compose را در Docker Compose به زبان ساده توضیح داده‌ایم. بدون Docker هم روی Ubuntu با sudo apt install redis-server نصب می‌شود.

برای اتصال Laravel، در .env کافی است:

.env
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=your-password
REDIS_PORT=6379

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=redis

امنیت: حداقل‌هایی که نباید فراموش شود

Redis برای اجرا در شبکه‌ی مورد اعتماد طراحی شده است. یک Redis باز روی اینترنت، در زمان کوتاهی پیدا و سوءاستفاده می‌شود.

  • هرگز پورت 6379 را روی اینترنت باز نکنید. در فایل redis.conf مقدار bind 127.0.0.1 -::1 بماند و protected-mode yes خاموش نشود.
  • رمز بگذارید، با requirepass یا بهتر، با ACL و کاربر جداگانه برای هر برنامه.
  • فایروال را طبق چک‌لیست ساعت اول سرور تنظیم کنید و یادتان باشد پورت‌های Docker از ufw رد می‌شوند.
  • دستورهای خطرناک مثل FLUSHALL و CONFIG را برای کاربر برنامه با ACL ممنوع کنید.
  • حافظه را محدود کنید: با maxmemory سقف بگذارید. برای کش، سیاست allkeys-lru مناسب است؛ برای صف از noeviction استفاده کنید تا Redis بی‌صدا کار شما را پاک نکند.

کی Redis لازم نیست

Redis یک سرویس دیگر است که باید نصب، مانیتور، به‌روز و پشتیبان‌گیری شود. این موارد معمولاً بدون آن هم خوب کار می‌کنند:

  • سایت کوچک روی یک سرور: کش فایلی یا پایگاه‌داده‌ای Laravel و صف database برای شروع کاملاً کافی است.
  • وقتی کندی از کوئری بد است: اول ایندکس بگذارید و کوئری را درست کنید. کش کردن کوئری بد، مشکل را پنهان می‌کند، حلش نمی‌کند.
  • هاست اشتراکی که اجازه‌ی اجرای Redis نمی‌دهد؛ در این حالت شاید وقت مهاجرت به VPS باشد، نه دور زدن مسئله.

نشانه‌های اینکه وقتش رسیده: پایگاه‌داده زیر بار خواندن‌های تکراری کند شده، برنامه روی بیش از یک سرور اجرا می‌شود و سشن مشترک می‌خواهد، یا صف database دیگر جواب حجم کارها را نمی‌دهد.

یک نکته‌ی جانبی: در سال ۲۰۲۴ مجوز Redis تغییر کرد و پروژه‌ی متن‌باز Valkey از آن جدا شد؛ از Redis 8 گزینه‌ی مجوز متن‌باز AGPL دوباره اضافه شده است. برای بیشتر پروژه‌ها، هر دو با دستورها و کلاینت‌های یکسان کار می‌کنند.

جمع‌بندی

Redis یک انبار کلید-مقدار در حافظه است: بسیار سریع، با ساختارهای داده‌ی کاربردی و TTL. برای کش، سشن، صف، شمارنده و محدودیت نرخ ابزار درجه‌یکی است، ولی منبع حقیقت داده‌های شما نیست. با Docker در یک دقیقه بالا می‌آید؛ فقط آن را به 127.0.0.1 یا شبکه‌ی داخلی ببندید، رمز بگذارید و سقف حافظه تعیین کنید. و اگر سایتتان کوچک است، تا وقتی نشانه‌ی واقعی نیاز ندیده‌اید، اضافه‌اش نکنید. مستندات رسمی در redis.io/docs است.