পরিচয়
এই নিবন্ধে, আমরা .NET Core-এ Redis-এর সাথে কীভাবে একটি বিতরণ করা লক তৈরি করতে হয় তা নিয়ে আলোচনা করব।
যখন আমরা ডিস্ট্রিবিউটেড সিস্টেম তৈরি করি, তখন আমরা একাধিক প্রক্রিয়ার মুখোমুখি হব যা একসাথে একটি শেয়ার্ড রিসোর্স পরিচালনা করে। এটি কিছু অপ্রত্যাশিত সমস্যা সৃষ্টি করবে কারণ তাদের মধ্যে শুধুমাত্র একজন শেয়ার করা সম্পদ এক সময়ে ব্যবহার করতে পারে!
এই সমস্যাটি সমাধান করতে আমরা একটি বিতরণ করা লক ব্যবহার করতে পারি।
কেন বিতরণ করা লক?
যথারীতি, আমরা এই সমস্যাটি পরিচালনা করতে একটি লক ব্যবহার করব৷
নিম্নলিখিত কিছু নমুনা কোড দেখায় যা একটি লকের ব্যবহার প্রদর্শন করে।
public void SomeMethod()
{
// Do something...
lock (obj)
{
// Do ....
}
// Do something...
} যাইহোক, এই ধরনের লক সমস্যাটি ভালভাবে কাজ করতে আমাদের সাহায্য করতে পারে না! এটি একটি ইন-প্রসেস লক যা শেয়ার্ড রিসোর্স দিয়ে শুধুমাত্র একটি প্রক্রিয়া সমাধান করতে পারে৷
৷আমাদের একটি ডিস্ট্রিবিউটেড লকের প্রয়োজনের এটিও প্রধান কারণ!
আমি এখানে একটি সাধারণ বিতরণ করা লক তৈরি করতে Redis ব্যবহার করব।
এবং কেন আমি এই কাজ করতে Redis ব্যবহার করব? রেডিসের একক-থ্রেড প্রকৃতি এবং পারমাণবিক ক্রিয়াকলাপ সম্পাদন করার ক্ষমতার কারণে।
কিভাবে একটি লক তৈরি করবেন?
আমি আপনাকে দেখানোর জন্য একটি .NET কোর কনসোল অ্যাপ্লিকেশন তৈরি করব।
পরবর্তী ধাপের আগে, আমাদের Redis সার্ভার চালানো উচিত!
StackExchange.Redis হল .NET-এর সবচেয়ে জনপ্রিয় Reids ক্লায়েন্ট, এবং এতে কোন সন্দেহ নেই যে আমরা নিম্নলিখিত কাজগুলি করতে এটি ব্যবহার করব৷
প্রথমে রেডিসের সাথে সংযোগ তৈরি করা হচ্ছে।
/// <summary>
/// The lazy connection.
/// </summary>
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
ConfigurationOptions configuration = new ConfigurationOptions
{
AbortOnConnectFail = false,
ConnectTimeout = 5000,
};
configuration.EndPoints.Add("localhost", 6379);
return ConnectionMultiplexer.Connect(configuration.ToString());
});
/// <summary>
/// Gets the connection.
/// </summary>
/// <value>The connection.</value>
public static ConnectionMultiplexer Connection => lazyConnection.Value; একটি শেয়ার্ড রিসোর্সে লক করার অনুরোধ করার জন্য, আমরা নিম্নলিখিতগুলি করি৷
৷
SET resource_name unique_value NX PX duration রিসোর্স_নাম হল এমন একটি মান যা আপনার অ্যাপ্লিকেশনের সমস্ত দৃষ্টান্ত ভাগ করবে৷
৷অনন্য_মান এমন কিছু যা আপনার আবেদনের প্রতিটি উদাহরণের জন্য অনন্য হতে হবে। এবং এই অনন্য মানটির উদ্দেশ্য হল লক (আনলক) অপসারণ করা।
অবশেষে, আমরা একটি সময়কালও প্রদান করি (মিলিসেকেন্ডে), যার পরে Redis দ্বারা লকটি স্বয়ংক্রিয়ভাবে সরানো হবে৷
এখানে সি# কোডের বাস্তবায়ন।
/// <summary>
/// Acquires the lock.
/// </summary>
/// <returns><c>true</c>, if lock was acquired, <c>false</c> otherwise.</returns>
/// <param name="key">Key.</param>
/// <param name="value">Value.</param>
/// <param name="expiration">Expiration.</param>
static bool AcquireLock(string key, string value, TimeSpan expiration)
{
bool flag = false;
try
{
flag = Connection.GetDatabase().StringSet(key, value, expiration, When.NotExists);
}
catch (Exception ex)
{
Console.WriteLine($"Acquire lock fail...{ex.Message}");
flag = true;
}
return flag;
} এখানে অধিগ্রহণ লক পরীক্ষা করার জন্য কোড আছে.
static void Main(string[] args)
{
string lockKey = "lock:eat";
TimeSpan expiration = TimeSpan.FromSeconds(5);
// 5 person eat something...
Parallel.For(0, 5, x =>
{
string person = $"person:{x}";
bool isLocked = AcquireLock(lockKey, person, expiration);
if (isLocked)
{
Console.WriteLine($"{person} begin eat food (with lock) at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");
}
else
{
Console.WriteLine($"{person} cannot eat food due to not getting the lock.");
}
});
Console.WriteLine("end");
Console.Read();
} কোড চালানোর পরে, আমরা নিম্নলিখিত ফলাফল পেতে পারি।

তালা পেতে পারে মাত্র একজন! অন্যরা অপেক্ষা করছে৷
যদিও Redis দ্বারা লকটি স্বয়ংক্রিয়ভাবে সরানো হবে, তবে এটি শেয়ার করা সম্পদের ভাল ব্যবহারও করে না!
কারণ যখন একটি প্রক্রিয়া তার কাজ শেষ করে, তখন এটি অন্যদের সম্পদ ব্যবহার করতে দেয়, অবিরাম অপেক্ষা না করে!
তাই আমাদেরও লকটি ছেড়ে দিতে হবে।
কিভাবে লক রিলিজ করবেন?
লকটি ছেড়ে দেওয়ার জন্য, আমরা এইমাত্র Redis এ আইটেমটি সরিয়ে দিয়েছি!
একটি লক তৈরি করার জন্য আমরা যা গ্রহণ করি, আমাদের সম্পদের অনন্য মূল্যের সাথে মেলে। এটি সঠিক লকটি ছেড়ে দেওয়া নিরাপদ করে তুলবে৷
৷ম্যাচিং করার সময়, আমরা লকটি মুছে ফেলব, যার মানে আনলক সফল হয়েছে। অন্যথায়, আনলক ব্যর্থ হয়েছে।
আমাদের একবারে get এবং del কমান্ডগুলি কার্যকর করতে হবে, তাই আমরা এটি করার জন্য একটি Lua স্ক্রিপ্ট ব্যবহার করব!
/// <summary>
/// Releases the lock.
/// </summary>
/// <returns><c>true</c>, if lock was released, <c>false</c> otherwise.</returns>
/// <param name="key">Key.</param>
/// <param name="value">Value.</param>
static bool ReleaseLock(string key, string value)
{
string lua_script = @"
if (redis.call('GET', KEYS[1]) == ARGV[1]) then
redis.call('DEL', KEYS[1])
return true
else
return false
end
";
try
{
var res = Connection.GetDatabase().ScriptEvaluate(lua_script,
new RedisKey[] { key },
new RedisValue[] { value });
return (bool)res;
}
catch (Exception ex)
{
Console.WriteLine($"ReleaseLock lock fail...{ex.Message}");
return false;
}
} একটি প্রক্রিয়া শেষ হলে আমাদের এই পদ্ধতিটি বলা উচিত৷
যখন একটি প্রক্রিয়া লক পায় এবং কোনো কারণে লকটি প্রকাশ করে না, তখন অন্যান্য প্রক্রিয়াগুলি মুক্তি না হওয়া পর্যন্ত অপেক্ষা করতে পারে না। এই সময়ে, অন্যান্য প্রক্রিয়াগুলি এগিয়ে যাওয়া উচিত৷
৷এই দৃশ্যটি মোকাবেলা করার জন্য এখানে একটি নমুনা রয়েছে৷
Parallel.For(0, 5, x =>
{
string person = $"person:{x}";
var val = 0;
bool isLocked = AcquireLock(lockKey, person, expiration);
while (!isLocked && val <= 5000)
{
val += 250;
System.Threading.Thread.Sleep(250);
isLocked = AcquireLock(lockKey, person, expiration);
}
if (isLocked)
{
Console.WriteLine($"{person} begin eat food (with lock) at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");
if (new Random().NextDouble() < 0.6)
{
Console.WriteLine($"{person} release lock {ReleaseLock(lockKey, person)} {DateTimeOffset.Now.ToUnixTimeMilliseconds()}");
}
else
{
Console.WriteLine($"{person} do not release lock ....");
}
}
else
{
Console.WriteLine($"{person} begin eat food (without lock) at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");
}
}); নমুনা চালানোর পরে, আপনি নিম্নলিখিত ফলাফল পেতে পারেন।
আপনি দেখতে পাচ্ছেন, 3 এবং 4 জন ব্যক্তি তালা ছাড়াই এগিয়ে যাবে।
এখানে সোর্স কোডটি আপনি আমার GitHub পৃষ্ঠায় খুঁজে পেতে পারেন৷
৷- RedisLockDemo
সারাংশ
এই নিবন্ধটি .NET কোরে Redis-এর সাহায্যে কীভাবে বিতরণ করা লক তৈরি করা যায় তা তুলে ধরা হয়েছে। এবং এটি একটি মৌলিক সংস্করণ, আপনি আপনার ব্যবসার উপর ভিত্তি করে উন্নতি করতে পারেন।
আমি আশা করি এটি আপনাকে সাহায্য করবে৷