34 पॉइंट द्वारा GN⁺ 2024-03-15 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Figma की डेटाबेस टीम ने Postgres स्टैक को horizontal sharding के ज़रिए स्केल करने की नौ महीने की यात्रा और लगभग असीमित स्केलेबिलिटी कैसे संभव हुई, इसका सारांश दिया

Figma की Postgres स्टैक horizontal sharding यात्रा

  • 2020 के बाद Figma के डेटाबेस स्टैक का आकार लगभग 100 गुना बढ़ गया: यह बिज़नेस विस्तार का संकेत देने वाली एक सकारात्मक समस्या थी, लेकिन साथ ही इसने तकनीकी चुनौतियाँ भी पैदा कीं। 2020 में कंपनी AWS के सबसे बड़े physical instance पर एक single Postgres डेटाबेस चला रही थी, और 2022 के अंत तक उसने caching, read replicas, और कई vertically partitioned डेटाबेस सहित एक distributed architecture बना लिया था।
  • Vertical partitioning: संबंधित tables के समूहों को उनके अपने vertical partitions में अलग करके क्रमिक scaling लाभ हासिल किए गए और growth से आगे रहने के लिए पर्याप्त गुंजाइश बनाए रखी गई। उदाहरण के लिए, “Figma files” या “organizations” जैसे संबंधित tables के समूहों को अलग vertical partitions में विभाजित किया गया।
  • Horizontal sharding की ओर बदलाव: यह पहचाना गया कि केवल vertical partitioning की भी सीमाएँ हैं। CPU उपयोग कम करने पर केंद्रित शुरुआती scaling प्रयासों के बाद, टीम ने बड़े और अधिक विविध fleet में अलग-अलग bottlenecks की निगरानी शुरू की। डेटाबेस scaling limits को CPU और IO से लेकर table size और लिखी गई rows की संख्या तक कई पहलुओं में मापा गया। इन सीमाओं की पहचान करना यह अनुमान लगाने के लिए महत्वपूर्ण था कि हर shard में कितनी गुंजाइश बची है।
  • Table size की सीमाएँ: कुछ tables कई terabytes और अरबों rows तक पहुँच गए, जिससे वे single डेटाबेस पर संभालना कठिन हो गया। इस आकार पर Postgres के vacuum operations — जो transaction ID खत्म होने से सेवा रुकने से बचाने के लिए ज़रूरी background tasks हैं — के दौरान reliability प्रभावित होने लगी। सबसे अधिक write-heavy tables जल्द ही Amazon RDS द्वारा समर्थित अधिकतम IOPS से भी आगे निकलने वाले थे। यह समस्या vertical partitioning से हल नहीं हो सकती थी, और डेटाबेस के ढहने से बचाने के लिए एक बड़े समाधान की ज़रूरत थी.

स्केल विस्तार के लिए आधार तैयार करना

  • डेवलपर पर प्रभाव को न्यूनतम रखना: जटिल relational data model का अधिकांश भाग सिस्टम स्तर पर संभालने का लक्ष्य रखा गया, ताकि application developers codebase के बड़े हिस्से को refactor करने के बजाय Figma में नए और रोचक features बनाने पर ध्यान दे सकें।
  • पारदर्शी विस्तार: लक्ष्य यह था कि भविष्य में स्केल करते समय application layer में अतिरिक्त बदलाव की ज़रूरत न पड़े। यानी, tables को compatible बनाने के शुरुआती तैयारी कार्य के बाद भविष्य का scaling product teams के लिए पारदर्शी हो सके।
  • महंगे backfill से बचना: ऐसा समाधान टालना था जिसमें Figma की बड़ी tables या सभी tables के लिए backfill करना पड़े। tables के आकार और Postgres throughput limits को देखते हुए, ऐसे backfill में कई महीने लग जाते।
  • क्रमिक प्रगति: ऐसा approach चुना गया जिसे धीरे-धीरे rollout किया जा सके, ताकि बड़े production changes का जोखिम कम हो। इससे बड़े outages का खतरा घटा और migration के दौरान Figma की reliability बनाए रखने में डेटाबेस टीम को मदद मिली।
  • एकतरफ़ा migration से बचना: physical sharding लागू होने के बाद भी rollback की क्षमता बनाए रखने पर ज़ोर था। इससे unknown variables सामने आने पर खराब स्थिति में फँसने का जोखिम कम हुआ।
  • मज़बूत data consistency बनाए रखना: ऐसे जटिल समाधान, जैसे double-writes, से बचा गया जिन्हें downtime के बिना लागू करना कठिन हो या जो consistency को नुकसान पहुँचा सकते हों। लक्ष्य ऐसा समाधान था जो लगभग zero downtime के साथ स्केल कर सके।
  • अपनी ताकतों का उपयोग: कड़े deadline pressure में काम करते हुए, टीम ने ऐसे approach को प्राथमिकता दी जिसे यथासंभव incremental तरीके से rollout किया जा सके। सबसे तेज़ी से बढ़ने वाली tables के लिए मौजूदा expertise और skills का उपयोग करने का निर्णय लिया गया.

संभावित विकल्पों की खोज

  • Horizontal sharding डेटाबेस विकल्पों की समीक्षा: Postgres या MySQL-compatible horizontal sharding डेटाबेस के लिए कई लोकप्रिय open source और managed solutions मौजूद हैं। CockroachDB, TiDB, Spanner, और Vitess का मूल्यांकन किया गया। लेकिन इन वैकल्पिक डेटाबेसों में migration करने के लिए दो अलग डेटाबेस stores के बीच consistency और reliability सुनिश्चित करने वाली जटिल data migration की आवश्यकता होती।
  • मौजूदा विशेषज्ञता का लाभ: पिछले कुछ वर्षों में टीम ने RDS Postgres को स्थिर और कुशल तरीके से चलाने में गहरी expertise विकसित की थी। migration की स्थिति में यह domain expertise फिर से शुरू से बनानी पड़ती। बहुत आक्रामक growth rate को देखते हुए, उपलब्ध समय केवल कुछ महीनों का था।
  • NoSQL डेटाबेस विकल्प को खारिज करना: कंपनी के बढ़ने पर आम तौर पर एक और scalable समाधान NoSQL डेटाबेस होता है। लेकिन Figma के पास पहले से Postgres architecture पर बना बहुत जटिल relational data model था, और NoSQL APIs ऐसी विविधता प्रदान नहीं करतीं। लक्ष्य यह था कि engineers लगभग पूरे backend application को rewrite करने के बजाय शानदार features ship करने और नए products बनाने पर ध्यान दें; इसलिए NoSQL एक व्यवहार्य समाधान नहीं था।
  • मौजूदा RDS Postgres infrastructure पर horizontal sharding समाधान बनाने पर विचार: एक छोटी टीम के लिए सामान्य-purpose horizontal sharding relational डेटाबेस को internally फिर से implement करना व्यावहारिक नहीं था। ऐसा करने का अर्थ होता उन tools से प्रतिस्पर्धा करना जिन्हें बड़े open source communities या विशेषज्ञ डेटाबेस vendors ने बनाया है। लेकिन क्योंकि Figma अपनी खास architecture के अनुसार horizontal sharding को customize कर रहा था, इसलिए बहुत छोटे feature set से भी काम चल सकता था। उदाहरण के लिए, shard के बीच transaction failures को संभालने के तरीके होने के कारण shard-spanning transactions में atomicity की गारंटी देने वाला support न देने का निर्णय लिया गया। application layer में ज़रूरी बदलावों को कम से कम रखने के लिए colocation strategy चुनी गई। इससे Postgres के एक ऐसे subset को support करना संभव हुआ जो अधिकतर product logic के साथ compatible था। साथ ही sharded Postgres और non-sharded Postgres के बीच backward compatibility बनाए रखना भी आसान रहा। अगर unknown variables सामने आते, तो non-sharded Postgres पर आसानी से rollback किया जा सकता था.

Horizontal sharding की राह

  • Horizontal sharding का परिचय: Horizontal sharding वह प्रक्रिया है जिसमें किसी single table या tables के समूह को तोड़कर डेटा को कई physical डेटाबेस instances में बाँटा जाता है। इस प्रक्रिया से application layer में horizontal-sharded tables physical layer पर किसी भी संख्या के shards को support कर सकते हैं। physical shard split को सिर्फ़ execute करके आगे भी हमेशा स्केल किया जा सकता है, और यह काम न्यूनतम downtime तथा application-level बदलावों के बिना, पारदर्शी रूप से background में किया जा सकता है। इस क्षमता ने Figma को बचे हुए डेटाबेस scaling bottlenecks से आगे निकलने और उसके आख़िरी बड़े scaling challenges में से एक को समाप्त करने में मदद की। अगर vertical partitioning ने हाईवे की रफ़्तार तक तेज़ होने में मदद की थी, तो horizontal sharding ने speed limit ही हटा दी और उड़ने की क्षमता दे दी।
  • Horizontal sharding की जटिलता: Horizontal sharding, पिछले scaling प्रयासों की तुलना में कहीं अधिक जटिल है। जब tables कई physical डेटाबेसों में विभाजित हो जाती हैं, तो ACID SQL डेटाबेस में सामान्य मानी जाने वाली reliability और consistency की कई विशेषताएँ खो जाती हैं। उदाहरण के लिए, कुछ SQL queries को support करना अप्रभावी या असंभव हो सकता है, और application code को इस तरह अपडेट करना पड़ता है कि queries को सही shard तक कुशलतापूर्वक route करने के लिए पर्याप्त जानकारी उपलब्ध हो। schema changes को इस तरह coordinate करना पड़ता है कि सभी shards sync में रहें, और foreign keys तथा globally unique indexes को अब Postgres enforce नहीं कर पाता। transactions कई shards में फैल सकती हैं, इसलिए Postgres के ज़रिए transactions को enforce करना संभव नहीं रह जाता। अब कुछ डेटाबेसों पर write सफल हो सकती है जबकि दूसरी विफल हो जाए। product logic को ऐसी “partial commit failures” के प्रति मज़बूत बनाना ज़रूरी है — उदाहरण के लिए, अगर किसी team को दो organizations के बीच move किया जा रहा हो और डेटा का केवल आधा हिस्सा ही बदल पाए, तो समस्या गंभीर हो सकती है।
  • Horizontal sharding की ओर बहुवर्षीय प्रयास: टीम जानती थी कि पूरी horizontal sharding हासिल करना कई वर्षों का प्रयास होगा। इसलिए ज़रूरी था कि परियोजना के जोखिम को कम करते हुए क्रमिक रूप से value दी जाए। पहला लक्ष्य था कि production में जितनी जल्दी हो सके, अपेक्षाकृत सरल लेकिन बहुत high-traffic table को shard किया जाए। इससे न केवल horizontal sharding की व्यवहार्यता साबित होती, बल्कि सबसे अधिक load वाले डेटाबेसों के लिए गुंजाइश भी बढ़ती। उसके बाद अधिक जटिल table groups को shard करते हुए अतिरिक्त features बनाए जा सकते थे। सबसे सरल संभव feature set भी अपने आप में काफी बड़ा काम था। शुरू से अंत तक, टीम को पहला table shard करने में लगभग नौ महीने लगे.

हमारा अनोखा दृष्टिकोण

  • Colos: संबंधित टेबल समूहों को एक ही sharding key और physical sharding layout साझा करने वाले colocation (प्यार से “colo” कहा जाता है) के रूप में horizontally shard किया गया। इससे डेवलपर्स को horizontally sharded tables के साथ इंटरैक्ट करने के लिए एक परिचित abstraction मिला।
  • Logical sharding: application layer के “logical sharding” और Postgres layer के “physical sharding” के कॉन्सेप्ट को अलग किया गया। views का उपयोग करके, ज्यादा जोखिम वाले distributed physical failover को चलाने से पहले ज्यादा सुरक्षित और कम लागत वाला logical sharding rollout किया गया।
  • DBProxy query engine: application layer में बने SQL queries को intercept करके, queries को अलग-अलग Postgres databases की ओर dynamically route करने वाली DBProxy service बनाई गई। DBProxy में एक query engine शामिल है जो complex horizontal sharding queries को parse और execute कर सकता है। DBProxy के जरिए dynamic load balancing और request hedging जैसी सुविधाएं लागू की जा सकीं।
  • Shadow application readiness: “shadow application readiness” framework जोड़ा गया, जो यह अनुमान लगा सकता है कि अलग-अलग संभावित sharding keys के तहत वास्तविक production traffic कैसे व्यवहार करेगा। इससे product teams को साफ तस्वीर मिली कि application logic को horizontal sharding के लिए तैयार करने हेतु कहाँ refactor करना है या क्या हटाना है।
  • Full logical replication: “filtered logical replication” लागू करने की जरूरत नहीं पड़ी, जिसमें हर shard पर डेटा का केवल एक subset कॉपी किया जाता। इसकी जगह पूरा dataset कॉपी किया गया, और फिर केवल उस subset पर read/write की अनुमति दी गई जो संबंधित shard का हिस्सा था.

Sharding लागू करना

  • Shard key चुनने का महत्व: horizontal sharding में सबसे महत्वपूर्ण फैसलों में से एक यह है कि कौन-सी shard key इस्तेमाल की जाए। horizontal sharding, shard key के इर्द-गिर्द कई data model constraints जोड़ता है। उदाहरण के लिए, ज्यादातर queries में shard key होना जरूरी है ताकि request को सही shard तक route किया जा सके। कुछ database constraints, जैसे foreign keys, तभी काम करते हैं जब foreign key ही sharding key हो। shard key ऐसी होनी चाहिए जो सभी shards में डेटा को समान रूप से वितरित करे, ताकि reliability issues पैदा करने वाले या scalability को प्रभावित करने वाले hotspots से बचा जा सके।
  • Figma का data model के अनुसार customized approach: Figma browser में चलता है, और कई users एक ही Figma file पर एक साथ collaborate कर सकते हैं। इसका मतलब है कि यह एक अपेक्षाकृत complex relational data model पर चलता है, जो file metadata, organization metadata, comments, file versions आदि को कैप्चर करता है। मौजूदा data model में कोई एक अच्छा candidate नहीं था, इसलिए सभी tables के लिए एक ही sharding key इस्तेमाल करने पर विचार किया गया, लेकिन इसके लिए unified sharding key जोड़ने हेतु composite keys बनानी पड़तीं, सभी table schemas में columns जोड़ने पड़ते, उन्हें भरने के लिए महंगा backfill चलाना पड़ता, और फिर product logic में बड़े स्तर पर refactoring करनी पड़ती। इसके बजाय, Figma के unique data model के हिसाब से approach को customize किया गया और UserID, FileID, OrgID जैसी कुछ sharding keys चुनी गईं। Figma की लगभग सभी tables को इन keys में से किसी एक के आधार पर shard किया जा सकता है।
  • Colos की शुरुआत: product developers के लिए एक परिचित abstraction देने हेतु colocation का कॉन्सेप्ट पेश किया गया। किसी colo के भीतर tables, एक single sharding key तक सीमित रहने पर cross-table joins और full transactions को support करती हैं। ज्यादातर application code पहले से ही database के साथ इसी तरह इंटरैक्ट कर रहा था, इसलिए application developers को tables को horizontal sharding के लिए तैयार करने हेतु बहुत कम बदलाव करने पड़े।
  • डेटा वितरण की समानता सुनिश्चित करना: sharding key चुनने के बाद, यह सुनिश्चित करना जरूरी था कि सभी backend databases में डेटा समान रूप से वितरित हो। दुर्भाग्य से, चुनी गई कई sharding keys auto-increment या Snowflake timestamp-prefixed IDs का उपयोग करती थीं। इससे बड़े hotspots बन सकते थे, जहाँ अधिकांश डेटा एक ही shard में चला जाता। ज्यादा randomized IDs पर migration की संभावना देखी गई, लेकिन इसके लिए महंगा और समय लेने वाला data migration चाहिए था। इसलिए routing के लिए sharding key के hash का उपयोग करने का निर्णय लिया गया। अगर पर्याप्त रूप से random hash function चुना जाए, तो डेटा का समान वितरण सुनिश्चित किया जा सकता है। इसका एक नुकसान यह है कि shard key पर range scans कम efficient हो जाते हैं, क्योंकि लगातार keys अलग-अलग database shards में hash हो जाती हैं। हालांकि, यह query pattern हमारे codebase में आम नहीं है, इसलिए यह स्वीकार्य समझौता था.

“Logical” समाधान

  • Horizontal sharding rollout का जोखिम कम करना: horizontal sharding rollout के जोखिम को कम करने के लिए, shard split चलाने की physical प्रक्रिया और application layer में tables को तैयार करने की प्रक्रिया को अलग करने का लक्ष्य रखा गया। इसके लिए “logical sharding” और “physical sharding” को अलग किया गया। इससे migration के दोनों हिस्सों को अलग करके स्वतंत्र रूप से लागू किया जा सका और जोखिम कम हुआ। logical sharding ने low-risk, percentage-based rollout के जरिए serving stack पर भरोसा बनाने में मदद की। जब bugs मिले, तब logical sharding को rollback करना एक साधारण configuration change था। physical shard operation को rollback करना संभव था, लेकिन data consistency सुनिश्चित करने के लिए ज्यादा complex coordination चाहिए था।
  • Logical sharding के बाद का व्यवहार: जब कोई table logically sharded हो जाती है, तो सभी read और write operations वैसे ही काम करते हैं जैसे वह पहले से horizontally sharded हो। reliability, latency और consistency के लिहाज से यह horizontally sharded लगती है, लेकिन डेटा अभी भी physical रूप से एक ही database host पर मौजूद रहता है। जब यह भरोसा हो गया कि logical sharding उम्मीद के मुताबिक काम कर रही है, तब physical sharding operation किया गया। इसमें एक single database से डेटा कॉपी करके कई backends में shard करना, और फिर read/write traffic को नए databases के जरिए reroute करना शामिल था.

एक सक्षम query engine

  • Horizontal sharding support के लिए backend stack का redesign: शुरुआत में application services सीधे connection pooling layer PGBouncer से बात करती थीं। लेकिन horizontal sharding के लिए कहीं ज्यादा complex query parsing, planning और execution की जरूरत थी। इसे support करने के लिए DBProxy नाम की नई golang service बनाई गई। DBProxy, application layer और PGBouncer के बीच स्थित है। इसमें load balancing, बेहतर observability, transaction support, database topology management और एक lightweight query engine जैसी logic शामिल है।
  • Query engine के मुख्य components:
    • Query parser: application से भेजे गए SQL को पढ़ता है और उसे abstract syntax tree (AST) में बदलता है।
    • Logical planner: AST को parse करता है और query plan से query type (insert, update आदि) तथा logical shard ID निकालता है।
    • Physical planner: query को logical shard ID से physical database पर map करता है। सही physical shard पर execute करने के लिए query को rewrite करता है।
  • “scatter-gather” तरीका: यह database में छुपन-छुपाई के खेल जैसा काम करता है: query को सभी shards पर भेजो (scatter), फिर हर shard से जवाब इकट्ठा करो (gather)। सुनने में मजेदार है, लेकिन अगर इसे complex queries के साथ ज्यादा इस्तेमाल किया जाए, तो database घोंघे जैसी धीमी हो सकती है।
  • Horizontally sharded दुनिया में queries लागू करना: single-shard queries को एक single shard key से filter किया जाता है। query engine को सिर्फ shard key निकालनी होती है और query को सही physical database तक route करना होता है। query execution की complexity को Postgres के ऊपर “push down” कर दिया जाता है। लेकिन अगर query में sharding key गायब हो, तो query engine को ज्यादा complex “scatter-gather” करना पड़ता है। इस स्थिति में query को सभी shards तक fan out करना पड़ता है (scatter चरण), और फिर results को aggregate करना पड़ता है (gather चरण)।
  • SQL compatibility को सरल बनाना: अगर DBProxy service पूरी SQL compatibility support करती, तो यह Postgres database query engine से बहुत मिलती-जुलती दिखती। API को सरल बनाकर DBProxy की complexity कम करनी थी, और unsupported queries को rewrite करने का बोझ application developers पर भी कम करना था। सही subset तय करने के लिए “shadow planning” framework बनाया गया, जो tables के संभावित sharding schema को define कर सकता था और real-time production traffic पर logical planning चरण चला सकता था। queries और उनसे जुड़े query plans को Snowflake database में log किया जा सकता था ताकि offline analysis चलाया जा सके। इस डेटा के आधार पर ऐसी query language चुनी गई जो query engine की worst-case complexity से बचते हुए सबसे सामान्य 90% queries को support करे। उदाहरण के लिए, सभी range scans और point queries की अनुमति है, लेकिन joins केवल उसी colo की दो tables के बीच, sharding key पर किए जाने पर ही अनुमति है.

आगे की दिशा

  • लॉजिकल shard का encapsulation: यह तय करना था कि लॉजिकल shard को कैसे encapsulate किया जाए। डेटा को अलग करने के लिए अलग Postgres database या Postgres schema इस्तेमाल करने के विकल्पों की जांच की गई। दुर्भाग्य से, इसका मतलब था कि लॉजिकल sharding करते समय physical data में बदलाव करना पड़ेगा, जो physical shard split जितना ही जटिल था।
  • Postgres view के माध्यम से shard का प्रतिनिधित्व: इसके बजाय, shard को Postgres view के रूप में दर्शाने का फैसला किया गया। हर table के लिए कई view बनाए जा सकते हैं, और हर view किसी दिए गए shard के data subset के अनुरूप होता है। इसका रूप कुछ ऐसा है: CREATE VIEW table_shard1 AS SELECT * FROM table WHERE hash(shard_key) >= min_shard_range AND hash(shard_key) < max_shard_range). सभी read और write ऑपरेशन इन्हीं view के माध्यम से किए जाते हैं।
  • मौजूदा unsharded physical database के ऊपर sharded view बनाना: जोखिम भरा physical reshard operation करने से पहले लॉजिकल sharding की जा सकती है। हर view को उसकी अपनी sharded connection pooler service के जरिए access किया जाता है। connection pooler अभी भी unsharded physical instance की ओर point करता है, जिससे वह sharded जैसा दिखाई देता है। query engine के feature flag के जरिए sharded read और write rollout को धीरे-धीरे, कम जोखिम के साथ जारी किया गया, और traffic को फिर से primary table पर route करके कुछ ही सेकंड में कभी भी rollback किया जा सकता था। पहला reshard चलाने तक, sharded topology की safety को लेकर भरोसा बन चुका था।
  • view पर निर्भर रहने का जोखिम: view performance overhead जोड़ते हैं, और कुछ मामलों में Postgres query planner के query optimize करने के तरीके को मूल रूप से बदल सकते हैं। इस approach को validate करने के लिए, sanitized production queries का एक query corpus इकट्ठा किया गया और view के साथ तथा बिना view के load test चलाए गए। यह पुष्टि हुई कि ज्यादातर मामलों में view बहुत कम performance overhead जोड़ते हैं, और सबसे खराब स्थिति में भी यह 10% से कम था। इसके अलावा, एक shadow read framework बनाया गया जो सभी real-time read traffic को view के जरिए भेजता था और view वाली तथा बिना view वाली queries की performance और correctness की तुलना करता था। नतीजे में यह पुष्टि हुई कि view, performance पर न्यूनतम असर के साथ, एक व्यवहार्य समाधान हैं।

टोपोलॉजी समस्या का समाधान

  • query routing के लिए DBProxy की topology समझ: tables और physical database की topology को समझना जरूरी था। लॉजिकल और physical sharding की अवधारणाओं के अलगाव के कारण, इन abstractions को topology के भीतर दर्शाने का तरीका चाहिए था।
  • table और shard key mapping: users table को user_id shard key से map करने और लॉजिकल shard ID (123) को सही लॉजिकल और physical database से map करने की आवश्यकता थी।
  • vertical partitioning और hardcoded config file पर निर्भरता: vertical partitioning में tables को उनके partition से map करने के लिए एक साधारण hardcoded config file पर निर्भरता थी। horizontal sharding में जाने पर इससे कहीं अधिक जटिल system की जरूरत पड़ी।
  • topology के dynamic बदलाव और DBProxy में state का तेज अपडेट: shard split के दौरान topology में dynamic बदलाव होते हैं, इसलिए requests को गलत database में route होने से बचाने के लिए DBProxy की state को तेजी से update करना जरूरी था।
  • topology बदलावों की backward compatibility: सभी topology बदलाव backward compatible थे, और site के critical path में किसी बदलाव की जरूरत नहीं थी।
  • जटिल horizontal sharding metadata को encapsulate करने वाली database topology का निर्माण: ऐसी database topology बनाई गई जो जटिल horizontal sharding metadata को encapsulate करती है और 1 सेकंड से कम समय में real-time updates देती है।
  • लॉजिकल और physical topology को अलग करके database management को सरल बनाना: production जैसा ही लॉजिकल topology non-production environment में बनाए रखते हुए physical databases की संख्या घटाकर लागत और जटिलता कम की गई।
  • topology library के जरिए topology invariants लागू करना: जैसे कि हर shard ID ठीक एक physical database से map हो, ऐसे invariants लागू करके horizontal sharding stack बनाते समय system की correctness बनाए रखी गई।

physical sharding operation

  • table की sharding तैयारी पूरी होने के बाद अंतिम चरण: unsharded database से sharded database में physical failover। horizontal sharding के लिए काफी वही logic दोबारा इस्तेमाल किया जा सका, लेकिन 1:1 database से 1:N में जाने जैसे कुछ उल्लेखनीय अंतर थे।
  • failover process को अधिक durable बनाने की जरूरत: sharding operation में ऐसे नए failure mode आते हैं जिनमें database के केवल एक हिस्से में operation सफल हो सकता है, इसलिए failover process को अधिक durable बनाना पड़ा।
  • vertical partitioning के दौरान अधिकांश जोखिम पहले ही कम किए जा चुके थे: चूंकि कई जोखिम vertical partitioning के दौरान पहले ही कम कर दिए गए थे, इसलिए पहली physical sharding operation तक उम्मीद से कहीं तेजी से पहुंचा जा सका।

horizontal sharding यात्रा की वर्तमान स्थिति

  • horizontal sharding में बहुवर्षीय निवेश: Figma ने भविष्य की scalability के लिए horizontal sharding में कई वर्षों के निवेश की जरूरत पहचानी, और सितंबर 2023 में पहला horizontal-sharded table जारी किया।
  • सफल failover execution: database primary पर 10 सेकंड की अस्थायी partial availability और replicas पर availability पर कोई असर नहीं होने के साथ सफल failover हासिल किया गया। sharding के बाद latency या availability में कोई regression नहीं हुआ।
  • जटिल shards का प्रबंधन: सबसे अधिक write rate वाले database में अपेक्षाकृत सरल shard को संभाला गया। इस वर्ष दर्जनों tables और हजारों code call sites वाले अधिक जटिल databases की sharding की योजना है।
  • Figma की सभी tables के लिए horizontal sharding की आवश्यकता: आखिरी scaling limit हटाने और वास्तविक breakout growth के लिए। पूरी तरह horizontal-sharded दुनिया बेहतर reliability, कम लागत, और अधिक developer velocity जैसे कई लाभ देती है।
  • हल किए जाने वाले मुद्दे:
    • horizontal-sharded schema updates का समर्थन
    • horizontal-sharded primary keys के लिए globally unique ID generation
    • business-critical use cases के लिए atomic cross-shard transactions
    • distributed globally unique indexes (फिलहाल केवल shard key शामिल करने वाले indexes में समर्थित)
    • horizontal sharding के साथ सहज रूप से compatible ORM models के जरिए developer velocity बढ़ाना
    • एक बटन क्लिक से shard split चलाने वाला पूरी तरह automated reshard operation
  • मौजूदा RDS horizontal sharding approach का पुनर्मूल्यांकन: यह यात्रा 18 महीने पहले बहुत तंग timeline दबाव में शुरू हुई थी। NewSQL store लगातार विकसित और परिपक्व हो रहे हैं। अब इतना समय मिल गया है कि मौजूदा रास्ते पर बने रहने और open source या managed solution पर जाने के बीच के trade-offs का फिर से मूल्यांकन किया जा सके।
  • horizontal sharding यात्रा में रोमांचक प्रगति: अभी भी हल किए जाने वाले कई challenges शुरुआती चरण में हैं। horizontal sharding stack के अलग-अलग हिस्सों पर और गहन विश्लेषण की उम्मीद है। अगर आपको ऐसे projects में रुचि है, तो संपर्क करें। भर्ती जारी है।

GN⁺ की राय

  • Figma की database team horizontal sharding के जरिए database scalability की सीमाओं को पार करना चाहती थी, और यह cloud-आधारित collaboration tools की growth और performance बनाए रखने की दिशा में एक महत्वपूर्ण कदम है।
  • horizontal sharding data management और query optimization में नई चुनौतियां लाती है, जिसके लिए database administrators और developers को नए ज्ञान और skills की जरूरत होती है।
  • horizontal sharding database scalability को काफी बेहतर बनाती है, लेकिन complex query processing और data consistency बनाए रखने के लिए नए समाधानों की मांग भी करती है।
  • इसी तरह की क्षमता देने वाले open source projects में CitusDB शामिल है, जो Postgres database को horizontal रूप से scale करने की सुविधा देता है।
  • horizontal sharding तकनीक अपनाते समय data model की complexity, query performance, system flexibility, और maintenance जैसे पहलुओं पर विचार करना चाहिए; यानी database scalability और आसान management के बीच संतुलन खोजना जरूरी है।

1 टिप्पणियां

 
GN⁺ 2024-03-15
Hacker News राय
  • बड़े टेबल और RDS IOPS सीमा

    • सबसे बड़ा टेबल कई TB तक पहुँचता है, और कहा गया है कि जल्द ही यह RDS द्वारा समर्थित अधिकतम IOPS को पार कर सकता है।
    • PostgreSQL के लिए RDS, 64TB वॉल्यूम पर अधिकतम 256,000 IOPS तक पहुँचता है।
    • Multi-AZ सेटअप के मामले में, इससे प्रति माह $70K की लागत आती है।
  • शार्डिंग के नतीजे और लागत

    • अंततः 5-way shard माना गया, जहाँ हर shard लगभग 50,000 IOPS और 12TB डेटा सपोर्ट करता है।
    • Multi-AZ सेटअप के मामले में, इससे प्रति माह $100K की लागत आती है।
  • शार्डिंग में लगा समय और लागत

    • पहले टेबल को shard करने में 9 महीने लगे।
    • एप्लिकेशन में बदलाव भी ज़रूरी थे, इसलिए 9 महीने * 20 कार्यदिवस/माह * (3 DB इंजीनियर + 2 app इंजीनियर) = 900 कार्यदिवस के रूप में गणना की गई।
    • अगर इंजीनियर का औसत वार्षिक वेतन $100K माना जाए, तो कुल लागत लगभग $400K बनती है।
  • YugabyteDB के साथ लागत तुलना

    • PostgreSQL-compatible NewSQL, YugabyteDB के लिए अनुमान है कि RDS के सर्वोच्च प्रदर्शन से मेल करने में प्रति माह $15K खर्च होगा।
    • Figma ने internally horizontal sharding लागू करने में लगभग 25 गुना ($400K/$15K) लागत खर्च की और अब भी RDS ही इस्तेमाल कर रहा है, जिसकी लागत लगभग 6 गुना ($100K/$15K) है।
  • ग्राहक-वार अलग डेटाबेस का प्रस्ताव

    • सुझाव है कि हर ग्राहक को अलग (logical) डेटाबेस में रखना शायद अधिक आसान हो सकता है।
    • अलग-अलग ग्राहकों के बीच transaction की ज़रूरत नहीं है, इसलिए ऐसा लगता है कि वे वास्तविकता से अधिक कठिन समस्या हल कर रहे हैं।
    • PostgreSQL के (logical) डेटाबेस अच्छी तरह scale होंगे या नहीं, यह अनिश्चित है, लेकिन सिद्धांततः यह असंभव नहीं है।
  • MySQL के Vitess जैसा PG वर्ज़न बनाने की बात

    • query rewriting दिलचस्प लगी।
    • DB और application के बीच एक layer रखने से तरह-तरह के ACL (access control list) भी संभव हो जाते हैं।
  • FoundationDB पर विचार

    • यह जिज्ञासा है कि FoundationDB को क्यों नहीं आज़माया गया।
    • PostgreSQL के vacuuming (garbage collection) में समस्या थी।
    • पुराने versions में vacuuming के लिए दोगुनी जगह चाहिए होती थी, लेकिन हो सकता है कि नए versions में यह बदल गया हो।
  • शार्डिंग को हैक की तरह देखने का दृष्टिकोण

    • low-level I/O buffering/caching को खुद संभालने के बजाय OS API पर निर्भर रहना बेहतर है।
    • DB sharding के लिए इसी तरह की तकनीक/infra अब भी पर्याप्त नहीं मानी जाती।
  • Citus extension का इस्तेमाल न करने पर सवाल

    • Citus, जो पहले से mature Postgres extension है, लेख में उल्लेखित नहीं है।
    • हो सकता है कि उन्हें Citus के बारे में पता न हो, या किसी खास वजह से उसे नज़रअंदाज़ किया गया हो।
  • Aurora Limitless के इस्तेमाल की संभावना

    • यह सवाल उठाया गया कि क्या Amazon Aurora Limitless इस्तेमाल किया जा सकता था।
  • NoSQL डेटाबेस की समझ

    • NoSQL उन backends के लिए उपयुक्त है जो unstructured data को संभालते हैं, जहाँ जटिल relational model की ज़रूरत नहीं होती।
    • Postgres इसे jsonb data type के साथ सपोर्ट करता है, लेकिन उनके पास पहले से अच्छा data model है, इसलिए इसकी ज़रूरत ज़्यादा नहीं पड़ती।
  • शार्डिंग की परिपक्वता और NewSQL समाधान पर विचार

    • सवाल है कि अब जबकि sharding mature हो चुकी है, क्या automatic sharding और multi-region support के लिए NewSQL solution पर विचार करना उचित होगा।
    • NewSQL डेटाबेस को operate करना सीखना भी एक अतिरिक्त लागत है।
  • Google की Spanner तकनीक और Figma का आकलन

    • Google में Spanner को ऐसी जादुई तकनीक माना जाता है जो असीम horizontal sharding और transaction को सपोर्ट करती है, और लगभग सभी project Spanner की ओर जा रहे हैं।
    • यह जिज्ञासा जताई गई कि Figma ने Cloud Spanner का मूल्यांकन कैसे किया, और क्या उन्होंने अपने horizontal Postgres schema में वास्तविक transaction support को छोड़ा (भले ही अस्थायी रूप से)।