paint-brush
स्प्रिंग बूट में ओपनटेलीमेट्री ट्रेसिंग: जावा एजेंट और माइक्रोमीटर के बीच चयन करनाद्वारा@nfrankel
193 रीडिंग

स्प्रिंग बूट में ओपनटेलीमेट्री ट्रेसिंग: जावा एजेंट और माइक्रोमीटर के बीच चयन करना

द्वारा Nicolas Fränkel8m2024/08/11
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

यह पोस्ट जावा एजेंट v1, जावा एजेंट v2 और माइक्रोमीटर ट्रेसिंग का उपयोग करके स्प्रिंग बूट एप्लिकेशन में ओपनटेलीमेट्री ट्रेसिंग समाधानों की तुलना करती है। यह कॉन्फ़िगरेशन, कार्यक्षमता और ट्रेसिंग क्षमताओं में अंतर को उजागर करता है, अवलोकन के लिए प्रत्येक दृष्टिकोण की प्रभावशीलता और अनुप्रयोग में अंतर्दृष्टि प्रदान करता है।
featured image - स्प्रिंग बूट में ओपनटेलीमेट्री ट्रेसिंग: जावा एजेंट और माइक्रोमीटर के बीच चयन करना
Nicolas Fränkel HackerNoon profile picture

ओपनटेलीमेट्री ट्रेसिंग के मेरे डेमो में दो स्प्रिंग बूट घटक हैं। एक जावा एजेंट का उपयोग करता है, और जब मैंने हाल ही में इसे v1.x से v2.x में अपग्रेड किया तो मैंने एक अलग व्यवहार देखा। दूसरे में, मैं माइक्रोमीटर ट्रेसिंग का उपयोग कर रहा हूँ क्योंकि मैं GraalVM नेटिव में संकलित करता हूँ, और यह जावा एजेंटों को संसाधित नहीं कर सकता।



इस पोस्ट में, मैं इन तीन तरीकों की तुलना करना चाहता हूं: जावा एजेंट v1, जावा एजेंट v2, और माइक्रोमीटर ट्रेसिंग।

आधार अनुप्रयोग और उसका बुनियादी ढांचा

मैं उसी बेस एप्लीकेशन का उपयोग करूंगा: एक सरल स्प्रिंग बूट एप्लीकेशन, जिसे कोटलिन में कोड किया गया है। यह एक सिंगल एंडपॉइंट प्रदान करता है।


  • अंत बिंदु से आगे के फ़ंक्शन का नाम entry() है
  • यह intermediate() नामक एक अन्य फ़ंक्शन को कॉल करता है
  • उत्तरार्द्ध उपरोक्त एंडपॉइंट पर कॉल करने के लिए, RestTemplate के प्रतिस्थापन, WebClient इंस्टेंस का उपयोग करता है
  • अनंत लूपिंग से बचने के लिए, मैं एक कस्टम अनुरोध हेडर पास करता हूं: यदि entry() फ़ंक्शन इसे ढूंढ लेता है, तो यह आगे नहीं बढ़ता है


नमूना ऐप अनुक्रम आरेख


इसका अनुवाद निम्नलिखित कोड में किया जाता है:


 @SpringBootApplication class Agent1xApplication @RestController class MicrometerController { private val logger = LoggerFactory.getLogger(MicrometerController::class.java) @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") if (done == null) intermediate() } fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() } }


प्रत्येक सेटअप के लिए, मैं दो चरणों की जांच करूंगा: प्राथमिक चरण, जिसमें ओपनटेलीमेट्री सक्षम है, और अतिरिक्त आंतरिक स्पैन बनाने के लिए अनुकूलन चरण।

माइक्रोमीटर ट्रेसिंग

माइक्रोमीटर ट्रेसिंग की उत्पत्ति माइक्रोमीटर से हुई है, जो एक "विक्रेता-तटस्थ अनुप्रयोग अवलोकनीयता मुखौटा" है।


माइक्रोमीटर ट्रेसिंग सबसे लोकप्रिय ट्रेसर लाइब्रेरी के लिए एक सरल मुखौटा प्रदान करता है, जिससे आप अपने JVM-आधारित एप्लिकेशन कोड को विक्रेता लॉक-इन के बिना इंस्ट्रूमेंट कर सकते हैं। यह आपके ट्रेसिंग प्रयास की पोर्टेबिलिटी को अधिकतम करते हुए आपकी ट्रेसिंग संग्रह गतिविधि में बहुत कम या कोई ओवरहेड जोड़ने के लिए डिज़ाइन किया गया है।


-- माइक्रोमीटर ट्रेसिंग साइट


माइक्रोमीटर ट्रेसिंग शुरू करने के लिए, कुछ निर्भरताएं जोड़ने की जरूरत है:


  • स्प्रिंग बूट एक्ट्यूएटर, org.springframework.boot:spring-boot-starter-actuator
  • माइक्रोमीटर स्वयं ट्रेसिंग, io.micrometer:micrometer-tracing
  • लक्ष्य ट्रेसिंग बैकएंड API के लिए एक "पुल"। मेरे मामले में, यह OpenTelemetry है, इसलिए io.micrometer:micrometer-tracing-bridge-otel
  • बैकएंड के लिए एक ठोस निर्यातक, io.opentelemetry:opentelemetry-exporter-otlp


हमें BOM की आवश्यकता नहीं है क्योंकि संस्करण पहले से ही स्प्रिंग बूट पैरेंट में परिभाषित हैं।


फिर भी, हमें दो रनटाइम कॉन्फ़िगरेशन पैरामीटर की आवश्यकता है: ट्रेस कहाँ भेजे जाने चाहिए, और घटक का नाम क्या है। वे MANAGEMENT_OTLP_TRACING_ENDPOINT और SPRING_APPLICATION_NAME चर द्वारा नियंत्रित होते हैं।


 services: jaeger: image: jaegertracing/all-in-one:1.55 environment: - COLLECTOR_OTLP_ENABLED=true #1 ports: - "16686:16686" micrometer-tracing: build: dockerfile: Dockerfile-micrometer environment: MANAGEMENT_OTLP_TRACING_ENDPOINT: http://jaeger:4318/v1/traces #2 SPRING_APPLICATION_NAME: micrometer-tracing #3
  1. जैगर के लिए ओपनटेलीमेट्री कलेक्टर सक्षम करें
  2. जैगर ओपनटेलीमेट्री gRPC एंडपॉइंट का पूर्ण URL
  3. OpenTelemetry का सेवा नाम सेट करें


परिणाम यह है:

जैगर पर बिना किसी अनुकूलन के माइक्रोमीटर ट्रेस


बिना किसी अनुकूलन के, माइक्रोमीटर HTTP अनुरोध प्राप्त करने और भेजने के दौरान स्पैन बनाता है।


फ़्रेमवर्क को भेजने के लिए RestClient में मैजिक इंजेक्ट करने की आवश्यकता होती है। इसके लिए हमें पहले वाले को बाद वाले को इंस्टेंटिएट करने देना चाहिए:


 @SpringBootApplication class MicrometerTracingApplication { @Bean fun restClient(builder: RestClient.Builder) = builder.baseUrl("http://localhost:8080/done").build() }


हम कई तरीकों से मैन्युअल स्पैन बना सकते हैं, एक OpenTelemetry API के ज़रिए। हालाँकि, सेटअप के लिए बहुत सारे बॉयलरप्लेट कोड की आवश्यकता होती है। सबसे सीधा तरीका माइक्रोमीटर का ऑब्ज़र्वेशन API है। इसका मुख्य लाभ एक ही API का उपयोग करना है जो मेट्रिक्स और ट्रेस दोनों को प्रबंधित करता है।


अवलोकन एपीआई वर्ग आरेख

अद्यतन कोड यहां है:


 class MicrometerController( private val restClient: RestClient, private val registry: ObservationRegistry ) { @GetMapping("/{message}") fun entry(@PathVariable message: String, @RequestHeader("X-done") done: String?) { logger.info("entry: $message") val observation = Observation.start("entry", registry) if (done == null) intermediate(observation) observation.stop() } fun intermediate(parent: Observation) { logger.info("intermediate") val observation = Observation.createNotStarted("intermediate", registry) .parentObservation(parent) .start() restClient.get() .header("X-done", "true") .retrieve() .toBodilessEntity() observation.stop() } }


जोड़े गए अवलोकन कॉल उत्पन्न ट्रेसों पर प्रतिबिंबित होते हैं:


अवलोकन एपीआई के साथ जैगर पर माइक्रोमीटर ट्रेस

ओपनटेलीमेट्री एजेंट v1

माइक्रोमीटर ट्रेसिंग का एक विकल्प जेनेरिक ओपनटेलीमेट्री जावा एजेंट है। इसका मुख्य लाभ यह है कि यह न तो कोड और न ही डेवलपर्स को प्रभावित करता है; एजेंट एक शुद्ध रनटाइम-स्कोप वाली चिंता है।


 java -javaagent:opentelemetry-javaagent.jar agent-one-1.0-SNAPSHOT.jar


एजेंट पर्यावरण चर के साथ ओपनटेलीमेट्री के कॉन्फ़िगरेशन का पालन करता है:


 services: agent-1x: build: dockerfile: Dockerfile-agent1 environment: OTEL_EXPORTER_OTLP_ENDPOINT: http://jaeger:4317 #1 OTEL_RESOURCE_ATTRIBUTES: service.name=agent-1x #2 OTEL_METRICS_EXPORTER: none #3 OTEL_LOGS_EXPORTER: none #4 ports: - "8081:8080"
  1. प्रोटोकॉल, डोमेन और पोर्ट सेट करें। लाइब्रेरी /v1/traces जोड़ती है
  2. OpenTelemetry का सेवा नाम सेट करें
  3. न तो मेट्रिक्स और न ही लॉग निर्यात करें


बिना किसी अतिरिक्त कॉन्फ़िगरेशन के, हमें निम्नलिखित निशान मिलते हैं:


एजेंट v1 जैगर पर बिना किसी अनुकूलन के निशान


एजेंट स्वचालित रूप से प्राप्त और भेजे गए अनुरोधों को ट्रैक करता है, साथ ही स्प्रिंग-संबंधित एनोटेशन के साथ चिह्नित फ़ंक्शन भी। कॉल स्टैक के अनुसार ट्रेस एक दूसरे के अंदर सही ढंग से नेस्ट किए गए हैं। अतिरिक्त फ़ंक्शन का पता लगाने के लिए, हमें अपने कोडबेस में एक निर्भरता जोड़ने की आवश्यकता है, io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations । अब हम @WithSpan एनोटेशन के साथ पहले से अनट्रेस किए गए फ़ंक्शन को एनोटेट कर सकते हैं।

@WithSpan वर्ग आरेख


value() भाग ट्रेस के लेबल को नियंत्रित करता है, जबकि kind span.kind विशेषता के रूप में अनुवादित होता है। यदि मान को खाली स्ट्रिंग पर सेट किया जाता है, जो डिफ़ॉल्ट है, तो यह फ़ंक्शन का नाम आउटपुट करता है। मेरे उद्देश्यों के लिए, डिफ़ॉल्ट मान पर्याप्त हैं।


 @WithSpan fun intermediate() { logger.info("intermediate") RestClient.builder() .baseUrl("http://localhost:8080/done") .build() .get() .header("X-done", "true") .retrieve() .toBodilessEntity() }


यह अपेक्षित नया intermediate() ट्रेस उत्पन्न करता है:

एजेंट v1 जैगर पर एनोटेशन के साथ ट्रेस करता है

ओपनटेलीमेट्री एजेंट v2

ओपनटेलीमेट्री ने इस साल जनवरी में एजेंट का नया प्रमुख संस्करण जारी किया। मैंने इसके साथ अपना डेमो अपडेट किया; अब ट्रेस केवल तभी बनाए जाते हैं जब ऐप अनुरोध प्राप्त करता है और भेजता है।

एजेंट v2 जैगर पर बिना किसी अनुकूलन के निशान


पिछले संस्करण की तरह, हम @WithSpan एनोटेशन के साथ ट्रेस जोड़ सकते हैं। एकमात्र अंतर यह है कि हमें entry() फ़ंक्शन को भी एनोटेट करना होगा। यह डिफ़ॉल्ट रूप से ट्रेस नहीं किया जाता है।

एजेंट v2 जैगर पर एनोटेशन के साथ ट्रेस करता है


बहस

स्प्रिंग दो कारणों से सफल हुआ: इसने जटिल समाधानों को सरल बनाया, यानी EJBs 2, और प्रतिस्पर्धी पुस्तकालयों पर एक अमूर्त परत प्रदान की। माइक्रोमीटर ट्रेसिंग की शुरुआत ज़िपकिन और जैगर पर एक अमूर्त परत के रूप में हुई, और यह पूरी तरह से समझ में आया। ओपनटेलीमेट्री को प्रोग्रामिंग भाषाओं और ट्रेस कलेक्टरों में अधिकांश पुस्तकालयों द्वारा समर्थित किए जाने के साथ यह तर्क बेमानी हो जाता है। अवलोकन API अभी भी माइक्रोमीटर ट्रेसिंग का एक बड़ा लाभ है, क्योंकि यह मेट्रिक्स और ट्रेस पर एकल API का उपयोग करता है।


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


अंत में, यह एक बुद्धिमानी भरा निर्णय है। आप जो स्पैन चाहते हैं उसके बारे में स्पष्ट होना बेहतर है, बजाय इसके कि आप कुछ ऐसे स्पैन हटा दें जिन्हें आप नहीं देखना चाहते।


जोनाथन इवानोव को उनकी मदद और उनकी समीक्षा के लिए धन्यवाद


इस पोस्ट का पूरा स्रोत कोड GitHub पर पाया जा सकता है:

आगे जाने के लिए:


मूल रूप से 3 अगस्त, 2024 को A Java Geek पर प्रकाशित