قفل توزیع شده با استفاده از Redis

هی هابر!

امروز ترجمه یک مقاله پیچیده در مورد اجرای قفل توزیع شده با استفاده از Redis را مورد توجه شما قرار می دهیم و از شما دعوت می کنیم تا در مورد چشم انداز Redis به عنوان یک موضوع صحبت کنید. تجزیه و تحلیل الگوریتم Redlock مورد بحث از مارتین کلپمن، نویسنده کتاب "برنامه های کاربردی با بار بالا"، داده شده اینجا.

قفل توزیع شده یک روش اولیه بسیار مفید است که در بسیاری از محیط‌ها استفاده می‌شود که در آن فرآیندهای مختلف باید بر روی منابع مشترک به شیوه‌ای انحصاری متقابل کار کنند.

تعدادی کتابخانه و پست وجود دارد که نحوه پیاده‌سازی DLM (مدیر قفل توزیع شده) را با استفاده از Redis توضیح می‌دهد، اما هر کتابخانه رویکرد متفاوتی دارد و تضمین‌هایی که ارائه می‌دهند در مقایسه با آنچه که با طراحی کمی پیچیده‌تر قابل دستیابی است، بسیار ضعیف است.

در این مقاله سعی خواهیم کرد یک الگوریتم متعارف شرطی را توضیح دهیم که نحوه اجرای قفل توزیع شده با استفاده از Redis را نشان می دهد. ما در مورد الگوریتمی به نام صحبت خواهیم کرد ردلاک، یک مدیر قفل توزیع شده را پیاده سازی می کند و به نظر ما این الگوریتم ایمن تر از روش معمول تک نمونه ای است. ما امیدواریم که جامعه آن را تجزیه و تحلیل کند، بازخورد ارائه کند و از آن به عنوان نقطه شروعی برای پروژه های پیچیده تر یا جایگزین استفاده کند.

پیاده سازی

قبل از اینکه به توضیح الگوریتم بپردازیم، چندین پیوند به پیاده سازی های آماده ارائه می دهیم. می توان از آنها برای مرجع استفاده کرد.

  • Redlock-rb (پیاده سازی برای روبی). نیز وجود دارد چنگال Redlock-rb، که یک بسته (جم) را برای سهولت توزیع، و نه تنها برای آن، اضافه می کند.
  • Redlock-py (پیاده سازی پایتون).
  • Aioredlock (پیاده سازی برای Asyncio Python).
  • Redlock-php (پیاده سازی برای PHP).
  • PHPRedisMutex (یک پیاده سازی دیگر برای PHP)
  • cheprasov/php-redis-lock (کتابخانه PHP برای قفل)
  • Redsync (پیاده سازی برای Go).
  • ردیسون (پیاده سازی برای جاوا).
  • Redis::DistLock (پیاده سازی برای پرل).
  • Redlock-cpp (پیاده سازی برای C++).
  • Redlock-cs (پیاده سازی برای C#/.NET).
  • RedLock.net (پیاده سازی برای C#/.NET). با پشتیبانی از پسوندهای async و lock.
  • اسکارلت لاک (پیاده سازی برای C#.NET با ذخیره داده قابل تنظیم)
  • Redlock4Net (پیاده سازی برای C#.NET)
  • گره قرمز (پیاده سازی برای NodeJS). شامل پشتیبانی برای گسترش قفل.

امنیت و ضمانت های در دسترس بودن

ما می‌خواهیم طرح خود را تنها با سه ویژگی که فکر می‌کنیم حداقل تضمین‌های لازم برای استفاده مؤثر از قفل توزیع‌شده را ارائه می‌دهند، مدل‌سازی کنیم.

  1. دارایی امنیتی: طرد متقابل. در هر زمان معین، فقط یک مشتری می تواند قفل را نگه دارد.
  2. ویژگی A: بدون بن بست. همیشه ممکن است در نهایت یک قفل بدست آورید، حتی اگر کلاینتی که منبع را قفل کرده از کار بیفتد یا بر روی یک بخش دیسک دیگر قرار گیرد.
  3. ویژگی در دسترس بودن B: تحمل خطا. تا زمانی که اکثر گره های Redis در حال اجرا هستند، مشتریان می توانند قفل ها را بدست آورند و آزاد کنند.

چرا پیاده سازی بر اساس بازیابی شکست در این مورد کافی نیست
برای درک اینکه چه چیزی را می‌خواهیم بهبود دهیم، بیایید وضعیت فعلی را در اکثر کتابخانه‌های قفل‌شده توزیع‌شده مبتنی بر Redis تجزیه و تحلیل کنیم.

ساده ترین راه برای قفل کردن یک منبع با استفاده از Redis، ایجاد یک کلید در نمونه است. به طور معمول، یک کلید با طول عمر محدود ایجاد می شود، این با استفاده از ویژگی expires ارائه شده در Redis به دست می آید، بنابراین دیر یا زود این کلید آزاد می شود (ویژگی 2 در لیست ما). هنگامی که مشتری نیاز به انتشار منبع دارد، کلید را حذف می کند.

در نگاه اول، این راه حل بسیار خوب کار می کند، اما یک مشکل وجود دارد: معماری ما یک نقطه شکست ایجاد می کند. اگر نمونه میزبان Redis از کار بیفتد چه اتفاقی می‌افتد؟ اونوقت یه برده اضافه کنیم! و اگر ارائه دهنده در دسترس نباشد از آن استفاده خواهیم کرد. متاسفانه این گزینه قابل اجرا نیست. با انجام این کار، ما قادر نخواهیم بود ویژگی mutual exclusion را که برای اطمینان از امنیت نیاز داریم به درستی پیاده سازی کنیم، زیرا Replication در Redis ناهمزمان است.

بدیهی است که در چنین مدلی شرایط مسابقه رخ می دهد:

  1. کلاینت A یک قفل روی Master بدست می آورد.
  2. Master قبل از اینکه ورودی کلید به Slave منتقل شود از کار می افتد.
  3. پیرو به رهبری ارتقا می یابد.
  4. کلاینت B روی همان منبعی که A قبلا قفل کرده است، قفل می‌گیرد. نقض امنیتی!

گاهی اوقات کاملا طبیعی است که در شرایط خاص مانند خرابی، بسیاری از مشتریان می توانند قفل را همزمان نگه دارند. در چنین مواردی می توان از یک راه حل مبتنی بر تکرار استفاده کرد. در غیر این صورت راه حلی را که در این مقاله توضیح داده شده است را توصیه می کنیم.

اجرای صحیح با یک نمونه واحد

قبل از تلاش برای غلبه بر کاستی‌های پیکربندی تک نمونه‌ای که در بالا توضیح داده شد، بیایید نحوه مدیریت صحیح این مورد ساده را درک کنیم، زیرا این راه‌حل در واقع در برنامه‌هایی معتبر است که هر از گاهی شرایط مسابقه قابل قبول است و همچنین به دلیل مسدود کردن یک نمونه واحد به عنوان پایه ای عمل می کند که در الگوریتم توزیع شده که در اینجا توضیح داده شده است استفاده می شود.

برای به دست آوردن قفل، این کار را انجام دهید:

SET resource_name my_random_value NX PX 30000

این دستور تنها در صورتی یک کلید را نصب می کند که از قبل وجود نداشته باشد (گزینه NX)، با دوره اعتبار 30000 میلی ثانیه (گزینه PX). کلید روی “myrandomvalue" این مقدار باید در همه مشتریان و همه درخواست‌های قفل منحصربه‌فرد باشد.
اساساً، یک مقدار تصادفی برای آزاد کردن ایمن قفل استفاده می‌شود، با اسکریپتی که به Redis می‌گوید: فقط در صورتی کلید را بردارید که وجود داشته باشد و مقدار ذخیره شده در آن دقیقاً همان چیزی باشد که انتظار می‌رفت. این با استفاده از اسکریپت Lua زیر به دست می آید:

if redis.call("get",KEYS[1]) == ARGV[1] then
    return redis.call("del",KEYS[1])
else
    return 0
end

این برای جلوگیری از برداشتن قفلی که توسط مشتری دیگر نگه داشته شده است مهم است. به عنوان مثال، یک کلاینت ممکن است قفلی را بدست آورد، سپس در برخی عملیات که بیشتر از قفل اول طول می کشد قفل شود (به طوری که کلید زمان انقضا داشته باشد)، و بعداً قفلی را که مشتری دیگر قرار داده است حذف کند.
استفاده از یک DEL ساده ناامن است زیرا یک کلاینت می تواند قفلی را که توسط کلاینت دیگری نگه داشته شده است حذف کند. در مقابل، هنگام استفاده از اسکریپت بالا، هر قفل با یک رشته تصادفی "امضا" می شود، بنابراین فقط مشتری که قبلا آن را قرار داده است می تواند آن را حذف کند.

این رشته تصادفی باید چه باشد؟ من حدس می‌زنم که باید 20 بایت از /dev/urandom باشد، اما می‌توانید راه‌های ارزان‌تری پیدا کنید تا رشته را به اندازه کافی برای اهداف خود منحصربه‌فرد کنید. برای مثال، خوب است که RC4 را با /dev/urandom بکاریم و سپس یک جریان شبه تصادفی از آن تولید کنیم. یک راه حل ساده تر شامل ترکیبی از زمان یونیکس در وضوح میکروثانیه به اضافه شناسه مشتری است. آنچنان ایمن نیست، اما احتمالاً در بیشتر زمینه‌ها به عهده این کار است.

زمانی که ما به عنوان اندازه گیری طول عمر کلید استفاده می کنیم، "طول عمر قفل" نامیده می شود. این مقدار هم مقدار زمانی است که قفل به طور خودکار آزاد می شود و هم مدت زمانی است که یک کلاینت باید یک عملیات را انجام دهد تا اینکه مشتری دیگر بتواند آن منبع را قفل کند، بدون اینکه در واقع ضمانت های انکار متقابل را نقض کند. این ضمانت فقط محدود به یک بازه زمانی خاص است که از لحظه خرید قفل شروع می شود.

بنابراین ما یک راه خوب برای به دست آوردن و آزاد کردن قفل را مورد بحث قرار داده ایم. سیستم (اگر در مورد یک سیستم غیر توزیعی متشکل از یک نمونه واحد و همیشه در دسترس صحبت می کنیم) امن است. بیایید این مفهوم را به یک سیستم توزیع شده تعمیم دهیم، جایی که چنین تضمینی نداریم.

الگوریتم ردلاک

نسخه توزیع شده الگوریتم فرض می کند که ما N Redis Master داریم. این گره ها کاملاً مستقل از یکدیگر هستند، بنابراین ما از تکرار یا هیچ سیستم هماهنگی ضمنی دیگری استفاده نمی کنیم. ما قبلاً نحوه به دست آوردن و آزاد کردن قفل را در یک نمونه به طور ایمن پوشش داده ایم. ما بدیهی می دانیم که الگوریتم، هنگام کار با یک نمونه، دقیقاً از این روش استفاده می کند. در مثال های خود ما N را بر روی 5 قرار دادیم که یک مقدار معقول است. بنابراین، ما باید از 5 Master Redis در رایانه ها یا ماشین های مجازی مختلف استفاده کنیم تا اطمینان حاصل کنیم که آنها تا حد زیادی مستقل از یکدیگر عمل می کنند.

برای به دست آوردن قفل، مشتری عملیات زیر را انجام می دهد:

  1. زمان فعلی را بر حسب میلی ثانیه دریافت می کند.
  2. به‌طور متوالی تلاش می‌کند تا یک قفل را در تمام N نمونه‌ها، با استفاده از نام کلید یکسان و مقادیر تصادفی در همه موارد، به دست آورد. در مرحله 2، زمانی که مشتری یک قفل را بر اساس هر نمونه تنظیم می‌کند، مشتری از تاخیری برای بدست آوردن آن استفاده می‌کند که در مقایسه با زمانی که پس از آن قفل به طور خودکار آزاد می‌شود، به اندازه کافی کوتاه است. به عنوان مثال، اگر مدت زمان مسدود کردن 10 ثانیه باشد، تاخیر می تواند در محدوده 5-50 میلی ثانیه باشد. این وضعیتی را که در آن کلاینت می تواند برای مدت طولانی در تلاش برای رسیدن به یک گره Redis شکست خورده مسدود بماند، حذف می کند: اگر نمونه در دسترس نباشد، سعی می کنیم در اسرع وقت به نمونه دیگری متصل شویم.
  3. برای گرفتن قفل، مشتری محاسبه می کند که چقدر زمان سپری شده است. برای انجام این کار، مهر زمانی را که در مرحله 1 به دست آمده بود، از مقدار زمانی واقعی کم می کند. اگر و فقط در صورتی که کلاینت بتواند قفل را در اکثر نمونه ها (حداقل 3) به دست آورد، و کل زمان لازم برای بدست آوردن به دست آوردن قفل، کمتر از مدت زمان قفل، قفل به دست آمده در نظر گرفته می شود.
  4. اگر قفلی به دست آمده باشد، مدت قفل به عنوان مدت قفل اولیه منهای زمان سپری شده محاسبه شده در مرحله 3 در نظر گرفته می شود.
  5. اگر کلاینت به دلایلی نتواند قفل را به دست آورد (یا قادر به قفل کردن موارد N/2+1 نبود، یا مدت زمان قفل منفی بود)، سپس سعی خواهد کرد قفل همه موارد (حتی مواردی را که فکر می‌کرد نمی‌تواند مسدود کند) را باز کند. ).

آیا الگوریتم ناهمزمان است؟

این الگوریتم بر این فرض استوار است که اگرچه ساعت همگام‌سازی شده‌ای وجود ندارد که همه فرآیندها بر روی آن کار کنند، زمان محلی در هر فرآیند هنوز تقریباً با همان سرعت جریان دارد و خطا در مقایسه با زمان کل پس از آن قفل کوچک است. به طور خودکار منتشر شد. این فرض بسیار شبیه به وضعیت معمول برای رایانه های معمولی است: هر رایانه دارای یک ساعت محلی است و معمولاً می توانیم روی این واقعیت حساب کنیم که اختلاف زمانی بین رایانه های مختلف کم است.

در این مرحله، ما باید قانون حذف متقابل خود را با دقت بیشتری فرمول بندی کنیم: طرد متقابل تنها در صورتی تضمین می شود که مشتری که قفل را در دست دارد در طول مدت اعتبار قفل خارج شود (این مقدار در مرحله 3 به دست آمد)، منهای مدت زمان بیشتر (در مجموع چند مورد). میلی ثانیه برای جبران اختلاف زمانی بین فرآیندها).

مقاله جالب زیر در مورد چنین سیستم هایی که نیاز به هماهنگی فواصل زمانی دارند بیشتر توضیح می دهد: اجاره ها: یک مکانیسم مقاوم در برابر خطا برای سازگاری حافظه پنهان فایل توزیع شده.

برای شکست دوباره تلاش کنید

هنگامی که مشتری نتواند قفل را بدست آورد، باید پس از یک تاخیر تصادفی دوباره تلاش کند. این کار برای همگام سازی چندین مشتری در تلاش برای به دست آوردن قفل در یک منبع به طور همزمان انجام می شود (که می تواند منجر به یک وضعیت "تقسیم مغز" شود که در آن هیچ برنده ای وجود ندارد). علاوه بر این، هر چه مشتری سریعتر سعی کند در اکثر نمونه های Redis قفل را بدست آورد، پنجره ای که در آن موقعیت تقسیم مغز می تواند رخ دهد باریک تر می شود (و نیاز به تلاش مجدد کمتر می شود). بنابراین، در حالت ایده‌آل، کلاینت باید سعی کند دستورات SET را به N نمونه به طور همزمان با استفاده از مالتی پلکس ارسال کند.

در اینجا شایان ذکر است که چقدر مهم است که مشتریانی که نمی‌توانند اکثر قفل‌ها را به دست آورند، قفل‌های به دست‌آمده (تا حدی) را آزاد کنند، به طوری که آنها مجبور نباشند قبل از دریافت مجدد قفل منبع، منتظر انقضای کلید بمانند. (البته اگر تکه تکه شدن شبکه اتفاق بیفتد، و کلاینت با نمونه های Redis ارتباط خود را از دست بدهد، باید جریمه در دسترس بودن را در حالی که منتظر انقضای کلید هستید بپردازید).

قفل را آزاد کنید

آزاد کردن قفل یک عملیات ساده است که صرفاً نیاز به باز کردن قفل همه موارد دارد، صرف نظر از اینکه به نظر می رسد مشتری یک نمونه خاص را با موفقیت قفل کرده است یا خیر.

ملاحظات امنیتی

آیا الگوریتم امن است؟ بیایید سعی کنیم تصور کنیم که در سناریوهای مختلف چه اتفاقی می افتد.

برای شروع، بیایید فرض کنیم که کلاینت توانسته است در اکثر موارد یک قفل به دست آورد. هر نمونه حاوی یک کلید با طول عمر یکسان برای همه خواهد بود. با این حال، هر یک از این کلیدها در زمان متفاوتی نصب شده اند، بنابراین در زمان های مختلف منقضی می شوند. اما، اگر اولین کلید در زمانی نصب شده باشد که بدتر از T1 نباشد (زمانی که قبل از تماس با سرور اول انتخاب می کنیم)، و آخرین کلید در زمانی که بدتر از T2 (زمانی که پاسخ دریافت شد) نصب شده باشد. از آخرین سرور)، پس ما مطمئن هستیم که اولین کلید در مجموعه ای که منقضی می شود حداقل زنده خواهد ماند MIN_VALIDITY=TTL-(T2-T1)-CLOCK_DRIFT. همه کلیدهای دیگر دیرتر منقضی می شوند، بنابراین می توانیم مطمئن باشیم که همه کلیدها حداقل برای این زمان به طور همزمان معتبر خواهند بود.

در طول مدتی که اکثر کلیدها معتبر می مانند، کلاینت دیگری نمی تواند قفل را بدست آورد، زیرا اگر کلیدهای N/2+1 از قبل وجود داشته باشد، عملیات N/2+1 SET NX نمی تواند موفقیت آمیز باشد. بنابراین، هنگامی که یک قفل به دست آمده است، غیرممکن است که دوباره آن را در همان لحظه بدست آورید (این امر موجب نقض خاصیت طرد متقابل می شود).
با این حال، ما می‌خواهیم مطمئن شویم که چندین مشتری که در یک زمان تلاش می‌کنند یک قفل را به دست آورند، نمی‌توانند همزمان موفق شوند.

اگر کلاینت اکثر نمونه ها را تقریباً یا بیشتر از حداکثر مدت زمان قفل قفل کرده باشد، قفل را نامعتبر در نظر می گیرد و قفل نمونه ها را باز می کند. بنابراین، ما فقط باید موردی را در نظر بگیریم که در آن مشتری موفق شد اکثر موارد را در زمانی کمتر از تاریخ انقضا مسدود کند. در این صورت با توجه به استدلال فوق در طول زمان MIN_VALIDITY هیچ مشتری نباید بتواند قفل را دوباره بدست آورد. بنابراین، بسیاری از مشتریان قادر خواهند بود موارد N/2+1 را در یک زمان (که در پایان مرحله 2 به پایان می‌رسد) قفل کنند، تنها زمانی که زمان قفل کردن اکثریت بیشتر از زمان TTL باشد، که قفل را نامعتبر می‌کند.

آیا می توانید یک مدرک رسمی از امنیت ارائه دهید، الگوریتم های مشابه موجود را نشان دهید، یا یک اشکال در بالا پیدا کنید؟

ملاحظات دسترسی

در دسترس بودن سیستم به سه ویژگی اصلی بستگی دارد:

  1. آزاد کردن خودکار قفل ها (به دلیل منقضی شدن کلیدها): کلیدها در نهایت دوباره در دسترس خواهند بود تا برای قفل ها استفاده شوند.
  2. این واقعیت که مراجعین معمولاً در زمانی که قفل مورد نظر به دست نیامده یا به دست آمده و کار به پایان رسیده است با برداشتن قفل به یکدیگر کمک می کنند. بنابراین این احتمال وجود دارد که برای بدست آوردن مجدد قفل، منتظر انقضای کلیدها نباشیم.
  3. این واقعیت که وقتی مشتری نیاز به تلاش مجدد برای بدست آوردن قفل دارد، مدت زمان نسبتاً طولانی تری نسبت به دوره مورد نیاز برای بدست آوردن بیشتر قفل ها منتظر می ماند. این امر احتمال ایجاد یک وضعیت دوشاخه در هنگام رقابت برای منابع را کاهش می دهد.

با این حال، یک جریمه در دسترس بودن برابر با TTL بخش های شبکه وجود دارد، بنابراین اگر بخش های به هم پیوسته وجود داشته باشد، جریمه ممکن است نامحدود باشد. این زمانی اتفاق می‌افتد که یک کلاینت قفلی را بدست می‌آورد و سپس قبل از اینکه بتواند آن را آزاد کند به بخش دیگری می‌ریزد.

در اصل، با توجه به بخش های شبکه به هم پیوسته بی نهایت، یک سیستم می تواند برای مدت زمان نامتناهی در دسترس باقی بماند.

عملکرد، failover و fsync

بسیاری از مردم از Redis استفاده می کنند زیرا به عملکرد سرور قفل بالا از نظر تأخیر مورد نیاز برای بدست آوردن و آزاد کردن قفل ها و تعداد اکتساب/انتشارهایی که می توانند در هر ثانیه تکمیل شوند نیاز دارند. برای برآورده کردن این نیاز، یک استراتژی برای برقراری ارتباط با سرورهای N Redis برای کاهش تأخیر وجود دارد. این یک استراتژی مالتی پلکسی است (یا "مالتی پلکس کردن افراد فقیر"، که در آن سوکت در حالت غیر مسدود کننده قرار می گیرد، همه دستورات را ارسال می کند و دستورات را بعدا می خواند، با این فرض که زمان رفت و برگشت بین مشتری و هر نمونه مشابه است) .

با این حال، اگر بخواهیم مدلی با بازیابی مطمئن از خرابی ها ایجاد کنیم، باید ملاحظات مربوط به ذخیره سازی طولانی مدت داده را نیز در نظر بگیریم.

اساساً، برای روشن شدن موضوع، اجازه دهید فرض کنیم که Redis را بدون ذخیره‌سازی طولانی‌مدت داده پیکربندی می‌کنیم. مشتری موفق می شود 3 مورد از 5 مورد را مسدود کند. یکی از نمونه‌هایی که کلاینت موفق به مسدود کردن آن شده است مجدداً راه‌اندازی می‌شود و در این لحظه دوباره 3 نمونه برای همان منبع وجود دارد که می‌توانیم آن‌ها را مسدود کنیم و کلاینت دیگری به نوبه خود می‌تواند نمونه راه‌اندازی مجدد شده را مسدود کند و ویژگی امنیتی را نقض کند. انحصار قفل ها را فرض می کند.

اگر داده های پیش رو (AOF) را فعال کنید، وضعیت کمی بهبود می یابد. برای مثال، می‌توانید با ارسال دستور SHUTDOWN و راه‌اندازی مجدد سرور، آن را ارتقا دهید. از آنجایی که عملیات انقضا در Redis از نظر معنایی به گونه‌ای پیاده‌سازی می‌شوند که حتی زمانی که سرور خاموش است، زمان همچنان به جریان می‌افتد، همه نیازهای ما خوب است. این طبیعی است تا زمانی که از خاموش شدن عادی اطمینان حاصل شود. در صورت قطع برق چه باید کرد؟ اگر Redis به صورت پیش‌فرض پیکربندی شده باشد و fsync هر ثانیه روی دیسک همگام‌سازی شود، ممکن است پس از راه‌اندازی مجدد، کلید خود را نداشته باشیم. از لحاظ تئوری، اگر می‌خواهیم امنیت قفل را در هنگام راه‌اندازی مجدد تضمین کنیم، باید آن را فعال کنیم fsync=always در تنظیمات ذخیره سازی طولانی مدت داده ها. این به طور کامل عملکرد را کاهش می دهد، تا سطح سیستم های CP که به طور سنتی برای اجرای ایمن قفل های توزیع شده استفاده می شود.

اما وضعیت بهتر از آن چیزی است که در نگاه اول به نظر می رسد. در اصل، امنیت الگوریتم حفظ می شود، زیرا وقتی نمونه پس از خرابی مجدداً راه اندازی می شود، دیگر در هیچ قفلی که در حال حاضر فعال است شرکت نمی کند.

برای اطمینان از این امر، فقط باید اطمینان حاصل کنیم که پس از یک شکست، نمونه برای مدتی کمی بیشتر از حداکثر TTL مورد استفاده ما در دسترس نخواهد بود. به این ترتیب ما تا تاریخ انقضا و انتشار خودکار تمام کلیدهایی که در زمان خرابی فعال بودند صبر می کنیم.

با استفاده از راه اندازی مجدد تاخیری، در اصل امکان دستیابی به امنیت حتی در صورت عدم وجود تداوم طولانی مدت در Redis وجود دارد. با این حال، توجه داشته باشید که این ممکن است منجر به جریمه برای نقض دسترسی شود. به عنوان مثال، اگر اکثر نمونه ها از کار بیفتند، سیستم در سطح جهانی برای TTL در دسترس نخواهد بود (و هیچ منبعی را نمی توان در این مدت مسدود کرد).

ما در دسترس بودن الگوریتم را افزایش می دهیم: مسدودسازی را گسترش می دهیم

اگر کار انجام شده توسط مشتریان شامل مراحل کوچک باشد، می توان مدت زمان قفل پیش فرض را کاهش داد و مکانیزمی برای گسترش قفل ها پیاده سازی کرد. در اصل، اگر کلاینت مشغول محاسبات است و مقدار انقضای قفل به طور خطرناکی پایین است، می‌توانید یک اسکریپت Lua را به همه موارد ارسال کنید که TTL کلید را گسترش می‌دهد، اگر کلید همچنان وجود داشته باشد و مقدار آن هنوز یک مقدار تصادفی است که زمانی که قفل بدست آمد

یک کلاینت تنها زمانی باید قفلی را برای دریافت مجدد در نظر بگیرد که بتواند اکثر موارد را در مدت اعتبار قفل کند.

درست است، از نظر فنی، الگوریتم تغییر نمی کند، بنابراین حداکثر تعداد تلاش های مکرر برای به دست آوردن قفل ها باید محدود باشد، در غیر این صورت ویژگی های دسترسی نقض می شود.

منبع: www.habr.com

اضافه کردن نظر