ابزاری به نام Jaeger برای بهتر دیدن خطاها در معماری ماکروسرویس و استفاده از آن در Spring boot 3.0

مقدمهتوی خیلی از پروژه های مایکروسرویس، برای هر عملیاتی که در پشت صحنه هر درخواست وبی وجود داره، ممکنه بخوایم بدونیم اون درخواست چطور، با چه پارامترهایی، در چه مدت زمانی و غیره داره انجام میشه یا زنجیره ای از عملیات های مختلف رو داریم و میخوایم بدونیم به تفکیک هر کدوم چه جزییاتی دارن. مثلا در نظر بگیرید یه معماری دارید به شکل زیر:نمونه معماری microservice به صورت چند لایههمونطور که توی تصویر بالا میبینید، ما 3 تا مایکروسرویس داریم که مایکروسرویس name-generator-service به دو سرویس دیگه درخواست ارسال میکنه. حالا برای اینکه بتونیم بهتر و سریعتر اشکال زدایی کنیم، نیاز به این داریم که یه سری لاگ بگذاریم. ممکنه مشکلات عدم دسترسی در شبکه و ارتباط بین مایکروسرویس ها یا کندی اونها باشه. حالا اگه هر سیستمی لاگ های خودش رو داشته باشه، پیدا کردن و مدیریت اونها سخت میشه. ابزارهای Distributed tracing به ما کمک میکنند تا بتونیم این مشکل رو رفع کنیم. یکی از این ابزارها Zipkin هستش و دیگری Jaeger که ما میخوایم در این مقاله به اون بپردازیم.معرفی Jaegerحالا که متوجه شدیم distributed tracing ها در معماری ماکروسرویس چه نقشی رو بازی میکنن، بریم سراغ معرفی Jaeger tracing.کلمه Jaeger در زبان آلمانی به معنای مبارز و معادل Hunter در زبان انگلیسی هستش و به عنوان یک ابزار متن باز توسط شرکت Uber معرفی شده.مدل داده ای که در Jaeger وجود داره سازگار با الگوی داده ای OpenTracing هستش. یک استاندارد برای Tracingها که ابزارهای مختلف بتونن با هم سازگاری بیشتری داشته باشن و مهاجرت از یه ابزار به ابزار دیگه راحت تر باشه. برای اطلاعات بیشتر به سایت The OpenTracing project مراجعه کنید.نکته: امروز که دارم این مقاله رو می نویسم پروژه OpenTracing داره منقضی میشه و جاش رو به OpenTelementry میده. در آینده از OpenTelementry براتون مینویسم. این موضوع ربطی به Jaeger نداره و این ابزار با هر دو پروتکل یا الگوی داده ای، سازگار هستش.پیاده سازی Jaeger Tracing در Spring boot 3.0ما فرض رو میگذاریم روی اینکه شما از ابزار Intellij Idea Ultimate استفاده نمی کنی و فقط دسترسی https://start.spring.io برای ایجاد پروژه Spring Boot داری. dependency یا ماژول وابسته "Spring Web" رو اضافه کنید کافیه. روی دکمه Generate کلیک کنید و کد رو دانلود کنید.اگر از Spring boot 2 به بالا استفاده می کنید وابسته زیر برای Maven کافیه: https://gist.github.com/m-tilab/f35e92525f700c323b6ff982b06c1ad0 اما اگه از Spring boot 3 به بالا استفاده میکنید، در نظر داشته باشید که با توجه به اینکه این وابسته بروز نشده نیاز دارید تا مجبور کنید ابزار build رو تا از نسخه قدیمی تر reactor-core استفاده کنه.پس برای Spring boot 3 در Maven به صورت زیر میشه: https://gist.github.com/m-tilab/798c1e96cf692c656d81e51e559ac6f8 یا معادلش در Gradle به صورت زیر هستش:https://gist.github.com/m-tilab/01643098626121544ebd6c7969194b5fدر کد بالا یاد گرفتیم که چطور از یک نسخه خاصی از یک ماژول زیر وابسته (sub-dependency) استفاده کنیم.در مرحله بعد یک کنترلر ایجاد میکنیم:https://gist.github.com/m-tilab/d769719c10b2f1ae4b03a6ec341e8061همونطور که میبینید دو مسیر به آدرس های /path1 و /path2 داریم که میتونیم این اپلیکیشن رو با دو پورت مختلف یکی با 8080 و دیگری با 8090 استارت کنیم و دو تا instance ازش داشته باشیم که /path1 در instance1 با استفاده از RestTemplate مسیر /path2 رو در instance2 فراخوانی کرده.تعریف spanهر span شامل نام عملیات، زمان شروع و مدت هستش. span ها میتونن زیر مجموعه داشته باشن. مثلا خرید از یک فروشگاه اینترنتی رو در نظر بگیرید، API که خرید رو نهایی میکنه بایستی دو عملیات انجام بده یکی نهایی سازی وضعیت خرید و دوم کم کردن موجودی کالا از انبار، پس ما برای کل متد یه span داریم که شامل دو زیر span که هر کدوم عملیات خودشون رو دارند.گام بعدی میریم سراغ راه اندازی خود Jaeger با استفاده از docker-compose: https://gist.github.com/m-tilab/c4ba0592f685ba78c724dcd4c8e2d816 ما میتونیم از Jaeger روی پروتکل های UDP و TCP استفاده کنیم. به صورت پیش فرض پنل ادمین Jaeger روی پورت 16686 هستش پس میتونید با آدرس http://localhost:16686/ بهش دسترسی داشته باشید.گام بعدی اتصال اپلیکیشن Spring boot به Jaeger هستش که به صورت زیر در application.yml بایستی تنظیم بشه:https://gist.github.com/m-tilab/5636f0619cbc2a46e74887c096896fc5حالا بریم برای تست دو اپلیکیشن رو بالا میاریم:https://gist.github.com/m-tilab/4d0ba6e2bd185f6a8675802c58246ecaحالا میتونیم با استفاده از CURL آدرس instance1 رو فراخوانی کنیم: curl-ihttp://localhost:8080/service/path1 اگر به کنسول در instance1 نگاه کنیم چیزی شبیه این خواهیم داشت: https://virgool.io/p/c6nugawkzlyh/INFO69938---[nio-8080-exec-1]i.j.internal.reporters.LoggingReporter:Spanreported:ed70bbaa2bd5b42f:c7c94163fc95fc1e:ed70bbaa2bd5b42f:1-GET که شامل سه بخش Root Span Id, Current Span Id, Parent Span Id هستش. حالا اگر به کنسول instance2 نگاه کنیم لاگ زیر رو خواهیم داشت:INFO 69885 --- [nio-8090-exec-1] i.j.internal.reporters.LoggingReporter : Span reported: ed70bbaa2bd5b42f:e9060cb1d5336c55:c7c94163fc95fc1e:1 - path2همونطور که میبینید دو مقدار مشترک بین instance2 و instance1 هستش.در ضمن میتونید موارد بالا رو هم در UI Jaeger هم مشاهده کنید:نمایی از Jaeger UIجمع بندیدر این مقاله سعی شد تا به معرفی ابزار jaeger یکپارچه سازیش با Spring boot اشاره بشه. این ابزار میتونه بهتون برای رفع مشکلات و بررسی کارایی اپلیکیشن شما بهتون کمک کنه.در ضمن میتونید به این صفحه سر بزنید و نمونه پروژه تمامی کدها رو یکجا داشته باشید:m-tilab/springboot3-jaeger-integration (github.com)موفق باشید