OpenTelemetry berhasil dijalankan, tetapi mengapa serumit ini?
(iconsolutions.com)- Permintaan pelanggan untuk dukungan OpenTelemetry memperlihatkan bahwa observability berbasis Prometheus·Jaeger·OpenTracing yang sudah ada tidak sepenuhnya sama dengan kebutuhan metrik, log, dan trace dari OTel
- Log dan metrik relatif mudah dipindahkan dengan menambahkan appender dan konfigurasi, tetapi distributed tracing jauh lebih sulit karena Spring dan Akka harus berbagi context tracing di dalam JVM yang sama
- OTel dan Lightbend Telemetry/OpenTracing memakai Tracer API dan implementasi SpanContext yang berbeda, sehingga transaksi yang sama terpecah menjadi trace terpisah
- Solusinya adalah meng-inject context OTel ke Java
Map, mengekstraknya sebagai Jaeger SpanContext, lalu mengaktifkannya secara manual denganGlobalExtendedTracer.get().local().activateContext()milik Lightbend - OTel membantu standardisasi observability, tetapi saat dicampur dengan instrumentasi berbasis Akka·Jaeger yang sudah ada, penghubungan context secara eksplisit mungkin diperlukan
Sinyal observability yang ingin disatukan OTel
- OpenTelemetry(OTel) adalah framework dan toolkit observability yang berupaya menstandarkan area tool yang sebelumnya terpisah menjadi tiga sinyal: metrik, log, dan trace
- Kombinasi yang ada sebelumnya terbagi berdasarkan peran
- Prometheus: metrik
- Agregator terpusat seperti Logstash dan Elasticsearch: log
- OpenTracing: distributed tracing
- OTel menyediakan bukan hanya spesifikasi, tetapi juga komponen inti
- OpenTelemetry Protocol(OTLP): protokol bagi aplikasi untuk melaporkan data telemetry
- OpenTelemetry Collector: komponen vendor-netral untuk menerima, memproses, dan mengekspor data telemetry
- SDK untuk lebih dari 10 bahasa: implementasi OTLP dan ekspor telemetry
- Aplikasi dapat mengirim sinyal ke OTel Collector melalui instrumentasi otomatis, API, dan SDK bahasa; infrastruktur juga dapat mengirim sinyal ke Collector
Dukungan yang sudah ada di IPF dan permintaan pelanggan
- IPF sudah memiliki integrasi ELK Stack, monitoring, dan dokumentasi observability, dan pelanggan juga telah menggunakannya di lingkungan produksi
- Karena karakteristik framework, tidak mungkin mengetahui aplikasi yang memakai library akan dideploy di lingkungan seperti apa, sehingga IPF harus menyediakan abstraksi dan default yang dapat dioverride tanpa memaksakan vendor tertentu
- Rekomendasi defaultnya adalah mengirim log ke agregator seperti Elasticsearch atau LogScale, serta mengaktifkan dan mendukung Prometheus, yang praktis sudah menjadi standar untuk metrik
- Pelanggan mengajukan tiga permintaan tracing berbasis OTel hampir secara bersamaan, dan karena tracing memakai OTel, muncul alur untuk ikut memindahkan log dan metrik
- Log dan metrik relatif mudah ditangani dengan menambahkan appender dan konfigurasi baru, tetapi tracing tetap menjadi masalah tersendiri
Mengapa propagasi context diperlukan dalam distributed tracing
- Untuk melacak satu transaksi dalam sistem terdistribusi, informasi yang menghubungkan panggilan tertentu dan transaksi harus diteruskan antar-sistem; ini disebut context propagation
- Trace adalah struktur induk yang membungkus beberapa unit kerja bernama span; span bisa berjumlah banyak dan dapat bertingkat
- Alur ketika tombol “buy now” ditekan di situs e-commerce dapat digabungkan sebagai satu trace
- Span saat frontend berkomunikasi dengan backend
- Span anak saat backend berkomunikasi dengan layanan pembayaran, pengiriman, dan manajemen pesanan
- Span anak tambahan saat tiap layanan downstream kembali berkomunikasi dengan sistem lain
- Saat memakai OTel, setiap layanan terdistribusi melaporkan bagian trace miliknya ke OTel Collector, lalu OTel menyusun seluruh alur di bawah satu trace ID
Empat standar propagasi context dan jejak OpenTracing
- Ada empat implementasi context propagation yang wajib didukung OTel
- Area Akka di IPF sudah mendukung OpenTracing yang dijadwalkan untuk dideprecate, dan menggunakan dukungan OpenTracing dari Lightbend Telemetry
- Lightbend Telemetry 2.20.0 menambahkan dukungan logs/events dan metrics OpenTelemetry, tetapi dukungan tracing yang penting belum ada
- Secara teori, tracing OTel tampak dekat dengan rebranding OpenTracing, dan OpenTracing di Lightbend Telemetry juga mendukung keempat cara propagasi, sehingga seharusnya terlihat akan berjalan; tetapi hasil nyatanya berbeda
Trace yang terputus antara Spring dan Akka
- IPF menggunakan Spring dan Akka bersama-sama
- Spring Boot dan Spring IoC: bootstrap aplikasi, konfigurasi, penyusunan dependensi
- Akka: event sourcing, scheduling, clustering, sharding, integrasi, dan lain-lain
- Pelanggan dapat memulai alur pembayaran dari Spring REST controller atau method yang diberi
@KafkaListener - Sebelum OTel, tiga area ini berjalan tanpa konflik besar
- Metrics: Spring dan Akka mengekspos endpoint Prometheus yang berbeda
- Logs: kedua framework memakai SLF4J dan Logback
- Traces: keduanya memakai OpenTracing
- Saat memakai OTel, metrics dan logs dikirim normal karena Spring dan Akka berjalan independen, tetapi tracing harus berbagi trace context yang sama di dalam JVM
- Masalah sebenarnya adalah konsep tracing yang sama di dalam aplikasi direpresentasikan oleh dua API berbeda, dan kedua API itu tidak saling berkomunikasi
- Perilaku yang benar adalah Akka HTTP client memakai ulang trace ID
123yang sudah ada dan hanya membuat span ID baru agar terlihat sebagai unit kerja baru dalam trace yang sama, tetapi yang terjadi justru dua trace yang tidak berhubungan dibuat
opentracing-shim dan konflik implementasi
- Di sisi OTel, ada
opentracing-shimyang membuat OTelTracerterlihat seperti OpenTracingTracer - Namun Lightbend Telemetry menggunakan implementasi Tracer kustom, sehingga baik shim maupun Jaeger gagal
- Log menampilkan error berikut
Expected to have an OpenTelemetry Span but got cinnamon.opentracing.TraceLocal$ContextOnlySpanExpected to have a JaegerSpanContext but got io.opentelemetry.opentracingshim.SpanContextShim
- Jaeger gagal ketika menerima context shim OTel, dan OTel gagal ketika menerima context Lightbend
Investigasi Java Agent dan tracing internal Lightbend
- Instrumentasi OTel dan Lightbend Telemetry sama-sama menggunakan Java Agent untuk memasang hook pada pemanggilan method tertentu di class tertentu dan melaporkan aktivitas ke tracer
- Karena instrumentasi Lightbend Telemetry bukan open source, kode tracer hasil decompile harus diteliti untuk memahami cara kerjanya
- Contoh reproduksi yang diperkecil dibuat untuk memeriksa di titik mana trace context OTel dari sisi Spring terputus saat berpindah ke sisi Akka
- Titik kegagalan Jaeger berada pada kode terkait di
JaegerTracer.java - Pemanggilnya adalah class instrumentasi proprietary Lightbend Telemetry,
OpenTracingAkkaPersistenceActorInstrumentation.class - Dalam kode hasil decompile, kondisi kuncinya adalah status
var5- Jika
var5, yang merupakan OpenTracingSpanContext, tidak null, span baru ditempelkan sebagai anak dari span aktif saat ini - Jika
var5null, span menjadi tidak terkait dengan trace yang sudah ada - Jika
var5bukan Jaeger SpanContext, Jaeger gagal
- Jika
Menghubungkan OTel dan OpenTracing dengan konversi manual
SpanContextdiambil darithis.traceLocal.currentContext(), dantraceLocaldiinisialisasi dariExtendedTracermilik Lightbend- Dokumentasi Lightbend menyediakan cara mengakses
ExtendedTracersecara globalGlobalExtendedTracer.get()
GlobalExtendedTracer.get()mengembalikanExtendedTracer, danlocal()mengembalikanTraceLocalyang sama seperti yang dipakai library instrumentasiTraceLocalini memiliki methodactivateContextyang menerima OpenTracingSpanContext- Alur solusinya terdiri dari empat langkah
- Tidak memakai shim OTel
- Meng-inject OpenTelemetry Context saat ini ke Java
Map - Mengekstrak Jaeger SpanContext memakai nilai
Maptersebut - Mengaktifkan Jaeger SpanContext di Lightbend
TraceLocalsebelum masuk ke Akka
- Operasi OTel propagators API yang digunakan adalah inject and extract operations
- Kode intinya mengikuti alur berikut
- Membuat
HashMapkosong - Menginjeksikan context OTel ke map dengan
GlobalOpenTelemetry.get().getPropagators().getTextMapPropagator().inject(...) - Membuat JaegerSpanContext dengan
new TextMapCodec(false).extract(new TextMapAdapter(otelContext)) - Mengaktifkan context sebelum masuk ke Akka dengan
GlobalExtendedTracer.get().local().activateContext(openTracingContext)
- Membuat
Perilaku yang terverifikasi dan rekomendasi operasional
- Setelah penghubungan manual, trace tersambung seperti yang diharapkan
- Dimulai dari panggilan Spring REST
/submit, seluruh alur terhubung sebagai satu trace - Bagian yang diinstrumentasi dengan OTel API dan bagian yang diinstrumentasi dengan OpenTracing API dapat dipakai bercampur
- Trace terpropagasi melewati batas HTTP
- Dimulai dari panggilan Spring REST
- Dalam contoh, nama yang berbeda dipakai untuk membedakan dua jenis instrumentasi, tetapi di lingkungan pelanggan sebenarnya disarankan menyamakan
otel.service.namedancinnamon.applicationagar dari luar terlihat seperti satu aplikasi
Mengapa rumit dan kekhawatiran yang tersisa
- Untuk menulis ulang Lightbend Telemetry dengan OTel API, banyak instrumentasi yang saat ini terikat pada Jaeger API harus diporting ke OTel API, sehingga bisa menjadi pekerjaan besar
- OTel Collector mendukung pengumpulan trace dalam format legacy Zipkin, sehingga Lightbend dapat menyediakan dukungan OTel penuh dengan mengandalkan dukungan legacy
- Penyebab langsung kompleksitas ini adalah upaya menggabungkan dua sistem instrumentasi yang memakai library tracing berbeda
- Proyek OTel berusaha merapikan ranah observability melalui standardisasi seperti semantic conventions; meski agak rumit untuk dipahami pada awalnya, proyek ini dinilai sebagai proyek FOSS yang berguna
- Masih ada kekhawatiran apakah Akka meneruskan trace context dengan benar antar-thread di dalam actor model
- Dalam uji beban kecil, perilakunya sesuai harapan
- Tiket terkait sudah dibuka di sisi Akka
1 komentar
Komentar Hacker News
Sepanjang mempelajari dan mem-porting Otel, rasanya seperti kembali lagi ke dunia Java. Setiap kali menelusuri kode baris demi baris, rasanya seperti EnterpriseFizzBuzz, sama sekali tidak discoverable, dan terminologi internalnya pun tampak seperti dibuat oleh orang-orang yang sedang mabuk sesuatu
Di NodeJS, penggunaan CPU sekitar 4 kali lipat dibanding StatsD, dan akhirnya saya membuat agregasi sendiri untuk menurunkan penggunaan serta mengurangi ledakan tag. StatsD tidak masalah meski beberapa proses melaporkan tag yang sama, tetapi OTEL malah menimpanya
Pada beban puncak, satu CPU berjalan di tingkat penggunaan 60–80%, dan sebelum ada sesuatu yang diubah, scaling vertikal pun tidak bisa dilakukan. Untuk bahasa yang memakai satu proses per core, OTEL terasa seperti secara aktif memusuhi, sampai seperti lelucon. Lebih baik pakai Prometheus saja, dan secara praktis memang tidak ada pesaing lain
Saat mencoba konfigurasi otel sederhana di .NET, saya membaca dokumentasi vendor yang dipilih organisasi selama berjam-jam tetapi tetap tidak paham, jadi saya masuk ke Discord yang dijalankan seorang rekan. Sebagian model bisnis mereka adalah “bayar kalau ingin memakai otel yang benar di produk open source”, dan saya langsung merasa bahwa berapa pun biayanya, itu sepadan
Daripada mengimplementasikan OTEL, saya lebih baik membuat satu lagi library event/pub-sub yang stabil tanpa pengalaman sebelumnya
Konfigurasi minimumnya juga sebenarnya cukup kecil: web UI, instance server, dan DB yang sudah Anda kenal sudah cukup: https://skywalking.apache.org/docs/main/latest/en/setup/back...
Ada kemiripan dengan Zabbix di ranah monitoring. Keduanya mungkin tidak akan membuat siapa pun terkesan, tetapi secara praktis sudah cukup berguna
process.vpid. Nilainya bisa dikoordinasikan dengan semacam objek global agar unik selama aplikasi hidupSetelah itu tinggal ada sesuatu yang menjumlahkannya dan menghapus atribut tersebut. Pada statsd/delta, jika satu pengiriman sinyal hilang, seluruh data menjadi kacau, tetapi pada pendekatan kumulatif, yang hilang hanya presisi
Kegunaan saya adalah metrik berbasis push dari alat “batch”, bukan proses long-running yang bisa di-scrape
Alasan Otel tampak kompleks adalah karena berbagai vendor observability sudah membuat implementasi observability menjadi sangat mudah dengan SDK, agen, dan API khusus mereka masing-masing. Otel mencoba menyelesaikan masalah ini, dan menurut saya orang-orang yang membuatnya melakukannya dengan sangat baik
Grafana juga patut dipuji karena menerima OpenTelemetry sebagai komponen kelas satu dalam ekosistemnya
Selama beberapa tahun saya mendorong penggunaan Datadog, tetapi untuk skala antara perusahaan menengah dan besar, harganya menjadi sulit ditanggung. Seiring waktu, saat OpenTelemetry API dan SDK menjadi stabil, kami menjadikannya standar observability aplikasi
Namun dokumentasinya secara umum masih bisa lebih baik, dan fakta bahwa dokumen onboarding berbeda-beda per bahasa bukanlah kondisi yang ideal
Tim kami saat ini memakai stack NodeJS/Typescript, dan kami membuat kumpulan paket serta contoh stack Grafana agar bisa cepat mulai memakai OpenTelemetry: https://github.com/zonneplan/open-telemetry-js
Masalah terbesar pada semua vendor APM adalah begitu agen ajaib punya hook kernel, berbagai hal yang tidak bisa dijelaskan developer mulai terjadi
Dulu di perusahaan lain kami mengadopsi Dynatrace, dan untungnya aplikasi sudah memiliki metrik bawaan yang cukup banyak sampai lead SRE menganggapnya sebagai “teladan” instrumentasi. Namun begitu agen Dynatrace dipasang di host aplikasi, muncul beberapa Heisenbug yang membutuhkan restart node, dan penurunan performa juga terukur langsung
Ironisnya, berkat metrik kami bisa menghindari penderitaan, tetapi tidak ada yang tahu cara memperbaikinya. Kasus terburuk adalah saat update MSSQL membuat failover mencemari connection pool ADO.NET secara aneh
Strukturnya hanya menjadi serumit yang diperlukan. Tidak perlu memakai fitur yang terasa seperti sihir; cukup gunakan subset yang paling bernilai dalam konteks dan mudah dipahami
Di tim kami, ini sangat sederhana. Kami memakai library yang hanya mengirim trace, dan trace memberi nilai terbesar untuk observabilitas aplikasi sekaligus bisa memuat jenis data lain. Pada dasarnya seperti memakai hashmap alih-alih string atau float
Kami memakai instrumentasi manual, bukan instrumentasi otomatis, sehingga secara sengaja menentukan apa yang akan diamati dan memahami dengan baik kode mana yang memancarkan span. Kami juga punya aturan penamaan yang sesuai dengan struktur kode
Untuk backend, kami memakai layanan pihak ketiga yang murah bersama instalasi Jaeger all-in-one untuk pengembangan lokal. Yang terakhir cukup menjalankan satu executable atau satu container Docker, dan tidak menyimpan span ke disk. Utamanya dipakai untuk meyakinkan anggota tim agar tidak membuat layanan pihak ketiga itu kebanjiran data
Untuk monitoring infrastruktur, kami sudah punya konfigurasi yang ada, dan dalam kasus kami tidak merasa ada nilai besar dari mengumpulkan semua log dan metrik infrastruktur. Saya melihat metrik dan log OTEL masih tahap awal, meski para vendor tidak mengatakan begitu
Saya masih mencari endpoint untuk mengirim metrik sekali pakai sederhana dari sebagian infrastruktur yang belum bisa di-scrape
Otel mungkin baik untuk proyek baru, tetapi menyalakannya pada layanan produksi yang sudah punya telemetri terasa seperti mengganti ban kendaraan yang sedang melaju
Saya percaya ini bisa bagus untuk proyek greenfield yang hanya memakai otel dan tidak punya framework non-otel. Tapi saya belum hidup di dunia seperti itu
Salah satu masalah terbesar adalah pengalaman pengembangan lokal. Saya ingin mendukung log, trace, dan metrik secara lokal, tetapi tidak ingin menjalankan banyak sekali image Docker untuk itu. Sebelum deploy, saya ingin bisa melihat di log seperti apa metrik, trace, baggage, dan activity span
Baru-baru ini tim .NET merilis .NET Aspire, dan itu sangat bagus. Di stack pengembangan lokal, mudah memvisualisasikan semuanya di satu tempat, dan ia bekerja seperti orchestrator berbasis kode
Saat deploy ke k8s, arahkan endpoint OTEL ke DataDog Agent dan semuanya langsung berjalan. Saya menghindari library trace kustom dan SDK milik DataDog, hanya memakai OTEL
Sekarang pengalaman pengembangannya sudah cukup baik
https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals...
https://docs.datadoghq.com/opentelemetry/#overview
Butuh 5 menit untuk setup pertama kali di mesin pengembangan lokal, lalu setelah itu cukup jalankan
/path/to/openobservedi tab terminal terpisah. Kalau ingin menghindari kompleksitas besar berupa satu binary yang di-link statis, mereka juga menyediakan image Docker untuk dijalankan lokal maupun remote :PIni adalah backend OpenTelemetry all-in-one dengan grafik yang cantik, dan di proyek-proyek saya sejauh ini belum pernah gagal dengan cara yang terdeteksi
Dengan Aspire, Anda menambahkan kompleksitas yang tidak perlu di level aplikasi dan terikat pada ekosistem yang sempit. Untuk pengembangan lokal ada banyak alternatif yang sudah teruji seperti docker compose, dan Aspire juga tidak terasa jauh lebih mudah daripada docker compose dan environment variable
Jika melakukan otel di Python, sebaiknya gunakan klien Logfire. Ini tetap berlaku meskipun Anda tidak memakai layanan Logfire
Kliennya open source, dan bisa mengirim ke endpoint apa pun yang kompatibel dengan otel. Selain itu, klien buatan tim pydantic ini 10 kali lebih baik dan sederhana daripada library otel resmi
Ada juga wawancara menarik tempat Samuel Colvin menjelaskan bagaimana ia sampai ke titik ini: https://www.bitecode.dev/p/samuel-colvin-on-logfire-mixing-p...
Jadi saya memulai proyek open source yang berfokus membuat adopsi OpenTelemetry semudah satu baris perintah: https://github.com/odigos-io/odigos
Saat ini banyak web framework sudah menangani sebagian besar instrumentasi untuk kita. Misalnya, kalau memakai opentelemetry-js dan meng-hosting sendiri sesuatu seperti https://signoz.io, itu bisa dijalankan dalam waktu kurang dari satu jam, dan tanpa menulis kode kustom pun kita bisa mendapatkan banyak data
OpenTelemetry tumbuh dari trace, tetapi metrik dan log jauh lebih baik diserahkan ke solusi yang memang khusus untuk itu
Rasanya seperti masalah “abstraksi yang bocor” atau “framework yang bocor”. Kalau ingin menaruh semuanya di bawah satu payung, database SQL juga bisa melakukan semua ini sekaligus. Namun itu bukan berarti harus begitu
https://cra.mr/the-problem-with-otel/
Meski begitu, setiap kali berurusan dengan OTel saya tetap tidak menyukainya
Kalau dibaca sampai akhir, terlihat bahwa sebagian besar rasa sakitnya dibuat sendiri. Di stack standar Python (mysql, flask, redis, requests, dan sebagainya), ini sangat mudah. Cukup tambahkan beberapa import di bagian atas service, semuanya tersambung otomatis dan melacak semuanya tanpa banyak ribut
aiohttpadalah 3.11.X, dan instrumentasi otomatis disebut mendukung3.X, tetapi [0] hasil nyatanya bergantung pada seberapa mutakhiraiohttpyang dipakai dan kondisi di sisi instrumentasi otomatisKalau semuanya pas, ini bekerja seperti sihir, tetapi celahnya cukup sempit
[0]: https://github.com/open-telemetry/opentelemetry-python-contr...
Trace berjalan dan spanmetrics exporter juga sudah dikonfigurasi; kalau melakukan query langsung ke prometheus, spanmetrics terlihat. Namun apa pun yang saya lakukan, itu tidak muncul di tab “monitor” milik jaeger
Setelah menghabiskan 3 hari untuk ini, atasan saya berkata, “bagaimana kalau instrumentasi manual saja lalu kirim semuanya ke SQL Server dan buat dashboard Grafana,” tetapi saya juga tidak ingin melakukan itu
Bahkan use case paling sederhana pun tidak berhasil. Apakah saya harus menambahkan Grafana lagi?
Alasannya rumit adalah karena ini dirancang bukan untuk engineer yang mengimplementasikannya, melainkan untuk perusahaan yang menjual software kompatibel Otel
Justru menurut saya backend cukup lambat dalam mengadopsinya
Makna kata memang berubah, jadi tidak apa-apa, tetapi menarik bahwa sekarang kita kehilangan kata untuk menulis software agar sesuai dengan spesifikasi, dan yang tersisa hanya “men-deploy software yang sudah ada ke server”