Herkese merhaba! Ben Dmitriy Apanasevich, MY.GAMES'te Java Geliştiricisiyim, Rush Royale oyunu üzerinde çalışıyorum ve OpenTelemetry çerçevesini Java arka ucumuzla entegre etme deneyimimizi paylaşmak istiyorum. Burada ele alınacak çok şey var: Bunu uygulamak için gereken kod değişikliklerini ve ayrıca kurmamız ve yapılandırmamız gereken yeni bileşenleri ele alacağız - ve tabii ki sonuçlarımızdan bazılarını paylaşacağız.
Davamıza biraz daha bağlam verelim. Geliştiriciler olarak, izlenmesi, değerlendirilmesi ve anlaşılması kolay yazılımlar oluşturmak istiyoruz (ve bu tam olarak OpenTelemetry'yi uygulamanın amacıdır - sistem verimliliğini en üst düzeye çıkarmak
Uygulama performansına ilişkin içgörüler toplamak için kullanılan geleneksel yöntemler genellikle olayların, ölçümlerin ve hataların manuel olarak günlüğe kaydedilmesini içerir:
Elbette, loglarla çalışmamızı sağlayan birçok framework var ve eminim ki bu yazıyı okuyan herkesin logları toplamak, saklamak ve analiz etmek için yapılandırılmış bir sistemi vardır.
Loglama da bizim için tam olarak yapılandırılmıştı, bu yüzden loglarla çalışmak için OpenTelemetry'nin sağladığı yetenekleri kullanmadık.
Sistemi izlemenin bir diğer yaygın yolu da ölçümlerden yararlanmaktır:
Metrikleri toplamak ve görselleştirmek için de tam yapılandırılmış bir sistemimiz vardı, bu nedenle burada da OpenTelemetry'nin metriklerle çalışma konusundaki yeteneklerini göz ardı ettik.
Ancak bu tür sistem verilerini elde etmek ve analiz etmek için daha az yaygın bir araç vardır
Bir iz, bir isteğin ömrü boyunca sistemimizde izlediği yolu temsil eder ve genellikle sistem bir istek aldığında başlar ve yanıtla sona erer. İzler, birden fazla
Bu tartışmada OpenTelemetry'nin izleme yönüne yoğunlaşacağız.
Ayrıca, OpenTelemetry projesinin birleştirilmesiyle ortaya çıkan OpenTelemetry projesine de biraz ışık tutalım.
OpenTelemetry artık çeşitli programlama dilleri için bir dizi API, SDK ve araç tanımlayan bir standarda dayalı kapsamlı bir bileşen yelpazesi sağlıyor ve projenin birincil hedefi veri üretmek, toplamak, yönetmek ve dışa aktarmak.
Bununla birlikte OpenTelemetry, veri depolama veya görselleştirme araçları için bir arka uç sunmuyor.
Biz sadece izlemeyle ilgilendiğimiz için, izleri depolamak ve görselleştirmek için en popüler açık kaynaklı çözümleri inceledik:
Sonuç olarak, etkileyici görselleştirme yetenekleri, hızlı geliştirme hızı ve metrik görselleştirme için mevcut Grafana kurulumumuzla entegrasyonu nedeniyle Grafana Tempo'yu seçtik. Tek, birleşik bir araca sahip olmak da önemli bir avantajdı.
OpenTelemetry'nin bileşenlerini de biraz inceleyelim.
Şartname:
API — veri türleri, işlemler, enumlar
SDK — şartname uygulaması, farklı programlama dillerinde API'ler. Farklı bir dil, alfa'dan kararlıya kadar farklı bir SDK durumu anlamına gelir.
Veri protokolü (OTLP) ve
Java API SDK'sı:
OpenTelemetry Collector , verileri alan, işleyen ve ileten önemli bir bileşendir. Daha yakından bakalım.
Saniyede binlerce isteği işleyen yüksek yüklü sistemler için veri hacmini yönetmek hayati önem taşır. İz verileri genellikle hacim açısından iş verilerini geride bırakır ve bu da hangi verilerin toplanıp depolanacağına öncelik verilmesini zorunlu hale getirir. İşte veri işleme ve filtreleme aracımızın devreye girdiği ve hangi verilerin depolanmaya değer olduğunu belirlemenizi sağlayan yer burasıdır. Genellikle ekipler, aşağıdakiler gibi belirli ölçütleri karşılayan izleri depolamak ister:
Hangi izlerin kaydedileceğini ve hangilerinin atılacağını belirlemek için kullanılan iki ana örnekleme yöntemi şunlardır:
OpenTelemetry Collector, veri toplama sisteminin yalnızca gerekli verileri kaydedecek şekilde yapılandırılmasına yardımcı olur. Yapılandırmasını daha sonra ele alacağız, ancak şimdilik, iz üretmeye başlaması için kodda neyin değiştirilmesi gerektiği sorusuna geçelim.
İz oluşturma gerçekten asgari düzeyde kodlama gerektiriyordu; uygulamalarımızı bir java aracıyla başlatmamız ve
-javaagent:/opentelemetry-javaagent-1.29.0.jar
-Dotel.javaagent.configuration-file=/otel-config.properties
OpenTelemetry çok sayıda
Aracı yapılandırmamızda, izlerde görmek istemediğimiz aralıklara sahip kütüphaneleri devre dışı bıraktık ve kodumuzun nasıl çalıştığına dair veri almak için onu şu şekilde işaretledik:
@WithSpan("acquire locks") public CompletableFuture<Lock> acquire(SortedSet<Object> source) { var traceLocks = source.stream().map(Object::toString).collect(joining(", ")); Span.current().setAttribute("locks", traceLocks); return CompletableFuture.supplyAsync(() -> /* async job */); }
Bu örnekte, " acquire locks
" adında yeni bir span oluşturma ihtiyacını işaret eden @WithSpan
açıklaması yöntem için kullanılmış ve oluşturulan span'a yöntem gövdesinde " locks
" niteliği eklenmiştir.
Yöntem çalışmayı bitirdiğinde, span kapatılır ve asenkron kod için bu ayrıntıya dikkat etmek önemlidir. Açıklamalı bir yöntemden çağrılan lambda işlevlerindeki asenkron kodun çalışmasıyla ilgili verileri elde etmeniz gerekiyorsa, bu lambdaları ayrı yöntemlere ayırmanız ve bunları ek bir açıklama ile işaretlemeniz gerekir.
Şimdi, tüm iz toplama sisteminin nasıl yapılandırılacağından bahsedelim. Tüm JVM uygulamalarımız, verileri OpenTelemetry toplayıcısına gönderen bir Java aracısıyla başlatılır.
Ancak, tek bir toplayıcı büyük bir veri akışını işleyemez ve sistemin bu kısmı ölçeklendirilmelidir. Her JVM uygulaması için ayrı bir toplayıcı başlatırsanız, kuyruk örneklemesi bozulur, çünkü iz analizi tek bir toplayıcıda gerçekleşmelidir ve istek birkaç JVM'den geçerse, bir izin aralıkları farklı toplayıcılarda son bulur ve analizleri imkansız hale gelir.
Burada, bir
Sonuç olarak, aşağıdaki sistemi elde ederiz: Her JVM uygulaması, tek görevi farklı uygulamalardan alınan ancak belirli bir iz ile ilgili verileri aynı toplayıcı işlemciye dağıtmak olan aynı dengeleyici toplayıcıya veri gönderir. Daha sonra, toplayıcı işlemci verileri Grafana Tempo'ya gönderir.
Bu sistemdeki bileşenlerin yapılandırmasına daha yakından bakalım.
Toplayıcı-dengeleyici yapılandırmasında aşağıdaki ana parçaları yapılandırdık:
receivers: otlp: protocols: grpc: exporters: loadbalancing: protocol: otlp: tls: insecure: true resolver: static: hostnames: - collector-1.example.com:4317 - collector-2.example.com:4317 - collector-3.example.com:4317 service: pipelines: traces: receivers: [otlp] exporters: [loadbalancing]
Toplayıcı-işlemcilerin yapılandırması daha karmaşıktır, o yüzden oraya bir bakalım:
receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:14317 processors: tail_sampling: decision_wait: 10s num_traces: 100 expected_new_traces_per_sec: 10 policies: [ { name: latency500-policy, type: latency, latency: {threshold_ms: 500} }, { name: error-policy, type: string_attribute, string_attribute: {key: error, values: [true, True]} }, { name: probabilistic10-policy, type: probabilistic, probabilistic: {sampling_percentage: 10} } ] resource/delete: attributes: - key: process.command_line action: delete - key: process.executable.path action: delete - key: process.pid action: delete - key: process.runtime.description action: delete - key: process.runtime.name action: delete - key: process.runtime.version action: delete exporters: otlp: endpoint: tempo:4317 tls: insecure: true service: pipelines: traces: receivers: [otlp] exporters: [otlp]
Toplayıcı-dengeleyici yapılandırmasına benzer şekilde, işleme yapılandırması Alıcılar, İhracatçılar ve Hizmet bölümlerinden oluşur. Ancak, verilerin nasıl işlendiğini açıklayan İşlemciler bölümüne odaklanacağız.
İlk olarak, tail_sampling bölümü şunu gösterir:
latency500-policy : bu kural, gecikmesi 500 milisaniyeyi aşan izleri seçer.
error-policy : bu kural, işleme sırasında hatalarla karşılaşan izleri seçer. İz aralıklarında "true" veya "True" değerlerine sahip "error" adlı bir dize niteliği arar.
probabilistic10-policy : Bu kural, normal uygulama çalışması, hatalar ve uzun istek işleme hakkında bilgi sağlamak için tüm izlerin %10'unu rastgele seçer.
Bu örnekte tail_sampling'e ek olarak, veri analizi ve depolama için gerekli olmayan gereksiz öznitelikleri silmek için resource/dele bölümü gösterilmektedir.
Ortaya çıkan Grafana iz arama penceresi, verileri çeşitli ölçütlere göre filtrelemenizi sağlar. Bu örnekte, oyun meta verilerini işleyen lobi hizmetinden alınan izlerin bir listesini gösteriyoruz. Yapılandırma, gecikme, hatalar ve rastgele örnekleme gibi niteliklere göre gelecekte filtrelemeye olanak tanır.
İzleme görünümü penceresi, isteği oluşturan çeşitli aralıklar dahil olmak üzere lobi hizmetinin yürütme zaman çizelgesini görüntüler.
Resimden de görebileceğiniz gibi olayların sırası şu şekildedir: kilitler alınır, ardından nesneler önbellekten alınır, ardından istekleri işleyen bir işlem yürütülür, ardından nesneler tekrar önbelleğe kaydedilir ve kilitler serbest bırakılır.
Veritabanı istekleriyle ilgili aralıklar, standart kütüphanelerin enstrümantasyonu nedeniyle otomatik olarak oluşturuldu. Buna karşılık, kilit yönetimi, önbellek işlemleri ve işlem başlatmayla ilgili aralıklar, yukarıda belirtilen açıklamalar kullanılarak iş koduna manuel olarak eklendi.
Bir aralığı görüntülerken, işleme sırasında ne olduğunu daha iyi anlamanızı sağlayan nitelikleri görebilirsiniz; örneğin, veritabanındaki bir sorguyu görebilirsiniz.
Grafana Tempo'nun ilginç özelliklerinden biri de
Gördüğümüz gibi, OpenTelemetry izlemeyle çalışmak gözlem yeteneklerimizi oldukça güzel bir şekilde geliştirdi. Minimum kod değişiklikleri ve iyi yapılandırılmış bir toplayıcı kurulumuyla, derin içgörüler elde ettik - ayrıca, Grafana Tempo'nun görselleştirme yeteneklerinin kurulumumuzu nasıl daha da tamamladığını gördük. Okuduğunuz için teşekkürler!