- Discord में स्टोर किए जाने वाले संदेशों की संख्या अरबों से बढ़कर खरबों तक पहुंचने पर, 2022 की शुरुआत तक 177-node Cassandra cluster का operational burden और अनिश्चित latency संभालना मुश्किल हो गया
channel_idऔर time bucket पर केंद्रित Cassandra design बड़े servers के concentrated read traffic में hot partition बनाता था, और quorum reads/writes की वजह से latency का असर ज्यादा users तक फैल जाता था- API और database के बीच Rust-आधारित data service रखकर, एक ही row के concurrent requests को merge किया गया और channel ID-आधारित consistent hash routing से database load कम किया गया
- ScyllaDB migration नया cluster बनाकर और Rust migrator के साथ किया गया, जिससे Spark-आधारित अनुमानित 3 महीने का काम घटकर 9 दिन रह गया और अधिकतम 3.2 million messages per second ट्रांसफर हुए
- मई 2022 के cutover के बाद nodes की संख्या 177 Cassandra से घटकर 72 ScyllaDB रह गई, पुराने messages lookup का p99 40~125ms से 15ms हुआ, और message insert p99 5~70ms से 5ms तक सुधर गया
Cassandra में बढ़ता operational burden
- Discord ने 2017 में अरबों संदेश कैसे स्टोर करता है प्रकाशित करते हुए MongoDB से Cassandra migration की प्रक्रिया साझा की थी
- उस समय लक्ष्य ऐसा database था जो scalable हो, failures के प्रति resilient हो, और maintenance अपेक्षाकृत कम मांगे, लेकिन storage बढ़ने के साथ Cassandra cluster खुद एक बड़ा operational burden बन गया
- message storage के लिए
cassandra-messagescluster 2017 में 12 nodes से बढ़कर 2022 की शुरुआत तक 177 nodes हो गया, और इसमें खरबों संदेश स्टोर थे - operations team को database issues के कारण बार-बार paged किया जाता था, latency अनिश्चित थी, और बहुत महंगे maintenance work को कम करने की जरूरत थी
message schema और hot partition
- सरल message schema में
channel_id,bucket,message_id,author_id,contentशामिल थे, और primary key((channel_id, bucket), message_id)थी - Discord के IDs Snowflake पर आधारित थे, इसलिए time-ordered sorting संभव थी, और messages को channel और static time window यानी bucket के आधार पर partition किया गया था
- Cassandra में किसी खास channel और bucket के सभी messages साथ स्टोर होते थे, और replication factor के अनुसार कई nodes पर replicate किए जाते थे
- छोटे friend-group servers और लाखों users वाले बड़े servers में message volume कई orders of magnitude तक अलग था, और यही अंतर partition-level load difference में बदल जाता था
- writes पहले commit log और memory structure memtable में append होती थीं और फिर disk पर flush होती थीं, लेकिन reads को memtable और कई SSTables देखनी पड़ सकती थीं, इसलिए उनकी cost ज्यादा थी
- बड़े servers में concurrent reads बढ़ने पर कोई खास partition hot partition बन जाता था, उस node की latency बढ़ती थी, और दूसरे queries भी प्रभावित होते थे
- क्योंकि reads और writes में quorum consistency level इस्तेमाल हो रहा था, hot partition संभाल रहे node की latency बढ़ने का असर ज्यादा users तक फैल जाता था
Cassandra maintenance bottleneck
- Cassandra की compaction भी बार-बार incident response का कारण बनती थी
- disk पर SSTables को compact करने से read performance सुधरती थी, लेकिन compaction backlog बढ़ने पर read cost भी बढ़ जाती थी
- जब कोई node compaction कर रहा होता था, तो latency chain reaction की तरह बढ़ सकती थी
- Discord अक्सर एक प्रक्रिया करता था जिसे वह “gossip dance” कहता था
- node को traffic से हटाकर compaction कराई जाती थी
- फिर उसे वापस जोड़कर Cassandra hinted handoff के hints catch up कराए जाते थे
- compaction backlog खत्म होने तक यह प्रक्रिया दोहराई जाती थी
- JVM garbage collector और heap settings की tuning में भी काफी समय जाता था, और GC pause बड़े latency spikes पैदा करता था
ScyllaDB पर जाने की वजह
- Discord messages के अलावा भी कई Cassandra clusters चला रहा था, और हर cluster में मिलती-जुलती समस्याएं दिख रही थीं
- ScyllaDB, जिसमें Discord ने पहले भी रुचि दिखाई थी, Cassandra-compatible database है, C++ में लिखा गया है, और बेहतर performance, तेज repair, shard-per-core architecture पर आधारित workload isolation, और garbage collection के बिना काम करने वाली संरचना देता है
- ScyllaDB भी पूरी तरह समस्या-मुक्त नहीं था, लेकिन Java के बजाय C++ में लिखा होना और garbage collector का न होना Cassandra के operational problems के सीधे विपरीत था
- experiments और tests में सुधार देखने के बाद Discord ने अपने सभी databases को ScyllaDB पर migrate करने का फैसला किया, और 2020 तक
cassandra-messagesको छोड़कर बाकी सब migrate कर दिए गए - message cluster आखिरी तक इसलिए बचा रहा क्योंकि वह खरबों messages और लगभग 200 nodes वाला बहुत बड़ा cluster था
- ScyllaDB की reverse query performance शुरुआती tests में requirements से कम थी
- reverse query वह होती है जिसमें table sorting के उलटी दिशा में scan किया जाता है; उदाहरण के लिए messages को ascending order में scan करना
- ScyllaDB team ने performance improvements को priority देकर implement किया, जिससे आखिरी database migration को रोकने वाली यह बाधा हट गई
Rust-आधारित data service
- Discord का मानना था कि सिर्फ database बदलने से सभी समस्याएं अपने-आप हल नहीं होंगी, इसलिए database के ऊपर की layer भी बदली गई
- API monolith और database cluster के बीच एक data service रखी गई, ताकि database की ओर जाने वाले concurrent requests को नियंत्रित किया जा सके
- data service Rust में लिखी गई
- Discord पहले भी कुछ projects में Rust का उपयोग कर चुका था
- Rust, safety छोड़े बिना C/C++ जैसी speed देता है
- Tokio ecosystem का उपयोग async I/O system बनाने की foundation के रूप में किया गया, और Cassandra व ScyllaDB drivers का support भी उपलब्ध था
- data service में लगभग हर database query के लिए एक gRPC endpoint था, और जानबूझकर इसमें business logic नहीं रखा गया
- इसका मूल विचार request coalescing था
- अगर कई users एक ही समय में एक ही row मांगें, तो database केवल एक बार query होता है
- पहला request service के अंदर worker task बनाता है, और बाद के requests उस task की मौजूदगी देखकर उसे subscribe कर लेते हैं
- worker task database query करता है और result row सभी subscribers को लौटाता है
routing से coalescing का असर बढ़ाना
- data service के आगे consistent hashing-based routing लागू की गई
- हर data service request के साथ routing key दी जाती थी, और messages के मामले में routing key channel ID थी
- क्योंकि एक ही channel के सभी requests एक ही service instance पर जाते थे, request coalescing और बेहतर काम करती थी
- उदाहरण के लिए, किसी बड़े server में
@everyonenotification आने पर बहुत से users app खोलकर वही message पढ़ते हैं, जिससे database traffic अचानक बढ़ सकता है - पहले की architecture में ऐसी स्थिति hot partition बना सकती थी और operations team को call पर आना पड़ सकता था, लेकिन data service ने database की ओर जाने वाले traffic spikes को काफी कम कर दिया
- इससे Cassandra cluster के hot partitions और latency पूरी तरह खत्म नहीं हुए, लेकिन नए ScyllaDB cluster की तैयारी और migration के लिए जरूरी समय मिल गया
खरबों messages का migration
- migration requirements साफ थीं
- खरबों messages migrate करने थे
- downtime नहीं होना चाहिए था
- Cassandra अब भी बार-बार incidents पैदा कर रहा था, इसलिए migration जल्दी खत्म करना जरूरी था
- Discord ने पहले super-disk storage topology का उपयोग करते हुए नया ScyllaDB cluster बनाया
- Local SSD से speed ली गई
- RAID के जरिए data को persistent disk पर mirror किया गया
- इस setup से local disk की speed और persistent disk की durability दोनों मिलीं
- शुरुआती योजना यह थी कि cutover time के बाद नया data ScyllaDB में जाए और पुराना data background में migrate किया जाए
- नए data के लिए Cassandra और ScyllaDB दोनों में dual write शुरू की गई, और साथ में ScyllaDB के Spark migrator की तैयारी हुई
- Spark migrator को काफी tuning चाहिए थी, और setup के बाद उसका estimated completion time 3 महीने था
- इसके बाद Discord ने अपनी मौजूदा fast database library को बढ़ाकर Rust में data migrator दोबारा लिखा
- database से token ranges पढ़े गए
- SQLite में local checkpoints लिखे गए
- data को bulk में ScyllaDB में भेजा गया
- नए Rust migrator का estimated completion time घटकर 9 दिन रह गया, और इसी speed की वजह से जटिल time-based approach के बजाय पूरा cutover एक साथ करना संभव हुआ
cutover और validation
- migration अधिकतम 3.2 million messages per second की रफ्तार से चला
- progress 99.9999% पर रुक गई, क्योंकि आखिरी कुछ token ranges में Cassandra पर compact न किए गए बहुत बड़े tombstone ranges थे
- उन token ranges को compact करने के कुछ सेकंड बाद migration पूरा हो गया
- Discord ने automated data validation के लिए read requests के एक छोटे हिस्से को दोनों databases पर भेजकर results compare किए, और परिणाम सही रहे
- ScyllaDB cluster ने पूरे production traffic में अच्छा प्रदर्शन किया, जबकि Cassandra में latency issues लगातार बढ़ते जा रहे थे
- team ने production में ही ScyllaDB को primary database पर switch कर दिया
cutover के बाद performance और scale
- message database का cutover मई 2022 में हुआ
- इसके बाद operations शांत और स्थिर रहे, और पूरे weekend incident response करते रहने या uptime बनाए रखने के लिए cluster nodes को लगातार adjust करने जैसी स्थिति खत्म हो गई
- nodes की संख्या 177 Cassandra nodes से घटकर 72 ScyllaDB nodes रह गई
- प्रति ScyllaDB node disk space 9TB था, जो Cassandra node के औसत 4TB से अधिक था
- tail latency में भी बड़ा सुधार हुआ
- पुराने messages lookup p99: Cassandra 40~125ms → ScyllaDB 15ms
- message insert p99: Cassandra 5~70ms → ScyllaDB 5ms
- performance improvements की वजह से Discord को अपने message database पर इतना भरोसा मिला कि वह नए product use cases खोल सका
World Cup traffic में दिखी load-handling क्षमता
- 2022 के अंत में World Cup के दौरान, दुनिया भर के users मैच देखते हुए Discord पर संदेश भेज रहे थे, और goal moments उसके message-send graph में भी साफ दिखे
- World Cup Final के message-send graph में मैच की घटनाओं के अनुरूप कई spikes दिखे
- Messi की penalty kick और Argentina की 1-0 बढ़त
- Argentina का दूसरा goal
- halftime के दौरान बना 15-minute plateau
- Mbappe का France के लिए goal, और 90 seconds बाद बराबरी दिलाने वाला दूसरा goal
- regular time का अंत और extra time की शुरुआत
- extra time के first half के halftime chat
- Messi का एक और goal
- Mbappe का equalizer
- extra time का अंत और penalty shootout की शुरुआत
- France की miss और Argentina की जीत
- message volume बहुत बढ़ने पर भी Rust-आधारित data service और ScyllaDB ने traffic संभाला
- अंतिम system को खरबों messages संभालने वाली architecture के रूप में व्यवस्थित किया गया
1 टिप्पणियां
Hacker News की राय
यह लेख लगता है कि garbage collection को काफी ज़्यादा दोष दे रहा है, लेकिन पिछला लेख [0] देखें तो यह Cassandra के इस्तेमाल के तरीके, Cassandra में बड़े पैमाने पर deletion को संभालने की सीमा, या शायद दोनों की सीमा के ज़्यादा करीब लगता है
एक उपयोगकर्ता ने API से लाखों messages मिटा दिए और चैनल में सिर्फ 1 message छोड़ा, और क्योंकि Cassandra deletion को tombstone के रूप में संभालता है, इसलिए जब उपयोगकर्ता वह चैनल खोलता था तो असली message सिर्फ 1 होने पर भी उसे लाखों tombstones scan करने पड़ते थे. व्याख्या यह है कि उस प्रक्रिया में JVM जितनी तेज़ी से उन्हें collect कर सकता था, उससे भी तेज़ garbage बन रहा था
GC tuning की भी बात आती है, लेकिन [1] देखें तो लगता है कि tuning बहुत की भी नहीं गई थी, और Cassandra तथा शायद JVM भी पुराने version इस्तेमाल कर रहे थे. यह बात भी बड़ी है कि वे अभी-अभी CMS से migrate हुए थे
0) https://discord.com/blog/how-discord-stores-billions-of-messages
भले ही वे मूल समाधान का इस्तेमाल गलत तरीके से कर रहे थे, मेरे हिसाब से ऐसा समाधान बेहतर है जिसका गलत इस्तेमाल करना कठिन हो
अगर 2022 में वे Java 11 चला रहे थे तो वह 4 साल पुराना runtime था, और Java 8 चला रहे थे तो 8 साल पुराना runtime, इसलिए संभव है कि वे performance में काफ़ी कुछ खो रहे थे
Needs (2023)
यह service layer एक बड़े और चमकदार distributed Varnish Cache जैसा लगा. Caching का ज़िक्र किए बिना “coalesce” शब्द चुनने से लगता है कि शायद वे वास्तव में बहुत caching नहीं करते, लेकिन इससे Varnish का “grace mode” और stampede रोकने का उपयोग याद आया, यानी वही संदर्भ जिसमें मैंने पहली बार ‘request coalescing’ सुना था https://varnish-cache.org/docs/6.1/users-guide/vcl-grace.htm...
और consistent hashing का बार-बार आना भी अच्छा लगा. यह ऐसी बढ़िया duct-tape जैसी तकनीक है जिसकी उपयोगिता मिलती-जुलती परिस्थितियों में साबित हो चुकी है. अगर आपको पता है कि क्या चीज़ कहाँ होनी चाहिए, तो आपको यह भी पता होता है कि सब लोग उसे ढूँढने कहाँ आएँगे
proxy_cache_use_stale updating;ScyllaDB के co-founder ने कुछ अतिरिक्त बातें जोड़ीं: Discord Cassandra के साथ repair पूरा नहीं कर पाता था, लेकिन Scylla में ऐसा नहीं था, और Scylla में LSM tree और compaction जैसी Cassandra से कई समानताएँ हैं, लेकिन अपने अलग CPU/IO scheduler की वजह से यह queries को compaction से ऊँची priority दे सकता है
वह आधे millisecond के लिए compaction को टाल सकता है, जब idle bandwidth काफ़ी हो, और इस पर कई लेख भी हैं. Scylla में
tombstone_gc=repairनाम का 1.5 साल पुराना एक ज़्यादा सुरक्षित mode भी है, और हाल ही में जारी हुई Raft और tablets आधारित नई architecture को वह users के लिए अगला बड़ा बदलाव बताते हैंअगर उन्होंने 40 साल से ज़्यादा पुराने distributed chat protocol IRC का इस्तेमाल किया होता, तो शायद यह समस्या शुरू से ही नहीं होती
इसकी एक खासियत यह भी है कि इसकी खुली specification है और कई implementations मौजूद हैं। यह कोई walled garden भी नहीं है। अगर आपको लगता है कि IRC आज के समय में बहुत पुराना हो चुका है, तो Matrix या XMPP देख सकते हैं। Discord ने कैसे दबदबा बना लिया, यह समझना मुश्किल है, और सच कहें तो यह कुछ हद तक त्रासदी जैसा है
कई devices पर बातचीत जारी रखने के लिए IRC में लगभग bounceर की जरूरत पड़ती है। यह संदेशों को encrypt भी नहीं करता, और वैकल्पिक रूप से सिर्फ client-server connection को encrypt करता है। end-to-end encryption न हो तो server या operator से privacy नहीं मिलती, और वह server आसानी से निशाना बनने वाला single point of failure बन जाता है
Matrix protocol अभी भी बदल रहा है और implementations specification के साथ कदम नहीं मिला पा रहे हैं। अगर आप Element नहीं इस्तेमाल करते, तो features और security दोनों में पीछे रह जाते हैं। XMPP भी IRC की तरह end-to-end encryption जैसी बुनियादी सुविधाओं के लिए optional extensions पर निर्भर करता है, और clients इन्हें पूरी तरह और सही ढंग से support करें, यह जरूरी नहीं।
soatok का analysis पढ़ने की सलाह दूँगा: https://soatok.blog/2024/08/04/against-xmppomemo/ https://soatok.blog/2024/08/14/security-issues-in-matrixs-ol...
2013 का Snowden मामला 11 साल पुराना है। अब end-to-end encryption को एक बुनियादी सुविधा और commodity की तरह माना जाना चाहिए, और इसे उतनी ही लगातार मांगना चाहिए जितनी पहले HTTPS के लिए मांग की जाती थी। बेशक, Discord end-to-end encryption लागू नहीं करता
हाल ही में मेरा एक बहुत तकनीकी समूह Telegram से Matrix पर गया, लेकिन user experience अच्छा नहीं था। ऐप्स buggy हैं, देखने में भी खास अच्छे नहीं लगते, और नए “Element” ऐप में SSO support नहीं था, इसलिए मैं अपना account इस्तेमाल ही नहीं कर सका। मेरे जैसे लोगों के लिए, जो खुद गहराई में जाकर चीजें समझ लेते हैं, ये छोटी असुविधाएँ चल सकती हैं, लेकिन मैं अपने दोस्तों को यह इस्तेमाल करने के लिए नहीं मना पाऊँगा
exe डाउनलोड करो, install करो, account बनाओ, और तुरंत चलने लगता है। यह कोई भी कर सकता है। बहुत सा उपयोगी और शानदार software मौजूद है, लेकिन उसका बड़ा हिस्सा आम लोगों के लिए आसान नहीं है, और कुछ या बहुतों में GUI तक नहीं है। लोग बहुत सारे चरण झेलने के बजाय अपनी पहचान बेच देना, यहाँ तक कि पैसे देना भी स्वीकार कर लेते हैं
इस लेख से मैंने जो निष्कर्ष निकाला, वह शायद लेखक की मंशा से थोड़ा अलग हो
“आखिरी वाला? हमारा दोस्त cassandra-messages. [...] यह शुरू से ही एक बड़ा cluster था। इसमें खरबों messages और लगभग 200 nodes थे, इसलिए किसी भी migration का जटिल काम होना तय था.”
Discord के scale को देखते हुए message store के लिए 200 से कम nodes होना चौंकाने वाला छोटा लगता है। मैं कहीं ज्यादा तेज scalability और ज्यादा moving parts वाली जटिल architecture की उम्मीद कर रहा था। असली complexity शायद लेख में दिखी बातों से ज्यादा हो, लेकिन जब मैं अपने उस अनुभव को याद करता हूँ जहाँ मैं इससे कम काम करने वाले 200 से अधिक physical nodes के लिए आंशिक रूप से जिम्मेदार था, तो सोचता हूँ कि आधुनिक cloud architectures कितनी बार over-engineered होती हैं
बहुत छोटे Cassandra node set में अरबों records स्टोर करने के अपने अनुभव से कहूँ तो, Cassandra on-call के लिए सचमुच कष्टदायक था और कई बार बड़े outages की वजह बना
[0] https://news.ycombinator.com/item?id=34950843
लेख बहुत बढ़िया लिखा गया है। अच्छा यह है कि समाधान का एक हिस्सा पूरी तरह कुछ और लाने के बजाय ScyllaDB पर जाना है, जिसे Cassandra के विकल्प की तरह इस्तेमाल किया जा सकता है
Discord पुराने संदेशों को हटाना व्यावहारिक रूप से असंभव बना देता है। यह privacy nightmare है, और समझ नहीं आता कि EU ने दखल क्यों नहीं दिया
मुख्य सवाल यह था कि Matrix को email के ज़्यादा करीब माना जाए या Facebook के। अगर वह email है, तो लोग यह सुनकर चौंक जाएंगे कि भेजने वाला मेरे mail spool से अपना संदेश मिटा सकता है; और अगर वह Facebook है, तो लोग यह सुनकर चौंक जाएंगे कि deletion right इस्तेमाल करने के बाद भी पोस्ट कहीं दिखाई दे रही है
इसे सुलझाने के लिए निर्णय लेना पड़ता है, और उनका कहना है कि उन्होंने पहले यह सोचकर रुख अपनाया कि GDPR की भावना वास्तव में क्या हासिल करना चाहती है
https://matrix.org/blog/2018/05/08/gdpr-compliance-in-matrix...
GDPR के नज़रिए से समस्या यह है कि Discord इसे हटाना मुश्किल बनाता है। अगर उसे account data delete करने का इरादा दिखता है, तो वह “anonymization” की ओर धकेलता है, और सार्वजनिक रूप से username संदेशों से अलग दिखता है, लेकिन फिर भी किसी खास व्यक्ति तक trace किया जा सकता है। अगर server side पर भी यही प्रक्रिया होती है, तो user की personally identifiable information हटाने की मांग लागू करने के लिए भारी मात्रा में संदेश खंगालने या पुराने संदेशों को बड़े पैमाने पर delete करने की नौबत आती है
मेरा मानना है कि EU Parliament सच में parliament नहीं है, क्योंकि नए कानून केवल Commission ही प्रस्तावित कर सकती है और निर्वाचित parliament आम तौर पर सिर्फ vote करती है, और Commission को नियंत्रित करने वाला आम जनता नहीं बल्कि अमेरिकी State Department है। Newsguard और Musk नहीं, बल्कि अमेरिकी big tech, Discord भी उसी political और financial establishment network में है, और वहाँ पूर्व State Department कर्मियों की भरमार है
अगर जन-आक्रोश न हो, तो EU-स्तरीय संस्थाएँ capture होने की संभावना रखती हैं, और public opinion को भी वही cyberpunk-style establishment नियंत्रित करता है जो अवैध Discord data से LLM train करता है और election ads target करता है। अंततः हमें इस बात की चिंता करनी चाहिए कि कहीं एक स्थायी establishment से बाहर निकलना असंभव Orwellian स्थिति न आ जाए
हालांकि, इस सब में से ज़्यादातर पर मैं व्यापक अर्थ में सही होने की संभावना सिर्फ 50% से थोड़ा अधिक ही मानता हूँ, इसलिए इसे काफी छानकर ही लेना चाहिए
Cassandra मूल रूप से एक ज़्यादातर append-only distributed fault-tolerant hash table के काफ़ी करीब है। अगर आपको बहुत ऊँचे write throughput के साथ ठीक ऐसी ही चीज़ चाहिए, तो यह अच्छा विकल्प है
लोग इसे database की तरह क्यों इस्तेमाल करते हैं, यह समझ नहीं आता। इसकी सीमाओं से तुरंत टकराना पड़ता है, और इसे database की तरह इस्तेमाल करने की तकलीफ़ scale बढ़ने के साथ और भी ज़्यादा होती जाती है
ऐसे में मुझे नहीं लगता कि यह chat server के message store के लिए समझदारी भरा विकल्प है। distributed system के log collection destination के रूप में, यानी जहाँ बहुत से clients data उंडेलते हैं लेकिन ज़्यादातर logs को audit करने की ज़रूरत नहीं होती, इसलिए किसी विशेष item को पढ़े जाने की संख्या 1 से भी कम होती है, वहाँ यह उपयुक्त लग सकता है। Discord messages स्पष्ट रूप से ऐसे नहीं हैं
मेरे अनुभव में, मैंने कोई ऐसा project नहीं देखा जो Cassandra का इस्तेमाल शुरू करने के लगभग 1 साल बाद भी उसी पर टिका रहा हो। सीमाओं से टकराने में लगभग 1 साल लगता है, और अंत में उसे Postgres जैसे database से बदलना पड़ता है
समझ नहीं आता कि वे बस sharding क्यों नहीं कर सकते। Discord के हर ‘server’ क्या एक-दूसरे से अलग-थलग नहीं हैं? अगर वे एक-दूसरे को संदेश नहीं भेज सकते, तो क्या trillions of messages को हज़ारों shards में बाँटकर, हर shard से कुछ billions messages संभालने को नहीं कहा जा सकता?
इसमें लिखा है, “ScyllaDB team ने improvements को प्राथमिकता देकर और high-performance reverse queries implement करके migration plan की आख़िरी database obstacle को हटा दिया”
जिज्ञासा है कि ScyllaDB इस्तेमाल शुरू करने से पहले ही यह करवाने के लिए उन्होंने कितना भुगतान किया होगा