OpenTelemetry चल पड़ा, लेकिन यह इतना जटिल क्यों था?
(iconsolutions.com)- ग्राहकों की OpenTelemetry सपोर्ट की मांग ने दिखाया कि मौजूदा Prometheus·Jaeger·OpenTracing-आधारित observability, OTel की metrics·logs·traces आवश्यकताओं से पूरी तरह मेल नहीं खाती
- logs और metrics को appender और configuration जोड़कर अपेक्षाकृत आसानी से स्थानांतरित किया गया, लेकिन distributed tracing कहीं अधिक कठिन था क्योंकि Spring और Akka को एक ही JVM के भीतर trace context साझा करना था
- OTel और Lightbend Telemetry/OpenTracing अलग-अलग Tracer API और SpanContext implementations का उपयोग करते थे, इसलिए एक ही transaction अलग-अलग trace में बंट गया
- समाधान यह था कि OTel context को Java
Mapमें inject किया जाए, उसे Jaeger SpanContext के रूप में extract किया जाए, और फिर Lightbend केGlobalExtendedTracer.get().local().activateContext()से उसे manually activate किया जाए - OTel observability को standardize करने में मदद करता है, लेकिन मौजूदा Akka·Jaeger-आधारित instrumentation के साथ मिलाने पर explicit context bridging की आवश्यकता पड़ सकती है
वे observability signals जिन्हें OTel एकीकृत करना चाहता है
- OpenTelemetry(OTel) एक observability framework और toolkit है, जो पहले अलग-अलग रहे tool domains को metrics, logs, और traces — इन तीन signals में standardize करने की कोशिश करता है
- पुराना संयोजन भूमिकाओं के हिसाब से बंटा हुआ था
- Prometheus: metrics
- Logstash और Elasticsearch जैसे centralized aggregators: logs
- OpenTracing: distributed tracing
- OTel सिर्फ specification ही नहीं, core components भी उपलब्ध कराता है
- OpenTelemetry Protocol(OTLP): वह protocol जिससे applications telemetry data report करती हैं
- OpenTelemetry Collector: vendor-neutral component जो telemetry data को receive, process और export करता है
- 10 से अधिक भाषाओं के लिए SDKs: OTLP और telemetry export implementations
- applications auto-instrumentation, API, और language SDKs के ज़रिए OTel Collector को signals भेज सकती हैं, और infrastructure भी Collector को signals भेज सकता है
IPF का मौजूदा सपोर्ट और ग्राहक अनुरोध
- IPF के पास पहले से ELK Stack integration, monitoring, और observability documentation थी, और ग्राहक इन्हें production environments में उपयोग भी कर रहे थे
- framework की प्रकृति के कारण यह पहले से नहीं पता हो सकता था कि library का उपयोग करने वाले applications किस environment में deploy होंगे, इसलिए किसी specific vendor को मजबूर करने के बजाय abstraction और override किए जा सकने वाले defaults देने पड़ते थे
- default recommendation यह थी कि logs को Elasticsearch, LogScale जैसे aggregators तक भेजा जाए, और metrics के लिए de facto standard बन चुके Prometheus को enable और support किया जाए
- ग्राहकों ने लगभग एक ही समय में OTel-आधारित tracing के तीन अनुरोध किए, और tracing को OTel पर ले जाने के साथ logs और metrics को भी साथ में ले जाने की प्रवृत्ति बनी
- logs और metrics को नए appender और configuration जोड़कर अपेक्षाकृत आसानी से संभाला गया, लेकिन tracing अलग समस्या बनकर रह गई
distributed tracing में context propagation की आवश्यकता क्यों होती है
- distributed systems में एक transaction को trace करने के लिए, systems के बीच वह जानकारी भेजनी पड़ती है जो specific calls और transaction को आपस में जोड़ती है; इसे context propagation कहा जाता है
- trace एक parent structure है जो span नाम की कई units of work को समेटता है, और spans कई हो सकते हैं तथा nested भी हो सकते हैं
- e-commerce site में “buy now” बटन दबाने का flow एक single trace के रूप में बंध सकता है
- frontend का backend से बात करने वाला span
- backend के payment, shipping, और order management services से बात करने वाले child spans
- और हर downstream service के अन्य systems से बात करने वाले अतिरिक्त child spans
- OTel का उपयोग होने पर हर distributed service trace के अपने हिस्से को OTel Collector को report करती है, और OTel एक single trace ID के तहत पूरे flow का निर्माण करता है
context propagation के चार standards और OpenTracing की विरासत
- OTel जिन context propagation implementations को अनिवार्य रूप से support करता है, वे चार हैं
- IPF का Akka क्षेत्र पहले से deprecation की ओर बढ़ रहे OpenTracing को support करता था, और Lightbend Telemetry के OpenTracing support का उपयोग कर रहा था
- Lightbend Telemetry 2.20.0 ने OpenTelemetry logs/events और metrics support जोड़ा, लेकिन महत्वपूर्ण tracing support अनुपस्थित था
- सैद्धांतिक रूप से OTel tracing, OpenTracing की rebranding जैसी लगती है, और Lightbend Telemetry का OpenTracing भी इन चार propagation formats को support करता है, इसलिए यह काम करना चाहिए था — लेकिन वास्तविक परिणाम अलग थे
Spring और Akka के बीच टूटा हुआ trace
- IPF Spring और Akka दोनों का उपयोग करता है
- Spring Boot और Spring IoC: application bootstrap, configuration, dependency wiring
- Akka: event sourcing, scheduling, clustering, sharding, integration आदि
- ग्राहक Spring REST controller या
@KafkaListenerलगे methods के जरिए payment flow शुरू कर सकते थे - OTel से पहले, ये तीनों क्षेत्र बिना बड़े टकराव के काम कर रहे थे
- Metrics: Spring और Akka अलग-अलग Prometheus endpoints expose करते थे
- Logs: दोनों frameworks SLF4J और Logback का उपयोग करते थे
- Traces: दोनों OpenTracing का उपयोग करते थे
- OTel के उपयोग पर metrics और logs में Spring और Akka स्वतंत्र रूप से काम करते रहे और सही तरह भेजे गए, लेकिन tracing के लिए JVM के भीतर वही trace context साझा होना ज़रूरी था
- असली समस्या यह थी कि application के भीतर tracing की एक ही अवधारणा को दो अलग APIs व्यक्त कर रही थीं, और वे APIs आपस में संवाद नहीं कर रही थीं
- सही व्यवहार यह होता कि Akka HTTP client मौजूदा trace ID
123को reuse करता और सिर्फ नया span ID बनाता, ताकि वही trace के भीतर नई unit of work के रूप में दिखे; लेकिन वास्तव में दो असंबंधित traces बन गए
opentracing-shim और implementation टकराव
- OTel पक्ष में एक
opentracing-shimहै, जो OTelTracerको OpenTracingTracerजैसा दिखाता है - लेकिन Lightbend Telemetry custom Tracer implementation का उपयोग कर रहा था, और इसी वजह से shim और Jaeger दोनों विफल हो गए
- logs में ये errors दिखाई दिए
Expected to have an OpenTelemetry Span but got cinnamon.opentracing.TraceLocal$ContextOnlySpanExpected to have a JaegerSpanContext but got io.opentelemetry.opentracingshim.SpanContextShim
- Jaeger को OTel shim context मिला तो वह fail हुआ, और OTel को Lightbend context मिला तो वह fail हुआ
Java Agent और Lightbend की internal tracing की जांच
- OTel और Lightbend Telemetry instrumentation दोनों Java Agent का उपयोग करके specific classes के specific method calls पर hook लगाते हैं और tracer को activity report करते हैं
- Lightbend Telemetry instrumentation open source नहीं थी, इसलिए उसके व्यवहार को समझने के लिए decompiled tracer code की जांच करनी पड़ी
- एक minimal reproducible example बनाकर यह देखा गया कि Spring पक्ष का OTel trace context Akka पक्ष तक जाते-जाते किस बिंदु पर टूट रहा है
- वह बिंदु जहां Jaeger fail हो रहा था,
JaegerTracer.javaके इस code में था - caller, Lightbend Telemetry की proprietary instrumentation class
OpenTracingAkkaPersistenceActorInstrumentation.classथी - decompiled code में मुख्य शर्त
var5की स्थिति थी- अगर OpenTracing
SpanContextयानीvar5null नहीं था, तो नया span मौजूदा active span के child के रूप में जुड़ता था - अगर
var5null था, तो span मौजूदा trace से असंबंधित हो जाता था - अगर
var5Jaeger SpanContext नहीं था, तो Jaeger fail हो जाता था
- अगर OpenTracing
manual conversion से OTel और OpenTracing को जोड़ना
SpanContextकोthis.traceLocal.currentContext()से लिया जा रहा था, औरtraceLocalको Lightbend केExtendedTracerसे initialize किया गया था- Lightbend documentation में
ExtendedTracerको globally access करने का तरीका दिया गया थाGlobalExtendedTracer.get()
GlobalExtendedTracer.get()एकExtendedTracerलौटाता है, औरlocal()वहीTraceLocalलौटाता है जिसका उपयोग instrumentation library करती है- इस
TraceLocalमेंactivateContextmethod था, जो OpenTracingSpanContextस्वीकार करता है - समाधान का flow चार चरणों का था
- OTel shim का उपयोग नहीं करना
- मौजूदा OpenTelemetry Context को Java
Mapमें inject करना - उस
Mapके मानों से Jaeger SpanContext को extract करना - Akka में प्रवेश करने से पहले Lightbend
TraceLocalमें Jaeger SpanContext को activate करना
- इस्तेमाल किया गया OTel propagators API कार्य inject and extract operations था
- मुख्य code इस flow का पालन करता है
- खाली
HashMapबनाना GlobalOpenTelemetry.get().getPropagators().getTextMapPropagator().inject(...)से OTel context को map में inject करनाnew TextMapCodec(false).extract(new TextMapAdapter(otelContext))से JaegerSpanContext बनानाGlobalExtendedTracer.get().local().activateContext(openTracingContext)से Akka में प्रवेश से पहले context activate करना
- खाली
सत्यापित व्यवहार और production सिफारिश
- manual bridging के बाद trace अपेक्षा के अनुसार जुड़ गया
- Spring REST call
/submitसे शुरू होकर पूरा flow एक single trace में जुड़ गया - OTel API से instrument किए गए हिस्से और OpenTracing API से instrument किए गए हिस्से साथ में उपयोग किए जा सके
- HTTP boundary के पार भी trace propagate हुआ
- Spring REST call
- example में दोनों instrumentation प्रकारों में फर्क दिखाने के लिए अलग-अलग names इस्तेमाल किए गए थे, लेकिन वास्तविक ग्राहक environments में बाहरी तौर पर एक single application की तरह दिखाने के लिए
otel.service.nameऔरcinnamon.applicationको समान रखने की सिफारिश की गई
यह इतना जटिल क्यों था और क्या चिंताएं बाकी हैं
- Lightbend Telemetry को OTel API पर दोबारा लिखने के लिए, Jaeger API से बंधी मौजूदा बहुत-सी instrumentation को OTel API पर port करना पड़ेगा, जो एक बड़ा काम हो सकता है
- OTel Collector legacy Zipkin format traces को collect करना support करता है, इसलिए Lightbend legacy support पर निर्भर रहकर पूर्ण OTel support दे सकता है
- जटिलता का सीधा कारण यह था कि दो अलग tracing libraries उपयोग करने वाली दो instrumentation प्रणालियों को जोड़ा जा रहा था
- OTel project semantic conventions जैसी standardization कोशिशों के जरिए observability क्षेत्र को व्यवस्थित करना चाहता है; शुरुआत में यह थोड़ा जटिल लगता है, लेकिन इसे उपयोगी FOSS project के रूप में आंका गया
- Akka actor model के भीतर threads के बीच trace context सही ढंग से पहुंचाता है या नहीं, यह चिंता अब भी बाकी है
- छोटे load tests में यह अपेक्षा के अनुसार काम करता दिखा
- इस संबंध में Akka पक्ष पर ticket खोला गया है
1 टिप्पणियां
Hacker News की राय
Otel सीखने और पोर्ट करने के पूरे दौरान ऐसा लगा जैसे फिर से Java दुनिया में लौट आया हूं। कोड को लाइन-दर-लाइन फॉलो करते हुए हर बार यह EnterpriseFizzBuzz जैसा लगा, discoverability बिल्कुल नहीं थी, और इसकी अपनी terminology भी ऐसी दिखती थी जैसे किसी नशे में लोगों ने बनाई हो
NodeJS में StatsD के मुकाबले CPU उपयोग लगभग 4 गुना था, और आखिर में हमने खुद aggregation बनाकर usage घटाया और tag explosion भी कम किया। StatsD में कई processes एक ही tag रिपोर्ट करें तो कोई दिक्कत नहीं, लेकिन OTEL उसे overwrite कर देता है
peak load पर एक CPU 60~80% उपयोग पर चल रहा था, और कुछ बदलने से पहले vertical scaling भी नहीं कर सकते थे। core प्रति process एक इस्तेमाल करने वाली languages के लिए OTEL सक्रिय रूप से hostile है, यह मजाक जैसा लगता है। बस Prometheus इस्तेमाल करना बेहतर है, और सच में कोई दूसरा competitor भी नहीं है
.NET में एक simple otel setup करने की कोशिश में, हमारी organization ने जिस vendor को चुना था उसके docs कई घंटे पढ़े फिर भी समझ नहीं आया, तो मैं एक colleague के चलाए Discord में गया। उनके business model का एक हिस्सा यह था कि “open-source product में ठीक से otel इस्तेमाल करना है तो पैसे दो”, और तुरंत लगा कि cost चाहे जितनी हो, value उसके लायक है
OTEL implementation करने के बजाय बिना prior experience के एक और stable event/pub-sub library बनाना बेहतर लगेगा
minimum setup भी सच में काफी छोटा है—web UI, server instance, और कोई DB जिसे आप पहले से जानते हों, इतना काफी है: https://skywalking.apache.org/docs/main/latest/en/setup/back...
monitoring space में यह कुछ-कुछ Zabbix जैसा है। दोनों किसी को wow नहीं करेंगे, लेकिन practicality पर्याप्त है
process.vpidजैसी relatively low-cardinality integer attribute बनाई। app के alive रहने तक उस value को unique रखने के लिए global object जैसी चीज से coordination किया जा सकता हैफिर कोई ऐसी चीज रख दें जो sum करे और उस attribute को हटा दे। statsd/delta में अगर एक signal transmission खो जाए तो पूरा data बिगड़ जाता है, लेकिन cumulative approach में सिर्फ precision घटती है
मेरा use case scrape करने योग्य long-running process नहीं, बल्कि “batch” tools से आने वाली push-based metrics है
Otel complex इसलिए दिखता है क्योंकि कई observability vendors ने अपने proprietary SDKs, agents, APIs से observability implement करना बहुत आसान बना दिया है। Otel इसी समस्या को solve करने की कोशिश है, और मुझे लगता है बनाने वाले यह काम बेहतरीन कर रहे हैं
Grafana ने OpenTelemetry को ecosystem के first-class component के रूप में अपनाया, यह भी प्रशंसनीय है
कई साल तक Datadog का इस्तेमाल आगे बढ़ाता रहा, लेकिन mid-size और large enterprises के बीच के scale पर price संभालना मुश्किल हो गया। समय के साथ OpenTelemetry API और SDK stable हुए, तो इसे application observability standard बना लिया
हालांकि docs overall और बेहतर हो सकते हैं, और onboarding docs का language के हिसाब से अलग होना ideal नहीं है
मौजूदा team NodeJS/Typescript stack पर है, और OpenTelemetry जल्दी शुरू करने के लिए packages का bundle और example Grafana stack बनाया है: https://github.com/zonneplan/open-telemetry-js
सभी APM vendors में सबसे बड़ी समस्या यह है कि जैसे ही magical agent के पास kernel hooks आ जाते हैं, developers के लिए explain न कर पाने वाली हर तरह की चीजें होने लगती हैं
पहले एक दूसरी company में Dynatrace introduce किया गया था। अच्छी बात यह थी कि app में पहले से पर्याप्त built-in metrics थे, इतना कि lead SRE उसे instrumentation का “model” मानता था। लेकिन app hosts पर Dynatrace agent install करते ही कई Heisenbugs पैदा हुए जिनके लिए node restart चाहिए था, और performance degradation भी सीधे measure हुआ
विडंबना यह है कि metrics की वजह से pain से बच गए, लेकिन उसे fix कैसे करें, यह कोई नहीं जानता था। सबसे खराब case वह था जब MSSQL update के दौरान failover ADO.NET connection pool को अजीब तरह से contaminate कर देता था
यह संरचना सिर्फ जरूरत के हिसाब से ही जटिल होती है। जादू जैसी सुविधाओं से बचकर, संदर्भ में सबसे ज्यादा मूल्यवान और समझने में आसान subset ही इस्तेमाल किया जा सकता है
हमारी टीम में यह बहुत सरल है। हम सिर्फ traces भेजने वाली library इस्तेमाल करते हैं, और traces application observability में सबसे ज्यादा value देते हैं और दूसरे प्रकार का data भी रख सकते हैं। मूल रूप से strings·floats की जगह hashmap इस्तेमाल करने जैसा है
automatic instrumentation के बजाय manual instrumentation इस्तेमाल करते हैं, जानबूझकर तय करते हैं कि क्या observe करना है और अच्छी तरह समझते हैं कि कौन-सा code spans emit करता है। code structure से मेल खाने वाला naming convention भी है
backend में एक सस्ती third-party service के साथ local development के लिए all-in-one Jaeger setup इस्तेमाल करते हैं। बाद वाले में बस एक executable या एक Docker container चलाना होता है और यह spans को disk पर store नहीं करता। मुख्य रूप से इसका इस्तेमाल team members को यह भरोसा दिलाने के लिए होता है कि वे third-party service को overflow नहीं करेंगे
infrastructure monitoring के लिए हमारा existing setup है, और हमारे case में हमें सभी infra logs और metrics collect करने में ज्यादा value नहीं दिखती। OTEL metrics और logs को हम अभी शुरुआती stage में मानते हैं, हालांकि vendors ऐसा नहीं कहते
मैं infrastructure के कुछ ऐसे हिस्सों में, जिन्हें अभी scrape नहीं किया जा सकता, simple one-off metrics भेजने के लिए endpoint ढूंढ रहा हूं
Otel नए project के लिए ठीक हो सकता है, लेकिन जिस production service में पहले से telemetry हो, उसमें इसे enable करना चलती गाड़ी के tyre बदलने जैसा लगा
मैं मानता हूं कि सिर्फ otel इस्तेमाल करने वाला और कोई non-otel framework न रखने वाला greenfield project हो तो यह अच्छा हो सकता है। लेकिन मैं अभी ऐसी दुनिया में नहीं रहता
सबसे बड़ी समस्याओं में से एक local development experience था। local में logs, traces, metrics support करना चाहता था, लेकिन इसके लिए ढेर सारी Docker images नहीं चलाना चाहता था। deploy करने से पहले logs में देखना चाहता था कि metrics, traces, baggage, activity spans कैसे दिखते हैं
हाल ही में .NET team ने .NET Aspire निकाला है, और यह बहुत अच्छा है। local development stack में सब कुछ एक जगह visualize करना आसान है, और यह code-based orchestrator की तरह काम करता है
k8s में deploy करते समय OTEL endpoint को DataDog Agent की ओर point कर दें तो सब कुछ बस काम करता है। DataDog की custom trace library और SDK से बचता हूं और सिर्फ OTEL इस्तेमाल करता हूं
अब development experience काफी अच्छा हो गया है
https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals...
https://docs.datadoghq.com/opentelemetry/#overview
पहली बार local dev machine पर setup करने में 5 मिनट लगते हैं, और उसके बाद अलग terminal tab में सिर्फ
/path/to/openobserveचलाना होता है। अगर single statically linked binary वाली “भारी complexity” से बचना चाहते हैं तो local·remote चलाने के लिए Docker image भी देते हैं :Pयह सुंदर graphs वाला all-in-one OpenTelemetry backend है, और मेरे projects में अभी तक detectable तरीके से fail नहीं हुआ
Aspire इस्तेमाल करने पर app level पर अनावश्यक complexity जुड़ती है और आप एक संकरे ecosystem में बंध जाते हैं। local development के लिए docker compose जैसे कई proven alternatives हैं, और Aspire, docker compose और environment variables से खास ज्यादा आसान भी नहीं है
अगर Python में otel कर रहे हैं तो Logfire का client इस्तेमाल करना बेहतर है। Logfire service न भी इस्तेमाल करें, तब भी
यह open source है और किसी भी otel-compatible endpoint पर भेज सकता है। साथ ही pydantic team का बनाया client official otel library से 10 गुना बेहतर और सरल है
Samuel Colvin कैसे यहां तक पहुंचे, इस पर एक दिलचस्प interview भी है: https://www.bitecode.dev/p/samuel-colvin-on-logfire-mixing-p...
इसलिए OpenTelemetry adoption को एक command line जितना आसान बनाने पर focused एक open source project शुरू किया: https://github.com/odigos-io/odigos
आजकल कई web frameworks ज़्यादातर instrumentation अपने-आप कर देते हैं। उदाहरण के लिए opentelemetry-js इस्तेमाल करके और https://signoz.io जैसी चीज़ को खुद host करें, तो एक घंटे से भी कम में चला सकते हैं, और custom code लिखे बिना भी काफ़ी data मिल जाता है
OpenTelemetry traces से बड़ा हुआ, लेकिन metrics और logs को specialist solutions पर छोड़ना कहीं बेहतर है
यह “leaky abstraction” या “leaky framework” वाली समस्या जैसा लगता है। अगर सब कुछ एक ही umbrella के नीचे रखना है, तो SQL database भी ये सब एक साथ कर सकता है। लेकिन इसका मतलब यह नहीं कि ऐसा करना चाहिए
https://cra.mr/the-problem-with-otel/
फिर भी OTel से काम पड़ता है तो अब भी नापसंद होता है
अंत तक पढ़ें तो समझ आता है कि ज़्यादातर दर्द खुद बनाया हुआ है। Python के standard stack (mysql, flask, redis, requests आदि) में यह बहुत आसान था। service के top पर बस कुछ imports डालें, और यह automatically जुड़कर बिना ज़्यादा झंझट के सब कुछ trace कर देता है
aiohttpका latest version 3.11.X है, और auto-instrumentation में3.Xsupport लिखा है [0], लेकिन असल नतीजा इस पर निर्भर करता है कि आप जोaiohttpइस्तेमाल कर रहे हैं वह कितना नया है और auto-instrumentation side की हालत कैसी हैअगर सब कुछ ठीक-ठीक match हो जाए तो यह जादू की तरह काम करता है, लेकिन वह needle eye काफ़ी संकरा है
[0]: https://github.com/open-telemetry/opentelemetry-python-contr...
traces काम कर रहे हैं और spanmetrics exporter भी configure किया है; prometheus को direct query करने पर spanmetrics दिखते हैं। लेकिन कुछ भी कर लूँ, jaeger के “monitor” tab में नहीं दिखते
इस पर 3 दिन लगाने के बाद boss ने कहा, “क्यों न बस manual instrumentation करके सब SQL server में भेज दें और Grafana dashboard बना दें,” लेकिन मैं वह भी नहीं करना चाहता
सबसे simple use case में भी नहीं चल रहा। क्या ऊपर से Grafana भी जोड़ना पड़ेगा?
यह जटिल इसलिए है कि इसे implement करने वाले engineers के लिए नहीं, बल्कि Otel-compatible software बेचने वाली companies के लिए design किया गया है
बल्कि मुझे लगता है कि backends adoption में काफ़ी धीमे थे
meanings बदलते हैं, इसमें दिक्कत नहीं, लेकिन यह दिलचस्प है कि अब specification के हिसाब से software लिखने के लिए शब्द गायब हो गया है और सिर्फ “existing software को server पर deploy करने” वाला अर्थ बचा है