কম্পিউটার টিউটোরিয়াল

এএসপি.নেট কোর এবং এজার রেডিস ক্যাশে ক্যাশ-এসাইড প্যাটার্ন বাস্তবায়ন

ভূমিকা

সফ্টওয়্যার ডেভেলপমেন্ট সাইকেলে, অ্যাপ্লিকেশনের পারফরম্যান্স অনেক সময় মূল ফোকাস থাকে। পারফরম্যান্স উন্নত করার অনেক উপায় রয়েছে, কিন্তু আধুনিক ক্লাউড অ্যাপ্লিকেশনগুলিতে পারফরম্যান্স উন্নত করার জন্য সবচেয়ে সাধারণভাবে ব্যবহৃত প্যাটার্নগুলোর একটি হলো ক্যাশ-এসাইড (Cache-Aside) প্যাটার্ন। এই পোস্টে, আমি ক্যাশ-এসাইড প্যাটার্ন এবং এএসপি.নেট কোর ব্যবহার করে এর বাস্তবায়ন সংক্ষিপ্তভাবে বর্ণনা করব।

ক্যাশ-এসাইড প্যাটার্ন কী?

এই প্যাটার্নটি খুবই সহজ এবং এর একমাত্র উদ্দেশ্য হলো ডেটা সোর্স থেকে অনুরোধ অনুযায়ী ডেটা ক্যাশে লোড করা। এটি ক্যাশে থাকা ডেটা এবং তার অন্তর্নিহিত ডেটা সোর্সের মধ্যে সংগতি বজায় রাখতে সাহায্য করে।

প্যাটার্নটির বৈশিষ্ট্যগুলো নিচে দেওয়া হলো:

  • যখন একটি অ্যাপ্লিকেশনকে ডেটা দরকার হয়, প্রথমে সেটি ক্যাশে খোঁজা করে।
  • যদি ডেটা ক্যাশে উপস্থিত থাকে, তবে অ্যাপ্লিকেশন ক্যাশ থেকে ডেটা ব্যবহার করে।
  • অন্যথায়, ডেটা ডেটা সোর্স থেকে রিট্রিভ করা হয়।

নিচে ডায়াগ্রামিক চিত্র দেওয়া হলো:

এএসপি.নেট কোর এবং এজার রেডিস ক্যাশে ক্যাশ-এসাইড প্যাটার্ন বাস্তবায়ন

অ্যাপ্লিকেশন দ্বারা মান পরিবর্তন হলে ক্যাশ অবজেক্টটিকে অবৈধ (invalidate) করতে হয়।

এএসপি.নেট কোর এবং এজার রেডিস ক্যাশে ক্যাশ-এসাইড প্যাটার্ন বাস্তবায়ন

ক্যাশ অবৈধ করার ক্রম গুরুত্বপূর্ণ। ডেটা সোর্সকে আপডেট করার পূর্বে ক্যাশ থেকে আইটেমটি সরিয়ে ফেলবেন না। যদি আপনি প্রথমে ক্যাশ থেকে আইটেমটি সরিয়ে ফেলেন, তবে ক্লায়েন্ট ডেটা স্টোর আপডেট হওয়ার আগে ही আইটেমটি ফেচ করতে পারে। এর ফলে ডেটা স্টোর এবং ক্যাশের মধ্যে ডেটা অসংগতি হবে।

এই প্যাটার্ন কখন ব্যবহার করবেন?

  • এই প্যাটার্ন আমাদের অনুরোধ অনুযায়ী ডেটা লোড করতে সক্ষম করে এবং এটি ব্যবহার করা যেতে পারে যখন রিসোর্সের ডিমান্ড অনিশ্চিত হয়।
  • যে ক্যাশে রিড-থ্রু (read-through) এবং রাইট-থ্রু (write-through) অপারেশন প্রদান করে না।

নোট

  • রিড-থ্রু (Read-Through): এটি একটি ক্যাশ যা ডেটাবেসের সাথে ইন-লাইন থাকে এবং ক্যাশ মিস হলে ডেটাবেস থেকে ডেটা লোড করে ক্যাশে পপুলেট করে।
  • রাইট-থ্রু (Write-Through): ক্যাশ ডেটাবেসের সাথে ইন-লাইন থাকে এবং ডেটা সবসময় মেন ডেটাবেসে যাওয়ার আগে ক্যাশের মধ্য দিয়ে যায়।

এজার রিসোর্স তৈরি

উপরোক্ত চিত্রের অনুযায়ী, আমাদের ডেটাবেস (এজার SQL সার্ভার) এবং ক্যাশ (এজার রেডিস ক্যাশ) দরকার। আপনি আপনার সুবিধামতো ডেটাবেস এবং ক্যাশ বেছে নিতে পারেন।

$resourceGroup="<Resource Group>"
$location="<location>"
$redisCacheName="<Redis cache name>"
$sqlServerName="<Azure SQL Server Name>"
$sqlDBName="<Azure SQL DB Name>"
$adminName="<admin name of SQL server>"
$adminPassword="<admin password of SQL Server>"

# রিসোর্স গ্রুপ তৈরি
az group create --name $resourceGroup --location $location

# বেসিক SKU-তে রেডিস ক্যাশ তৈরি
az redis create --name $redisCacheName --resource-group $resourceGroup --location $location --sku Basic --vm-size c0

# SQL সার্ভার তৈরি
az sql server create -l $location -g $resourceGroup -n $sqlServerName -u $adminName -p $adminPassword

# বেসিক SKU-তে SQL ডেটাবেস তৈরি
az sql db create -g $resourceGroup -s $sqlServerName -n $sqlDBName --service-objective Basic

বাস্তবায়ন

এএসপি.নেট কোর ওয়েব এপিআই প্রজেক্ট তৈরি করে এবং রেডিস ক্যাশ ও এন্টিটি ফ্রেমওয়ার্ক কোরের জন্য প্রয়োজনীয় নুগেট প্যাকেজ যোগ করে বাস্তবায়ন শুরু করি।

dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.Extensions.Caching.StackExchangeRedis

প্রথমে, একটি কান্ট্রি (Country) মডেল ক্লাস তৈরি করি।

public class Country {
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsActive { get; set; }
}

এখন, স্টার্টআপ ক্লাসের ConfigureServices মেথডে EF Core এবং রেডিস ক্যাশের ডিপেন্ডেন্সি রেজিস্টার করি।

public void ConfigureServices(IServiceCollection services) {
    services.AddControllers();
    services.AddDbContext<CountryContext>(optionsAction => 
        optionsAction.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    services.AddStackExchangeRedisCache(setupAction => {
        setupAction.Configuration = Configuration.GetConnectionString("RedisConnectionString");
    });
}

রেডিস ক্যাশ এবং SQL ডেটাবেসের কানেকশন স্ট্রিং uchun appsettings.json ফাইলটি পরিবর্তন করি।

"ConnectionStrings": {
    "RedisConnectionString": "<Redis Cache ConnectionString>",
    "DefaultConnection": "<SQL Server Connection string>"
}

DbContext ক্লাস যোগ করি।

public class CountryContext : DbContext {
    public DbSet<Country> Countries { get; set; }
    public CountryContext(DbContextOptions dbContextOptions) : base(dbContextOptions) { }
}

GetCountries মেথডটি একটি কী ব্যবহার করে ক্যাশ থেকে আইটেম রিট্রিভ করার চেষ্টা করে। যদি মিল খুঁজে পায়, তবে সেটি রিটার্ন করে। অন্যথায়, ডেটা ডেটাবেস থেকে রিট্রিভ করা হবে এবং ক্যাশে পপুলেট হবে। ক্যাশ করা আইটেমটি ৫ মিনিটের পর এক্সপায়ার হওয়ার জন্য কনফিগার করা হয়েছে।

[Route("api/[controller]")]
[ApiController]
public class CountryController : ControllerBase {
    private readonly IDistributedCache cache;
    private readonly CountryContext countryContext;

    public CountryController(IDistributedCache cache, CountryContext countryContext) {
        this.cache = cache;
        this.countryContext = countryContext;
    }

    // GET: api/<CountryController>
    [HttpGet]
    public async Task<IEnumerable<Country>> GetCountries() {
        var countriesCache = await cache.GetStringAsync("countries");
        var value = (countriesCache == null) ? default : JsonConvert.DeserializeObject<IEnumerable<Country>>(countriesCache);
        
        if (value == null) {
            var countries = countryContext.Countries.ToList();
            if (countries != null && countries.Any()) {
                await cache.SetStringAsync("Countries", JsonConvert.SerializeObject(countries), 
                    new DistributedCacheEntryOptions {
                        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
                    });
                return countries;
            }
        }
        return value;
    }
}

AddCountries মেথডটি প্রদর্শন করে কিভাবে ডেটাবেসে ডেটা যোগ/আপডেট করার সময় ক্যাশকে অবৈধ করা যায়।

// POST api/<CountryController>
[HttpPost]
public async Task<ActionResult<string>> AddCountries([FromBody] Country country, CancellationToken cancellationToken) {
    if (country == null) return BadRequest("country is null");
    await countryContext.AddAsync(country);
    await countryContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
    await cache.RemoveAsync("countries", cancellationToken).ConfigureAwait(false);
    return Ok("cache has been invalidated");
}

উপসংহার

এই নিবন্ধে, আমি ক্যাশ-এসাইড প্যাটার্ন এবং এএসপি.নেট কোর ও এজার রেডিস ক্যাশ ব্যবহার করে এর প্রাথমিক বাস্তবায়ন বর্ণনা করেছি। হ্যাপি ক্যাশিং!

আশা করি নিবন্ধটি আপনার পছন্দ आएगा। যদি আপনার মতে নিবंधটি আকর্ষণীয় হয়, তবে দয়া করে লাইক এবং শেয়ার করুন।

  1. জাভাস্ক্রিপ্ট রেগুলার এক্সপ্রেশন-এ 'dotAll' ফ্ল্যাগ ব্যাখ্যা

  2. Keras ব্যবহার করে পাইথনে সম্পূর্ণ মডেল সংরক্ষণ করা

  3. অ্যান্ড্রয়েডে টাইপিং করার সময় EditText-এ ক্যারেক্টার গণনার পদ্ধতি

  4. CSS-এ ::first-line 의사-এলিমেন্ট