परिचय
महीनों के पुनरावृत्ति के बाद, Lighter का एंड-टू-एंड p99 280 ms से घटकर 55 ms पर स्थिर हो गया। ट्रांज़ैक्शन प्रोसेसिंग p99 20–30 ms के स्पाइक्स से घटकर 1 ms से नीचे आ गया। हॉट पथ एप्लाई टाइम 100–250 µs पर है। यह सब मेननेट पर, बड़े पैमाने पर।
कितना बड़े पैमाने पर? 5 जून, 2026 को, Lighter ने एक ही दिन में 811 मिलियन ट्रांज़ैक्शन का सर्वकालिक उच्च स्तर हासिल किया, औसतन 9,388 TPS और 20,740 TPS की चरम गति के साथ।
Lighter का सीक्वेंसर Go में लिखा गया है। ट्रांज़ैक्शन Lighter L2 पर निष्पादित होते हैं, जिनके पूर्ण क्रिप्टोग्राफिक प्रूफ L1 पर सेटल होते हैं। मुख्य आर्किटेक्चरल अंतर्दृष्टि यह है कि प्रूफिंग को एक्ज़ीक्यूशन से डिकपल्ड किया गया है: प्रूफ जनरेशन एसिंक्रोनस रूप से चलता है और कभी भी ट्रेडिंग को ब्लॉक नहीं करता। इसका मतलब है कि ट्रेडर्स द्वारा अनुभव की जाने वाली विलंबता पूरी तरह से Lighter के एक्ज़ीक्यूशन और API लेयर्स द्वारा निर्धारित होती है।
Lighter की API लेयर वह सेवा है जिसके साथ ट्रेडर्स सीधे इंटरैक्ट करते हैं। यह मेमोरी में एक्सचेंज स्टेट का पूर्ण, अप-टू-डेट व्यू बनाए रखता है और उस स्थानीय स्टेट से REST और WebSocket कनेक्शन प्रदान करता है। एक महत्वपूर्ण गोरूटीन एक्ज़ीक्यूशन इंजन से स्टेट अपडेट प्राप्त करता है और उन्हें रियल-टाइम में इन-मेमोरी कैश पर लागू करता है। डाउनस्ट्रीम की सभी चीज़ें (WebSocket पुश, API रीड, ट्रांज़ैक्शन सिमुलेशन) इन्हीं कैश से सर्व होती हैं।
मुख्य अवधारणाएँ शामिल
निम्नलिखित अवधारणाएँ इस तकनीकी लेख के बाकी हिस्से में शामिल मुख्य विषयों का एक उच्च-स्तरीय अवलोकन प्रदान करती हैं:
मेननेट से पहले इसे ढूंढें: सिंथेटिक खातों और यथार्थवादी लोड के साथ एक समान लोडटेस्ट वातावरण, जो प्रोडक्शन की तुलना में अधिक आक्रामक रूप से इंस्ट्रूमेंटेड है, ट्रेडर्स के नोटिस करने से पहले ही बाधाओं को पकड़ लेता है।
दोहरी-वातावरण अवलोकन योग्यता: लोडटेस्ट ऐसे मेट्रिक्स रखता है जो प्रोडक्शन के लिए बहुत महंगे हैं; मेननेट की रियल-टाइम निगरानी ताजगी, सिमुलेशन विलंबता और एंड-टू-एंड ट्रांज़ैक्शन लाइफसाइकिल के लिए की जाती है। साथ में, वे पूर्ण कवरेज देते हैं।
हजारों आवंटनों से मृत्यु: हीप-भारी प्रकारों और डीप कॉपी को स्टैक-आवंटित विकल्पों और अपरिवर्तनीय स्नैपशॉट से व्यवस्थित रूप से बदलना। GC वाली भाषा में, कम आवंटन = कम पॉज़ = कम टेल लेटेंसी।
OS-स्तरीय नियंत्रण: महत्वपूर्ण थ्रेड्स को समर्पित CPU कोर पर लगभग रियल-टाइम प्राथमिकता के साथ पिन करना।
हार्डवेयर-जागरूक डिप्लॉयमेंट: NUMA-जागरूक प्लेसमेंट सुनिश्चित करता है कि हॉट पथ के पास तेज़, स्थानीय मेमोरी एक्सेस हो। लेटेंसी स्टैक में अंतिम परत।
सुविधा पर बाइनरी को प्राथमिकता: हॉट पथ पर हाथ से बनाई गई बाइनरी सीरियलाइज़ेशन रिफ्लेक्शन और आवंटन ओवरहेड को समाप्त करती है। प्रति सेकंड हजारों अपडेट में हर बचाया गया माइक्रोसेकंड संयोजित होता है।
मेननेट पर हिट करने से पहले बाधाओं का पता लगाना
जो आप देख नहीं सकते, उसे ठीक नहीं कर सकते। किसी भी चीज़ को ऑप्टिमाइज़ करने से पहले, हमने यह पहचानने के लिए टूलिंग में भारी निवेश किया कि समय वास्तव में कहाँ खर्च हो रहा है।
लोडटेस्ट वातावरण
जब हम कुछ परीक्षण करना चाहते हैं, तो हम एक समर्पित लोडटेस्ट वातावरण शुरू करते हैं: मेननेट इंफ्रास्ट्रक्चर की एक समान प्रतिलिपि जो समान कॉन्फ़िगरेशन के साथ, समान डिप्लॉयमेंट टोपोलॉजी के तहत सेवाएँ चलाती है। यह हमेशा चालू नहीं रहता; हम इसे किसी विशिष्ट परीक्षण के लिए मांग पर लाते हैं और बाद में इसे तोड़ देते हैं।
एक बार यह वातावरण तैयार हो जाने पर, हम सिंथेटिक खाते बनाते हैं और तनाव के तहत वास्तविक बाजार स्थितियों का अनुकरण करने के लिए यथार्थवादी ट्रेडिंग लोड उत्पन्न करते हैं। यह अनुमति देता है:
- अतिरिक्त-ग्रैन्युलर टाइमिंग: हॉट पथ के अंदर प्रति-चरण समय, प्रति-ऑपरेशन कैश बिल्ड अवधि, और सबमिशन से लेकर कन्फ़र्मेशन तक हर चरण को ट्रैक करने वाले ट्रांज़ैक्शन लाइफसाइकिल टाइमस्टैम्प।
- ऑन-डिमांड प्रोफ़ाइलिंग और फ्लाइट रिकॉर्डर: हम लोड के दौरान अनुरोध पर CPU, मेमोरी और एक्ज़ीक्यूशन ट्रेस प्रोफ़ाइल कैप्चर करते हैं। Go का फ्लाइट रिकॉर्डर हमें हमेशा चालू ट्रेस संग्रह देता है। जब कोई धीमी घटना का पता चलता है, तो एक्ज़ीक्यूशन के अंतिम कुछ सेकंड स्वचालित रूप से कैप्चर हो जाते हैं, जिससे हम घटना के बाद क्षणिक लेटेंसी स्पाइक्स का निदान कर सकते हैं।
- वितरित ट्रेसिंग: हमने हॉट पथ में हर प्रमुख फ़ंक्शन को ट्रेस स्पैन के साथ इंस्ट्रूमेंट किया, जिससे हमें एक ही अपडेट साइकिल के भीतर, सेवा सीमाओं के पार, समय कहाँ खर्च होता है, इसकी बारीक दृश्यता मिलती है।
दोहरी-वातावरण निगरानी
हम दोनों वातावरणों (मेननेट और लोडटेस्ट) की बारीकी से निगरानी करते हैं, लेकिन ग्रैन्युलैरिटी के विभिन्न स्तरों पर।
मेननेट की रियल-टाइम में कड़ी निगरानी की जाती है। हम ट्रेडिंग अनुभव के लिए मायने रखने वाली हर चीज़ को ट्रैक करते हैं:
- ताजगी ट्रैकिंग: हम सबसे सक्रिय बाजारों पर
order_bookWebSocket चैनल के माध्यम से लेटेंसी मापते हैं। मूल रूप से, ऑर्डर बुक अपडेट उत्पन्न होने और क्लाइंट द्वारा इसे प्राप्त करने के बीच का अंतर। यह वह मीट्रिक है जो सबसे सीधे तौर पर ट्रेडर्स द्वारा महसूस किए गए अनुभव को दर्शाता है: आप जिस ऑर्डर बुक को देख रहे हैं वह कितनी पुरानी है? हम इसे दो बिंदुओं पर ट्रैक करते हैं। सबसे महत्वपूर्ण है एक्ज़ीक्यूशन इंजन → क्लाइंट: वह पूरी पाइपलाइन जब एक्ज़ीक्यूशन इंजन स्टेट चेंज को प्रोसेस करता है से लेकर जब परिणामीorder_bookअपडेट क्लाइंट पर पहुंचता है। हम API लेयर → क्लाइंट भी मापते हैं: API लेयर प्रत्येक आउटगोइंग अपडेट को टाइमस्टैम्प करता है और क्लाइंट इसकी तुलना अपनी घड़ी से करता है, जिससे हमें अंतिम-मील लेटेंसी अलगाव में मिलती है। - ड्राई-रन लेटेंसी: API लेयर प्रत्येक ट्रांज़ैक्शन को एक्ज़ीक्यूशन इंजन को पास करने से पहले ड्राई-रन करता है (सिग्नेचर, नॉन्स और बैलेंस को मान्य करना)। प्रत्येक ड्राई-रन का समय लिया जाता है और रिपोर्ट किया जाता है।
- एंड-टू-एंड ट्रांज़ैक्शन लाइफसाइकिल: सबमिशन से कन्फ़र्मेशन तक पूर्ण-चक्र लेटेंसी हिस्टोग्राम।
- कैश प्रभावशीलता: हम कितनी बार मेमोरी से सर्व करते हैं बनाम धीमी स्टोरेज पर वापस जाते हैं।
लोडटेस्ट की और भी अधिक ग्रैन्युलर निगरानी की जाती है। क्योंकि यह वास्तविक ट्रेडर्स की सेवा नहीं कर रहा है, हम ओवरहेड की चिंता किए बिना इंस्ट्रूमेंटेशन को बढ़ा सकते हैं: हॉट पथ के अंदर प्रति-चरण समय, आवंटन प्रोफ़ाइलिंग, प्रत्येक कैश म्यूटेशन पर अतिरिक्त हिस्टोग्राम बकेट। यह बारीक ग्रैन्युलैरिटी माइक्रो-लेवल रिग्रेशन को पकड़ती है जो मेननेट के प्रोडक्शन-सुरक्षित मेट्रिक्स प्रकट नहीं करेंगे।
मेननेट निगरानी हमें बताती है कि सिस्टम वास्तविक ट्रेडर्स के लिए अभी कैसा प्रदर्शन कर रहा है। लोडटेस्ट निगरानी प्रोडक्शन तक पहुंचने से पहले रिग्रेशन को पकड़ती है।
डीप कॉपी उन्मूलन और हीप आवंटन युद्ध
Go का गार्बेज कलेक्टर विलंबता पर कर है। प्रत्येक हीप आवंटन अंततः एक GC पॉज़ बन जाता है, और ट्रेडिंग इंजन पर GC पॉज़ ट्रेडर्स के लिए लेटेंसी स्पाइक हैं। इसलिए हम हॉट पथ से गुज़रे और जहाँ भी संभव हुआ, आवंटन में कटौती की। परिणाम कम लेटेंसी स्पाइक और अधिक पूर्वानुमानित प्रदर्शन था।
डीप कॉपी उन्मूलन
डीप कॉपी आवंटन कारखाने हैं। हमने उन्हें कुछ तरीकों से लक्षित किया:
- अपरिवर्तनीय स्नैपशॉट: ऑर्डर बुक कैश को अपरिवर्तनीय बनाया गया। रीड वर्तमान स्नैपशॉट के लिए एक पॉइंटर लौटाते हैं, कोई कॉपी नहीं। अपडेट एक नया संस्करण बनाते हैं और इसे
atomic.Pointerके माध्यम से परमाणु रूप से स्वैप करते हैं। - अनावश्यक प्रतियाँ हटाई गईं: ऐसे कोड पथ मिले जो डीप-कॉपी डेटा करते थे जिसे बाद में कभी म्यूटेट नहीं किया गया। उन्हें पूरी तरह से हटा दिया गया।
आवंटन-जागरूक डिज़ाइन
- स्टैक-आवंटित संख्यात्मक: हीप-भारी
big.Intऔरbig.Ratको हॉट पथ पर स्टैक-आवंटित विकल्पों (int128,float64,int64डिवीज़न) से बदला गया: मूल्य रूपांतरण, ऑर्डर बुक डेप्थ मैप, आकार गणना। मुख्य फ़ॉर्मेटिंग फ़ंक्शन पर 8.3× तेज़, प्रति ऑपरेशन शून्य हीप आवंटन। - सशर्त अपडेट: जब कुछ नहीं बदला, तो आवंटन छोड़ें।
- पूर्व-आकारित संग्रह: डेटा संरचनाओं को पहले से साइज़ करके ग्रो-एंड-कॉपी चक्रों को समाप्त करें।
- बफ़र पुन: उपयोग: सब्सक्राइबर पथ प्रति सेकंड हजारों अपडेट को डिसीरियलाइज़ करता है। हमने पूल-आधारित मध्यवर्ती बफ़र के पुन: उपयोग से आवंटन कम किए।
इसने टेल को चपटा कर दिया। पहले, Lighter का एंड-टू-एंड p99 (एक्ज़ीक्यूशन इंजन से क्लाइंट, order_book WebSocket चैनल पर मापा गया) आवंटन-भारी अवधि के दौरान 200–280 ms तक स्पाइक करता था। डीप कॉपी उन्मूलन, अपरिवर्तनीय कैश और हीप आवंटन कार्य के बाद, p99 लगभग कोई स्पाइक के बिना ~50–60 ms के फ्लैट बैंड पर स्थिर हो गया:

एंड-टू-एंड लेटेंसी: एक्ज़ीक्यूशन इंजन -> क्लाइंट (p99)
API लेयर पर GC दबाव भी मापने योग्य रूप से गिरा, लेकिन यह केवल एक ही बदलाव नहीं था। हमने मौलिक रूप से API सर्वर कैश के संचालन के तरीके को फिर से तैयार किया। पहले, कैश में TTL-आधारित समाप्ति थी और प्रत्येक अपडेट पर नई वस्तुएँ आवंटित करते थे। उनमें से प्रत्येक अल्पकालिक आवंटन GC कार्य बन गया। पुन: कार्य के बाद, पूर्ण एक्सचेंज स्टेट एक स्नैपशॉट से हॉट-स्टार्ट किया जाता है और लंबे समय तक चलने वाली, अपरिवर्तनीय संरचनाओं के रूप में मेमोरी में रखा जाता है जो परमाणु रूप से स्वैप हो जाती हैं। इसने TTL कोलाहल और प्रति-अपडेट आवंटन को हटा दिया, और GC दबाव उनके साथ गिर गया। हम मेमोरी उपयोग की बारीकी से निगरानी करते हैं और कार्यशील सेट सीमित है।
हमने पुराने-शैली के apiserver और पुन: तैयार किए गए apiserver को मेननेट ट्रैफ़िक पर साथ-साथ चलाया। पुन: तैयार किए गए सर्वर का GC पॉज़ अवधि (p75) ~3 ms के आसपास था, जबकि पुराने सर्वर पर ~5–6 ms था। लगभग आधा GC पॉज़ समय:

GC पॉज़ अवधि: मानक बनाम स्नैपशॉट API सर्वर
आवृत्ति एक और भी स्पष्ट कहानी बताती है। पुराना apiserver पुन: तैयार किए गए सर्वर की तुलना में ~2.2× अधिक बार GC चक्र ट्रिगर करता था, जो सीधे तौर पर कम अल्पकालिक आवंटन और कुल मिलाकर कम GC दबाव को दर्शाता है:

GC चक्र आवृत्ति: मानक API सर्वर बनाम स्नैपशॉट API सर्वर
एक्ज़ीक्यूशन इंजन पर GOGC ट्यूनिंग
हमने एक्ज़ीक्यूशन इंजन पर भी समान GC सोच लागू की। Go का GOGC पैरामीटर नियंत्रित करता है कि गार्बेज कलेक्टर कितनी आक्रामक रूप से चलता है। डिफ़ॉल्ट मेमोरी दक्षता के लिए CPU समय का व्यापार करता है, लेकिन विलंबता-महत्वपूर्ण पथ के लिए, व्यापार गलत था।
GOGC ट्यूनिंग के बाद, एक्ज़ीक्यूशन इंजन की GC अवधि औसतन ~30 µs से, 100 µs तक स्पाइक के साथ, घटकर ~10 µs के स्थिर बैंड पर आ गई। लगभग कोई स्पाइक के बिना ~3× कमी:

GOGC ट्यूनिंग के बाद एक्ज़ीक्यूशन इंजन GC अवधि
तीन महीने के मेननेट डेटा से पुष्टि होती है कि सुधार बना रहा: बाद की अवधि सपाट और पूर्वानुमानित है।
ट्रांज़ैक्शन प्रोसेसिंग में भी इसके साथ सुधार हुआ। 90 दिनों के मेननेट डेटा में, सभी ट्रांज़ैक्शन प्रकारों (क्रिएट ऑर्डर, कैंसल, लिक्विडेट, डीलेवरेज, ट्रांसफर और अधिक) को कवर करते हुए, p99 GOGC ट्यूनिंग से पहले बार-बार 20–30 ms के स्पाइक से घटकर बाद में ज्यादातर 1 ms से नीचे आ गया, कभी-कभी 3–4 ms के आउटलायर्स के साथ। सुधार दो महीने से अधिक समय से बना हुआ है:

ट्रांज़ैक्शन प्रोसेसिंग समय - p99 (पिछले 90 दिन)
स्नैपशॉट सेवा — कम डेटा, हॉट डिप्लॉय
आवंटन ओवरहेड को समाप्त करने के बाद, हमने अगली बाधा पर हमला किया: आंतरिक संदेश बस के माध्यम से बहने वाले डेटा की मात्रा। हमने एक स्नैपशॉट सेवा बनाई जो पूर्ण इन-मेमोरी स्टेट स्नैपशॉट बनाए रखती है। इसके दो प्रमुख प्रभाव थे:
- वायर पर कम डेटा। स्नैपशॉट सेवा के पूर्ण स्टेट रखने से, एक्ज़ीक्यूशन इंजन को अब हर अपडेट पर संदेश बस के माध्यम से पूर्ण स्टेट को पुश करने की आवश्यकता नहीं है। यह कम डेटा लिखता है, जिसका अर्थ है कम नेटवर्क बैंडविड्थ की खपत और प्राप्त करने वाले सिरे पर कम डिसीरियलाइज़ेशन कार्य।
- शून्य वार्म-अप डिप्लॉय। डिप्लॉय पर, API लेयर एक स्नैपशॉट (खाते, ऑर्डर बुक, बाजार जानकारी, API सार्वजनिक कुंजी) से बूट होता है और तुरंत सेवा देने के लिए तैयार होता है। कैश भरने के दौरान कोई वार्म-अप अवधि नहीं होती। स्नैपशॉट लोड करने के बाद, API लेयर अपडेट स्ट्रीम की सदस्यता लेता है और डेल्टा को रियल-टाइम में लागू करता है।
स्नैपशॉट बेस के ऊपर, इन-मेमोरी कैश लगातार अपडेट होते रहते हैं:
- खाता जानकारी:
sync.Mapके माध्यम से लॉक-फ्री रीड, अपडेट के लिए परमाणु पॉइंटर स्वैप। - ऑर्डर बुक: अपरिवर्तनीय स्नैपशॉट के रूप में संग्रहीत। रीड को एक पॉइंटर मिलता है, अपडेट एक नया संस्करण स्वैप करते हैं। रीड पथ पर कोई लॉक नहीं।
- API कुंजी कैश: सभी कुंजियाँ मेमोरी में फिट हो जाती हैं। बाहरी लुकअप को पूरी तरह से समाप्त कर दिया गया।
परिणाम: पूरा एक्सचेंज स्टेट स्थानीय मेमोरी में रहता है, रियल-टाइम में अपडेट होता है, और प्रत्येक डिप्लॉय हॉट शुरू होता है।
एक्ज़ीक्यूशन इंजन पर प्रभाव महत्वपूर्ण था। पहले, एक्ज़ीक्यूशन इंजन नेटवर्क पर कैश कुंजियाँ लिख रहा था, अपडेट जिन्हें सेवाएँ समय-समय पर पढ़ती थीं। सब कुछ मेमोरी में रहने और स्नैपशॉट सेवा द्वारा स्टेट वितरण को संभालने के साथ, वे नेटवर्क राइट अनावश्यक हो गए। हमने उन्हें हटा दिया। परिणाम: ब्लॉक टाइम p99 ~2.6 ms से घटकर ~1.2–1.8 ms हो गया, सिर्फ इसलिए क्योंकि एक्ज़ीक्यूशन इंजन अब बहुत कम लिखता है:

ब्लॉक टाइम - p99
CPU प्लानिंग
एक बार जब हमने यूजरस्पेस में सब कुछ ऑप्टिमाइज़ कर लिया, तो हम कर्नेल तक पहुंचे।
हमारे पास कई गोरूटीन हैं और उन्हें चलाने के लिए CPU पर शेड्यूल करने की आवश्यकता है। शेड्यूलिंग ओवरहेड को कम करना कम-विलंबता प्रणालियों के लिए महत्वपूर्ण है। डिफ़ॉल्ट रूप से, Go का रनटाइम गोरूटीन को OS थ्रेड्स पर मल्टीप्लेक्स करता है, और OS थ्रेड्स को CPU कोर में स्वतंत्र रूप से स्थानांतरित कर सकता है। दोनों अप्रत्याशित विलंबता का परिचय देते हैं।
हमने चार तंत्रों को स्टैक करके इसे समाप्त किया:
- `runtime.LockOSThread()`: गोरूटीन को एक ही OS थ्रेड में लॉक करता है, Go के शेड्यूलर को इसे स्थानांतरित करने से रोकता है।
- `sched_setaffinity` के माध्यम से CPU आत्मीयता: उस OS थ्रेड को एक विशिष्ट CPU कोर (Linux) पर पिन करता है। यह कर्नेल को इसे कोरों के बीच स्थानांतरित करने से रोकता है, L1/L2 कैश अमान्यकरण से बचाता है।
- SCHED_FIFO के माध्यम से उच्च-प्राथमिकता शेड्यूलिंग: थ्रेड की शेड्यूलिंग प्राथमिकता को बढ़ाता है, यह सुनिश्चित करता है कि कर्नेल इसे अन्य कार्यों पर पसंद करता है।
- बिजी-वेट स्पिन लूप: हॉट पथ एक खाली
defaultकेस के साथselectचलाता है, इसलिए गोरूटीन कभी पार्क नहीं करता। इसके बिना, Go गोरूटीन को "रनेबल" स्थिति में ले जाता है जब कोई डेटा उपलब्ध नहीं होता है, और पुनर्निर्धारण वेक-अप विलंबता जोड़ता है। स्पिन लूप के साथ, गोरूटीन अपने पिन किए गए कोर पर चलता रहता है और शून्य शेड्यूलिंग देरी के साथ नए अपडेट उठाता है।
प्रभाव को सही ढंग से मापना यहाँ मायने रखता है। एप्लाई टाइम ट्रैफ़िक स्थितियों के साथ बदलता है, इसलिए पूर्ण संख्याएँ लोड के साथ बदलती हैं। पिनिंग के प्रभाव को अलग करने के लिए, हमने API सर्वरों के दो समूहों को समान ट्रैफ़िक के तहत साथ-साथ चलाया। एक समूह नियंत्रण के रूप में अनपिन रहा, और हमने दूसरे को CPU पिनिंग पर स्विच किया। उनके बीच प्रतिशत अंतर, समान लोड के तहत एक ही समय पर मापा गया, वास्तविक कहानी बताता है।
पिनिंग से पहले, दोनों समूह एक साथ ट्रैक करते हैं। समान आधार विलंबता, समान स्पाइक व्यवहार:

हॉट पथ एप्लाई टाइम - CPU योजना से पहले
एक समूह पर पिनिंग सक्षम करने के बाद, यह लगातार अनपिन बेसलाइन के नीचे रहता है। समान ट्रैफ़िक, कम विलंबता। पिन किए गए समूह के स्पाइक भी कम कैप होते हैं, क्योंकि थ्रेड माइग्रेशन जिटर और L1/L2 कैश अमान्यकरण समाप्त हो जाते हैं:

हॉट पथ एप्लाई टाइम - CPU योजना के बाद
NUMA-जागरूक डिप्लॉयमेंट
CPU पिनिंग अकेले पर्याप्त नहीं है यदि पिन किए गए कोर की मेमोरी एक्सेस NUMA सीमाओं को पार करती है। NUMA नोड अपनी स्थानीय मेमोरी वाले CPU का एक समूह है। दूरस्थ NUMA नोड से मेमोरी तक पहुँचने पर स्थानीय एक्सेस की तुलना में 10× पेनाल्टी लगती है।
Lighter के API सर्वर मूल रूप से 2 NUMA नोड्स वाली बड़ी मशीनों पर चल रहे थे:
1$ lscpu | grep NUMA2NUMA node(s): 23NUMA node0 CPU(s): 0-954NUMA node1 CPU(s): 96-19156$ cat /sys/devices/system/node/node0/distance710 100
दूरी मैट्रिक्स कहानी बताता है: स्थानीय एक्सेस की लागत 10, क्रॉस-नोड एक्सेस की लागत 100 है। 10× पेनाल्टी। मशीन साझा करने वाले N API सर्वरों के साथ, कुछ के पास अनिवार्य रूप से उनका पिन किया गया CPU एक NUMA नोड पर और उनकी कार्यशील मेमोरी (इन-मेमोरी कैश, अपडेट बफ़र) दूसरे पर थी। प्रत्येक हॉट पथ पुनरावृत्ति क्रॉस-नोड कर का भुगतान कर रही थी।
समाधान प्रतिस्पर्धी था: हमने API सर्वरों को एकल NUMA नोड वाली छोटी मशीनों पर स्थानांतरित किया। आधा स्पेक, लेकिन सभी मेमोरी एक्सेस अब स्थानीय होने की गारंटी है:
1$ lscpu | grep NUMA2NUMA node(s): 13NUMA node0 CPU(s): 0-95
इसने एक साथ लागत में कटौती की और विलंबता में सुधार किया। हॉट पथ एप्लाई टाइम और गिरकर ~100–250 µs की सीमा में आ गया, ऑफ-पीक के दौरान ~100 µs तक गिरता है। इसकी तुलना 2-NUMA-नोड मशीनों पर अकेले CPU पिनिंग के साथ ~200–520 µs की सीमा से करें:

हॉट पथ एप्लाई टाइम - NUMA ऑप्टिमाइज़ेशन
कस्टम बाइनरी सीरियलाइज़ेशन
Lighter का एक्ज़ीक्यूशन इंजन एक आंतरिक संदेश बस के माध्यम से API लेयर को स्टेट अपडेट प्रकाशित करता है। प्रत्येक सिस्टम अपडेट इस पथ के माध्यम से बहता है। मूल सीरियलाइज़ेशन एक सामान्य-उद्देश्य एन्कोडिंग लाइब्रेरी का उपयोग करता था, लेकिन रिफ्लेक्शन, टाइप स्विच और प्रति-फ़ील्ड आवंटन ने हॉट पथ पर अनावश्यक ओवरहेड बनाया।
हमने इसे हाथ से बनाई गई बाइनरी सीरियलाइज़ेशन से बदल दिया: सिस्टम में प्रत्येक इकाई प्रकार के लिए फिक्स्ड-लेआउट, शून्य-रिफ्लेक्शन एनकोड/डिकोड। प्रत्येक प्रकार में एक समर्पित एनकोडर/डिकोडर होता है जो ज्ञात बाइट ऑफ़सेट पर फ़ील्ड पढ़ता और लिखता है। कोई रिफ्लेक्शन या टाइप स्विच नहीं, और न्यूनतम आवंटन। प्रत्येक कोडेक में रिग्रेशन को पकड़ने के लिए राउंड-ट्रिप और फ़ज़ टेस्ट होते हैं।
परिणाम प्रत्येक डाउनस्ट्रीम कैश को खिलाने वाले पथ पर काफी कम सीरियलाइज़ेशन ओवरहेड था।
स्वतंत्र बेंचमार्किंग समुदाय सदस्य @UngusTrade द्वारा बनाए और बनाए रखे गए डैशबोर्ड के माध्यम से उपलब्ध है, जो स्थायी ट्रेडिंग स्थानों पर लाइव ट्रांज़ैक्शन लेटेंसी की तुलना करता है: latency.perps.trading

![[अल्टीमेट एडिशन] Recruit Holdings का एक पूर्व कर्मचारी द्वारा गहन विश्लेषण (मेरे द्वारा लिखित, AI द्वारा नहीं)](/cdn-cgi/image/width=1920,quality=90,format=auto,metadata=none/https%3A%2F%2Fcms-assets.youmind.com%2Fmedia%2F1783619810056_4fyuz8_HMtxHM_bIAA-0_J.jpg)



