ویژگی تصویر

مقدمه‌ای بر کتابخانه redis-py در پایتون

  /  پایتون   /  کتابخانه redis-py در پایتون
بنر تبلیغاتی الف

کتابخانه redis-py یکی از پراستفاده‌ترین کلاینت‌های Redis برای زبان پایتون است که رابطی ساده و پرقدرت برای کار با دیتابیس در حافظه Redis فراهم می‌کند. این کتابخانه از نسخه‌های مدرن Redis، امکاناتی مانند پایپلاین (pipeline)، تراکنش‌ها، Pub/Sub، Sentinel و حتی پشتیبانی از حالت async و کلاستر را پوشش می‌دهد. در ادامه با نصب، مبانی استفاده و بهترین شیوه‌ها آشنا می‌شویم.

نصب و نسخه‌ها

برای نصب نسخهٔ رسمی و به‌روز:

pip install redis

این نسخه از redis-py (نسخهٔ 4.x به بعد) شامل پشتیبانی از asyncio و امکانات جدید است. همیشه با pip show redis نسخه را بررسی کنید.

اتصال به سرور Redis

from redis import Redis

r = Redis(host='localhost', port=6379, db=0, decode_responses=True)

r.set('greeting', 'سلام دنیا')
print(r.get('greeting'))  # 'سلام دنیا'

در این مثال، یک شیٔ Redis ایجاد می‌کنیم که به localhost متصل است. پارامتر decode_responses=True باعث می‌شود پاسخ‌ها به صورت رشته (str) بازگردانده شوند به‌جای بایت‌ها. متدهای پایه مثل set و get برای کار با کلیدها استفاده می‌شوند.

پایپلاین و تراکنش‌ها (Pipeline & Transactions)

پایپلاین باعث می‌شود چندین دستور پشت سر هم بدون انتظار پاسخ اجرا و سپس نتایج یکجا دریافت شوند؛ مفید برای بهبود کارایی.

pipe = r.pipeline()
pipe.set('a', 1)
pipe.incr('a')
pipe.get('a')
results = pipe.execute()
print(results)  # [True, 2, '2']

در کد بالا سه دستور در پایپلاین اضافه شده و سپس با execute ارسال می‌شوند. اگر بخواهیم تراکنش اتمیک داشته باشیم، می‌توانیم از transaction=True یا از بلوک with استفاده کنیم تا چند دستور در یک MULTI/EXEC اجرا شوند.

استفادهٔ Async (asyncio)

import asyncio
from redis.asyncio import Redis

async def main():
    r = Redis(host='localhost', port=6379, decode_responses=True)
    await r.set('counter', 0)
    await r.incr('counter')
    print(await r.get('counter'))
    await r.close()

asyncio.run(main())

این مثال نشان می‌دهد چگونه با استفاده از redis.asyncio می‌توان در کدهای async/await از Redis استفاده کرد. توجه داشته باشید که باید در پایان اتصال را ببندید یا از مدیریت منابع استفاده کنید.

Pub/Sub برای انتشار و اشتراک پیام

# Publisher
r.publish('channel:news', 'خبر جدید')

# Subscriber (همزمانی ساده)
pub = r.pubsub()
pub.subscribe('channel:news')
for message in pub.listen():
    print(message)

الگوی Pub/Sub برای ساختن سیستم‌های نوتیفیکیشن، پیام‌رسانی بین سرویس‌ها یا بروزرسانی‌های بلادرنگ کاربرد دارد. در نسخه‌های async نیز می‌توان با کلاس‌های مربوطه از Pub/Sub استفاده کرد.

پشتیبانی از Sentinel و Cluster

اگر از Redis Sentinel برای HA یا از Redis Cluster برای شاردینگ استفاده می‌کنید، redis-py ابزارهایی دارد تا اتصال مدیریت شود.

from redis.sentinel import Sentinel

sentinel = Sentinel([('localhost', 26379)], socket_timeout=0.1)
master = sentinel.master_for('mymaster', decode_responses=True)
master.set('k', 'v')

کد بالا به یک Sentinel متصل می‌شود و از master_for برای گرفتن اتصال به مستر فعلی استفاده می‌کند. برای Redis Cluster نیز می‌توان از RedisCluster استفاده کرد:

from redis.cluster import RedisCluster

rc = RedisCluster(startup_nodes=[{"host": "127.0.0.1", "port": "7000"}], decode_responses=True)
rc.set('c', 'clustered')
print(rc.get('c'))

با این کد می‌توانید از کلاستر استفاده کنید؛ توجه داشته باشید که پیکربندی کلاستر و نسخهٔ سرور اهمیت زیادی دارد.

ذخیرهٔ داده‌های پیچیده (مثلاً JSON)

Redis ماژول‌هایی مانند RedisJSON دارد، اما ساده‌ترین روش در نبود ماژول ذخیرهٔ JSON، سریالایز کردن دستی است:

import json
r.set('user:1', json.dumps({'id': 1, 'name': 'Ali'}))
user = json.loads(r.get('user:1'))

در این روش با json.dumps داده را به رشته تبدیل و ذخیره می‌کنیم و با json.loads آن را برمی‌گردانیم. اگر از ماژول RedisJSON استفاده کنید، می‌توانید عملیات مستقیم روی ساختارهای JSON انجام دهید اما نیازمند نصب و پیکربندی ماژول در سرور است.

نمونه جدول: مقایسهٔ کاربردی چند نوع دیتا

نوع دادهموارد استفادهمثال متدها
Stringکش، توکن، وضعیت‌هاGET, SET, INCR
Listصف پیام، لاگ سادهLPUSH, RPOP, LRANGE
Setمجموعه‌ی بدون تکرارSADD, SREM, SMEMBERS
Hashاشیاء با فیلدهاHSET, HGETALL
ZSetرتبه‌بندی، صف اولویتZADD, ZRANGE

نکات کاربردی و بهترین شیوه‌ها

  • همیشه از connection pool (پیش‌فرض فعال است) استفاده کنید تا مدیریت اتصالات بهتر شود.
  • برای مقادیر باینری یا بزرگ، از decode_responses=False استفاده کرده و مدیریت بایت‌ها را خودتان انجام دهید.
  • برای عملیات اتمیک و چند مرحله‌ای از Lua scripting استفاده کنید تا از شرایط رقابتی جلوگیری شود.
  • پایپلاین‌ها را برای کاهش تعداد round-tripها به کار ببرید؛ اما مراقب محدودیت حافظه سرور باشید.
  • در محیط‌های چندنخی (threaded)، از کلاینت‌هایی که به درستی thread-safe هستند یا از pool استفاده کنید.

مثال اسکریپت Lua برای افزایش شرطی

lua = """
local key = KEYS[1]
local inc = tonumber(ARGV[1])
local val = tonumber(redis.call('get', key) or '0')
val = val + inc
redis.call('set', key, val)
return val
"""
res = r.eval(lua, 1, 'counter', 5)
print(res)

در این مثال یک اسکریپت Lua اجرا می‌کنیم که مقدار یک کلید را به‌صورت اتمیک افزایش می‌دهد. eval با ارسال کد Lua به سرور اجرا می‌شود و مزیت آن جلوگیری از race condition است.

عیب‌یابی و خطاهای متداول

  • ConnectionError یا Timeout: بررسی کنید سرور Redis در دسترس است و پارامترهای timeout و socket مشخص شده مناسب‌اند.
  • پیغام‌های مربوط به نسخهٔ سرور: برخی امکانات نیازمند نسخهٔ خاص Redis یا ماژول‌های اضافه‌اند.
  • Memory errors: با دستور INFO و MONITOR مصرف حافظه را بررسی و سیاست eviction مناسب را تنظیم کنید.

جمع‌بندی

redis-py یک ابزار کامل و بالغ برای کار با Redis در پایتون است؛ با یادگیری مفاهیم پایه مانند اتصال، پایپلاین، تراکنش و الگوهای Pub/Sub می‌توانید از Redis در پروژه‌های وب، کشینگ، صف‌های پیام و سیستم‌های real-time بهره ببرید. توجه به نسخهٔ کتابخانه، ویژگی‌های سرور و رعایت بهترین شیوه‌ها (مثل استفاده از pool و پایپلاین) کیفیت عملکرد برنامهٔ شما را به‌طور چشمگیری بهبود می‌دهد.

آیا این مطلب برای شما مفید بود ؟

خیر
بله
موضوعات شما در انجمن: