वापरकर्ता एक तिकीट उघडतो: मोबाईल ॲप संथ (sluggish) चालत आहे. तुम्ही तुमचे डॅशबोर्ड तपासता. CPU वापर (utilization) स्थिर आहे. एरर रेट्स शून्य आहेत. तुमचे APM संकेत आश्वासक हिरव्या रंगात आहेत. दृश्यमान निकषांनुसार बॅकएंड निरोगी आहे. परंतु वापरकर्ता चुकीचा नाही. संथपणा वास्तविक आहे आणि तो अँड्रॉइड डिव्हाइस आणि तुमचा सर्व्हर यांच्यातील लांब, अंधाऱ्या कॉरिडॉरमध्ये कुठे तरी घडत आहे.

समस्या अशी आहे की बहुतेक observability टूल्स ॲप्लिकेशनच्या सीमेवर (boundary) थांबतात. तुमचे फ्रेमवर्क विनंती (request) पार्स केल्यानंतर काय घडते, तेच ते मोजतात. ते डेटाबेस क्वेरी, कॅशे हिट्स आणि डाउनस्ट्रीम सर्व्हिस कॉल्सचा मागोवा घेतात. पण ते विनंतीच्या स्वतःच्या यंत्रणेकडे (mechanics) दुर्लक्ष करतात: OkHttp कॉल Android HTTP स्टॅकच्या आत किती वेळ घालवतो, अस्थिर मोबाईल नेटवर्कमधील प्रवास, TLS handshake negotiation, आणि तुमच्या कोडच्या कार्यान्वयापूर्वी कर्नल क्यू (kernel queues) मध्ये होणारी शांत प्रतीक्षा. या त्रुटींमुळे मिलिसेकंद—किंवा पूर्ण सेकंद—जातात, तर तुमचे APM शांत राहते.

एन्क्रिप्शनमुळे ही अंधता पूर्ण होते. आधुनिक Android ॲप्स सर्व काही BoringSSL द्वारे राउट करतात. पॅकेट कर्नल नेटवर्क स्टॅकपर्यंत पोहोचण्यापूर्वीच HTTP हेडर्स एन्क्रिप्ट केलेले असतात. एक मानक tcpdump किंवा नेटवर्क हुक केवळ अस्पष्ट (opaque) TLS रेकॉर्ड्स पाहू शकतो. ट्रॅफिक वाहतूक होत आहे हे तुम्ही पाहू शकता, परंतु ते वाचू शकत नाही. तुम्ही निश्चितपणे एखाद्या विशिष्ट कर्नल-स्तरीय TCP सेगमेंटला विशिष्ट वापरकर्त्याच्या API कॉलशी जोडू शकत नाही. तुम्हाला आवश्यक असलेला trace context हा सायफरटेक्स्ट (ciphertext) मध्ये अडकलेला असतो.

eBPF हे समीकरण बदलते कारण ते तुमच्या ॲप्लिकेशन कोडमध्ये बदल न करता तुम्हाला सिस्टीममध्ये आतून बाहेर (inside out) इन्स्ट्रुमेंट (instrument) करण्याची परवानगी देते. तुमच्या ॲपला स्वतःचा लॅटन्सी (latency) रिपोर्ट करण्यास सांगण्याऐवजी, तुम्ही थेट कर्नल आणि महत्त्वाच्या userspace लायब्ररीजला लहान प्रोग्राम्स जोडता. हे प्रोग्राम्स घटना घडताच त्यांचे निरीक्षण करतात, तुम्हाला आवश्यक माहिती काढतात आणि ती रिंग बफरमध्ये (ring buffer) पाठवतात. तुमच्या Android APK मध्ये एका हलक्या (lightweight) हेडरव्यतिरिक्त कोणताही SDK ब्लोट (bloat) नसतो आणि तुमच्या बॅकएंड क्लासेस पुन्हा लिहिणारा कोणताही instrumentation agent नसतो.

चार-भागांची सेटअप

ही पाइपलाइन तयार करण्यासाठी निरीक्षणाचे चार स्वतंत्र स्तर समाविष्ट आहेत.

1. traceparent अँकर. Android डिव्हाइसवर, तुम्ही एक OkHttp interceptor जोडता जो प्रत्येक आउटबाउंड विनंतीमध्ये W3C traceparent हेडर इंजेक्ट करतो. मोबाईल बाजूने आवश्यक असलेला हा एकमेव बदल आहे आणि तो अत्यंत कमी आहे. हे हेडर एन्क्रिप्टेड पेलोडमध्ये तुमच्या बॅकएंडपर्यंत प्रवास करते. कारण ते HTTP लेयरमध्ये असते, त्यामुळे TLS इंजिन शेवटी जे प्लेनटेक्स्ट (plaintext) उघडते, त्यामध्ये ते सुरक्षित राहते.

2. TCP आगमन वेळ (TCP arrival timing). बॅकएंड होस्टवर, तुम्ही नेटवर्क इंटरफेसशी जोडलेले eBPF Traffic Control हुक्स वापरता. हे प्रोग्राम्स वैयक्तिक TCP सेगमेंट आल्यावर कार्यान्वित होतात. ते कडेला (edge) सिक्वेन्स नंबर्स आणि टाइमस्टॅम्प्स कॅप्चर करतात. आता तुम्हाला तुमचे ॲप्लिकेशन एक सिंगल बाइट वाचण्यापूर्वीच, बिट्स वायरवरून बाहेर पडले आणि तुमच्या मशीनमध्ये प्रवेश केले, हे अचूकपणे समजते.

3. डिक्रिप्शन प्रोब्स (Decryption probes). तुमचे बॅकएंड OpenSSL किंवा BoringSSL वापरून TLS समाप्त (terminate) करते. येथेच ही आर्किटेक्चर मनोरंजक होते. uprobes—डायनॅमिक userspace प्रोब्स—वापरून, तुम्ही TLS लायब्ररीमधील SSL_write आणि SSL_read ला जोडता. प्लेनटेक्स्ट डेटा एन्क्रिप्शन इंजिनमधून पार पडताच हे फंक्शन्स कार्यान्वित होतात. तुमचा eBPF प्रोग्राम तो डिक्रिप्ट केलेला बफर वाचतो, traceparent हेडर शोधतो आणि तो काढतो. आता कर्नलकडे कोणत्याही कस्टम टूलमध्ये सर्टिफिकेट्स किंवा कीज हाताळण्याशिवाय, रॉ TCP फ्लो आणि विशिष्ट मोबाईल विनंती यांच्यात थेट मॅपिंग उपलब्ध असते.

4. कर्नल क्यूइंग (Kernel queueing). डेटा डिक्रिप्ट होऊन तयार झाल्यानंतरही, तुमचे ॲप्लिकेशन ते त्वरित वापरणार नाही. तुम्ही सॉकेट बफर्स आणि शेड्युलिंग इव्हेंट्स हाताळणाऱ्या संबंधित कर्नल फंक्शन्सना kprobes जोडता. हे क्यूइंग लॅटन्सी (queueing latency) मोजते: विनंत्या कर्नलमध्ये किती वेळ वाट पाहतात, कारण तुमची प्रोसेस CPU साठी स्पर्धा करत आहे किंवा अद्याप read() कॉल केलेला नाही.

हे चारही सिग्नल स्रोत eBPF रिंग बफरमध्ये इव्हेंट्स लिहितात. userspace मध्ये चालणारी एक साइडकार (sidecar) प्रोसेस हा बफर रिकामी करते, traceparent ID द्वारे इव्हेंट्सचे सहसंबंध (correlate) करते आणि प्रत्येक विनंतीसाठी एक सुसंगत टाइमलाइन तयार करते. जे पूर्वी विस्कळीत कर्नल नॉईज (kernel noise) होते, ते आता एक स्ट्रक्चर्ड ट्रेस (structured trace) बनते.

संपूर्ण मार्ग वाचणे

एकत्रित आउटपुट सहसा फ्लेम ग्राफ (flame graph) किंवा स्ट्रक्चर्ड स्पॅन ट्री (structured span tree) म्हणून दर्शवले जाते, जे लॅटन्सीला चार ठोस भागांमध्ये विभागते:

  • नेटवर्क ट्रान्झिट वेळ (Network transit time): अँड्रॉइड रेडिओकडून विनंतीचा (request) शेवटचा बाइट पाठवल्यापासून ते बॅकएंड NIC कडे तो पोहोचण्यापर्यंतचा कालावधी. सेल्युलर अस्थिरता (cellular volatility) याच टप्प्यावर दिसून येते.
  • TLS हँडशेक कालावधी (TLS handshake duration): एनक्रिप्टेड टनेल (encrypted tunnel) तयार करण्यासाठी लागणारा वेळ. अस्थिर नेटवर्कवर, हा वेळ प्रत्यक्ष डेटा ट्रान्सफरपेक्षा कितीतरी जास्त असू शकतो.
  • कर्नल क्यूइंग लॅटन्सी (Kernel queueing latency): सेगमेंट आल्यानंतर परंतु युजरस्पेस (userspace) तो वापरण्यापूर्वी कर्नल बफर्स आणि शेड्युलर क्यूमध्ये घालवलेला वेळ.
  • ॲप्लिकेशन प्रोसेसिंग वेळ (Application processing time): तुमचा बॅकएंड फ्रेमवर्क आणि बिझनेस लॉजिक प्रत्यक्षात वापरणारा वेळ.

तुम्हाला असे आढळू शकते की ८००ms च्या मोबाईल विनंतीमध्ये (request) तुमचा JSON पार्सर केवळ ४०ms वापरतो. लॉस-प्रवण (lossy) कनेक्शनमुळे अडकलेल्या TLS हँडशेकमध्ये आणखी २००ms वाया जातात. ओव्हरसबस्क्राइब्ड होस्टवरील कर्नल बॅकलॉगमध्ये आणखी ३००ms गायब होतात. तुमचे APM केवळ ४०ms चीच नोंद करत होते. कर्नल-स्तरीय दृश्यमानता (kernel-level visibility) नसल्यामुळे, तुम्ही पूर्णपणे चुकीच्या गोष्टीचे ऑप्टिमायझेशन केले असते.

खरोखर स्केलेबल असा ओव्हरहेड (Overhead That Actually Scales)

पारंपारिक APM एजंट्स तुमच्या लँग्वेज रनटाइममधील कॉल्स इंटरसेप्ट करून दृश्यमानता मिळवतात. ते मेथड्स (methods) रॅप करतात, स्पॅन ऑब्जेक्ट्स (span objects) अलोकेट करतात आणि तुमच्या प्रोसेस हीपमध्ये (process heap) टेलिमेट्री डेटा सिरीयलाईझ (serialize) करतात. लोड वाढल्यावर, हा ओव्हरहेड वेगाने वाढतो. सिरीयलायझेशनचा खर्च वाढतो. गार्बेज कलेक्शनचा (Garbage collection) ताण वाढतो. तुम्ही तुमच्या ॲप्लिकेशनच्या स्वतःच्या संसाधनांचा वापर करून दृश्यमानता मिळवत असता.

eBPF प्रोग्राम्स कर्नल व्हर्च्युअल मशीनमध्ये चालतात आणि ते नेटिव्ह मशीन सूचनांमध्ये (native machine instructions) JIT-compiled केले जातात. लोड होण्यापूर्वी एक व्हेरिफायर त्यांची सुरक्षा तपासतो. प्रत्येक प्रोब (probe) मार्गामध्ये मायक्रोसेकंद जोडतो, मिलीसेकंद नाही. इव्हेंट्स मॅच करणे आणि ग्राफ रेंडर करणे ही जड कामे तुमच्या सर्व्हिसच्या 'हॉट पाथ'च्या (hot path) बाहेर, साइडकारमध्ये (sidecar) होतात. तुम्ही हीप अलोकेशन (heap allocations) वाढवत नाही. तुम्ही रिक्वेस्ट हँडलिंगमध्ये सिरीयलायझेशनचा अतिरिक्त भार (serialization taxes) टाकत नाही. प्रति सेकंद हजारो विनंत्या पाठवणाऱ्या सेवांसाठी, हा फरक अत्यंत महत्त्वाचा आहे.

चालवण्यासाठी काय आवश्यक आहे

हे कोणतेही जादूचे साधन (magic bullet) नाही आणि हे तुम्ही फक्त चालू किंवा बंद करू शकणारे मॅनेज्ड SaaS देखील नाही. तुम्हाला आधुनिक eBPF सपोर्ट असलेले बॅकएंड कर्नल आवश्यक आहे, ज्यामध्ये BTF टाईप माहिती समाविष्ट असेल जेणेकरून तुमचे प्रोब्स कर्नल स्ट्रक्चर्समधून सुरक्षितपणे प्रवास करू शकतील. तुमच्या TLS लायब्ररीने असे सिम्बॉल्स (symbols) उपलब्ध करून दिले पाहिजेत ज्यांना uprobes लक्ष्य करू शकतील; जर तुम्ही स्ट्रिप केलेले किंवा मोठ्या प्रमाणावर कस्टमाइझ केलेले OpenSSL बिल्ड असलेले स्टॅटिकली लिंक्ड बायनरी (statically linked binary) वापरत असाल, तर तुम्हाला त्याचा विचार करावा लागेल. तसेच, मोबाईल क्लायंट आणि TLS टर्मिनेशन पॉईंट दरम्यान असलेल्या कोणत्याही प्रॉक्सी किंवा एज गेटवेमधून तुमचा traceparent हेडर सुरक्षितपणे पुढे जातोय की नाही, याची खात्री करणे देखील आवश्यक आहे.

परंतु ज्या टीम्स "मोबाईल स्लो आहे" अशा तक्रारींमुळे (tickets) त्रस्त आहेत आणि ज्यांचे मूळ-कारण विश्लेषण (root-cause analysis) करणे कठीण जात आहे, त्यांच्यासाठी ही आर्किटेक्चर केवळ अंदाज लावण्याऐवजी ठोस सिग्नल प्रदान करते. तुम्ही नेटवर्कच्या स्थितीबद्दल अंदाज लावणे थांबवता आणि विशिष्ट पाईप्सद्वारे विशिष्ट विनंत्या मोजण्यास सुरुवात करता.

मुख्य निष्कर्ष (The Real Takeaway)

तुम्हाला एनक्रिप्टेड मोबाईल ट्रॅफिकला अशा अपारदर्शक स्ट्रीम (opaque stream) म्हणून पाहण्याची गरज नाही जी तुमच्या फ्रेमवर्कमध्ये पोहोचल्यावर जादूने दृश्यमान होते. बॅकएंडवर धोरणात्मकरीत्या ठेवलेले eBPF प्रोब्स आणि एक साधा OkHttp हेडर एकत्र करून, तुम्ही अँड्रॉइड डिव्हाइसपासून सुरू होणारी एक विनंती TLS डिक्रिप्शन, कर्नल क्यूज आणि तुमच्या ॲप्लिकेशन लॉजिकपर्यंत फॉलो करू शकता—तुमचे मोबाईल ॲप पुन्हा न लिहिता आणि पारंपारिक APM प्रमाणे तुमच्या बॅकएंड कोडमध्ये बदल न करता. हे केवळ टप्प्याटप्प्याने होणारे सुधारणा नाही. हे संपूर्ण एंड-टू-एंड ऑब्झर्व्हेबिलिटी (end-to-end observability) आहे.