Django

⌘K
  1. Home
  2. Django
  3. Django তে কিভাবে কাজ করতে...
  4. Speed Optimization
  5. ( ক্যাশিং ০ ১ ) Redis দিয়ে Low-Level Caching বা কোয়েরি ক্যাশিং

( ক্যাশিং ০ ১ ) Redis দিয়ে Low-Level Caching বা কোয়েরি ক্যাশিং

কেন Redis Django এর জন্য বেশিরভাগ ক্ষেত্রে ভালো পছন্দ:

  1. উচ্চ পারফরম্যান্স: Redis সম্পূর্ণরূপে in-memory ডাটাবেস হওয়ায়, এটি দ্রুততম রিড/রাইট অপারেশন করতে সক্ষম।
  2. রিচ ডাটা স্ট্রাকচার: Redis শুধু key-value স্টোরই নয়, বরং লিস্ট, সেট, হ্যাশ, sorted set, এবং আরো অনেক ডাটা স্ট্রাকচার সমর্থন করে, যা ফ্লেক্সিবিলিটি বৃদ্ধি করে।
  3. পার্সিস্টেন্স সমর্থন: Redis এর ডাটাগুলো মেমোরিতে রাখলেও, এটি ডিস্কে ডাটাগুলোকে পার্সিস্ট করতে পারে, যা অনেক ক্ষেত্রে জরুরি।
  4. শক্তিশালী ক্যাশিং কন্ট্রোল: Redis আপনাকে TTL (Time-To-Live) সেট করতে দেয়, যার মাধ্যমে সহজেই ক্যাশ এক্সপায়ারেশন নিয়ন্ত্রণ করা যায়।

কেন ডাটাবেস কোয়েরি ক্যাশিং দরকার?

  • লোড কমায়: ক্যাশিং ডাটাবেসের উপর লোড কমিয়ে দেয়, কারণ বারবার একই কোয়েরি করার প্রয়োজন হয় না।
  • রেসপন্স টাইম বৃদ্ধি: ক্যাশ থেকে ডাটা সরাসরি পাওয়া গেলে তা অনেক দ্রুত হয়।
  • সার্ভার রিসোর্সের সাশ্রয়: ক্যাশিং ব্যবহারে সার্ভারের CPU এবং RAM এর উপর লোড কমে, যা অ্যাপ্লিকেশনের স্কেলেবিলিটি বৃদ্ধি করে।

Django ORM Query Caching – আরও কিছু পদ্ধতি:

  • Low-level caching: Django এর cache মডিউল ব্যবহার করে কোয়েরি বা ভিউ লেভেলে ক্যাশিং করা যায়।
  • Per-view caching: Django এর @cache_page ডেকোরেটর ব্যবহার করে ভিউ-লেভেলে ক্যাশিং করা যায়।
  • Database caching: Django এর database ক্যাশ ব্যাকএন্ড ব্যবহার করে ডাটাবেসে ক্যাশ সংরক্ষণ করা যায়, তবে এটি মেমরি ভিত্তিক ক্যাশিং এর মতো দ্রুত নয়।

Redis এবং Django এর মধ্যে সংযোগ (Basics of Caching with Redis)

লোকাল ডেভেলপমেন্ট বনাম প্রোডাকশন ক্যাশিং সার্ভার:

  • লোকাল ডেভেলপমেন্ট:
    • ডেভেলপমেন্টের সময় আপনার লোকাল মেশিনে Redis সার্ভার চালানো খুবই কার্যকরী। এতে ডেভেলপমেন্ট সহজ হয় এবং ক্যাশিং সম্পর্কিত ইস্যুগুলি সহজেই ডিবাগ করা যায়।

প্রোডাকশন:

  • প্রোডাকশন পরিবেশে, Redis-কে একটি ডেডিকেটেড সার্ভার বা ক্লাউড সার্ভারে চালানো উচিত।
  • এর প্রধান কারণ হলো: Redis ডেটা মেমোরিতে ধরে রাখে, যা উচ্চ-মাত্রায় রিসোর্স কনজাম্পশন করতে পারে। একারণে, Redis সার্ভারকে অ্যাপ্লিকেশন সার্ভার থেকে আলাদা রাখা উচিত যাতে উভয়ের রিসোর্স ব্যবহার নিজেদের জন্য অপটিমাইজ থাকে।
  • উদাহরণস্বরূপ, আপনি AWS Elasticache Redis বা DigitalOcean Managed Redis ব্যবহার করতে পারেন।

Django এ Redis ক্যাশিং সেটআপ:

install in windows link

  1. প্রথমে Redis ইনস্টল করুন:
sudo apt update
sudo apt install redis-server
sudo service redis-server start

Django প্রজেক্টে django-redis প্যাকেজ ইনস্টল করুন:

pip install django-redis

settings.py ফাইলে Redis কনফিগার করুন:

# settings.py

CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': 'redis://127.0.0.1:6379/1',
        'OPTIONS': {
            'CLIENT_CLASS': 'django_redis.client.DefaultClient',
        }
    }
}

Database Query Caching এবং Dynamic Content Handling

ইস্যু: নতুন পোস্ট যুক্ত হলে ক্যাশ আপডেট হয় না!

  • যখন তুমি একটি ক্যাশড ভিউ ব্যবহার করো, সেখানে নতুন ডেটা যোগ হলে ক্যাশ আপডেট না হওয়ার সম্ভাবনা থাকে। যেমন, নতুন ব্লগ পোস্ট যোগ হলে সেটি Redis ক্যাশে রিফ্লেক্ট হয় না।

সমাধান:

  1. Cache Invalidation Strategy:
    • ক্যাশ করার সময় তুমি যখনই নতুন ডেটা যুক্ত করবা বা কোন ডেটা আপডেট করবা, তখনই Redis ক্যাশকে ইনভ্যালিডেট (মুছে ফেলা) করতে হবে। Redis লাইব্রেরি বা Django কনফিগারেশন ব্যবহার করে এই কাজ করা যায়।

Redis ব্যবহার করে create, read, update, delete (CRUD) অপারেশনগুলো কিভাবে Django তে ক্যাশিং-এর মাধ্যমে হ্যান্ডেল করতে হবে, সেটি উদাহরণ সহ বিস্তারিত দেখাবো। Redis-based caching ব্যবহারে প্রতিটি CRUD অপারেশনের জন্য ক্যাশিং কিভাবে পরিচালনা করতে হবে তা খুব গুরুত্বপূর্ণ, কারণ নতুন ডেটা যোগ, মুছে ফেলা, অথবা আপডেট হলে ক্যাশ আপডেট হতে হবে।

আমরা এখানে একটি BlogPost মডেলের উদাহরণ ব্যবহার করবো যেখানে সব পোস্টের ডেটা ক্যাশিং করা হবে, এবং CRUD অপারেশনগুলো Redis ক্যাশ-এর সাহায্যে হ্যান্ডেল করা হবে।

BlogPost Model Setup

# models.py

from django.db import models

class BlogPost(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()

    def __str__(self):
        return self.title

Read and Cache All Blog Posts

# views.py

from django.core.cache import cache
from django.shortcuts import render
from .models import BlogPost

def get_all_blog_posts(request):
    # Check if data exists in Redis cache
    posts = cache.get('all_blog_posts')
    
    if not posts:
        # If not in cache, query from database and set in cache
        posts = list(BlogPost.objects.all())
        cache.set('all_blog_posts', posts, timeout=600)  # Cache for 10 minutes

    return render(request, 'all_posts.html', {'posts': posts})

কী ঘটছে:

  • প্রথমে আমরা cache.get ব্যবহার করে Redis থেকে ডেটা ফেচ করার চেষ্টা করছি।
  • যদি Redis-এ না থাকে, আমরা ডাটাবেস থেকে ডেটা ফেচ করছি এবং Redis-এ সেট করছি cache.set এর মাধ্যমে।

Part 3: Create Operation and Cache Invalidation

# views.py

from django.shortcuts import redirect

def create_blog_post(request):
    if request.method == 'POST':
        # Create new blog post
        BlogPost.objects.create(
            title=request.POST.get('title'),
            content=request.POST.get('content')
        )
        # Invalidate the cached data
        cache.delete('all_blog_posts')  # Clear cached posts
        return redirect('get_all_blog_posts')
    
    return render(request, 'create_post.html')

কী ঘটছে:

  • যখন নতুন পোস্ট তৈরি হচ্ছে, তখন cache.delete দিয়ে Redis-এ সংরক্ষিত আগের ক্যাশড ডেটা মুছে ফেলা হচ্ছে।

Part 4: Update Operation and Cache Invalidation

# views.py

def update_blog_post(request, post_id):
    post = BlogPost.objects.get(id=post_id)

    if request.method == 'POST':
        post.title = request.POST.get('title')
        post.content = request.POST.get('content')
        post.save()

        # Invalidate the cached data
        cache.delete('all_blog_posts')  # Clear cached posts

        return redirect('get_all_blog_posts')

    return render(request, 'update_post.html', {'post': post})

কী ঘটছে:

  • পোস্ট আপডেটের সময় cache.delete ব্যবহার করে ক্যাশড ডেটা মুছে ফেলা হচ্ছে।

Part 5: Delete Operation and Cache Invalidation

# views.py

def delete_blog_post(request, post_id):
    post = BlogPost.objects.get(id=post_id)
    post.delete()

    # Invalidate the cached data
    cache.delete('all_blog_posts')  # Clear cached posts

    return redirect('get_all_blog_posts')

কী ঘটছে:

  • পোস্ট মুছে ফেলার সময় ক্যাশড ডেটাও মুছে ফেলা হচ্ছে, যাতে ক্যাশড ডেটা রিফ্রেশ হয়।

Part 6: Read a Single Post and Cache it Separately

# views.py

def get_single_blog_post(request, post_id):
    # Try to fetch the post from Redis cache
    post = cache.get(f'blog_post_{post_id}')
    
    if not post:
        # If not in cache, fetch from database and set in cache
        post = BlogPost.objects.get(id=post_id)
        cache.set(f'blog_post_{post_id}', post, timeout=600)  # Cache for 10 minutes

    return render(request, 'single_post.html', {'post': post})

কী ঘটছে:

  • এখানে get_single_blog_post ভিউতে একক পোস্টকে Redis-এ ক্যাশ করে রাখা হচ্ছে।

Advanced Caching Consideration: Selective Cache Invalidation Strategies

ক্যাশড ডেটা পরিচালনার জন্য, একটি ভাল স্ট্র্যাটেজি হলো Selective Cache Invalidation। যেমন, সব পোস্টের ক্যাশ মুছে না ফেলে শুধু আপডেট হওয়া বা ডিলিট হওয়া পোস্টের ক্যাশড ডেটা মুছে ফেলা। উদাহরণস্বরূপ, যদি একটি নির্দিষ্ট পোস্ট আপডেট হয় বা মুছে ফেলা হয়, তখন শুধু সেই পোস্টের Redis key মুছে ফেলা:

def update_blog_post(request, post_id):
    post = BlogPost.objects.get(id=post_id)

    if request.method == 'POST':
        post.title = request.POST.get('title')
        post.content = request.POST.get('content')
        post.save()

        # Invalidate the cache for that specific post
        cache.delete(f'blog_post_{post_id}')
        cache.delete('all_blog_posts')  # Invalidate all posts cache as well

        return redirect('get_all_blog_posts')

    return render(request, 'update_post.html', {'post': post})

How can we help?