परिचय
इस लेख में, हम चर्चा करेंगे कि .NET Core में Redis के साथ डिस्ट्रिब्यूटेड लॉक कैसे बनाएं।
जब हम डिस्ट्रिब्यूटेड सिस्टम्स बनाते हैं, तो हम कई प्रक्रियाओं का सामना करेंगे जो एक साझा संसाधन को एक साथ संभालते हैं। यह इस तथ्य के कारण कुछ अप्रत्याशित समस्याएं पैदा करेगा कि उनमें से केवल एक ही एक समय में साझा संसाधन का उपयोग कर सकता है!
हम इस समस्या को हल करने के लिए डिस्ट्रिब्यूटेड लॉक का उपयोग कर सकते हैं।
डिस्ट्रिब्यूटेड लॉक क्यों?
हमेशा की तरह, हम इस समस्या को संभालने के लिए एक लॉक का उपयोग करेंगे।
निम्नलिखित लॉक के उपयोग को दर्शाने वाले कुछ नमूना कोड दिखाता है।
public void SomeMethod() {
// कुछ करें...
lock (obj) {
// करें ....
}
// कुछ करें...
}
हालांकि, इस प्रकार का लॉक हमें समस्या को अच्छी तरह से हल करने में मदद नहीं कर सकता! यह एक इन-प्रोसेस लॉक है जो केवल साझा संसाधनों के साथ एक प्रक्रिया को हल कर सकता है।
यही मुख्य कारण है कि हमें डिस्ट्रिब्यूटेड लॉक की आवश्यकता है!
मैं यहां Redis का उपयोग करके एक सरल डिस्ट्रिब्यूटेड लॉक बनाऊंगा।
और मैं यह काम करने के लिए Redis का उपयोग क्यों करता हूं? Redis की सिंगल-थ्रेडेड प्रकृति और एटॉमिक ऑपरेशन्स करने की इसकी क्षमता के कारण।
लॉक कैसे बनाएं?
मैं आपको दिखाने के लिए एक .NET Core कंसोल एप्लिकेशन बनाऊंगा।
अगले चरण से पहले, हमें Redis सर्वर चलाना चाहिए!
StackExchange.Redis .NET पर सबसे लोकप्रिय Redis क्लाइंट है, और इसमें कोई संदेह नहीं है कि हम निम्नलिखित कार्यों को करने के लिए इसका उपयोग करेंगे।
सबसे पहले Redis के साथ कनेक्शन बनाना।
/// <summary>
/// आलसी कनेक्शन।
/// </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>
/// कनेक्शन प्राप्त करता है।
/// </summary>
/// <value>कनेक्शन।</value>
public static ConnectionMultiplexer Connection => lazyConnection.Value;
साझा संसाधन पर लॉक का अनुरोध करने के लिए, हम निम्नलिखित करते हैं।
SET resource_name unique_value NX PX duration
resource_name एक मान है जिसे आपके एप्लिकेशन के सभी इंस्टेंसेस साझा करेंगे।
unique_value कुछ ऐसा होना चाहिए जो आपके एप्लिकेशन के प्रत्येक इंस्टेंस के लिए यूनिक हो। और इस यूनिक मान का उद्देश्य लॉक को हटाना (अनलॉक) है।
अंत में, हम एक अवधि (मिलीसेकंड में) भी प्रदान करते हैं, जिसके बाद लॉक को Redis द्वारा स्वचालित रूप से हटा दिया जाएगा।
यहां C# कोड में कार्यान्वयन है।
/// <summary>
/// लॉक प्राप्त करता है।
/// </summary>
/// <returns><c>true</c>, यदि लॉक प्राप्त हुआ, <c>false</c> अन्यथा।</returns>
/// <param name="key">कुंजी।</param>
/// <param name="value">मान।</param>
/// <param name="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($"लॉक प्राप्त करने में विफल...{ex.Message}");
flag = true;
}
return flag;
}
यहां लॉक प्राप्त करने का टेस्ट कोड है।
static void Main(string[] args) {
string lockKey = "lock:eat";
TimeSpan expiration = TimeSpan.FromSeconds(5);
// 5 व्यक्ति कुछ खाते हैं...
Parallel.For(0, 5, x => {
string person = $"person:{x}";
bool isLocked = AcquireLock(lockKey, person, expiration);
if (isLocked) {
Console.WriteLine($"{person} लॉक के साथ खाना खाना शुरू करता है at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");
} else {
Console.WriteLine($"{person} लॉक न मिलने के कारण खाना नहीं खा सकता।");
}
});
Console.WriteLine("समाप्त");
Console.Read();
}
कोड चलाने के बाद, हमें निम्नलिखित परिणाम मिल सकता है।

केवल एक व्यक्ति लॉक प्राप्त कर सकता है! अन्य प्रतीक्षा कर रहे हैं।
हालांकि लॉक Redis द्वारा स्वचालित रूप से हटा दिया जाएगा, यह साझा संसाधन का अच्छा उपयोग भी नहीं करता!
क्योंकि जब एक प्रक्रिया अपना काम पूरा करती है, तो उसे दूसरों को संसाधन का उपयोग करने देना चाहिए, अंतहीन प्रतीक्षा नहीं करनी चाहिए!
इसलिए हमें लॉक को रिलीज़ करने की भी आवश्यकता है।
लॉक कैसे रिलीज़ करें?
लॉक रिलीज़ करने के लिए, हमने बस Redis में आइटम को हटा दिया!
जैसा कि हम लॉक बनाने में लेते हैं, हमें संसाधन के यूनिक मान से मेल खाना होगा। यह सही लॉक को रिलीज़ करना सुरक्षित बना देगा।
मिलान करते समय, हम लॉक को हटा देंगे, जिसका अर्थ है कि अनलॉक सफल रहा। अन्यथा, अनलॉक असफल रहा।
हमें गेट और डेल कमांड्स को एक साथ निष्पादित करने की आवश्यकता है, इसलिए हम इसे करने के लिए एक Lua स्क्रिप्ट का उपयोग करेंगे!
/// <summary>
/// लॉक रिलीज़ करता है।
/// </summary>
/// <returns><c>true</c>, यदि लॉक रिलीज़ हुआ, <c>false</c> अन्यथा।</returns>
/// <param name="key">कुंजी।</param>
/// <param name="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 लॉक विफल...{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} लॉक के साथ खाना खाना शुरू करता है at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");
if (new Random().NextDouble() < 0.6) {
Console.WriteLine($"{person} लॉक रिलीज़ करता है {ReleaseLock(lockKey, person)} {DateTimeOffset.Now.ToUnixTimeMilliseconds()}");
} else {
Console.WriteLine($"{person} लॉक रिलीज़ नहीं करता ....");
}
} else {
Console.WriteLine($"{person} बिना लॉक के खाना खाना शुरू करता है at {DateTimeOffset.Now.ToUnixTimeMilliseconds()}.");
}
});
नमूना चलाने के बाद, आपको निम्नलिखित परिणाम मिल सकता है।
जैसा कि आप देख सकते हैं, व्यक्ति 3 और 4 बिना लॉक के आगे बढ़ेंगे।
यहां सोर्स कोड है जिसे आप मेरे GitHub पेज पर पा सकते हैं।
- RedisLockDemo
सारांश
इस लेख ने .NET Core में Redis के साथ डिस्ट्रिब्यूटेड लॉक्स बनाने का परिचय दिया। और यह एक बेसिक वर्जन है, आप अपने बिजनेस के आधार पर सुधार कर सकते हैं।
मुझे आशा है कि यह आपकी मदद करता है।