पहली बार आपको वास्तव में अवलोकन की आवश्यकता तब नहीं होती जब आप शांति से डैशबोर्ड को देख रहे होते हैं। ऐसा तब होता है जब कोई उपयोगकर्ता "चेकआउट धीमा है" लिखता है, त्रुटि ग्राफ़ सामान्य दिखता है और लॉग में आपको केवल डिस्कनेक्ट किए गए संदेशों की एक पंक्ति मिलती है।
OpenTelemetry उस क्षण से बचने के लिए बनाया गया था: अधिक ग्राफिक्स के लिए नहीं, बल्कि टुकड़ों को जोड़ने के लिए। एक अनुरोध API में प्रवेश करता है, एक डेटाबेस को कॉल करता है, एक बाहरी प्रदाता के माध्यम से जाता है, एक कतारबद्ध नौकरी पोस्ट करता है, और हो सकता है कि बाद में तीन सेवाएं विफल हो जाएं। वितरित अनुरेखण के बिना, आप हाथ से उस कहानी का पुनर्निर्माण करते हैं। OpenTelemetry के साथ कम से कम आपके पास एक नक्शा है।
बात trace की नहीं, कहानी की है
ए trace span का एक क्रम है। ऐसे डालें कि ठंड लगे. व्यवहार में, प्रत्येक span कहानी का एक अंश है: POST /checkout, SELECT inventory, call payment provider, publish order.created।
महत्व तब आता है जब आप वास्तविक प्रश्नों का उत्तर देना शुरू करते हैं:
- कौन सी बाह्य सेवा धीमी हो रही है?
- क्या त्रुटियाँ किसी विशिष्ट संस्करण से आती हैं?
- क्या समस्या सभी को प्रभावित करती है या सिर्फ एक किरायेदार को?
- क्या पुनः प्रयास एक टाइमआउट छुपा रहा है?
- अतुल्यकालिक कार्य शुरू होता है लेकिन फिर कहीं और समाप्त हो जाता है?
ये प्रश्न जल्दबाजी में फेंके गए console.log से हल नहीं हो सकते। दरअसल, अक्सर आपात स्थिति में जोड़ा गया लॉग आज आपकी मदद करता है और कल शोर बन जाता है।
मैं इसे किसी ऐप में कैसे डालूंगा Node.js
सबसे स्वस्थ सेटअप सरल है: ऐप टेलीमेट्री उत्पन्न करता है, Collector तय करता है कि इसे कहां भेजना है।
Node.js app -> OpenTelemetry Collector -> backend di observability
सीधे विक्रेता को निर्यात क्यों नहीं किया जाता? क्योंकि पहले तो यह तेज़ लगता है, फिर आपको एहसास होता है कि प्रत्येक सेवा में अलग-अलग कॉन्फ़िगरेशन, अलग-अलग पुनः प्रयास, अलग-अलग फ़िल्टर होते हैं और संवेदनशील डेटा को हटाने या गंतव्य बदलने के लिए कोई केंद्रीय बिंदु नहीं होता है।
Collector सभी सही मायनों में उबाऊ है। यह OTLP प्राप्त करता है, बैचिंग करता है, फ़िल्टर कर सकता है, सैंपलिंग कर सकता है, सामान्य विशेषताएँ जोड़ सकता है और कई सिस्टम में निर्यात कर सकता है।
स्व-यंत्रीकरण: अच्छा है, लेकिन पर्याप्त नहीं
Node.js में मैं ऑटो-इंस्ट्रूमेंटेशन से शुरुआत करूंगा। यह आपको HTTP, समर्थित फ्रेमवर्क, डेटाबेस और सामान्य पुस्तकालयों में तत्काल दृश्यता प्रदान करता है।
npm install @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http
फिर आप बाकी ऐप से पहले SDK को इनिशियलाइज़ करें:
import { NodeSDK } from '@opentelemetry/sdk-node'; import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; const sdk = new NodeSDK({ traceExporter: new OTLPTraceExporter({ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT, }), instrumentations: [getNodeAutoInstrumentations()], }); sdk.start();
हालाँकि, यह रूपरेखा को देखता है, आपके उत्पाद को नहीं। यह जानता है कि आपने एक क्वेरी बनाई है, लेकिन यह नहीं जानता कि वह क्वेरी "क्रिएट ऑर्डर" या "रिन्यू सब्सक्रिप्शन" में थी। इसके लिए आपको उन बिंदुओं पर span मैनुअल की आवश्यकता है जहां प्रभुत्व मायने रखता है।
const span = tracer.startSpan('checkout.create_order'); try { span.setAttribute('cart.items_count', input.items.length); const order = await createOrder(input); span.setAttribute('order.id', order.id); return order; } catch (error) { span.recordException(error as Error); throw error; } finally { span.end(); }
मैं कहीं भी span मैनुअल नहीं रखूंगा। मैं उन्हें वहां रखूंगा जहां, सुबह तीन बजे, मैं यह समझना चाहूंगा कि आधा कोड आधार पढ़े बिना क्या हुआ।
तीन नियम जो बहुत अधिक अराजकता से बचते हैं
पहला नियम: प्रत्येक सेवा में service.name, वातावरण और संस्करण होना चाहिए। यह मामूली लगता है, लेकिन इन विशेषताओं के बिना trace बहुत कम उपयोगी है। जब कोई परिनियोजन किसी चीज़ को तोड़ता है, तो आप दो सेकंड में संस्करण के अनुसार फ़िल्टर करना चाहते हैं।
दूसरा नियम: विशेषताओं में संवेदनशील डेटा न डालें। ईमेल, टोकन, पूर्णांक पेलोड और पते दुर्घटनावश अवलोकनीय बैकएंड में समाप्त नहीं होने चाहिए। यदि आपको किसी उपयोगकर्ता की पहचान करने की आवश्यकता है, तो आंतरिक आईडी, हैशिंग या कम संवेदनशील फ़ील्ड पर विचार करें।
तीसरा नियम: कार्डिनैलिटी पर ध्यान दें. user.id को trace की विशेषता के रूप में समझा जा सकता है। एक मीट्रिक लेबल के रूप में यह आपकी लागत और प्रदर्शन को नष्ट कर सकता है।
मेट्रिक्स: कुछ, लेकिन अच्छे
मैं बहुत व्यावहारिक मेट्रिक्स के साथ शुरुआत करूंगा:
- दरें, त्रुटियां और अनुरोधों की अवधि;
- बाहरी निर्भरता की विलंबता;
- टाइमआउट और पुनः प्रयास की संख्या;
- पूंछ की गहराई;
- कार्य की अवधि;
- प्रति संस्करण त्रुटियों का प्रतिशत.
बाकी जरूरत पड़ने पर जोड़ दिया जाता है. ग्राफ़ से भरे डैशबोर्ड जिन्हें कोई नहीं देखता, वे फर्नीचर हैं, अवलोकनीयता नहीं।
लॉग: अभी भी उपयोगी है, लेकिन जुड़ा हुआ है
लॉग गायब नहीं होते. जब वे trace_id और span_id रखते हैं तो वे और अधिक उपयोगी हो जाते हैं। तो आप एक त्रुटि लॉग से शुरू कर सकते हैं और trace खोल सकते हैं, या धीमी trace से शुरू कर सकते हैं और केवल उस पथ में उत्पादित लॉग को पढ़ सकते हैं।
सहसंबंध के बिना, आप सुइयों की तलाश कर रहे हैं। सहसंबंध के साथ, कम से कम आप जानते हैं कि किस दराज में देखना है।
वह चेकलिस्ट जिसका उपयोग मैं यह कहने से पहले करूंगा कि "हम कवर हो गए हैं"
- trace वास्तव में कई सेवाओं को पार करता है।
- लॉग में
trace_idऔरspan_idशामिल हैं। - Collector को बैचिंग और मेमोरी सीमा के साथ कॉन्फ़िगर किया गया है।
- त्रुटियाँ span में दर्ज की जाती हैं।
- एक सैंपलिंग नीति है.
- मेट्रिक्स ने कार्डिनैलिटी को नियंत्रित किया है।
- संवेदनशील डेटा फ़िल्टर किया जाता है।
- अलर्ट उपयोगकर्ता के लक्षणों से शुरू होते हैं, यादृच्छिक ग्राफ़ से नहीं।
निष्कर्ष
OpenTelemetry उत्पादन समस्याओं को अपने आप हल नहीं करता है। लेकिन आपके उनसे निपटने का तरीका बदल जाता है। आँख बंद करके लॉग जोड़ने के बजाय, आप अनुरोध के वास्तविक पथ का अनुसरण करना शुरू करते हैं।
मेरे लिए यह संकेत सरल है कि यह काम कर रहा है: जब कुछ होता है, तो टीम यह पूछना बंद कर देती है कि "हम कहाँ देख रहे हैं?" और पूछने लगता है "वह टुकड़ा धीमा क्यों है?" यहीं पर अवलोकनशीलता एक उपकरण बन जाती है, न कि डैशबोर्ड का संग्रह।