डिस्ट्रिब्यूटेड लॉकिंग लागू करने के तरीके (2016)
(martin.kleppmann.com)- Redis आधारित Redlock fault-tolerant distributed lock का लक्ष्य रखता है, लेकिन correctness दांव पर लगे कामों के लिए इसकी safety अपर्याप्त है, और efficiency optimization के लिए यह जरूरत से ज्यादा जटिल है
- distributed lock में पहले duplicate work घटाने के efficiency उद्देश्य और shared state को सुरक्षित रखने के correctness उद्देश्य को अलग करना चाहिए; आकलन का आधार यह है कि failure होने पर लागत बढ़ती है या data corruption होता है
- परफेक्ट lock service होने पर भी लंबे GC pause, process suspension और network delay के कारण lease expiry के बाद stale write execute हो सकती है, इसलिए fencing token जरूरी है
- Redlock हर lock acquisition पर monotonically increasing token नहीं बना सकता, और Redis key expiry
gettimeofdayआधारित system clock पर निर्भर करती है, जिससे clock jump या delay की स्थितियों में safety टूट सकती है - correctness की जरूरत वाले locks के लिए ZooKeeper जैसे consensus system और fencing token checks इस्तेमाल करें, और Redis single-node lock को approximate, non-critical use cases तक सीमित रखें
Redlock की समीक्षा का शुरुआती बिंदु
- Redlock Redis के ऊपर fault-tolerant distributed lock, अधिक सटीक रूप से lease, लागू करने वाला algorithm है
- इसकी 10 से अधिक independent implementations पहले से मौजूद हैं, और यह पता नहीं कि कौन इस algorithm पर निर्भर है, इसलिए public review करना मूल्यवान है
- Redis स्वयं servers के बीच temporary, approximate और तेजी से बदलने वाला data share करने के use case के लिए अच्छी तरह उपयुक्त है
- उदाहरण: IP address के हिसाब से request counter, user ID के हिसाब से unique IP set
- चिंता की बात यह है कि Redis को धीरे-धीरे ऐसे data management क्षेत्रों में इस्तेमाल किया जा रहा है जहाँ ज्यादा मजबूत consistency और durability अपेक्षित होती है, और distributed locks भी ऐसे ही क्षेत्रों में से एक हैं
lock का उद्देश्य: efficiency या correctness?
- distributed application में lock वह mechanism है जिससे जब कई nodes वही काम करने की कोशिश करें, तो एक समय में केवल एक ही उसे execute करे
- lock इस्तेमाल करने के कारण मोटे तौर पर दो प्रकार के होते हैं
- efficiency: वही महंगी computation दो बार न करने के लिए optimization; failure होने पर बस AWS cost थोड़ी बढ़ती है या वही email notification दो बार चला जाता है
- correctness: concurrent processes को same state खराब करने से रोकने का mechanism; failure होने पर file corruption, data loss, permanent inconsistency, गलत medication administration जैसी गंभीर समस्याएँ हो सकती हैं
- efficiency उद्देश्य वाले lock के लिए 5 Redis servers और majority confirmation इस्तेमाल करने वाले Redlock की cost और complexity अनावश्यक है
- single Redis instance और जरूरत पड़ने पर asynchronous replication इस्तेमाल करना अधिक उपयुक्त है
- इस स्थिति में power failure या Redis node issue के कारण कुछ locks खो सकते हैं, लेकिन non-critical optimization हो तो यह tolerable failure है
- 5 replicas और majority के कारण Redlock correctness-critical lock के लिए उपयुक्त दिख सकता है, लेकिन वास्तव में यह उस उद्देश्य के लिए अनुपयुक्त है
केवल lease से resource को सुरक्षित रूप से protect नहीं किया जा सकता
- distributed system के locks multi-threaded application के mutex से अलग होते हैं; nodes और network independent रूप से fail हो सकते हैं, इसलिए वे अधिक जटिल हैं
- shared storage में file update करने का typical flow है: lock acquire करना, file पढ़ना, modify करना, फिर write करना, lock release करना
- lock का उद्देश्य दो clients को read-modify-write एक साथ करके updates खो देने से रोकना है
- यदि client lock पकड़े हुए लंबे समय तक रुक जाए, तो lease expire हो सकती है
- GC के कारण client लंबे समय तक pause हो सकता है
- lease crash हुए client को lock हमेशा के लिए पकड़े रहने से रोकने वाला अच्छा design है, लेकिन pause time expiry time से लंबा हो जाए तो client expiry जाने बिना dangerous write execute कर सकता है
- यह समस्या केवल theoretical case नहीं है; HBase में भी पहले ऐसी ही समस्या रही है
- “stop-the-world” GC pause कुछ cases में कई मिनट तक चला है
- HotSpot JVM का CMS जैसा “concurrent” GC भी कभी-कभी application को रोकना पड़ता है
- write से ठीक पहले lock expiry check करने से यह हल नहीं होता
- GC last check और write operation के बीच सहित किसी भी point पर running thread को रोक सकता है
process pause और network delay आम threat model हैं
- लंबे GC pause न होने वाला runtime इस्तेमाल करने पर भी process कई वजहों से रुक सकता है
- memory में मौजूद न होने वाला address read करने पर page fault हो सकता है
- यदि disk EBS है, तो variable read Amazon network के जरिए synchronous request में बदल सकता है
- CPU contention, scheduler delay, गलती से भेजा गया
SIGSTOPभी process रोक सकता है
- network delay भी वही समस्या पैदा करता है
- application ने write request भेजी, लेकिन packet delay होकर lease expiry के बाद storage server तक पहुँच सकता है
- GitHub के एक outage में network packets लगभग 90 seconds delay हुए थे
- Ethernet और IP जैसे packet networks packets को arbitrary रूप से delay कर सकते हैं, और वास्तव में ऐसा होता है
- इसलिए अच्छी तरह managed network में भी timing assume नहीं की जा सकती, और simple lease-based code किसी भी lock service के साथ fundamentally safe नहीं है
fencing token से stale writes को block करना चाहिए
- समाधान यह है कि हर storage write request में fencing token शामिल किया जाए
- fencing token एक संख्या है जो हर बार client के lock acquire करने पर बढ़ती है
- उदाहरण: client 1 token 33 के साथ lease लेता है, फिर लंबे समय तक pause होता है और lease expire हो जाती है
- client 2 token 34 के साथ नई lease लेता है और storage को write request भेजता है
- बाद में client 1 जागकर token 33 के साथ write भेजता है, तो storage token 33 request reject करता है क्योंकि वह पहले ही अधिक ऊँचे token 34 को process कर चुका है
- safe रहने के लिए storage server को token actively check करना चाहिए और जिस write का token value पीछे चला गया हो उसे reject करना चाहिए
- यदि lock service strictly monotonically increasing tokens generate करे, तो lock को safe बनाया जा सकता है
- ZooKeeper को lock service के रूप में इस्तेमाल करने पर
zxidया znode version number को fencing token के रूप में इस्तेमाल किया जा सकता है
- ZooKeeper को lock service के रूप में इस्तेमाल करने पर
- Redlock की बड़ी समस्या यह है कि इसमें fencing token generation capability नहीं है
- Redlock का unique random value आवश्यक monotonic increase प्रदान नहीं करता
- single Redis node का counter पर्याप्त नहीं है क्योंकि वह node fail हो सकता है
- कई nodes के counters एक-दूसरे से diverge हो सकते हैं
- fencing token generate करने के लिए भी संभवतः consensus algorithm की जरूरत होगी
Redlock safety के लिए timing assumptions पर निर्भर है
- distributed algorithm में practical model asynchronous model और unreliable failure detector है
- process arbitrary duration के लिए रुक सकता है
- packet network में arbitrary रूप से delay हो सकता है
- clock arbitrary रूप से गलत हो सकती है
- फिर भी algorithm को सही decision लेना चाहिए
- clock का उपयोग केवल timeout generate करने के लिए किया जा सकता है, ताकि node down होने पर हमेशा इंतजार न करना पड़े
- timeout को accurate होना जरूरी नहीं है, और request timeout होने का मतलब यह नहीं कि peer node जरूर down है
- यह network delay या local clock error भी हो सकता है
- Redis key expiry तय करते समय monotonic clock नहीं बल्कि
gettimeofdayइस्तेमाल करता हैgettimeofdayमें system time discontinuously jump कर सकता है- यदि NTP clock adjust करे या admin manually time बदल दे, तो Redis key expiry अपेक्षा से बहुत तेज या बहुत धीमी हो सकती है
- asynchronous model के algorithms सामान्यतः timing assumptions के बिना safety बनाए रखते हैं, और timeout जैसे failure detectors केवल liveness को प्रभावित करते हैं
- timing खराब हो तो performance बिगड़ सकती है, लेकिन गलत decision नहीं लिया जाना चाहिए
- Redlock इससे अलग है: इसकी safety कई timing assumptions पर निर्भर करती है
- सभी Redis nodes को लगभग सही duration तक key रखनी चाहिए
- network delay expiry time से पर्याप्त कम होना चाहिए
- process pause expiry time से बहुत छोटा होना चाहिए
खराब timing में Redlock टूटने के उदाहरण
- जब 5 Redis nodes A, B, C, D, E और clients 1, 2 हों, तो किसी एक node की clock आगे jump करे तो दोनों clients विश्वास कर सकते हैं कि उनके पास lock है
- client 1 A, B, C से lock लेता है और network issue के कारण D, E तक नहीं पहुँच पाता
- C की clock आगे jump करती है और lock expire हो जाता है
- client 2 C, D, E से lock लेता है और network issue के कारण A, B तक नहीं पहुँच पाता
- नतीजा यह कि client 1 और 2 दोनों खुद को lock holder मानते हैं
- यदि C lock को disk पर persist करने से पहले crash होकर तुरंत restart हो जाए, तो भी similar problem हो सकती है
- Redlock documentation crash हुए node के restart को सबसे लंबे lock TTL से अधिक delay करने की सलाह देता है
- यह restart delay भी reasonably accurate time measurement पर निर्भर है, और clock jump होने पर fail हो सकता है
- client process pause भी Redlock को तोड़ सकता है
- client 1 A, B, C, D, E को lock request भेजता है
- जब responses transit में होते हैं, client 1 stop-the-world GC में चला जाता है
- सभी Redis nodes के locks expire हो जाते हैं
- client 2 A, B, C, D, E से lock लेता है
- client 1 GC खत्म करके kernel network buffer में पड़े success responses प्राप्त करता है
- दोनों clients विश्वास करते हैं कि वे lock hold करते हैं
- Redis C में लिखा है और उसमें GC नहीं है, यह बात मदद नहीं करती
- समस्या उन systems में होती है जहाँ client GC pause झेल सकता है
- fencing token जैसे तरीके से client 2 के lock लेने के बाद client 1 का काम रोकना होगा, तभी safety होगी
- लंबा network delay भी process pause जैसा effect दे सकता है
- TCP user timeout को Redis TTL से बहुत छोटा set करने पर delayed packets ignore होने की संभावना है, लेकिन निश्चित होने के लिए specific TCP implementation देखनी होगी
- इस case में भी हम फिर time measurement accuracy की समस्या पर लौट आते हैं
Redlock द्वारा आवश्यक synchronous system assumptions
- Redlock केवल ऐसे synchronous system model में सही काम करता है जिसमें ये properties हों
- network delay की upper bound guaranteed हो
- process pause time limited हो
- clock error limited हो
- synchronous model का मतलब clocks का exactly synchronized होना नहीं है, बल्कि network delay, pause और clock drift के लिए ज्ञात fixed upper bounds होना है
- Redlock assume करता है कि delay, pause और drift सभी lock TTL की तुलना में छोटे हैं
- timing problem TTL जितनी बड़ी हो जाए तो algorithm fail हो जाता है
- आम data center environment में ऐसी timing assumptions ज्यादातर समय satisfied हो सकती हैं; इसे partially synchronous system कहा जाता है
- यदि correctness lock पर निर्भर है, तो “ज्यादातर समय” पर्याप्त नहीं है
- timing assumption टूटते ही Redlock safety violate कर सकता है, जैसे एक client की lease expire होने से पहले दूसरे client को lease दे देना
- GitHub का 90-second packet delay example वास्तविक environments में synchronous system model assume करना कठिन होने का evidence है
- Raft, Viewstamped Replication, Zab, Paxos partially synchronous system model या failure detectors वाले asynchronous model के लिए design किए गए consensus algorithms की category में आते हैं
- ऐसे algorithms में timing assumptions छोड़नी पड़ती हैं, और ध्यान रखना चाहिए कि distributed system के network, processes और clocks को वास्तविकता से अधिक reliable assume न किया जाए
निष्कर्ष और recommended options
- Redlock efficiency optimization locks के लिए अनावश्यक रूप से heavy और expensive है, और correctness-critical locks के लिए पर्याप्त safe नहीं है
- खास तौर पर यह network delay और operation execution time की upper bounds वाले synchronous system को effectively assume करता है, और assumption टूटने पर safety violate हो सकती है
- इसमें लंबे network delays या paused processes से system को protect करने के लिए fencing token generation capability भी नहीं है
- यदि best-effort based efficiency optimization lock चाहिए, तो Redis का single-node lock algorithm इस्तेमाल करना बेहतर है
- conditional set-if-not-exists से lock लें
- value match होने पर ही atomically delete करके lock release करें
- code में साफ document करें कि lock approximate है और कभी-कभी fail हो सकता है
- 5 Redis nodes का cluster setup करने की जरूरत नहीं है
- correctness की जरूरत वाले locks के लिए Redlock न इस्तेमाल करें; ZooKeeper जैसे consensus system का उपयोग करें
- संभव हो तो locks implement करने वाले Curator recipes इस्तेमाल कर सकते हैं
- कम से कम reasonable transaction guarantees देने वाला PostgreSQL जैसा database इस्तेमाल कर सकते हैं
- lock के नीचे सभी resource access में fencing token checks enforce करने चाहिए
- Redis अपने intended use cases में इस्तेमाल किया जाए तो उपयोगी tool है, और हर tool की सीमाएँ होती हैं, इसलिए उन सीमाओं को समझकर plan करना चाहिए
- 9 फरवरी 2016 के update में Redlock के original author Salvatore ने rebuttal post publish की, लेकिन conclusion वही रहता है
1 टिप्पणियां
Hacker News की राय
काम पर हम Temporal इस्तेमाल कर रहे हैं, और dedicated workflow व signals से distributed lock implement किया है
अब तक यह ठीक चल रहा है, और lock के distributed processing वाले हिस्से को Temporal features पर छोड़ देने से implementation भी काफ़ी सरल है
जानना चाहता हूँ कि इस क्षेत्र में Temporal अकेला standout है, या इसी स्तर के alternatives भी हैं
यह Uber से अलग हुआ है और बड़े vendors इसे इस्तेमाल करते हैं, तो यह काफी production-proven लगता है
distributed locks के लिए आम तौर पर PostgreSQL advisory lock इस्तेमाल करता हूँ
काम database से संबंधित न भी हो, तो भी transaction शुरू करके advisory lock ले लें, तो lock तब तक बना रहता है जब तक app उसे खुद release न करे या crash वगैरह से transaction खत्म न हो जाए
अब तक मुझे यह काफ़ी safe लगा, लेकिन अभी एहसास हुआ कि मैंने कभी यह verify नहीं किया कि database connection अभी भी ठीक है या नहीं
अगर database-related काम हो तो query fail होने के साथ काम भी fail हो जाएगा, लेकिन वरना हो सकता है कि lock खो चुका हो और पता भी न चले
fencing token या atomic operation जैसी चीज़ों के बिना अगर absolute correctness चाहिए, तो शायद अंत में हर operation के लिए two-phase commit ही चाहिए होता है
शायद जो आप करना चाहते थे उसे सही तरह करने के लिए “EXCLUSIVE” या “ACCESS EXCLUSIVE” इस्तेमाल करना होगा, या operation के लिए two-phase commit या idempotency सुनिश्चित करनी होगी
[0] https://www.postgresql.org/docs/current/explicit-locking.htm...
ज़्यादातर libraries आम तौर पर connection pool इस्तेमाल करती हैं, इसलिए lock के लिए dedicated connection लेना होगा और periodic lock check भी उसी connection से करना होगा
पहले मैंने इस blog के comments में जो comment लिखा था, और अपने blog पर जो reply लिखा था, उन्हें पढ़ना अच्छा रहेगा
बिना किसी क्रम के कहूँ तो, लेखक ने algorithm कैसे काम करता है इसके core points मिस कर दिए, और फिर बचे हुए कमजोर आधारों पर algorithm को reject कर दिया
यह कहना भी सही नहीं कि modern computers और APIs में roughly सही समय जितना इंतज़ार करना असंभव है। GC pauses bounded होते हैं और monotonic clocks भी काम करती हैं, इसलिए यह स्वीकार्य assumption है
automatic release mechanism अपने आप में potential race condition expose करता है, इस आधार पर आलोचना करना और algorithm के goals व system model के भीतर आलोचना करना अलग बातें हैं
Redlock कई सालों से कई use cases में सफलतापूर्वक इस्तेमाल हुआ है, और अगर timeout को job completion time तथा सामान्य operating systems में हो सकने वाले arbitrary pauses से काफी बड़ा रखा जाए, तो race condition पैदा करना बहुत मुश्किल है
बेशक अगर automatic release timeout बहुत छोटा रखा गया है और job आसानी से उतना समय ले सकता है, तो वह design error है, लेकिन वह Redlock की समस्या नहीं है
अगर timeout काफी छोटा हो (जैसे 1–2 सेकंड), काम आम तौर पर उस timeout का लगभग 90% लेता हो, और RedLock lock hold करते समय किया जाने वाला काम दूसरे lock holder के साथ कभी भी simultaneously run नहीं होना चाहिए, तो क्या आप RedLock इस्तेमाल करेंगे?
मेरे हिसाब से यहाँ सही जवाब हमेशा “नहीं” है। क्योंकि client के काम खत्म करने से पहले lease expire होने का जोखिम बहुत बड़ा है
RedLock हर स्थिति में mutual exclusion guarantee नहीं कर सकता, इसलिए काम को idempotent बनाना होगा, और इस तरह के case को optimistic lock से implement करना बेहतर है
low-level और algorithms knowledge फिर से मजबूत कर रहा हूँ; इस topic पर अच्छी books कौन-सी हैं? लेखक की लिखी book मेरे पास है
मज़े के लिए कुछ बनाकर देखना चाहता हूँ, लेकिन resources या तो toy-level हैं या बहुत complex
कोई एक topic चुनकर सच में implement करके देखें
पहले इसी material के आधार पर distributed lock blog post लिखी थी: https://medium.com/sahibinden-technology/an-easy-integration...
“lock में timeout होता है (यानी यह lease है)” वाली explanation अजीब लगती है
पहली बात, अगर client crash हो जाए तो timed lease न भी हो, OS या supervisor को lock release करना चाहिए; और अगर दोनों मर जाएँ, तो connection आखिरकार टूटेगा, और network system reset, timeout, heartbeat न मिलने आदि से इसे detect करके connection को invalidate करेगा और फिर lock छोड़ेगा
दूसरी बात, अगर समस्या यह है कि client bug के कारण crash हुए बिना lock बहुत देर तक पकड़े रहता है, तो क्या किसी supervisor को इसे detect करके दूसरों के लिए lock release करने से पहले client को kill नहीं करना चाहिए?
तीसरी बात, अगर ऐसे corner cases से निपटने के लिए timeout वाला lock रखा जाता है, तो क्या असली program को exception, signal, termination जैसी किसी तरह से notify नहीं करना चाहिए? और lock release करने से पहले क्या यह verify होने का इंतज़ार नहीं करना चाहिए कि program को notification मिल गई?
timeout लग जाने के बाद भी program को normal control flow जारी रखने देने का विचार ही problem की root cause जैसा लगता है, लेकिन समझ नहीं आता सब इसे क्यों नजरअंदाज कर देते हैं। क्या मैं कोई obvious वजह मिस कर रहा हूँ?
lock को अपनी तरफ invalidate करने वाली entity storage service है, और Redlock जो extra guarantees नहीं देता उनके बिना client अपनी समस्या खुद detect नहीं कर पाता
कुछ cases में ये packets drop हो जाते हैं, और remote machine का client पहले ही मर चुका होता है लेकिन server पर open connection बचा रह सकता है
वैसे, downvote मैंने नहीं किया था
Deno और Deno Deploy द्वारा होस्ट किए गए Deno KV से distributed lock लागू किया था
अंदरूनी तौर पर यह distributed database FoundationDB का उपयोग करता है, और local devices पर चल रहे Deno instances उसी Deno KV से connect होकर lock हासिल करते हैं
PostgreSQL इस्तेमाल करने पर भी
SELECT FOR UPDATEसे काम हो जाता है, लेकिन database खुद distributed नहीं है2018 में हमने अपने use case के लिए Redis पर विचार किया था, लेकिन आखिर में कम चमकदार समाधान चुना, और सच में वह एक बार भी fail नहीं हुआ
use case यह था कि किसी campaign के सीमित ticket set में से identifier वाले tickets एक-एक करके बांटने थे, कुछ वैसा जैसे Ticketmaster venue seats assign करता है
request आने पर उपलब्ध ticket देना था, request का metadata assigned ticket से जोड़ना था, और फिर उसे आगे की requests के target से बाहर करना था
पहले over-allocation, under-allocation, duplicate allocation जैसी fail campaigns हो चुकी थीं, इसलिए correctness मुख्य बात थी
Redis से lock acquire करना, lock check करना, काम करना, lock release करना—ऐसी simple implementation भी try की, लेकिन उस समय हमारे लिए operational burden बड़ा था, और अच्छा हुआ कि हम उस रास्ते पर नहीं गए
अंतिम चुनाव Postgres था। हमारा “distributed lock” Postgres की native features का उपयोग करने वाली composite
UPDATEstatement के अधिक करीब था, और हमने request को एक तरह के set operation में बदल दिया ताकि database success record या failure indicator लौटाए। ACID transactions जीत गएcorrectness हल करने के बाद हमने scale और performance देखी; हमें प्रति सेकंड लाखों requests की जरूरत नहीं थी, लेकिन sudden spikes के लिए criteria थे
cluster के अंदर read/write database instances को optimize किया, बड़े या ज्यादा demand वाले campaigns को strategically designated systems पर रखा, और 2 साल तक optimization जारी रखी, लेकिन ticket distribution fail campaign एक भी नहीं हुआ
मैं distributed lock technology का expert नहीं हूं; बस जिस समस्या को हल करना था उस पर focus किया, कुछ चीजें आजमाईं, और सही समाधान मिल गया
UPDATEtransaction कुछ microseconds ही चलता है, इसलिए समस्या को centralize किया जा सकता है, और वही ज्यादा simple, fast और safe हैलेकिन लेख में बताए अनुसार यह distributed problem नहीं है
distributed systems में lock, multi-threaded app के mutex से अलग होता है; कई nodes और network अपने-अपने तरीके से independently fail हो सकते हैं, इसलिए यह ज्यादा complex है
जब transaction कुछ seconds से लेकर कई hours तक लग सकता है, और संबंधित machine lock पकड़े हुए fail हो सकती है, तब distributed lock की जरूरत होती है
इस case में constraint है “N से ज्यादा tickets मत बेचो”, और ऐसी problems के अधिकांश real-world traffic scale को traditional relational database के transactional behavior से हल किया जा सकता है; internal lock management database पर छोड़ दें
मैं चाहूंगा कि developers “distributed lock बनाना है” पर बहुत जल्दी न कूदें। लगभग हमेशा बेहतर जवाब होता है, लेकिन वह जवाब हर application के लिए अलग होता है
नए Cloudflare के SQLite जैसी चीज के लिए यह fit हो सकती है
मैंने यह बात पहली बार यहां पढ़ी थी: https://code.flickr.net/2010/02/08/ticket-servers-distribute...
बहुत से engineers बहुत देर होने तक correctness problems की सच में परवाह नहीं करते। यह security जैसा है
परवाह करें भी तो अक्सर यह verify नहीं करते कि वे जो कर रहे हैं वह सही है या नहीं
उदाहरण के लिए मेरे क्षेत्र में microservices, actors, processes network पर messages भेजते-लेते हैं, और जो implementations मैं देखता हूं उनमें 95% से ज्यादा में ऐसे edge cases होते हैं जहां messages खो सकते हैं या order बदलकर process हो सकते हैं
लेकिन इस problem को ठीक करने के लिए incentives ठीक से aligned नहीं हैं। executives और engineers का compensation structure customers और shareholders के लिए best outcomes से मेल नहीं खाता
बिना खास वजह function calls के बीच network boundary डालना चाहते हैं, फिर उस function call के लिए HTTP servers और clients, JSON serialization/deserialization अंतहीन बनाते रहते हैं; किस्मत अच्छी हो तो gRPC इस्तेमाल करते हैं, और फिर उस network boundary के पार distributed transactions जैसी चीजें फिर से implement करने की कोशिश करते हैं
अंत में बचता है unavoidable “दूर से होने वाली डरावनी interactions” को संभालने का busywork
product team और engineering team को इस पर सहमत होना चाहिए, और SLO violate होने पर focus system reliability पर shift करना चाहिए
सभी को मनाना कठिन है, इसलिए अच्छी leadership जरूरी है
जब bugs सामने आते हैं, नए features धीमे या लगभग न के बराबर होते हैं, और customers छोड़कर जाने लगते हैं, तब quality को process का हिस्सा बनाने की जरूरत का तर्क बहुत आसान हो जाता है
mature leaders जितना जल्दी हो सके उससे पहले ही कदम बढ़ाते हैं
[0] https://en.wikipedia.org/wiki/British_Post_Office_scandal
लेकिन कल के managers को यह समझाने का साफ तरीका नहीं दिखता कि इसे ठीक से बनाने के लिए समय दें
यह चीज़ को बहुत ज़्यादा जटिल बना देता है
अगर लेख में बताए गए fencing token जैसी कोई चीज़ है, तो lock की ज़रूरत नहीं है
token का monotonic रूप से बढ़ना भी ज़रूरी नहीं; client और storage के पास साझा तौर पर मौजूद कोई passive unique value काफ़ी है
इसे version token कहें, तो यह monotonic increasing value भी हो सकता है और आम तौर पर ज़्यादा आसानी से generate होने वाला UUID भी काम करता है। तकनीकी रूप से पूरे storage data का hash भी संभव है, लेकिन practical नहीं है
flow ऐसा है। client storage से मौजूदा version token और modify किए जाने वाला data साथ में लाता है, और storage data व token को atomically read करके यह guarantee करता है कि वह token उसी data version का है
उसके बाद client changes के साथ version token वापस भेजता है, और storage बदलावों को तभी accept करता है जब current token भेजे गए token से match करे, और atomically नया version token generate करता है
दूसरे कारणों से lock introduce किया जा सकता है, लेकिन distributed system में यह storage integrity से independent होना चाहिए
“lock” शब्द भी मुझे ख़ास पसंद नहीं है। यह temporary है और guaranteed नहीं, इसलिए lease या reservation उसका अर्थ बेहतर बताते हैं
यह complexity को database की तरफ़ push करने का तरीका है, लेकिन यहाँ याद रखना चाहिए कि बात distributed lock की है
single database हो तो मामला तब तक सरल है जब तक database crash होकर इस स्थिति में न आ जाए कि कौन-सी CAS write सच में apply हुई, यह पता न हो
high availability और multi-datacenter backup की ज़रूरत वाले बड़े systems में node failure के आसपास के scenarios के कारण यह तरीका भी टूट सकता है और काफ़ी complex हो जाता है
आम तौर पर Paxos जैसे transaction log का इस्तेमाल होता है। distributed systems में आसान solution मानकर नहीं चलना चाहिए। यह हमेशा सिरदर्द होता है
efficiency के लिहाज़ से lock लेने पर वही काम बेवजह दो बार करने से बचा जा सकता है। उदाहरण के लिए कोई महंगा computation
अगर lock fail हो जाए और दो nodes वही काम कर दें, और result सिर्फ़ थोड़ा extra cost या वही email notification duplicate होना हो, तो यह मामूली हो सकता है
लेकिन कई nodes का वही काम करना मुझे उदाहरण में लिखी बात से कहीं ज़्यादा खराब लगता है। क्योंकि यह scalable distributed processing को ही बाधित कर सकता है
मान लें storage system में दो nodes हैं और दो read-modify-write processes चल रहे हैं। process 1 और 2 दोनों पहला token
abcपाते हैंprocess 1 commit करता है, token
cdeमें बदल जाता है और change node 2 पर stream होता है, लेकिन network delay के कारण node 2 तक देर से पहुँचता हैइस बीच process 2 token
abcके साथ node 2 पर commit करता है, तो node 2 ने अभी node 1 का message नहीं पाया है, इसलिए वह change accept कर लेता है और system inconsistent state में पहुँच जाता हैmonotonic increasing fencing token हो तो ऐसा नहीं होता। क्योंकि वह requirement token देने से पहले nodes को पूरे operation order पर agree करने के लिए मजबूर करती है