1 पॉइंट द्वारा GN⁺ 2024-08-11 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Screenshotbot अलग DB के बिना वेब सर्वर प्रोसेस की RAM state को डेटा स्टोर की तरह इस्तेमाल करता है, और snapshots व transaction logs से failure के बाद state restore करता है
  • SQL serialization, DB round-trips और अलग background job service को घटाकर single-process development experience को सरल बनाता है, और in-memory indexes व thread-based processing का इस्तेमाल करता है
  • High availability Raft consensus algorithm से transaction log को 3 servers पर replicate करके हासिल की जाती है; leader failure होने पर कुछ सेकंड में नया leader requests संभाल लेता है
  • वास्तविक implementation में Common Lisp, bknr.datastore, open-source bknr.cluster, Baidu Braft और EFS का संयोजन है; server restart आम तौर पर 1–2 महीनों में एक बार के स्तर पर होता है
  • एक प्रसिद्ध enterprise customer की CI हर commit और Pull Request पर सैकड़ों बार API call करती है, फिर भी 4-core 16GB machine पर CPU usage अधिकतम करीब 20% रहता है, जिसका अधिकांश हिस्सा image processing से आता है

RAM state को database की तरह संभालने वाली संरचना

  • पारंपरिक web services में Rails, Django, Node जैसे web framework और MySQL, PostgreSQL, MongoDB जैसे database को साथ में चुनना सामान्य तरीका रहा है
  • पिछले 10 वर्षों में इस approach पर दोबारा विचार करने लायक environment changes हुए हैं
    • Disks NVMe के कारण तेज़ हो गए हैं
    • EBS/EFS जैसी disks अधिक robust हो गई हैं
    • RAM सस्ती हो गई है, इसलिए अधिकांश startups का data RAM में फिट हो सकता है
    • सैकड़ों cores वाली machines rent पर ली जा सकती हैं
    • 2014 में Raft consensus algorithm प्रकाशित हुआ और मजबूत implementations बढ़ीं
  • यह architecture web service और database instance को मिलाकर, process की memory state को database की तरह इस्तेमाल करता है
  • SQLite की तरह data को serialize करके store नहीं करता, बल्कि RAM में मौजूद objects और fields को सीधे application state के रूप में संभालता है

Explore: शुरुआती product iteration को सरल बनाने का तरीका

  • अगर सारा data RAM में हो, तो SQL queries से serialize करने की जरूरत नहीं होती, और कई frontend servers को single DB से जोड़ने वाली संरचना भी कम हो जाती है
  • Load बढ़ने पर अधिक RAM और CPU वाले बड़े server का इस्तेमाल करके response दिया जा सकता है
  • Indexes के लिए disk latency के हिसाब से बने B-tree के बजाय in-memory hash table जैसी structures इस्तेमाल की जा सकती हैं
    • Screenshotbot में functional collections का उपयोग करने वाले indexes scalability के लिए महत्वपूर्ण थे
  • Data lookup RAM read होता है, इसलिए DB round-trips घटाने के लिए special structures या Async-IO की जरूरत नहीं होती
  • Background jobs उसी बड़े process के अंदर चलने वाले threads बन जाते हैं, और concurrency handling ज्यादातर in-memory mutex और condition variable से हल की जा सकती है

Failure recovery: snapshots और transaction logs

  • Process crash के लिए RAM की पूरी state को समय-समय पर snapshot के रूप में save किया जाता है
  • Last snapshot के बाद के changes को memory state बदलने से पहले disk पर transaction log के रूप में record किया जाता है
    • foo.setBar(2) पहले यह transaction record करता है कि foo का bar field 2 में बदल गया, फिर actual field बदलता है
    • new Foo() पहले यह transaction record करता है कि Foo object बनाया गया, फिर नया object return करता है
  • Restart के समय पहले snapshot पढ़ा जाता है और transaction log replay करके state restore की जाती है
  • Index changes को transaction log में डालना जरूरी नहीं है
    • उदाहरण के लिए अगर Foo के bar field पर index है, तो setBar index update करता है, और यह update snapshot load या transaction replay process में भी फिर से होता है

Single process से संभव होने वाला code pattern

  • सभी requests उसी process में process होती हैं, इसलिए server memory में closures store करके page request handling में इस्तेमाल किया जा सकता है
  • Screenshotbot के https://screenshotbot.io/n/nnnnnnn format वाले URLs internal closures से map होते हैं
  • Closure object references रखता है, इसलिए हर page transition पर object ID pass करने या object serialize करने की जरूरत कम हो जाती है
  • Debugging, profiling और monitoring का target भी एक service तक सीमित हो जाता है
    • MySQL slow query log जैसे अलग DB observation points खत्म हो जाते हैं
    • अगर एक service down होती है तो site भी down होती है, लेकिन माना जाता है कि जब service और server केवल एक हों तो failure की संभावना भी कम होती है
    • Server मरने पर AWS कुछ मिनटों में नया server उठा सकता है
  • Test code भी आसान हो जाता है क्योंकि database को mock करने की जरूरत नहीं होती

Expand: Raft से high availability हासिल करना

  • अगर high-risk customer 99.999% availability मांगता है, तो केवल single-server structure पर्याप्त नहीं है
    • Server failure होने पर AWS द्वारा फिर से server उठाने तक कुछ मिनट लग सकते हैं
    • Process को disk snapshot restore करने में भी कुछ मिनट लग सकते हैं
    • Redeployment के दौरान service restart से server कई मिनट down रह सकता है
  • Raft consensus algorithm finite state machine यानी web server/database के transaction log को replicate करता है
  • 3 machines पर replication करने से leader failure होने पर कुछ सेकंड में नया leader elect हो जाता है और requests process करना जारी रखता है
  • Developer के code लिखने के तरीके को बहुत बदले बिना, एक सरल service को high-availability database जैसा बनाया जा सकता है
  • Raft-based configuration में server down किए बिना rolling deployment भी संभव है

Extract: sharding और expected bottlenecks

  • अधिक बड़े customers को संभालने के चरण में, बड़ी कंपनियां database के लिए जिस तरह इस्तेमाल करती हैं उसी तरह sharding लागू की जा सकती है
  • हर shard अपना cluster हो सकता है
  • Screenshotbot पहले से ही हर enterprise customer को dedicated cluster देता है
  • Meta ने MySQL cluster replication संभालने के लिए Raft पर switch किया था, और Screenshotbot अलग database के बिना समान तरीका इस्तेमाल करता है
  • मुख्य bottleneck candidate commit-thread scaling है
    • Read threads अच्छी तरह parallelize होते हैं
    • एक commit-thread transactions को एक-एक करके apply करता है
    • Raft कई transactions को साथ में disk पर commit करता है, इसलिए disk latency महत्वपूर्ण नहीं है
    • चिंता का बिंदु तब है जब transaction apply करने की CPU cost single-core performance से आगे निकल जाए
    • ऐसे cases में commit cost profile करके कुछ काम transaction thread के बाहर ले जाया जा सकता है या sharding पर विचार किया जा सकता है

Screenshotbot का actual stack

  • Screenshotbot Common Lisp का इस्तेमाल करता है
  • Initial implementation में MySQL इस्तेमाल हुआ था, लेकिन MySQL से concurrency संभालना मुश्किल होने के कारण उसे bknr.datastore से replace किया गया
  • bknr.datastore वह library है जो Explore चरण में समझाई गई structure को Common Lisp के लिए provide करती है
  • इस structure में single process के अंदर threads web requests handle करते हैं, इसलिए strong multithreading महत्वपूर्ण है
    • इसी requirement के कारण Ruby या Python उपयुक्त नहीं माने जाते
  • Closures को server memory में बनाए रखने के कारण server को बार-बार restart करना मुश्किल है
    • Restart करने पर closures खो जाते हैं
    • इसके बजाय running process में hot reloading से code update किया जाता है
    • Common Lisp class definitions बदलने पर existing objects update करने का standard, जैसे reinitialize-instance, जैसी features provide करता है

Clusters, file storage और operational scale

  • Server restart फिलहाल आम तौर पर 1–2 महीनों में एक बार के आसपास होता है
  • Restart की जरूरत होने पर Raft cluster में rolling restart किया जाता है
  • प्रति installation 3-server cluster इस्तेमाल होता है, और यह configuration एक server down होने की स्थिति allow करती है
  • Kubernetes फिलहाल इस्तेमाल नहीं किया जा रहा और अभी जरूरत नहीं मानी जाती
  • Raft implementation bknr.datastore के ऊपर बनाई गई अपनी library है
    • bknr.cluster को open source के रूप में publish किया गया है
    • Internally Baidu का Braft इस्तेमाल करता है
    • Braft background snapshots handle करता है, जिससे snapshot creation के दौरान भी server requests process करना जारी रख सकता है
  • Image files या ऐसे blobs जिन्हें datastore में नहीं रखना चाहिए, तीनों servers द्वारा साझा किए गए EFS में store किए जाते हैं
    • EFS high-availability NFS है
    • S3 की तुलना में error conditions को अलग से handle न करना पड़े, इसलिए इसे काम करने में आसान माना जाता है
    • External servers से interaction किए बिना disk पर write करने के कारण testability भी बेहतर होती है

मौजूदा performance और applicability

  • Screenshotbot कुछ बड़े enterprise customers और खास तौर पर एक बहुत प्रसिद्ध customer को support करता है
  • यह उस customer की CI में चलता है, और हर commit व Pull Request पर सैकड़ों API requests प्राप्त करता है
  • इस load के बावजूद request processing के लिए 4-core 16GB machine पर्याप्त है
    • Replication servers भी similar machines इस्तेमाल करते हैं और ज्यादातर idle रहते हैं
    • CPU usage अधिकतम करीब 20% है
    • CPU usage का अधिकांश हिस्सा image processing से आता है
  • जरूरत से बड़े scale की कल्पना करके design न करना महत्वपूर्ण है
  • Common Lisp चुनने पर संबंधित configuration Screenshotbot OSS के रूप में इस्तेमाल की जा सकती है

1 टिप्पणियां

 
GN⁺ 2024-08-11
Hacker News की रायें
  • यह आर्किटेक्चर काफ़ी हद तक वैसा ही है जैसे HashiCorp के Nomad, Consul और Vault बनाए गए हैं (मैं Nomad maintainers में से एक हूं)। यह निश्चित रूप से असामान्य आर्किटेक्चर है, लेकिन इसकी आदत पड़ जाए तो developer experience काफी अच्छा होता है
    in-memory state को आप अपनी पसंद के रूप में रख सकते हैं, इसलिए application के हिसाब से indexing और query functions खुद बना सकते हैं। Raft FSM में :memory: SQLite इस्तेमाल किया जा सकता है, लेकिन अगर आप in-memory transactional store बना या ढूंढ सकते हैं (हम अपना go-memdb इस्तेमाल करते हैं), तो state पढ़ना बस function call बन जाता है। stale reads या write skew को रोकना भी सरल है। लिखे जाने वाले हर object में Raft index होता है, इसलिए आप ऐसा API बना सकते हैं जैसे “follower से object foo query करो, लेकिन कम-से-कम index 123 तक wait करो।” यह बहुत-सी उस “magic” को हटा देता है जिसे आम तौर पर RDBMS या external store में धकेल दिया जाता है
    हालांकि “infra” क्षेत्र से बाहर किसी नए startup के लिए ऐसा आर्किटेक्चर चुनने में सावधानी बरतूंगा। असल में आप अपना database बना रहे होते हैं। nodes के बीच RPC, disk persistence, in-memory transactional state store जैसे बुनियादी हिस्सों को ठीक से चुनना या खुद लिखना पड़ता है। upgrades खास तौर पर मुश्किल होते हैं, और नया code Raft log में ऐसी entities लिखने की कोशिश कर सकता है जिन्हें पुराने version के nodes समझ नहीं पाते। इससे भी बुरा यह कि processing का तरीका बदल जाए और पुराने nodes उसे गलत समझ लें। मुफ्त का खाना नहीं होता

    • “Raft FSM में :memory: SQLite इस्तेमाल किया जा सकता है” वाला हिस्सा rqlite[1] के शुरुआती करीब 7 साल तक इस्तेमाल किए गए basic design जैसा था। लेकिन rqlite disk-based SQLite पर चला गया, और WAL mode तथा PRAGMA synchronous=OFF[2] के साथ यह RAM में लिखने जितना तेज, या काफी नज़दीक था। इससे :memory: SQLite database की सीमाओं से भी बचना संभव हुआ, जिनमें से एक maximum size 2GB limit है। शुरुआत से ही disk mode इस्तेमाल करना चाहिए था, लेकिन यह अब समझ आया
      चूंकि rqlite भी Nomad जैसी ही Raft library[3] इस्तेमाल करता है, इसलिए इनमें से कुछ बातें आप पहले से जानते होंगे
      upgrade की समस्या सचमुच मौजूद है। सोचता हूं Nomad में यह field में अक्सर सामने आती है या नहीं। rqlite के 10 साल के development में नया Raft Entry type introduce करना बहुत rare रहा, और असल users के सामने यह सिर्फ एक बार आया। इससे निपटने का एक तरीका यह है कि पहले ऐसा version deploy किया जाए जो नए type को समझता हो लेकिन उसे कभी लिखता न हो, और जब वह version पूरी तरह install हो जाए तब उस version पर upgrade किया जाए जो सच में नया type लिखता है। हालांकि हमने वास्तव में ऐसा कभी किया नहीं है, और end users से भी discipline चाहिए
      [1] https://www.rqlite.io
      [2] सुनने में जोखिम भरा लग सकता है, लेकिन मौजूदा rqlite design में startup पर main SQLite database को Raft log से पूरी तरह rebuild किया जाता है (Raft log हर write पर fsync होता है)। इसलिए power outage आदि से SQLite database corrupt हो भी जाए, तो उसका बहुत मतलब नहीं है क्योंकि SQLite database rqlite का authoritative data store नहीं है
      [3] https://github.com/hashicorp/raft
    • यहां की दूसरी replies की तुलना में मैं भी data को memory में बनाए रखने के विचार के प्रति ज्यादा open हूं। लेख में Common Lisp और hot reloading इस्तेमाल करने वाली बात देखकर मैंने सोचा, “अगर वह team है, तो उन्हें जो चाहें करने दो। बस हर कोई उस team में काम नहीं करता”
    • “upgrades खास तौर पर मुश्किल होते हैं” यह बात बिल्कुल सही है। लेकिन यह उन Explore stage वाले startups पर लागू नहीं होती जिन्हें replication की जरूरत नहीं है, और हमने भी लंबे समय तक ऐसा ही किया। product iteration के लिए यह आर्किटेक्चर जिस stage में सबसे ज्यादा उपयोगी होता है, वह यही है
      हालांकि Expand stage में replication इस्तेमाल करना शुरू करते ही engineering tasks पैदा होते हैं, यह सही है। फिर भी ये सभी हल किए जा सकने वाले problems हैं। Common Lisp में code को hot reload किया जा सकता है, जिससे कुछ migrations बहुत आसान हो जाती हैं
  • कई दशक पहले PG ने लिखा था कि Viaweb में उन्होंने database का इस्तेमाल नहीं किया था, और यह अजीब लगता था कि web apps database के frontend जैसे बन जाते हैं, जबकि desktop apps ऐसे नहीं होते[0]. HN भी database का इस्तेमाल नहीं करता
    लेकिन अब आधुनिक desktop और mobile apps अक्सर database, आम तौर पर SQLite, इस्तेमाल करने लगे हैं, इसलिए यह बात अब वैसी की वैसी सही नहीं रह गई है। वजह यह है कि relational data storage और querying बहुत व्यापक तरह की applications में काफी उपयोगी साबित हुए हैं
    [0] https://www.paulgraham.com/vwfaq.html

    • link पढ़कर लगता है कि “database” का मतलब सभी के लिए एक जैसा नहीं है
      vwfaq में अब भी disk से data पढ़ने की बात है, और “HTTP request का जवाब देने के लिए process शुरू करता है” जैसी बात भी है। यहां “database” से शायद data को persist करने वाला अलग server, और उस data को लाने के लिए दूसरे server से communicate करने वाली संरचना मतलब रही होगी
      इस परिभाषा में स्वाभाविक रूप से SQLite database में नहीं आएगा। और अगर आप पहले से disk से data पढ़ रहे हैं, तो आप या तो database इस्तेमाल कर रहे हैं या अस्थायी तौर पर अपनी खुद की persistence layer implement कर चुके हैं। सवाल यह है कि app start होते समय SQLite से data पढ़ना क्या अब भी database इस्तेमाल करना माना जाएगा
      इस सोच की दिक्कत यह है कि यह इस बात को नजरअंदाज करती है कि database का core value data को सुविधाजनक तरीके से store और retrieve करना है, बिना low-level details की चिंता किए। data को database में store करने का मतलब यह नहीं कि कहीं Postgres instance चलाकर web के जरिए data लाया जा रहा है। अगर आप सारा data memory में रखते हैं और log-structured data structure के साथ snapshots को disk पर save करने वाला process रखते हैं, तो बधाई हो। आपने अभी-अभी अपना database बना लिया है
    • PG के लेख से प्रभाव पड़ा है, यह साफ है। हम भी Common Lisp इस्तेमाल करते हैं, और इस field में PG से बचना मुश्किल है। हालांकि लगता नहीं कि Viaweb ने bknr.datastore की तरह transaction log इस्तेमाल किया था, और उसी वजह से development process कहीं ज्यादा smooth हो गया
    • जब PG ने Viaweb लिखा था, तब SQLite खुद भी आज जितना आम नहीं था। सही कहें तो उस समय SQLite अस्तित्व में ही नहीं था। अगर SQLite नहीं होता और विकल्प असल में सिर्फ key-value stores ही होते, तो ज्यादातर cases में filesystem इस्तेमाल करना भी ठीक रहता
      दूसरा, पिछले 20 सालों में RDBMS queries काफी सरल हो गई हैं। boilerplate code घटाने वाले तमाम ORM और row mappers आ गए हैं
      desktop और mobile apps के लिए उपयोगी full-text search जैसी advanced features भी आ गई हैं। आज desktop app में RDBMS इस्तेमाल करना अच्छा विकल्प है
    • HN database इस्तेमाल नहीं करता? थोड़ा और समझा सकते हैं? काफी चौंकाने वाली बात है
    • तब जमाना अलग था। मेरी जानकारी में Viaweb कई Common Lisp instances से बना था, और user session की सारी state अलग-अलग machines की memory में रहती थी। मुझे याद है कि कहीं पढ़ा था कि production में user से call पर बात करते हुए उन्होंने real time में bug patch किया था
      web बहुत बड़ा हो चुका है, और ऐसी कई practices आज काम नहीं करेंगी। अगर मैं आज की testing burden के साथ customer से call पर रहते हुए production machine में live fix push करूं, तो यहां बहुत से लोग मेरी मानसिक स्थिति पर शक करेंगे
  • कुछ दिलचस्प experiment करने की इच्छा समझ आती है, लेकिन MySQL या Postgres के सबसे basic हिस्से सीखने से बचने के लिए ऐसा करना भारी समय की बर्बादी लगता है। बस उसके ऊपर बना दीजिए, खासकर अगर public cloud पर चला रहे हैं तो
    round-trip latency बढ़ने या concurrency issues वाली बात मुझे convincing नहीं लगती। दूसरी समस्या के लिए basic tuning या noisy customers को अलग करने जैसे सरल समाधान होते हैं। उनके blog के दूसरे लेख में वे रोज 1 करोड़ rows जोड़ने की संभावना और indexing challenges की बात करते हैं, लेकिन वह सचमुच कोई बड़ी बात नहीं है। उसका 10 गुना भी हो जाए तो भी मेरे हिसाब से custom solution engineer करने का कारण नहीं बनता
    जब तक सच में जरूरत न हो, “worse is better” ही सही है, और जब वह समय आएगा तो आपको साफ पता चल जाएगा। तब bottleneck भी पता होगा, इसलिए शुरुआत से ही over-engineer करने की बजाय आप ज्यादा समझदारी से प्रतिक्रिया दे पाएंगे

    • server-based database engine हो तो network calls कम करने का तर्क अब भी दिया जा सकता है। संदिग्ध है, लेकिन संभव है
      लेकिन blogger का SQLite न चुनने की वजह यह बताना कि उसमें गैर-जरूरी features हो सकते हैं, हैरान करने वाला है। यह बेतुका है और किसी चीज को justify नहीं करता
      लेख ऐसा पढ़ा जाता है जैसे यह काल्पनिक समस्या के खराब solution से शुरू होता है, और फिर obvious solution को reject करने के लिए जबरन logic गढ़ने की हताश कोशिश करता है
    • मुझे जिज्ञासा है कि अगर इन्होंने wheel को फिर से invent करने में समय न लगाया होता, तो क्या business successful होता। public में बनाना और blog में लिखना ही product का प्रचार करता है और technical क्षमता दिखाता है। अगर उन्होंने बस ऐसी boring technology इस्तेमाल की होती जो साथ जोड़ने पर अच्छी चलती है, तो कहने को कम रह जाता, और इसलिए PR effect भी कम हो जाता क्या?
      पता नहीं मेरी सोच गलत है, या फिर यह विवादास्पद लेकिन अनावश्यक लगने वाला extra effort ही product का हिस्सा है और इस space में सफल होने का तरीका भी
  • “हम SQLite जैसी किसी चीज़ की बात नहीं कर रहे जहाँ डेटा अब भी serialize होता है” से शुरू करके आखिर में अपने ही transaction log पर पहुँचना अजीब है, जहाँ serialization भी चाहिए और replication भी। database replication तो मूल रूप से ऐसे ही होता है
    अगर पूरा load एक ही server पर आ रहा है, तो बस उसी server पर database चलाइए और “database round-trip घटाने वाला खास architecture” जैसी चीज़ें भूल जाइए। अगर सारा डेटा RAM में फिट हो जाता है, तो चाहें तो database के लिए ramdisk इस्तेमाल करें और standard tools से persistent storage में replicate कर दें। असल में वही सरल है

    • कुल मिलाकर यह “अपना SQLite + Raft replication बना लिया” जैसा summarize होता है। बस इसमें SQLite की परखी हुई reliability या memory को disk पर efficient तरीके से spill करने की क्षमता नहीं है
      इसलिए मूल रूप से यह https://litestream.io/ जैसा लगता है। explicit Raft setup की वजह से failover शायद तेज़ हो सकता है। मैं Litestream user नहीं हूँ, इसलिए बारीक फर्क नहीं जानता, लेकिन यह बहुत मिलता-जुलता सुनाई देता है
      इस तरह की over-simplification से अलग, idea खुद मुझे काफी पसंद है, और लेख concept को काफी अच्छी तरह convince भी करता है। बहुत सारे systems में, अगर वे असामान्य रूप से सफल भी हो जाएँ, तो यह business के अधिकांश या पूरे हिस्से को संभालने लायक scale कर जाएगा, और performance लगभग किसी भी alternative की तुलना में बेतुकी हद तक अच्छी होगी
    • मुझे नहीं लगता ramdisk की भी ज़रूरत है। database पहले से ही सब कुछ memory में cache करता है, और सिर्फ writes ही disk तक पहुँचती हैं
      database को cold start करने के बाद कोई काफी बड़ा select दो बार चलाकर देख लें
    • यह समझना ज़रूरी है कि हर startup तीन चरणों से गुजरता है: Explore, Expand, Extract। एक चरण में जो सरल है, वह दूसरे चरण में सरल नहीं होता
      transactional database Expand और Extract चरणों में सरल होते हैं, लेकिन Explore चरण में वे product के बजाय infrastructure problems पर focus करवाकर extra burden बन जाते हैं। Explore चरण में customers नहीं होते, इसलिए data भी नहीं होता, और data reliability भी महत्वपूर्ण नहीं होती
      bknr.datastore के साथ सब कुछ memory में रखने वाला तरीका (बिना replication) Explore चरण में सरल है। लेकिन Expand चरण में पहुँचते ही data consistency सुनिश्चित करने का operational burden आ जाता है
      फिर भी Expand चरण तक पहुँचते-पहुँचते आप product validate कर चुके होते हैं और काफी code भी लिख चुके होते हैं। उसे transactional database पर फिर से लिखना समझदारी नहीं है; ऊपर Raft replication जोड़ना ज्यादा आसान है
    • सहमत हूँ। WAL को फिर से बनाना मतलब उससे जुड़ी सारी परेशानियाँ भी फिर से बनाना या ignore करना। log से recover करने में काफी समय लगता दिखता है, इसलिए शायद log checkpointing तक भी अभी ठीक से नहीं पहुँचे हैं
    • trading systems साफ तौर पर सब कुछ RAM में pre-allocated structures में रखते हैं। बात इस पर निर्भर करती है कि आप कौन-सा trade-off चुनते हैं
  • इस लेख की logic हैरान करने वाली है। क्या यह stateful applications को ज्यादा सरल और तेज़ बनाने का तरीका है?
    premise कमजोर है और claims बहुत बड़े हैं। लेखक serialization की कठिनाई को बढ़ा-चढ़ाकर दिखाता है ताकि कमजोर claim ज्यादा मजबूत लगे

    • blog post में “देखो हम कितने smart हैं” वाला भाव बहुत जोर से आता है
      ऐसे लोगों के साथ काम करना आम तौर पर मुश्किल होता है। अच्छा है कि मुझे जिस startup को डुबोना है, वह मिल गया ताकि उनसे deal न करना पड़े
    • और फिर transaction को log में लिखने और दूसरे nodes पर replicate करने के लिए serialization implement करता है
  • नया project शुरू करने पर data structure आम तौर पर “attributes वाली items की list” होता है। उदाहरण के लिए, मैं अभी एक fitness app लिख रहा हूँ, और data workouts की list है; हर workout में title, description, video URL और बाकी attributes हैं
    आम तौर पर मैं उन items को data directory की YAML files में डालकर शुरू करता हूँ। असल में यह custom YAML dialect है जिसमें original YAML की अजीब बातें नहीं हैं। हर value string होती है, और कोई magical type conversion नहीं होता। नई item बनाना बस vim crunches.yaml से data डालना है, और इस data structure में edit और delete करना भी बहुत आसान है
    project बड़ा होने पर आम तौर पर DB schema बनाता हूँ और items को MariaDB या SQLite में move करता हूँ
    इस बार items (workouts) को SQLite DB के JSON column में move करने का सोच रहा हूँ। एक item की सारी attributes को single JSON field में store करूँगा, और एक छोटा DB explorer लिखूँगा जो JSON field को YAML की तरह edit करने देता हो। मकसद human-readable data edit करने की सुविधा बनाए रखना है
    DB explorer लिखना काफी straightforward लगता है। थोड़े ncurses से table browse करेंगे, एक select करेंगे, rows browse करेंगे, rows insert/delete करेंगे। field edit करते समय Vim खोलेंगे। अगर field JSON है, तो Vim में भेजने से पहले उसे YAML में बदलेंगे, और user के Vim exit करने पर फिर JSON में वापस बदल देंगे

  • लेख की शुरुआत में जो बताया गया, वह मूल रूप से NUMA machines के काम करने के तरीके जैसा था (जैसे SGI Altix या UV)। साथ ही, उनके बताए फायदे low latency और बड़े RAM में multithreading से काम parallelize कर पाने के थे। clustering 10 लाख डॉलर से अधिक की machines के low-cost alternative के तौर पर आई थी। AS/400 की persistence से भी समानता है, जहाँ app बस memory में लिखता है और वह transparently disk पर map हो जाता है
    अब हम सस्ते hardware के साथ clustered NUMA machine के फायदों की ओर समय में पीछे लौट रहे हैं। इस दौरान improvements भी हुए हैं, और लेख पढ़ने में रोचक था
    अतीत की एक और technique थी cluster के अंदर TCP/IP stack हटाकर उससे जुड़ी समस्याएँ खत्म करना। Active Messages जैसे solutions hardware के ऊपर एक पतली layer थे। strong consistency built-in वाले network router designs भी हैं। ये लोग काफी कुछ कर सकते हैं
    बड़ा होने पर hardware opportunities भी हैं। CPU side पर SGI ने दो चीजें कीं। NUMA machines ने एक system में CPUs और RAM की संख्या scale की, और FPGA को सीधे memory bus में लगाकर custom accelerator की तरह इस्तेमाल करने दिया। अंत में, कुछ computer science papers ने multithreading bottleneck को खत्म या कम करने के लिए processor instruction set, on-chip network वगैरह में बदलाव किए। OpenPiton जैसे chips open और customizable cores के साथ core count बढ़ाते हैं (जैसे 32)

  • “अगर डेटा को SQL queries में serialize करने की ज़रूरत न हो, तो सोचिए कितनी शानदार चीज़ें बनाई जा सकती हैं” — यह बात पर्याप्त रूप से परिपक्व Actor model[0] implementations में पहले से मौजूद है, जैसे Akka Event Sourcing[1]. अगली समस्या को भी यह संभालता है
    “लेकिन अहम हिस्सा यह है कि process crash होने पर recover कैसे किया जाए। जवाब आसान है। समय-समय पर पूरी RAM का snapshot ले लेना चाहिए”
    “web development के लिए नया architecture” बनाने की ज़रूरत के बिना यह मूल रूप से हल हो जाता है। actors का उपयोग करके RAFT protocol को explore करने की open source कोशिशें यहां[2] और यहां[3] भी हैं
    0 - https://en.wikipedia.org/wiki/History_of_the_Actor_model
    1 - https://doc.akka.io/docs/akka/current/typed/persistence.html
    2 - https://github.com/Michael-Dratch/RAFT_Implementation
    3 - https://github.com/invkrh/akka-raft

  • मेरा पहला ख़याल था, “अरे, Common Lisp में लिखते समय मैं भी ऐसा ही करता था; मज़ेदार है कि किसी ने उस technique को फिर से खोज लिया”
    लेकिन ऐसा नहीं था; बस Lisp वाले और भी निकले

  • “RAM बहुत सस्ती है” शायद developers की सबसे बड़ी गलतफहमी हो सकती है
    SSDs throughput या IOPS के हिसाब से 100~10000 गुना बेहतर हुए हैं, और vCPU की dollar-per-performance भी 20~50 गुना बढ़ी है। 45/32nm से अब हम 5nm/3nm तक आ गए हैं, और instructions per clock भी कहीं ज़्यादा हो गए हैं
    लेकिन RAM की कीमत CPU या SSD जितनी लगभग नहीं घटी। यह बहुत तेज़ हुई हो सकती है, higher-density chips से ज़्यादा memory लगाई जा सकती है, और channels भी dual से बढ़कर 8 या 12 हो गए हो सकते हैं। लेकिन 2008~2022 के DRAM spot prices देखें, तो सबसे कम DRAM price तीन बार लगभग समान 2.8 डॉलर/GB के स्तर पर था। उसी अवधि में cycle के हिसाब से यह 6~8 डॉलर/GB तक ऊपर-नीचे हुआ। यानी पिछले लगभग 15 सालों में अगर आपने trough या peak पर DRAM खरीदी, तो inflation को नज़रअंदाज़ करने पर कीमत मोटे तौर पर ±10~20% के भीतर समान रही होगी
    2022 के मध्य में जाकर ही 2.8 डॉलर/GB की barrier टूटी और यह 1 डॉलर/GB के आसपास तक गिरा, फिर DDR5 के हिसाब से लगभग 2 डॉलर/GB पर टिक गया
    अब एक server में 4TB RAM लगाई जा सकती है। इसका मतलब यह नहीं कि DRAM बहुत सस्ती है। औसत developer या big tech developer 2010 की तुलना में कहीं ज़्यादा कमाने लगा है, इसलिए RAM कहीं ज़्यादा affordable लगती है। वास्तव में, पिछले 15 सालों के सबसे निचले स्तर पर भी DRAM price की गिरावट मुश्किल से 2 गुना से थोड़ी ज़्यादा रही है। और 1~2 साल के भीतर DRAM prices फिर से तेज़ी से बढ़ने की संभावना काफ़ी है

    • एक और व्याख्या भी संभव है। individual node की maximum RAM capacity पिछले दशकों में तेजी से बढ़ी है
      सरल उदाहरण के लिए, अगर 20 साल पहले कोई specific node 16GB RAM तक सीमित था, तो system में 4TB RAM पाने के लिए 256 nodes चाहिए होते (हर OS overhead को छोड़कर)
      आज एक single node वही पूरा 4TB एक chassis में रख सकता है
      RAM chips की कुल लागत शायद नहीं बदली हो, लेकिन physical system में उस RAM को वास्तव में इस्तेमाल करने की लागत नाटकीय रूप से कम हो गई है
    • साथ ही, कई developers तब भी बहुत जल्दी distributed systems की तरफ़ हाथ बढ़ा देते हैं, जब सिर्फ़ और RAM खरीदना काफ़ी होता। लेखक का मतलब शायद यही रहा होगा
    • data के लिए धन्यवाद। दूसरे reply से सहमत हूं। “सस्ती” कहने के बजाय शायद कहना चाहिए था कि सैकड़ों GB RAM वाली machines हासिल करना आसान हो गया है