درخواست ردیابی در Node.js – انجمن DEV

ضرب المثلی وجود دارد که می گوید توسعه دهندگان نرم افزار مانند ما 90 درصد از زمان خود را صرف رفع اشکال می کنند و تنها 10 درصد از زمان ما را در واقع برای نوشتن کد می گذارند. این کمی اغراق آمیز است! درست است که اشکال زدایی بخش مهمی از کار ما است، به خصوص در این عصر معماری میکروسرویس ها. امروزه برای ما غیرعادی نیست که صدها – حتی هزاران – میکروسرویس را به طور همزمان در سرورهای تولیدی خود داشته باشیم.
به طور سنتی، وقتی صحبت از اشکال زدایی مشکلات نرم افزاری به میان می آید، به گزارش ها تکیه می کنیم. با این حال، همه گزارش ها مفید نیستند. آنها می توانند نامشخص باشند، به عنوان مثال، فقط کد وضعیت خطا را نشان می دهند یا یک خطای عمومی را نشان می دهند، مانند “مشکلی پیش آمد.” حتی اگر گزارش یک خطای خاص تری را ثبت کند – مانند “شناسه درخواست کاربر نامعتبر است” با یک خطای درخواست بد “400” – به دلیل تعداد زیاد، ممکن است ساعت ها یا روزها طول بکشد تا علت اصلی مشکل را بفهمیم. خدمات درگیر اینجاست که ردیابی درخواست وارد عمل می شود.
با اعمال ردیابی درخواست در برنامه Node.js، میتوانیم جریان خطای مشکلساز را که به صورت بصری نمایش داده میشود، ببینیم. این به ما کمک میکند تا مشخص کنیم کدام سرویسها ممکن است در این خطا دخیل باشند و به سرعت علت اصلی مشکل را پیدا کنیم. در این مقاله، ردیابی درخواست را تعریف میکنیم، اهمیت آن را بررسی میکنیم و چگونگی اعمال موثر ردیابی درخواست را در برنامه Node.js بررسی میکنیم.
ردیابی درخواست چیست؟
ردیابی درخواست به تکنیک یافتن درخواستهای فرعی از سرویسهای متعددی اشاره دارد که هنگام انجام یک درخواست راهاندازی میشوند. در معماری میکروسرویس ها، به ویژه در یک برنامه کاربردی توزیع شده، یک سرویس اغلب نیاز به یکپارچه سازی با سایر سرویس ها، پایگاه های داده یا وابستگی های شخص ثالث دارد. در نتیجه، هنگامی که یک درخواست اجرا می شود، درخواست های داخلی نیز راه اندازی می شوند.
چرا ما به درخواست ردیابی نیاز داریم
برای رفع اشکال یک خطا، باید بدانیم درخواستی که خطا را ایجاد کرده است چگونه ایجاد می شود. سیاههها به تنهایی کافی نیستند. آنها فقط به ما می گویند که کدام نوع خطا رخ داده است، اما زمینه مشکل را به ما نمی گویند.
از طرف دیگر Traces درخواست های اجرا شده در یک درخواست والد را به ما نشان می دهد. همچنین می توانیم درخواستی را که بلافاصله قبل از درخواست والدین انجام شده است، ببینیم. به طور خلاصه، ردیابی درخواست یک نمای کلی از روند درخواست را در اختیار ما قرار می دهد. با ترکیب ردیابی ها با لاگ ها، می توانیم علت اصلی مشکل را شناسایی کنیم. علاوه بر این، ردیابی زمان اشکالزدایی ما را کاهش میدهد، زیرا به برجسته کردن منشأ واقعی یک مسئله به روشی ساده و سریع با عبور از آبشارهای خطای گزارش کمک میکند.
یک درخواست درخواست
سلام توسعه دهنده، در حالی که شما در حال مطالعه در مورد ردیابی درخواست هستید، ما یک درخواست از شما داریم… ما دوست داریم یک ستاره از شما در GitHub for Amplication دریافت کنیم. آن را بهعنوان یک امتیاز بالای پنج مجازی در نظر بگیرید که باعث میشود قلب توسعهدهندگان ما از بین برود. بعلاوه، وقتی به 10000 ستاره رسیدیم، به تیم قول یک مهمانی پیتزا داده ام. بنابراین، اگر میخواهید چند توسعهدهنده هیجانزده با سس گوجهفرنگی روی صورتشان ببینید، یک 🌟 در GitHub به ما بدهید!
لطفا ما را مانند یک تماس بدون قول معلق نگذارید! بنابراین روی دکمه ستاره درخشان کلیک کنید و مقداری عشق Amplication را پخش کنید.
ردیابی درخواست چگونه کار می کند
هنگامی که یک کاربر اقدامی را انجام می دهد – برای مثال، کلیک کردن روی دکمه “تأیید” برای خرید یک کفش از یک فروشگاه تجارت الکترونیکی – چندین درخواست اجرا می شود. ابتدا، پس از کلیک کاربر روی “تأیید”، یک ردیابی جدید ایجاد می شود. سپس یک فاصله والد فعال خواهد شد. در داخل گستره والد، ممکن است یک درخواست API برای بررسی اصالت کاربر و یک API دیگر برای تأیید اینکه آیا کاربر مجوز انجام پرداخت را دارد وجود داشته باشد. درخواستهای API اضافی نیز میتوانند اجرا شوند، مانند بررسی تعداد کفشهای موجود در انبار، یا تأیید اینکه موجودی کاربر به اندازه کافی برای پرداخت بالا است.
همه این درخواستها ثبت میشوند و در محدوده والد گنجانده میشوند. در نتیجه، میتوانیم ببینیم که چگونه این درخواستها با یکدیگر مرتبط هستند، و اگر درخواستی با شکست مواجه شد، میتوانیم بگوییم چه اتفاقی افتاده است که ممکن است به عنوان یک محرک عمل کرده باشد.
نحوه پیاده سازی ردیابی درخواست برای برنامه های Node.js.
برای پیاده سازی ردیابی درخواست برای برنامه Node.js، باید برای هر درخواست در سرویس فعلی یک شناسه درخواست منحصر به فرد اختصاص دهیم تا به سرویس های دیگر ارسال شود. در نتیجه، میتوانیم از این شناسه برای ردیابی و تجسم درخواستها در معماری سیستم خود و شناسایی علت اصلی خرابی استفاده کنیم.
ابزارهای رایجی که از ردیابی درخواست پشتیبانی می کنند
تعدادی از ابزارهای پشتیبان مشاهدهپذیری منبع باز مانند Jaeger، Zipkin و Signoz وجود دارد که از ذخیره و تجسم ردیابیهای درخواست پشتیبانی میکنند. پیش از این، دو استاندارد محبوب برای قالب ردیابی وجود داشت: OpenTracing و OpenCensus. ابزارها اغلب فقط از یکی یا دیگری پشتیبانی میکنند، و ادغام برنامههای نرمافزاری با ابزارهای مورد نیازشان را به چالشی تبدیل میکنند. خوشبختانه، OpenTracing و OpenCensus در سال 2019 در OpenTelemetry متحد شدند و به توسعه دهندگان نرم افزار اجازه دادند تا ردیابی درخواست را با سهولت نسبی پیاده سازی کنند.
OpenTelemetry مجموعهای از ابزارها است که میتوانند ردیابیها را تجسم کنند، دادههای مربوط به زمان صرف شده برای پردازش هر درخواست را جمعآوری کنند، و درخواستها را به صورت بازههای جداگانه در ردیابی ثبت کنند. برای اینکه ابزارهای مشاهدهپذیری مختلف بتوانند ردیابی را تجسم کنند، برنامهها باید از قالبهای OpenTelemetry پیروی کنند.
ردیابی درخواست را به عنوان یک میان افزار پیاده سازی کنید
فرض کنید برنامهای داریم که به کاربران امکان میدهد پستهای وبلاگی برای بررسی فیلمها ایجاد کنند. این برنامه API هایی را برای کاربران فراهم می کند تا بتوانند یک حساب کاربری ایجاد کنند، وارد شوند و پست های وبلاگ جدید ایجاد کنند.
ما از OpenTelemetry برای اعمال ردیابی درخواست برای برنامه استفاده خواهیم کرد. سپس آثار به Jaeger ارسال خواهد شد. برنامه ما از MongoDB به عنوان پایگاه داده و Express به عنوان وب سرور استفاده می کند. ما باید وابستگی های زیر را نصب کنیم تا OpenTelemetry به درخواست API ردیابی کند.
npm install --save @opentelemetry/api
npm install --save @opentelemetry/sdk-trace-node
npm install --save opentelemetry-instrumentation-express
npm install --save @opentelemetry/instrumentation-mongodb
npm install --save @opentelemetry/instrumentation-http
همچنین باید وابستگی Jaeger را برای ارسال ردیابی OpenTelemetry به Jaeger نصب کنیم تا بتوانیم ردیابی ها را بعداً از طریق صفحه رابط کاربری گرافیکی Jaeger مشاهده کنیم.
npm install --save @opentelemetry/exporter-jaeger
برای پیاده سازی درخواست ردیابی به عنوان یک میان افزار، اجازه دهید یک فایل جدید در دایرکتوری ریشه پروژه به نام tracing.js ایجاد کنیم. کد زیر را در فایل کپی کنید:
const { Resource } = require("@opentelemetry/resources");
const { SemanticResourceAttributes } = require("@opentelemetry/semantic-conventions");
const { SimpleSpanProcessor } = require("@opentelemetry/sdk-trace-base");
const { NodeTracerProvider } = require("@opentelemetry/sdk-trace-node");
const { trace } = require("@opentelemetry/api");
//exporter
const { JaegerExporter } = require("@opentelemetry/exporter-jaeger");
//instrumentations
const { ExpressInstrumentation } = require("opentelemetry-instrumentation-express");
const { MongoDBInstrumentation } = require("@opentelemetry/instrumentation-mongodb");
const { HttpInstrumentation } = require("@opentelemetry/instrumentation-http");
const { registerInstrumentations } = require("@opentelemetry/instrumentation");
//Exporter
module.exports = (serviceName) => {
const exporter = new JaegerExporter({
endpoint: "http://localhost:14268/api/traces",
});
const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: serviceName,
}),
});
provider.addSpanProcessor(new SimpleSpanProcessor(exporter));
provider.register();
registerInstrumentations({
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
new MongoDBInstrumentation(),
],
tracerProvider: provider,
});
return trace.getTracer(serviceName);
};
در کد، ابزار دقیق برنامه را ثبت میکنیم تا ردیابیهایی را به درخواستهای MongoDB، درخواستهای سرور Express و درخواستهای HTTP الصاق کنیم:
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation(),
new MongoDBInstrumentation(),
]
ردیابی ها به نقطه پایانی Jaeger ارسال می شوند: http://localhost:14268/api/traces
.
همچنین باید یک خط کد را به فایل ورودی برنامه اضافه کنیم تا بتوانیم OpenTelemetry را برای ارسال آثار به برنامه فعال کنیم:
const tracer = require("./tracing")("blog-movie-review-service");
قبل از اینکه برنامه خود را برای بررسی ردیابی های درخواست شروع کنیم، باید سرویس Jaeger را برای ذخیره ردیابی ها باز کنیم. دستور زیر را برای راه اندازی سرویس Jaeger با استفاده از Docker اجرا کنید:
docker run -d --name jaeger \
-e COLLECTOR_ZIPKIN_HOST_PORT=:9411 \
-p 5775:5775/udp \
-p 6831:6831/udp \
-p 6832:6832/udp \
-p 5778:5778 \
-p 16686:16686 \
-p 14250:14250 \
-p 14268:14268 \
-p 14269:14269 \
-p 9411:9411 \
jaegertracing/all-in-one:1.32
بیایید برنامه را بالا بیاوریم و سپس به صفحه Jaeger GUI برویم تا ردهای ثبت شده را ببینیم.
شکل 1: ردیابی های گرفته شده در صفحه Jager GUI نشان داده شده است
می بینیم که ردیابی ها توسط OpenTelemetry گرفته شده اند و در Jaeger ذخیره می شوند. برای بررسی ردیابی مربوط به درخواست API برای ایجاد یک پست وبلاگ جدید، روی اولین ردیابی (شکل 1) کلیک کنید تا جزئیات ظاهر شوند (شکل 2).
شکل 2: جزئیات مربوط به ردیابی درخواست موفقیت برای ایجاد یک پست جدید
در اینجا، میتوانیم ببینیم که در داخل ردیابی، دهانههایی برای درخواست HTTP (POST /v1/posts) و درخواست MongoDB (mongodb.insert) وجود دارد.
بیایید ببینیم زمانی که یک authorId نامعتبر برای پست ارائه می کنیم، یک درخواست API ناموفق چگونه به نظر می رسد:
شکل 3: جزئیات مربوط به ردیابی درخواست ناموفق برای ایجاد یک پست جدید
در اینجا، میبینیم که درخواست API نتوانست درخواست HTTP ایجاد کند زیرا برنامه در حال تأیید اعتبار authorId است و هیچ درخواستی برای درج پست وبلاگ به MongoDB ارسال نشده است.
با اعمال ردیابی درخواست در برنامه ما، میتوانیم به راحتی برنامه را اشکال زدایی کنیم و کشف کنیم که در کدام مرحله از درخواست API مشکل ایجاد میشود.
بهترین روش ها برای ردیابی درخواست
همانطور که دیدیم، اعمال ردیابی درخواست برای یک برنامه Node.js ما را قادر می سازد تا مسائل نرم افزاری را به سرعت و به طور موثر بررسی کنیم. برای دستیابی به نتایج بهینه ردیابی درخواست، باید سه روش اصلی را هنگام اعمال ردیابی درخواست برای برنامه خود دنبال کنیم.
1. فرمت های استاندارد OpenTelemetry را دنبال کنید
پیروی از فرمتهای استاندارد OpenTelemetry به ابزارهای دیگری که میتوانند با OpenTelemetry ادغام شوند (مانند Zipkin، Jaeger یا Prometheus) اجازه میدهد تا آثار را به طور موثر ذخیره و تجسم کنند. ما میتوانیم ابزاری را انتخاب کنیم که با نیازهای خاص ما مطابقت داشته باشد، مثلاً برای دستیابی به تجسم بهتر بدون اعمال یک قالب جدید ردیابی.
2. برای هر منبع یک رشته منحصر به فرد انتخاب کنید
انتخاب یک رشته منحصر به فرد برای هر منبع به ما امکان می دهد تا مشکل نرم افزار را به سرعت بر اساس رشته منحصر به فرد ردیابی کنیم. فرض کنید می خواهیم درخواست API ناموفق را برای ایجاد یک پست وبلاگ جدید در برنامه آزمایشی ردیابی کنیم. از لاگ برنامه، شناسه ردیابی یکتای مورد استفاده برای درخواست API را به دست آوردیم. ما میتوانیم شناسه ردیابی منحصربهفرد را بگیریم و Jaeger را جستجو کنیم تا تصویر کاملی از اشتباه رخ داده به دست آوریم.
3. نام Span مناسب را انتخاب کنید
انتخاب نام span که با نام متد فراخوانی شده توسط span مطابقت داشته باشد به ما امکان می دهد بفهمیم در زمان بروز مشکل در برنامه چه اتفاقی می افتد. همچنین باید یک تگ span سفارشی برای حفظ ردیابی اضافه کنیم. این ما را قادر میسازد بهجای یافتن شناسه ردیابی و جستجوی آن، مستقیماً برچسب سفارشی را جستجو کنیم.
به عنوان مثال، ما می توانیم یک تگ span سفارشی برای ردیابی مربوط به ایجاد یک پست وبلاگ جدید اضافه کنیم. هنگامی که ما نیاز به بررسی یک موضوع مربوط به ایجاد پست های وبلاگ داریم، می توانیم از تگ span سفارشی استفاده کنیم و تمام ردپای ایجاد پست های نقد فیلم جدید بلافاصله نمایش داده می شود.
نتیجه
در دنیای نرم افزارهای توزیع شده و معماری میکروسرویس، یک گزارش برنامه به تنهایی برای اشکال زدایی در هنگام بروز مشکل کافی نیست. برای دستیابی به قابلیت مشاهده به طوری که بتوانیم مشکلات نرم افزاری را به سرعت اشکال زدایی کنیم، باید ردیابی درخواست را در برنامه Node.js خود پیاده سازی کنیم. قالب استاندارد ردیابی OpenTelemetry دستیابی به قابلیت ردیابی را آسان می کند، زیرا ما می توانیم به سادگی از یکی از ابزارهای متعددی که به راحتی در دسترس است برای کمک به فرآیند ردیابی درخواست استفاده کنیم.