ردیابی خدمات، OpenTracing و Jaeger

ردیابی خدمات، OpenTracing و Jaeger

ما از معماری میکروسرویس در پروژه های خود استفاده می کنیم. هنگامی که گلوگاه های عملکرد رخ می دهد، زمان زیادی صرف نظارت و تجزیه لاگ ها می شود. هنگام ثبت زمان‌بندی عملیات‌های جداگانه در یک فایل گزارش، معمولاً درک اینکه چه چیزی منجر به فراخوانی این عملیات شده است، ردیابی توالی اقدامات یا تغییر زمانی یک عملیات نسبت به دیگری در سرویس‌های مختلف دشوار است.

برای به حداقل رساندن کار دستی، تصمیم گرفتیم از یکی از ابزارهای ردیابی استفاده کنیم. در مورد اینکه چگونه و چرا می توانید از ردیابی استفاده کنید و چگونه آن را انجام دادیم، و در این مقاله مورد بحث قرار خواهد گرفت.

چه مشکلاتی را می توان با ردیابی حل کرد

  1. گلوگاه های عملکرد را هم در یک سرویس واحد و هم در کل درخت اجرا بین تمام سرویس های شرکت کننده پیدا کنید. مثلا:
    • بسیاری از تماس‌های متوالی کوتاه بین سرویس‌ها، به عنوان مثال، به geocoding یا به یک پایگاه داده.
    • انتظارهای طولانی I/O مانند انتقال شبکه یا خواندن دیسک.
    • تجزیه طولانی داده ها
    • عملیات طولانی که نیاز به cpu دارد.
    • بخش هایی از کد که برای دریافت نتیجه نهایی مورد نیاز نیستند و می توانند حذف شوند یا به تأخیر بیفتند.
  2. به وضوح درک کنید که به چه ترتیبی چه چیزی نامیده می شود و چه اتفاقی می افتد هنگام انجام عمل.
    ردیابی خدمات، OpenTracing و Jaeger
    مشاهده می شود که مثلاً Request به سرویس WS آمد -> سرویس WS داده ها را از طریق سرویس R تکمیل کرد -> سپس یک درخواست به سرویس V ارسال کرد -> سرویس V داده های زیادی را از سرویس بارگیری کرد. سرویس R -> به سرویس P -> سرویس P دوباره به سرویس R رفت -> سرویس V نتیجه را نادیده گرفت و به سرویس J -> رفت و تنها پس از آن پاسخ را به سرویس WS برگرداند، در حالی که به محاسبه چیز دیگری در پس زمینه.
    بدون چنین ردیابی یا مستندات دقیقی برای کل فرآیند، درک آنچه در هنگام نگاه کردن به کد برای اولین بار اتفاق می افتد بسیار دشوار است و کد در سرویس های مختلف پراکنده شده و در پشت دسته ای از بن ها و رابط ها پنهان می شود.
  3. مجموعه ای از اطلاعات در مورد درخت اجرا برای تجزیه و تحلیل معوق بعدی. در هر مرحله از اجرا، می توانید اطلاعاتی را که در این مرحله در دسترس است به ردیابی اضافه کنید و سپس بفهمید که چه داده های ورودی منجر به سناریوی مشابه شده است. مثلا:
    • شناسه کاربر
    • حقوق
    • نوع روش انتخاب شده
    • خطای لاگ یا اجرا
  4. تبدیل ردیابی ها به زیرمجموعه ای از معیارها و تجزیه و تحلیل بیشتر در قالب معیارها.

چه ردی می تواند ثبت شود. طول

در ردیابی مفهوم دهانه وجود دارد، این یک آنالوگ از یک ورود به سیستم به کنسول است. آبگرم دارای:

  • نام، معمولاً نام متدی است که اجرا شده است
  • نام سرویسی که در آن span ایجاد شده است
  • شناسه منحصر به فرد خود را داشته باشید
  • نوعی متا اطلاعات به شکل یک کلید/مقدار که در آن وارد شده است. به عنوان مثال، پارامترهای متد یا متد با خطا به پایان رسید یا خیر
  • زمان شروع و پایان برای این بازه زمانی
  • شناسه فاصله والدین

هر span به جمع آوری کننده span ارسال می شود تا به محض اتمام اجرای خود در پایگاه داده برای بررسی بعدی ذخیره شود. در آینده، می توانید با اتصال توسط شناسه والد، درختی از تمام دهانه ها بسازید. هنگام تجزیه و تحلیل، می‌توانید برای مثال، تمام بازه‌های موجود در برخی از سرویس‌ها را بیابید که بیش از مدتی طول کشیده است. علاوه بر این، با رفتن به یک دهانه خاص، کل درخت را در بالا و پایین این دهانه ببینید.

ردیابی خدمات، OpenTracing و Jaeger

Opentrace، Jagger و نحوه اجرای آن برای پروژه هایمان

یک استاندارد مشترک وجود دارد opentrace، که توضیح می دهد چگونه و چه چیزی باید جمع آوری شود، بدون اینکه با ردیابی به یک پیاده سازی خاص در هیچ زبانی گره بخورد. به عنوان مثال، در جاوا، تمام کار با ردیابی ها از طریق API مشترک Opentrace انجام می شود، و در زیر آن، به عنوان مثال، Jaeger یا یک پیاده سازی پیش فرض خالی که هیچ کاری انجام نمی دهد، می تواند پنهان شود.
استفاده می کنیم شکارچی به عنوان پیاده سازی Opentrace. از چندین جزء تشکیل شده است:

ردیابی خدمات، OpenTracing و Jaeger

  • Jaeger-agent یک عامل محلی است که معمولاً روی هر دستگاه نصب می شود و سرویس ها در پورت پیش فرض محلی به آن وارد می شوند. اگر هیچ عاملی وجود نداشته باشد، معمولاً ردیابی همه خدمات در این دستگاه غیرفعال می شود
  • Jaeger-collector - همه عوامل ردیابی های جمع آوری شده را به آن ارسال می کنند و آنها را در پایگاه داده انتخابی قرار می دهد.
  • پایگاه داده cassandra ترجیحی آنها است، اما ما از elasticsearch استفاده می کنیم، پیاده سازی هایی برای چند پایگاه داده دیگر و یک پیاده سازی در حافظه وجود دارد که چیزی را روی دیسک ذخیره نمی کند.
  • Jaeger-query سرویسی است که به پایگاه داده می رود و ردپای جمع آوری شده قبلی را برای تجزیه و تحلیل برمی گرداند
  • Jaeger-ui یک رابط وب برای جستجو و مشاهده آثار است، به jaeger-query می رود.

ردیابی خدمات، OpenTracing و Jaeger

یک جزء جداگانه را می توان پیاده سازی opentrace jaeger برای زبان های خاص نامید که از طریق آن span ها به jaeger-agent ارسال می شود.
اتصال Jagger در جاوا به پیاده سازی رابط io.opentracing.Tracer می رسد، پس از آن همه ردیابی ها از طریق آن به عامل واقعی پرواز می کنند.

ردیابی خدمات، OpenTracing و Jaeger

همچنین برای کامپوننت فنری، می توانید متصل شوید opentracing-spring-cloud- starter و پیاده سازی از جیگر opentracing-spring-jaeger-cloud- starter که به طور خودکار ردیابی را برای هر چیزی که از این مؤلفه ها عبور می کند پیکربندی می کند، به عنوان مثال درخواست های http به کنترلرها، درخواست ها به پایگاه داده از طریق jdbc و غیره.

ردیابی ورود در جاوا

جایی در سطح بالا، اولین Span باید ایجاد شود، این می تواند به طور خودکار انجام شود، برای مثال، توسط کنترل کننده فنری هنگام دریافت درخواست، یا به صورت دستی اگر درخواستی وجود ندارد. سپس از طریق Scope زیر منتقل می شود. اگر یکی از روش‌های زیر بخواهد یک Span اضافه کند، ActiveSpan فعلی را از Scope می‌گیرد، یک Span جدید ایجاد می‌کند و می‌گوید والد آن ActiveSpan حاصل شده است و Span جدید را فعال می‌کند. هنگام فراخوانی سرویس‌های خارجی، دامنه فعال فعلی به آنها منتقل می‌شود و آن سرویس‌ها با اشاره به این بازه، دهانه‌های جدیدی ایجاد می‌کنند.
تمام کارها از طریق نمونه Tracer انجام می شود، اگر مکانیسم DI کار نمی کند، می توانید آن را از طریق مکانیسم DI یا GlobalTracer.get () به عنوان یک متغیر سراسری دریافت کنید. به طور پیش فرض، اگر ردیاب مقداردهی اولیه نشده باشد، NoopTracer برمی گردد که هیچ کاری انجام نمی دهد.
علاوه بر این، محدوده فعلی از طریق ScopeManager از ردیاب به دست می‌آید، یک محدوده جدید از محدوده فعلی با اتصال به دهانه جدید ایجاد می‌شود و سپس Scope ایجاد شده بسته می‌شود، که دهانه ایجاد شده را می‌بندد و Scope قبلی را برمی‌گرداند. حالت فعال Scope به یک رشته گره خورده است، بنابراین هنگام برنامه‌نویسی چند رشته‌ای، نباید فراموش کنید که span فعال را به رشته دیگری برای فعال‌سازی بیشتر محدوده یک رشته دیگر با اشاره به این دهانه منتقل کنید.

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)) {
                ...
            }
        });
    }
}

برای برنامه‌نویسی چند رشته‌ای، TracedExecutorService و پوشش‌های مشابهی نیز وجود دارد که به‌طور خودکار در هنگام راه‌اندازی وظایف ناهمزمان، دامنه فعلی را به رشته ارسال می‌کند:

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

برای درخواست های http خارجی وجود دارد TracingHttpClient

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

مشکلاتی که با آن مواجه بودیم

  • اگر ردیاب در یک سرویس یا جزء استفاده نشود، Beans و DI همیشه کار نمی کنند سیم کشی خودکار Tracer ممکن است کار نکند و باید از GlobalTracer.get استفاده کنید.
  • اگر متد جزء یا سرویس نباشد، یا اگر متد از یک متد همسایه از همان کلاس فراخوانی شود، حاشیه نویسی کار نمی کند. شما باید مراقب باشید که بررسی کنید چه چیزی کار می کند و اگر @Traced کار نمی کند از ایجاد ردیابی دستی استفاده کنید. همچنین می توانید یک کامپایلر اضافی برای حاشیه نویسی های جاوا وصل کنید، سپس آنها باید در همه جا کار کنند.
  • در بوت فنری و فنری قدیمی، پیکربندی خودکار ابر فنری opentraing به دلیل اشکالات در DI کار نمی کند، سپس اگر می خواهید ردپاها در اجزای فنری به طور خودکار کار کنند، می توانید آن را با قیاس با 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
  • سعی با منابع در groovy کار نمی کند، باید در نهایت از try استفاده کنید.
  • هر سرویس باید spring.application.name مخصوص به خود را داشته باشد که تحت آن ردیابی ها ثبت می شود. چه می کند یک نام جداگانه برای فروش و تست، به طوری که با آنها تداخل با هم.
  • اگر از GlobalTracer و tomcat استفاده می‌کنید، همه سرویس‌هایی که در این تامکت اجرا می‌شوند یک GlobalTracer دارند، بنابراین نام سرویس همه آنها یکسان خواهد بود.
  • هنگام اضافه کردن ردیابی به یک متد، باید مطمئن باشید که آن متد بارها در یک حلقه فراخوانی نشده است. لازم است یک ردی مشترک برای همه تماس ها اضافه شود که کل زمان کار را تضمین می کند. در غیر این صورت بار اضافی ایجاد می شود.
  • یک بار در jaeger-ui، درخواست‌های بسیار زیادی برای تعداد زیادی ردیابی انجام شد و از آنجایی که منتظر پاسخ نبودند، دوباره این کار را انجام دادند. در نتیجه، jaeger-query شروع به خوردن مقدار زیادی از حافظه و کاهش سرعت الاستیک کرد. با راه اندازی مجدد jaeger-query کمک شد

نمونه برداری، ذخیره و مشاهده آثار

سه نوع وجود دارد آثار نمونه برداری:

  1. Const که همه ردیابی ها را ارسال و ذخیره می کند.
  2. احتمالاتی که ردیابی ها را با مقداری احتمال مشخص فیلتر می کند.
  3. Ratelimiting که تعداد ردیابی ها در ثانیه را محدود می کند. شما می توانید این تنظیمات را روی کلاینت، چه در jaeger-agent یا در کلکتور، پیکربندی کنید. اکنون ما از const 1 در پشته ارزیابی استفاده می کنیم، زیرا درخواست های زیادی وجود ندارد، اما زمان زیادی می برد. در آینده، اگر این بار بیش از حد بر سیستم وارد شود، می توانید آن را محدود کنید.

اگر از casandra استفاده می کنید، به طور پیش فرض فقط ردیابی را برای دو روز ذخیره می کند. استفاده می کنیم الاستیک و آثار برای همیشه ذخیره می شوند و حذف نمی شوند. یک فهرست جداگانه برای هر روز ایجاد می شود، به عنوان مثال jaeger-service-2019-03-04. در آینده، باید تمیز کردن خودکار آثار قدیمی را پیکربندی کنید.

برای مشاهده ردیابی ها به موارد زیر نیاز دارید:

  • سرویسی را که می‌خواهید با آن ردیابی فیلتر کنید، انتخاب کنید، برای مثال tomcat7-default برای سرویسی که در تامکت در حال اجرا است و نمی‌تواند نام خود را داشته باشد.
  • سپس عملیات، فاصله زمانی و حداقل زمان عملیات را مثلاً از 10 ثانیه انتخاب کنید تا فقط اجراهای طولانی انجام شود.
    ردیابی خدمات، OpenTracing و Jaeger
  • به یکی از ردپاها بروید و ببینید چه چیزی در آنجا کم شده است.
    ردیابی خدمات، OpenTracing و Jaeger

همچنین، اگر شناسه درخواستی شناخته شده باشد، در صورتی که این شناسه در بازه ردیابی ثبت شده باشد، می‌توانید از طریق جستجوی برچسب، یک ردیابی توسط این شناسه پیدا کنید.

اسناد

مقالات

تصویری

منبع: www.habr.com

اضافه کردن نظر