Pelacakan Layanan, OpenTracing, dan Jaeger

Pelacakan Layanan, OpenTracing, dan Jaeger

Kami menggunakan arsitektur layanan mikro dalam proyek kami. Saat kemacetan kinerja terjadi, banyak waktu dihabiskan untuk memantau dan menguraikan log. Saat mencatat waktu operasi individu ke file log, biasanya sulit untuk memahami apa yang menyebabkan pemanggilan operasi ini, untuk melacak urutan tindakan atau pergeseran waktu dari satu operasi relatif ke operasi lain di layanan yang berbeda.

Untuk meminimalkan tenaga kerja manual, kami memutuskan untuk menggunakan salah satu alat penelusuran. Tentang bagaimana dan mengapa Anda dapat menggunakan pelacakan dan bagaimana kami melakukannya, dan akan dibahas dalam artikel ini.

Masalah apa yang bisa diselesaikan dengan pelacakan

  1. Temukan hambatan kinerja baik dalam satu layanan maupun di seluruh pohon eksekusi di antara semua layanan yang berpartisipasi. Misalnya:
    • Banyak panggilan pendek berturut-turut antar layanan, misalnya, ke geocoding atau ke database.
    • Menunggu I/O lama, seperti transfer jaringan atau pembacaan disk.
    • Penguraian data yang panjang.
    • Operasi panjang membutuhkan cpu.
    • Bagian kode yang tidak diperlukan untuk mendapatkan hasil akhir dan dapat dihapus atau ditunda.
  2. Pahami dengan jelas urutan apa yang disebut dan apa yang terjadi saat operasi dilakukan.
    Pelacakan Layanan, OpenTracing, dan Jaeger
    Dapat dilihat bahwa, misalnya, Permintaan datang ke layanan WS -> layanan WS menambahkan data melalui layanan R -> kemudian mengirim permintaan ke layanan V -> layanan V memuat banyak data dari layanan R -> pergi ke layanan P -> layanan P pergi ke layanan R lagi -> layanan V mengabaikan hasilnya dan pergi ke layanan J -> dan baru kemudian mengembalikan respons ke layanan WS, sambil terus menghitung sesuatu yang lain di latar belakang.
    Tanpa jejak atau dokumentasi mendetail untuk keseluruhan proses, sangat sulit untuk memahami apa yang terjadi saat melihat kode untuk pertama kali, dan kode tersebut tersebar di berbagai layanan dan tersembunyi di balik sekumpulan tempat sampah dan antarmuka.
  3. Pengumpulan informasi tentang pohon eksekusi untuk analisis selanjutnya yang ditangguhkan. Pada setiap tahap eksekusi, Anda dapat menambahkan informasi ke pelacakan yang tersedia pada tahap ini, lalu mencari tahu data masukan apa yang menyebabkan skenario serupa. Misalnya:
    • identitas pengguna
    • Hak
    • Jenis metode yang dipilih
    • Kesalahan log atau eksekusi
  4. Mengubah trace menjadi subkumpulan metrik dan analisis lebih lanjut sudah dalam bentuk metrik.

Jejak apa yang bisa dicatat. Menjangkau

Dalam tracing ada konsep span, ini analog dari satu log, ke console. Spa memiliki:

  • Nama, biasanya nama metode yang dieksekusi
  • Nama layanan tempat span dihasilkan
  • ID unik sendiri
  • Semacam informasi meta berupa kunci/nilai yang telah masuk ke dalamnya. Misalnya, parameter metode atau metode berakhir dengan kesalahan atau tidak
  • Waktu mulai dan berakhir untuk rentang ini
  • ID rentang induk

Setiap rentang dikirim ke pengumpul rentang untuk disimpan dalam database untuk ditinjau nanti segera setelah selesai dieksekusi. Di masa mendatang, Anda dapat membuat pohon dari semua rentang dengan menghubungkan dengan id induk. Saat menganalisis, Anda dapat menemukan, misalnya, semua rentang di beberapa layanan yang memakan waktu lebih lama. Selanjutnya, dengan pergi ke rentang tertentu, lihat keseluruhan pohon di atas dan di bawah rentang ini.

Pelacakan Layanan, OpenTracing, dan Jaeger

Opentrace, Jagger, dan bagaimana kami mengimplementasikannya untuk proyek kami

Ada standar umum opentrace, yang menjelaskan bagaimana dan apa yang harus dikumpulkan, tanpa terikat dengan menelusuri implementasi tertentu dalam bahasa apa pun. Misalnya, di Java, semua pekerjaan dengan jejak dilakukan melalui Opentrace API umum, dan di bawahnya, misalnya, Jaeger atau implementasi default kosong yang tidak melakukan apa pun, tidak dapat disembunyikan.
Kami menggunakan Kain triko vol sebagai implementasi Opentrace. Ini terdiri dari beberapa komponen:

Pelacakan Layanan, OpenTracing, dan Jaeger

  • Jaeger-agent adalah agen lokal yang biasanya dipasang di setiap mesin dan layanan masuk ke dalamnya di port default lokal. Jika tidak ada agen, jejak semua layanan di mesin ini biasanya dinonaktifkan
  • Jaeger-collector - semua agen mengirim jejak yang dikumpulkan ke sana, dan menempatkannya di database yang dipilih
  • Database adalah cassandra pilihan mereka, tetapi kami menggunakan elasticsearch, ada implementasi untuk beberapa database lain dan implementasi dalam memori yang tidak menyimpan apa pun ke disk
  • Jaeger-query adalah layanan yang masuk ke database dan mengembalikan jejak yang sudah dikumpulkan untuk dianalisis
  • Jaeger-ui adalah antarmuka web untuk mencari dan melihat jejak, masuk ke jaeger-query

Pelacakan Layanan, OpenTracing, dan Jaeger

Komponen terpisah dapat disebut implementasi opentrace jaeger untuk bahasa tertentu, di mana rentang dikirim ke agen jaeger.
Menghubungkan Jagger di Jawa turun untuk mengimplementasikan antarmuka io.opentracing.Tracer, setelah itu semua jejak melalui itu akan terbang ke agen sebenarnya.

Pelacakan Layanan, OpenTracing, dan Jaeger

Juga untuk komponen pegas, Anda dapat menghubungkan opentracing-spring-cloud-starter dan implementasi dari Jaeger opentracing-spring-jaeger-cloud-starter yang akan secara otomatis mengonfigurasi penelusuran untuk semua yang melewati komponen ini, misalnya permintaan http ke pengontrol, permintaan ke database melalui jdbc, dll.

Melacak logging di Jawa

Di suatu tempat di tingkat atas, Span pertama harus dibuat, ini dapat dilakukan secara otomatis, misalnya, oleh pengontrol pegas saat permintaan diterima, atau secara manual jika tidak ada. Ini kemudian ditransmisikan melalui Ruang Lingkup di bawah ini. Jika ada metode di bawah ini yang ingin menambahkan Span, dibutuhkan activeSpan saat ini dari Scope, membuat Span baru dan mengatakan induknya adalah activeSpan yang dihasilkan, dan menjadikan Span baru aktif. Saat memanggil layanan eksternal, rentang aktif saat ini diteruskan ke layanan tersebut, dan layanan tersebut membuat rentang baru dengan mengacu pada rentang ini.
Semua pekerjaan melalui instance Tracer, Anda bisa mendapatkannya melalui mekanisme DI, atau GlobalTracer.get() sebagai variabel global jika mekanisme DI tidak berfungsi. Secara default, jika pelacak belum diinisialisasi, NoopTracer akan kembali tanpa melakukan apa-apa.
Selanjutnya, ruang lingkup saat ini diperoleh dari pelacak melalui ScopeManager, ruang lingkup baru dibuat dari ruang lingkup saat ini dengan mengikat rentang baru, dan kemudian Ruang Lingkup yang dibuat ditutup, yang menutup rentang yang dibuat dan mengembalikan Ruang Lingkup sebelumnya ke keadaan aktif. Lingkup terikat ke utas, jadi saat pemrograman multi-utas, Anda tidak boleh lupa untuk mentransfer rentang aktif ke utas lain, untuk aktivasi lebih lanjut Cakupan utas lain dengan mengacu pada rentang ini.

io.opentracing.Tracer tracer = ...; // GlobalTracer.get()

void DoSmth () {
   try (Scope scope = tracer.buildSpan("DoSmth").startActive(true)) {
      ...
   }
}
void DoOther () {
    Span span = tracer.buildSpan("someWork").start();
    try (Scope scope = tracer.scopeManager().activate(span, false)) {
        // Do things.
    } catch(Exception ex) {
        Tags.ERROR.set(span, true);
        span.log(Map.of(Fields.EVENT, "error", Fields.ERROR_OBJECT, ex, Fields.MESSAGE, ex.getMessage()));
    } finally {
        span.finish();
    }
}

void DoAsync () {
    try (Scope scope = tracer.buildSpan("ServiceHandlerSpan").startActive(false)) {
        ...
        final Span span = scope.span();
        doAsyncWork(() -> {
            // STEP 2 ABOVE: reactivate the Span in the callback, passing true to
            // startActive() if/when the Span must be finished.
            try (Scope scope = tracer.scopeManager().activate(span, false)) {
                ...
            }
        });
    }
}

Untuk pemrograman multi-utas, ada juga TracedExecutorService dan pembungkus serupa yang secara otomatis meneruskan rentang saat ini ke utas saat tugas asinkron diluncurkan:

private ExecutorService executor = new TracedExecutorService(
    Executors.newFixedThreadPool(10), GlobalTracer.get()
);

Untuk permintaan http eksternal ada MenelusuriHttpClient

HttpClient httpClient = new TracingHttpClientBuilder().build();

Masalah yang kami hadapi

  • Kacang dan DI tidak selalu berfungsi jika pelacak tidak digunakan dalam layanan atau komponen Kabel otomatis Pelacak mungkin tidak berfungsi dan Anda harus menggunakan GlobalTracer.get().
  • Anotasi tidak berfungsi jika itu bukan komponen atau layanan, atau jika metode dipanggil dari metode tetangga dari kelas yang sama. Anda harus berhati-hati untuk memeriksa apa yang berhasil dan menggunakan pembuatan jejak manual jika @Traced tidak berfungsi. Anda juga dapat melampirkan kompiler tambahan untuk anotasi java, lalu anotasi tersebut akan berfungsi di mana saja.
  • Pada boot musim semi dan musim semi yang lama, konfigurasi otomatis opentraing spring cloud tidak berfungsi karena bug di DI, maka jika Anda ingin jejak di komponen pegas bekerja secara otomatis, Anda dapat melakukannya dengan analogi dengan github.com/opentracing-contrib/java-spring-jaeger/blob/master/opentracing-spring-jaeger-starter/src/main/java/io/opentracing/contrib/java/spring/jaeger/starter/JaegerAutoConfiguration.java
  • Coba dengan sumber daya tidak berfungsi di groovy, Anda harus menggunakan coba akhirnya.
  • Setiap layanan harus memiliki spring.application.name sendiri di mana jejak akan dicatat. Apa artinya memisahkan nama untuk penjualan dan pengujian, agar tidak mengganggu mereka bersama.
  • Jika Anda menggunakan GlobalTracer dan Tomcat, maka semua layanan yang berjalan di Tomcat ini memiliki satu GlobalTracer, jadi semuanya akan memiliki nama layanan yang sama.
  • Saat menambahkan jejak ke suatu metode, Anda perlu memastikan bahwa itu tidak dipanggil berkali-kali dalam satu lingkaran. Penting untuk menambahkan satu jejak umum untuk semua panggilan, yang menjamin total waktu kerja. Jika tidak, beban berlebih akan dibuat.
  • Sekali di jaeger-ui, permintaan terlalu besar dibuat untuk sejumlah besar jejak, dan karena mereka tidak menunggu tanggapan, mereka melakukannya lagi. Akibatnya, jaeger-query mulai memakan banyak memori dan melambat secara elastis. Dibantu dengan me-restart jaeger-query

Sampling, menyimpan dan melihat jejak

Ada tiga jenis jejak sampel:

  1. Const yang mengirim dan menyimpan semua jejak.
  2. Probabilistik yang memfilter jejak dengan probabilitas tertentu.
  3. Ratelimiting yang membatasi jumlah jejak per detik. Anda dapat mengonfigurasi pengaturan ini di klien, baik di agen jaeger atau di kolektor. Sekarang kami menggunakan const 1 di tumpukan valuator, karena permintaannya tidak terlalu banyak, tetapi butuh waktu lama. Di masa mendatang, jika ini akan membebani sistem secara berlebihan, Anda dapat membatasinya.

Jika Anda menggunakan cassandra, secara default hanya menyimpan jejak selama dua hari. Kami menggunakan pencarian elastis dan jejak disimpan sepanjang waktu dan tidak dihapus. Indeks terpisah dibuat untuk setiap hari, misalnya jaeger-service-2019-03-04. Di masa mendatang, Anda perlu mengonfigurasi pembersihan otomatis dari jejak lama.

Untuk melihat jejak yang Anda butuhkan:

  • Pilih layanan yang ingin Anda filter jejaknya, misalnya, Tomcat7-default untuk layanan yang berjalan di Tomcat dan tidak boleh memiliki namanya sendiri.
  • Kemudian pilih operasi, interval waktu dan waktu operasi minimum, misalnya dari 10 detik, untuk hanya melakukan eksekusi yang lama.
    Pelacakan Layanan, OpenTracing, dan Jaeger
  • Pergi ke salah satu jejak dan lihat apa yang melambat di sana.
    Pelacakan Layanan, OpenTracing, dan Jaeger

Selain itu, jika beberapa id permintaan diketahui, Anda dapat menemukan jejak dengan id ini melalui pencarian tag, jika id ini dicatat dalam rentang jejak.

ДокумСнтация

Artikel

Video

Sumber: www.habr.com

Tambah komentar