Computer >> कंप्यूटर ट्यूटोरियल >  >> प्रोग्रामिंग >> Redis

.NET Core में Redis डिस्ट्रिब्यूटेड लॉक लागू करना

परिचय

इस लेख में, हम चर्चा करेंगे कि .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();
}

कोड चलाने के बाद, हमें निम्नलिखित परिणाम मिल सकता है।

.NET Core में Redis डिस्ट्रिब्यूटेड लॉक लागू करना

केवल एक व्यक्ति लॉक प्राप्त कर सकता है! अन्य प्रतीक्षा कर रहे हैं।

हालांकि लॉक 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 के साथ डिस्ट्रिब्यूटेड लॉक्स बनाने का परिचय दिया। और यह एक बेसिक वर्जन है, आप अपने बिजनेस के आधार पर सुधार कर सकते हैं।

मुझे आशा है कि यह आपकी मदद करता है।

  1. Android में अनसॉर्टेड लिंक्ड लिस्ट से डुप्लिकेट कैसे हटाएं? Android में अनसॉर्टेड लिंक्ड लिस्ट से डुप्लिकेट कैसे हटाएं?

    Android में अनसॉर्टेड लिंक्ड लिस्ट से डुप्लिकेट हटाना यह उदाहरण दर्शाता है कि Android में अनसॉर्टेड (अक्रमित) लिंक्ड लिस्ट से डुप्लिकेट मान कैसे हटाए जाते हैं। चरण 1: नया प्रोजेक्ट बनाएं Android Studio में File → New Project पर जाएं और आवश्यक विवरण भरकर एक नया प्रोजेक्ट बनाएं। चरण 2: लेआउट XML में

  1. HTML DOM KeyboardEvent metaKey गुण HTML DOM KeyboardEvent metaKey गुण

    HTML DOM KeyboardEvent metaKey गुण बूलियन मान (true/false) लौटाता है जो दर्शाता है कि मेटा कुंजी घटना का उपयोग करके दबाई गई थी या नहीं। सिंटैक्स निम्नलिखित सिंटैक्स है − बूलियन मान लौटाना − event.metaKey उदाहरण आइए KeyboardEvent metaKey गुण का एक उदाहरण देखें − <!DOCTYPE html> <html> &l

  1. HTML DOM Link type गुण HTML DOM Link type गुण

    Link type गुण लिंक किए गए दस्तावेज़ के प्रकार को सेट/लौटाता है। सिंटैक्स निम्नलिखित सिंटैक्स है − type विशेषता का मान लौटाना linkObject.type type को वैध मान पर सेट करना linkObject.type = value नोट  − वैध मानों में "text/javascript", "text/css", "image/gif", आद