<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های میثم | Maysam</title>
        <link>https://virgool.io/feed/@maysampx</link>
        <description>توسعه‌دهنده نرم‌افزار (بلاگ: Pasm.ir)</description>
        <language>fa</language>
        <pubDate>2026-06-21 07:45:41</pubDate>
        <image>
            <url>https://static.virgool.io/images/default-avatar.jpg</url>
            <title>میثم | Maysam</title>
            <link>https://virgool.io/@maysampx</link>
        </image>

                    <item>
                <title>پایش پایگاه‌داده SQL Server با ابزار Query Store</title>
                <link>https://virgool.io/@maysampx/introduction-to-query-store-in-sql-server-ea72zqrnliwc</link>
                <description>برخلاف سر و صدای NoSQLای ها، دیتابیس‌های رابطه‌ای هنوز هم در جایگاه خاص خودشان در صنعت یکه‌تاز اند و سهم قابل توجهی از بازار فنی را در دست دارند؛ به عنوان نمونه در سیستم‌های مالی مثلا در بسترهای ETL مالی و ابزارهای Core banking بخش زیادی از منطق تجاری (business logic) با بهره‌گیری از دیتابیس‌های رابطه‌ای مثل SQL Server، Oracle، MySQL و... در معیّت داده و دیتابیس (DB-centric) مدیریت می‌شود [ حتی به غلط:) ]. یکی از علل مهم گرایش به این دیتابیس‌ها احتمالا «تضمین سازگاری داده‌ای» و به طور کلی فراهم کردن سیستم‌ای مبتنی بر تراکنش (Transaction) هست که سر بزنگاه‌های عملیاتی [به‌ویژه عملیات مالی که ماهیت تراکنشی دارند]، بشه بهش اتکا کرد. این سیستم‌ها (یا دیتابیس‌ها) نوعا وفاداری و تعهد ویژه‌ای به مفاهیم بنیادی جبر رابطه‌ای، جامعیت داده‌ای، اجرای اتمیک و چندین معیار دیگر، ضمن بهره‌گیری [گاهاً] پایین از منابع را دارند. با این مقدمه میخوام بگم دیتابیس‌های این شکلی در کاربردهای خاصی که اهمیت معیارهایی مثل «قابلیت اطمینان - reliability» و «سازگاری - consistency» به نسبت دیگر معیارهای سنجش کارایی [مثل تعداد OPS بالا در عملیات Write در کاربردهای Streaming] بالاست، به طور جدی و البته با چالش‌های نگهداری و Tuning خاص خودشان حضور دارند. به طور کلی این‌ها هم مثل هر سیستمی نیاز به پایش (monitoring) دارند که بفهمیم چه موقع چه «رخدادی» اتفاقی افتاده و در مرتبه بالاتر بتواند به observability سیستم کمک کند تا «علت» اون رخدادها هم برای ما مشخص بشود.قبل از اینکه به جزئیات و ساختار این ابزار بپردازیم، بهتره قصه «اهمیت مساله» را کمی جزئی‌تر تعریف کنیم. موارد زیر عموماً باعث می‌شوند «پایش عملکرد دیتابیس» خودش به صورت مجزا یک «نیازمندی» باشد که برای آن دنبال رهیافت باشیم.تشخیص روندها در رشد داده و عملیات (trendy events)پایش میزان مصرف توان پردازشی در بازه‌های زمانی مشخص با workload های مختلفپایش روند دسترسی به حافظه اصلی و استفاده از آن در workload های مختلفتشخیص رخدادهای CPU-burst و IO-burst کوتاه و گذارا (عموما بدون الگوی ثابت)پایش عملکرد شاخص‌ها (indices)پایش مدت زمان اجرای تراکنش‌ها پیدا کردن گلوگاه‌‌های (bottlenecks) عملیاتی و داده‌ای ساده و چند سطحیپیش‌تر، در این پست (+لینک) در خصوص چند مورد از گلوگاه‌ها (یا تنگناها) نوشته‌ام.پایش میزان Lockهای اتفاق افتاده بر روی رکوردها، صفحات و شاخص‌هاپایش نموداری، به منظور تشخیص Spikeها و استخراج الگوهای معنادارپایش پلن‌های اجرایی (Execution plans) ایجاد شده برای پرس و جوهااستخراج الگوی دسترسی به منابع مختلف توسط یک دیتابیس مشخصتشخیص Deadlockها، keylockها و به طور کلی lockها اتفاق افتادهاستخراج آمار اجرای پرس و جوهاتشخیص پرس و جوها و پلن‌هایی با مساله پارامترسازی (Parameterization problem)و طبیعیتا موارد جزئی دیگراین موارد نه فقط در پایش دیتابیس بلکه در نظارت بر سیستم‌های دیگر نیز نوعا یک «مساله» است. در دیتابیس SQL Server چندین ابزار از جمله SQL Profiler، Activity Monitor و Standard Reportها وجود دارند که اطلاعات خوبی را می‌شود از آن‌ها استخراج کرد و به نوعی بار بخش زیادی از فرآیند پایش را بر دوش می‌کشند. اما در نسخه‌های جدید این دیتابیس (SQL Server 2016 به بعد) ابزار جدیدی به اسم Query Store معرفی شده‌است. این ابزار سعی می‌کند تاریخچه‌ای از اجرای پرس و جوها و پلن‌های اجرایی را جمع‌آوری کند و سپس یک سری گزارش‌ها را تولید کند، به همین علت در ابتدا بهش «Flight data recorder» گفته می‌شد. به‌نظر پایه و اساس این ابزار این صفحه (+لینک) نسبتا قدیمی با پرس و جوهای کاربردی است.تصویر زیر معماری کلی فرآیند Profiling در Query Store را نشان می‌دهد:معماری کلی فرآیند Profiling در Query Store در این طراحی، فرآیند «پایش» به صورت ضمنی و نهان در هر جایی که یک پرس و جو بخواهد اجرا شود حضور دارد، یعنی عمل «پاییدن» خودش یه Cross-cutting requirement در طراحی این ابزار بوده‌است.همانطور که می‌دانید SQL Server یکی از نقاط قوت‌اش بهینه‌ساز پرس و جو و قابلیت‌های حول آن است که [اغلب، نه لزوماً]  سعی می‌کند بهترین پلن اجرایی را برای پرس و جوها تولید بکند (+لینک)، به عبارتی پیش از اجرای هر پرس و جو [در قالب Function یا SP]، دیتابیس یک پلن اجرایی برای آن تولید می‌کند. Query store هم گوش به زنگِ تولید این پلن‌ها (Query plan در نمودار) می‌ایستد و پس از تولید، آن‌را به همراه متن پرس و جو (Query text) در حافظه اصلی تحت عنوان «Query plan and text» نگه می‌دارد. به عنوان یک وظیفه موازی و مجزای دیگر، جزئیات اجرای پرس و جو را نیز تحت عنوان «Query runtime statistics» در حافظه نوشته و بافر می‌کند. این اطلاعات بافر شده‌ در حافظه اصلی، به صورت ناهمگام (Asynchronous) در یک دیتابیس رابطه‌ای ذخیره می‌گردد و در نهایت بر روی دیسک نگه‌داری می‌شود.ابزار Query store از طریق نسخه‌های جدید SSMS در دسترس است و می‌شود با تنظیمات مختلفی از جمله اینکه بازه‌های زمانی برای Profiling، اندازه فایل Logها و مدت زمان نگه‌داری Log ها و... چقدر باشد، آن را پیکربندی (configuration) کرد. +اینجا روند راه اندازی و تنظیمات اولیه به شکل سر راست توضیح داده شده‌است و +اینجا نیز تنظیمات پیشنهادی و برخی نکات مهم ارائه شده است.پس از اینکه این ابزار را پیکربندی کردید، به این دسته‌ از گزارش‌ها دسترسی خواهید داشت:بخش Regressed Queries:پرس و جوهایی که اخیرا کند شده اند؛ به عبارتی پرس و جوهایی که پلن اجرایی شان به‌نسبت پلن‌های تولید شده قبلی وضعیت بدتری پیدا کرده باشند در اینجا دسته‌بندی می‌شوند. معمولا پلن‌ها، در حافظه اصلی Cache می‌شوند، بنابراین Profiler در دوره زمانی تعیین‌شده یا پیش‌فرض، Plan cache را آپدیت کرده و به صورت پلن‌های Regressed گزارش می‌کند.زمانی‌که Workload سیستم بالا برود و کندی محسوس بشود، به صورت تجربی، ما اولین بخشی که در [در زمان رخداد کندی و کمی پس از رفع ‌شدن آن] بررسی می‌کنیم اینجاست. به‌ویژه موقعی‌که سیستم در پیک کاری خود باشد. به عنوان نمونه در سیستم‌های مالی در بازار سرمایه [مثلا سیستم مدیریت سفارشات سهام (OMS)] که بازه زمانی فعالیت محدود و مشخصی دارند [با پیک‌هایی متنوع] و رخدادهایی مثل بازگشایی بازار، تلاش برای headshot کردن سهم‌ها از طرف معامله‌گران، صف‌های خرید و فروش و... که نوعاً به صورت دسته‌ای و رقابتی اتفاق می‌افتند و با عملیات دیگه همبسته اند (Correlated)، این بخش کاربرد جالبی پیدا کرده و کمک می‌کند پرس و جوهای کند آشکار بشوند، اتفاقی که در اجرای منفرد و مجزای اون پرس و جو، در وضعیت بار کم، دیده نمی‌شده.بخش Overall Resource Consumption:میزان مصرف منابع مختلف منطقی و فیزیکی را در یک بازه زمانی مشخصی (به‌طور پیش‌فرض یک ماه گذشته) نشان می‌دهد. در واقع این بخش تجمیع داده‌های «Query runtime statistics» است که در معماری Profiling در تصویر اول پیداست. این گزارش در 4 معیار کلی زیر و به صورت نمودار میله‌ای نشان داده می‌شود: مدت زمان اجرا به میلی‌ثانیه (Duration)تعداد اجرای پرس و جوها (Execution count)زمان اختصاص داده‌شده پردازنده به میلی‌ثانیه (CPU time)حجم داده‌های خواندن منطقی (Logical reads in KB)به ازای هر بازه زمانی (هر روز)، در هر 4 معیار بالا، جزئیات آمده در تصویر زیر ارائه می‌شود. هر کدام از این فیلدها به‌طرز جالبی، ‌می‌تواند سودمند باشد. مثلا با مقایسه Logical reads و Logical writes میشه یک نسبتی از میزان داده‌های نوشتنی - خواندنی به دست آورد (Write intensive vs. Read intensive بودن پرس و جوها)، یا به عنوان یه نمونه دیگر نسبت دسترسی به دیسک را در مقایسه با تعداد Logical reads سنجید. یه مورد جالب دیگر مقداری است که برای «Temp DB Memory Used in KB» گزارش می‌کند؛ به شکل تجربی می‌تواند راهگشا باشد، به عنوان نمونه دیتابیسی را فرض کنید که با تعداد زیادی Table-valued function و SP دارد به‌اصطلاح کار می‌کند و متغیرهای Temp جدولی متنوعی هم داخل هر کدام تعریف شده است، این مقدار یک دیدی می‌دهد و میزان مصرف Temp DB توسط دیتابیس فعلی را در بازه مشخص گزارش می‌کند.این گزارش‌ها به طور کلی برای بررسی‌های دوره‌ای گزینه مناسبی است؛ مثلا می‌شود پنجره زمانی را به اندازه بازه‌های بین releaseها تنظیم کرد و تاثیر بهبودها و تغییرات را سنجید.بخش Top Resource Consuming Queries:این گزارش نیز یکی از کاربردی‌ترین گزارش‌های Query Store هست. به ازای تمامی فیلد [یا سنجه]هایی که در گزارش قبلی [همین تصویر بالایی] ملاحظه کردید، گزارش جزیی و مقایسه‌ای می‌دهد که شامل موارد زیر است:پلن‌های اجرایی ایجاد شده به همراه نمودار عملکرد هر کدام (Plan summary)نمودار میله‌ای نزولی از پرس و جوها با توجه به سنجه انتخاب‌شده (مثلا Duration)جزئیات هر پلن اجرایی (شامل هزینه اجرایی هر بخش از پرس و جو)نکته جالب این گزارش، در اینه که اساساً خود سنجه‌ها را یک Resource می‌بیند و پرس و جوهایی با بیشترین میزان از آن سنجه را به عنوان پرس و جوی پر هزینه تشخیص می‌دهد. مثلا در سنجه Execution Count که تعداد اجرای هر پرس و جو را گزارش می‌کند، چندتا مورد زیر را می‌شود استنتاج کرد:مقایسه تعداد اجرای پرس و جوها و به دست آوردن یک تناسب بین درخواست‌های APP و اجراهای دیتابیس [جهت تصدیق تعداد درخواست‌ها در APP-side و DB-side].تشخیص رفتار نادرست در APP وقتی یک پرس و جوی متناظر با آن، با انحراف معیار بالاتری نسبت به بقیه اجرا گردد.تشخیص تعداد اجرای بالای پرس و جو و انجام فرآیند بهینه‌سازی با هدف معین، از جمله Index گذاری مناسب و استفاده از Memory-optimized tables و موارد دیگر.یا در سنجه CPU time به راحتی می‌توان پرس و جوهای CPU-bound یا هر پرس و جویی با بیشترین تقاضای توان پردازشی را تشخیص داد. این سنجه به نوعی در مورد طراحی سرویس و بحث‌های تجاری هم می‌تواند به طراح فنی و تجاری محصول دید بدهد، به عنوان نمونه در طراحی API، میزان منابع مصرفی و پیش‌بینی در خصوص بحث‌های مطرح در SLA می‌تواند مفید باشد؛ منظورم به طور کلی دیدگرفتن هست و قطعا نمی‌تواند ملاک اصلی در  سنجش کارایی در هر کاربردی باشد.در سنجه Physical reads، ممکن است موارد زیر به چشم بیاید:عملکرد Indexها در سطح دیسک (مثلا هزینه به‌روزرسانی Clustered indexها)ارزیابی کارایی Indexها در پلن‌های تولید شدهمقایسه پلن‌های تولیدشده و امکان Force کردن پلن‌ای که بهینه‌تر عمل کرده است.بررسی عملکرد Pageها و Partitionهابررسی انواع رویکردهای پیمایش شاخص‌ها و جدول‌ها (از جمله Index Seek، Index and table Scan، Key lookup و موارد مرتبط دیگر)در سنجه Wait time، عموماً پرس و جوهای با «تعداد اجرای کم و کندی بالا»، و یا پرس و جوهای با «تعداد اجرای بالا و کندی محسوس» را به راحتی می‌توان تشخیص داد.در این  بخش نیز مشابه موارد قبلی می‌توان یک پلن اجرایی نسبت به پلن‌های دیگر ترجیح داد و به لیست Forced planها اضافه کرد.بخش Queries With Forced Plans:در این قسمت پلن‌هایی که برای پرس و جوهای مختلف به عنوان پلن Forced انتخاب شده است، آورده می‌شود. در  این تصویر، یک نمونه از Forced planهایی که پیش‌تر Force کردم را آوردم، ملاحظه می‌کنید که به ازای یک پرس و جو، 9 پلن اجرایی توسط SQL Server تشخیص داده شده است که بر اساس شاخص Avg Duration، پلن اجرایی با شناسه «15809» را به عنوان پلن بهتر، به صورت Forced انتخاب کرده‌ام.یکی از قابلیت‌های جالبی که این بخش ارائه می‌دهد همین امکان مقایسه بین پلن‌های مختلف در مقایسه با پلنی است که Force شده است. به عبارتی در طول زمان می‌توان سنجید که آیا پلن Forceشده کارایی مطلوب را دارد یا خیر؟علاوه بر این موارد، به ازای هر پلن Forceشده چندین مشخصه را هم گزارش می‌کند که می‌تواند به طراح پایگاه‌داده و بهنیه‌ساز دید دقیقی بدهد، از جمله موارد زیر:تعداد شکست در Force کردن پلن این مورد به نظرم خیلی مهم است. ممکن است شما پیش از اعمال تغییراتی، مثلا حذف یا افزودن یک Index، یک پلن را force کرده باشید، سپس Indexای که در پلن مورد نظر تاثیرگذار بود حذف کنید، بنابراین پلن دیگر مثل سابق compile نخواهد شد و در نتیجه force کردن آن هم عملا با شکست (failure) روبرو خواهد شد.آخرین زمانی که پلن انتخاب‌شده compile شده استآخرین زمان اجرای پرس و جوآخرین زمان اجرای پرس و جو با پلن forceشدهبخش Queries With High Variation:یکی از بخش‌های جذاب Query store همین نوع گزارش است. در این قسمت پرس و جوهایی که روند اجرایی آن‌ها الگوی پایداری نداشته باشد، گزارش‌شده و دسته‌بندی می‌شوند. به عنوان نمونه یک پرس و جو ممکن است بر مبنای سنجه‌های مختلف ارزیابی کارایی، گاهی کند و گاهی بهتر عمل کند و این روند به صورت نوسانی بدون الگوی خاصی ادامه پیدا کند که با احتمال بالایی در این بخش گزارش خواهد شد.عموما در پایگاه داده SQL Server پرس و جوهایی که مشکل parameterization [جاگذاری مقادیر literal با متغیرهای placeholder به منظور پیش‌گیری از ایجاد چندین پلن تکراری برای یک پرس و جوی یکسان] را داشته باشند، در این قسمت مشاهده می‌شود. به عنوان نمونه مطابق آن‌چه در نمودار بالایی ملاحظه می‌کنید، با انتخاب سنجه CPU Time و زیرسنجه‌ی انحراف معیار، پرس و جویی که از نظر زمان اجرایی و توان پردازشی در بازه زمانی داده‌شده رفتار متفاوتی داشته باشد، به‌طرز خوبی تفکیک می‌شود. برای بررسی بهتر می‌توان در زمان پیک کاری سامانه بازه زمانی Profiling را محدود به مقدار مشخصی کرد تا عملکرد پرس و جوها در قالب پنجره‌های زمانی مختلف سنجیده شود.در خصوص مساله Parametrization در SQL Server اینجا (+لینک) به‌شکل خوبی صحبت شده‌است.بخش Query Wait Statistics:در این قسمت از جنبه‌های مختلفی از جمله حافظه (memory)، پردازنده (CPU)، IO شبکه (Network IO)، قفل‌ها (Locks) و...، پرس‌ و جوهای Wait شده برای دریافت منابع را می‌توان دید.یکی از جذابیت‌های این بخش، گزارش سرراست بن‌بست‌ (Deadlock)ها است. برحسب تجربه‌، با گرفتن گزارش زیر پرس و جوهایی که بیشترین میزان Wait را در دسته Lock داشته باشند، با احتمال بالایی دچار بن‌بست از نوع به‌خصوصی [مثلا Keylock یا Page lock یا Row lock] شده اند.Query Wait Statistics ---&gt; Lock ---&gt; Based on &quot;max wait time&quot;برای نمونه در تصویر زیر یک گزارش از دیتابیسی با منطق تجاری نسبتا پیچیده در حوزه مالی را آورده ام.در این نمودار، سه پرس و جو که زمان Wait یکسانی دارند، دقیقا سه SP و Functionای هستند که بر روی یک کلید اصلی (Primary clustered index) و یک کلید کاور تعریف‌شده (Non-clustered covered index) به مساله keylock برخورده اند.البته برای پیداکردن بن‌بست‌ها بهتر است از Extended Eventها که کاملا منطبق بر این مساله اند استفاده بشود. با این حال گزارش‌های این بخش نیز می‌تواند کاربردی باشد.صحبت پایانی:در کل، زمانی‌که بخشی از منطق تجاری نسبتاً پیچیده‌ای را به دیتابیس انتقال داده‌باشید و یا حتی سمت APP هندل کرده باشید اما نهایتاً دیتابیس در تیررس درخواست‌های متنوع با نرخ اجرای بالا قرار گیرد، و از طرفی مشکلات کارایی و کندی پیش بیاید بدون اینکه دقیقا بدانید این موارد از کدامین بخش ناشی شده‌است، این ابزار به‌طرز شگفت‌انگیزی به کارتان خواهد آمد. در حقیقت ما وقتی سراغ این ابزار رفتیم که ابزارهای دیگر مثل Activity monitor، SQL Profiler و... یا جزئیات کمتری را گزارش می‌کردند و یا اینکه UI خوبی برای Visualization جزئیات نداشتند. بنابراین پیدا کردن سرنخ تعدادی از مشکلات مرتبط با کارایی، Indexها و... بدون Query Store دشوار بود.</description>
                <category>میثم | Maysam</category>
                <author>میثم | Maysam</author>
                <pubDate>Sat, 08 May 2021 18:51:29 +0430</pubDate>
            </item>
                    <item>
                <title>اندر باب «گلوگاه - Bottleneck»‌ در سیستم‌های نرم‌افزاری - بخش نخست</title>
                <link>https://virgool.io/@maysampx/%D8%A8%D8%B1%D8%B1%D8%B3%DB%8C-%DA%86%D9%86%D8%AF-%DA%AF%D9%84%D9%88%DA%AF%D8%A7%D9%87-%D8%AF%D8%B1-%D8%B3%DB%8C%D8%B3%D8%AA%D9%85-%D9%87%D8%A7%DB%8C-%D9%86%D8%B1%D9%85-%D8%A7%D9%81%D8%B2%D8%A7%D8%B1%DB%8C-%D8%A8%D8%AE%D8%B4-%D9%86%D8%AE%D8%B3%D8%AA-brdd5sgg7wg5</link>
                <description>در خصوص این عکس و مفهوم فنی «گلوگاه» می‌توان ساعت‌ها در کُنجی نشست و از «زیبایی» نوشت.عکاس : فرید کامران‌نیاراهبری یک سیستم نرم‌افزاری و مساله «گلوگاه - bottleneck» مشابه داستان این عکس هست [همین تصویر محض]، همچون گَله‌ای با چند ده یا چند صد راس چارپای داده‌ای و عملیاتی که عموماً نیاز به هدایت‌گری دارند، و شبانی، به دنبال هدایت آن‌ها از روی گذرگاه‌هایی در بستری [با تاب و توانی محدود] است. کارایی نوعاً لفظی‌ست که اغلب در مواجهه با همین محدودیت‌ها معنادار می‌شود. منابع هم که در اغلب سیستم‌ها، محدود به یک میزان مشخصی است و همین مساله در سیستم‌های نرم‌فزاری نیز از جنبه‌های مختلفی مثل دیسک، پردازنده، حافظه اصلی و باقی موارد برقرار است [البته در سطح سخت‌افزار و... نیز قطعا وجود دارد، اینجا صرفا تاکید بر جنبه‌های نرم‌افزاری است]. طبیعتاً در یک سیستم نرم‌افزاری نیز، به طور کلی، هر مولفه (component)ای که کارایی کل سیستم یا بخش مهمی [زیر سیستمی - sub system] از آن را به صورت لحظه‌ای یا مداوم محدود کند، گلوگاه گفته می‌شود. به عنوان نمونه یک سیستم حسابداری نسبتا بزرگی را متصور شوید که از هسته پردازشی قدرتمندی برای محاسبه جزئیات کارمزدها، مالیات، بیمه و هر قاعده پیچیده و دهن پرکن دیگری برخوردار باشد اما کارایی آن توسط زیر سیستم گزارش‌گیری [با عملیات نسبتا ساده] برای کاربران، ضمن برخورداری از منابع زیرساختی بالا با بهره‌گیری (utilization) پایین محدود شود. از این قصه‌گویی که بگذریم در ادامه در مورد چند نوع مرسوم از این گلوگاه صحبت خواهیم کرد.کاشتن گلوگاه‌ با انتقال تاخیر موجود در APIهای سرویس بیرونی به درون سیستم یکی از گلوگاه‌هایی که طراحان با دست خود در درون سیستم [به‌ویژه یک سیستم با طراحی monolithic] می‌کارند، وابسته کردن و در انتظار نگه‌داشتن منابع [مثلا threadها] به تعدادی API بیرونی است. یکی از پیش‌فرض‌های این نوع طراحی، این است که سیستم بیرونی همیشه در وضعیت پایدار (stable) قرار دارد و زمان پاسخ تضمینی به ازای هر درخواست ارائه می‌دهد، اما اغلب اوقات، این فرض در عمل می‌تواند نقض شود، و سیستم بیرونی علاوه بر تاخیر، دچار قطعی و شکست نیز بشود. چیزی که در آن لحظه درک جزییات تاخیر را در سیستم بیرونی برای طراح سیستم فعلی سخت می‌کند وجود انتزاع (abstraction) ای است که شکل گرفته است. این انتزاع هرچند برای سادگی و ارائه تصویر یکپارچه ایجاد شده است اما جزئیات مساله را با کشیدن نقابی از ابهام، پنهان کرده است. بنابراین زیر سیستم یا ماژولی که مسئولیت اصلی اتصال به APIهای سیستم بیرونی را [آن‌هم به صورت همگام] دارد می‌تواند یک گلوگاه بالقوه باشد.به عنوان نمونه سیستمی را فرض کنید که قیمت رمزارزهای متنوعی را از سیستم‌های بیرونی مختلفی دریافت می‌کند و به صورت لحظه‌ای در صفحه‌ای نموداری را ترسیم و به‌روزرسانی می‌کند. در این سیستم برای رسم نمودار در صورتی که از رویکردهای ناهمگام و Push شدن داده‌ها استفاده نشود، ماژول ترسیم نمودار بایستی به ازای بیشترین تاخیر ممکن در مجموعه API بیرونی، منتظر بماند.احتمالاً یکی از دم دستی‌ترین رهیافت‌ها، در این مواقع، تغییر رویکرد اتصال همگام به رویکردی ناهمگام با قابلیت صف‌بندی (queuing) و ذخیره‌سازی (persistence) مناسب با بهره‌گیری از Callback متدها و یا دیگر روش‌های مطرح، باشد. در این وضعیت هر Thread حاملِ درخواست با تحویل درخواست به Endpoint فراخوانی ناهمگام، به وضعیت آزاد در می‌آید و منابع به سیستم باز می‌گردد، ضمن اینکه سیستم نوسان پایین و نسبتا پایداری را تجربه می‌کند.+اینجا، کیان، به خوبی به اهمیت ارتباط ناهمگام پرداخته است.نشت حافظه، تبدیل مویرگی حافظه به گلوگاهی بالفعلاین مورد به صورت کاملا آرام و با خیز زمانی ملایمی، می‌تواند سیستم رو به اصطلاح از پا در آرد. عموماً در ابتدای کار اگر تست اساسی صورت نگیرد، دیده نمی‌شود و ممکن است که پس از استقرار (deployment) سیستم، گاها کمی بعد از اینکه توسعه دهنده‌ها بِشکن‌ها را زده‌اند و شمع‌ها را فوت کرده اند، عرض اندامی کند و در نتیجه شاخص‌های کارایی و بهره‌گیری افت کنند. طبیعتاً بدون Profiling درست و درمان پیدا کردن مساله سخت خواهد بود. APP اگر کمی منطق تجاری پیچیده‌ای داشته باشد، حدس و گمان هم مسیر طولانی برای رسیدن به سرنخ خواهد بود. جالبه که GC هم راه بیرون رفتن از چاه نیست و مساله دقیقا باید مشخص بشه که در کدامین بخش از سیستم و از چه نوعی رخ داده است. برای نمونه، APP جاوایی رو فرض کنید که در یک سیستم مخابراتی به عنوان یک مولفه واسط [Proxy] بین دو APP دیگر عمل می‌کند، به این شکل که هر گونه داده جریانی (Streaming data) عبوری را پردازش کرده و ممکن است یک سری فراداده (meta data یا payload) به انتهای بسته‌های داده‌ای اضافه می‌کند. فرض کنید که تمام پردازش‌ها نیز به صورت حافظه‌ای (In-memory) باشد و دیسک نیز درگیر نیست. در این حالت با تنها یک ایراد جزئی در مدیریت حافظه و عدم آزادسازی دستی منابعی که GC قادر به تشخیص آن‌ها نباشد [بحث Unclosed resource، Static fields و موارد دیگر در جاوا] حافظه به یک گلوگاه تبدیل می‌شود.در این اینجا (+لینک و +لینک) به چند نمونه از مواردی که ممکن است رخ بدهد، اشاره شده است.معطلی Threadها در پردازش همگام درخواست‌های دریافتی از وب‌سرور فرض کنید سیستمی وجود دارد که ضمن برخورداری از منابع قدرتمندِ زیرساختی [مقیاس‌پذیر عمودی Vertically scalable]، تنها تعداد محدودی Thread می‌تواند از سیستم‌عامل بگیرد [مثلا 2500تا با اولویت یکسان، کاری با ذاتی یا تعریف‌شده بودن این محدودیت نداریم] و در مقابلِ این سیستم نیز، وب‌سرور قدرتمندی مثل Nginx قرار داده شده است که صرفا درخواست‌ها را به سمت Endpoint تنظیم شده روانه می‌کند و درخواست‌های داخلی این سیستم با زیرسیستم‌های آن نیز به صورت کاملا همگام (synchronous) هندل می‌شود و تا اتمام درخواست Thread مشغول می‌ماند. برای راحتی کار فرض کنید اغلب این درخواست‌ها نیز به یک تراکنش در دیتابیس رابطه‌ای با ظرفیت محدود [مثلا 200 درخواست بر ثانیه در بهترین حالت] نگاشت می‌شود.در این وضعیت در صورتی که سیستم، در لایه App، تعداد درخواست بالاتر از میزان گذردهی دیتابیس رابطه‌ای را تجربه کند، به مرور تاخیر از DB به لایه‌های بالاتر سرایت می‌کند و میانگین زمان پاسخ (response time) درخواست‌ها در سمت App افزایش پیدا می‌کند، به حدی که با افزایش درخواست‌های ارسالی، سیستم با میزانی بالاتر از 2500 درخواست، به طور پیوسته و در زمان مشخصی روبرو می‌شود، در این حالت سیستم [یا بهتر بگم OS] احتمالا تلاش می‌کند context را بین Threadها مرتب switch کند تا بتواند درخواست‌ها را بگیرد و دوباره به سمت دیتابیسی که ظرفیت عادی خود را ندارد [بدون وجود مکانیزم Back pressure] و [از طریق Appای که به] سقف connection pool خود نیز رسیده است ارسال کند. حالا احتمالاً دو مساله رخ داده است:    -  دیتابیس مطابق روال عادی 200 درخواست بر ثانیه را پاسخگو نیست و زمان اجرای پرس و جو به مراتب بالاتر رفته است.    - دوم اینکه، Threadها همگی در وضعیت Busy و منتظر پاسخ از سمت دیتابیس اند و سیستم به طور کلی قفل شده است.در این وضعیت به ترتیب دو گلوگاه در سمت دیتابیس و اپلیکیشن رخ داده است که به نوعی مرتبط با همدیگر اند و همبستگی (correlation) عملیاتی بین آن‌ها وجود دارد. این حالت نوعاً یکی از انواع گلوگاه‌های چند سطحی است که در گلوگاه بعدی یک تصویر انتزاعی مشابه از آن آورده‌ام.محدود بودن کارایی عمل کلیدی در یک سیستم، در نتیجه، مخفی ماندن گلوگاه‌های عملیات جانبیدر یک سیستم فروشگاه اینترنتی فرض کنید، یکی از عملیات اصلی، ثبت کالا یا خدمت در سبد خرید (Register new order) باشد و یکی از شاخص‌های سطح بالای سنجش کارایی سیستم نیز، «طول مدت زمان ثبت سفارش تا پرداخت الکترونیکی»، با صرف نظر از زمان‌های گشت و گذار باشد. در شرایط عادی این عمل و عملیات دیگر با تاخیر کمتری اتفاق بیافتد، اما در پیک کاری سیستم، به عنوان نمونه در زمان «حراج» یا «رخدادهای تقویمی مثل اعیاد و بلک‌فرایدِی» کندی در سیستم مشاهده شود، به طوری که تعداد «عملیات ثبت در سبد/واحد زمانی» کاهش داشته باشد و یا حد بالای تعداد آن به یک عدد پایین‌تر از انتظار افت کند. منظور از کندی نیز افزایش معنادار همین شاخص زمانی و همبستگی آن با تعداد سفارشات باشد که اشاره شد. با بررسی Logها مشخص می‌شود که کندی در فرآیند «ثبت کالا در سبد» در سطح دیسک و دیتابیس رخ می‌دهد [گلوگاه 1] و تیم فنی نیز به عنوان مثال با یک رویکرد نهان‌سازی (caching) این تاخیر را برطرف می‌کند و تعداد «سفارشات/واحد زمان»، را به میزان قابل توجهی افزایش می‌دهد. نکته جالب توجه اینجاست که با رفع این گلوگاه، تاخیر درشاخص مطرح‌شده همچنان معنادار [بالاتر از سطح انتظار] است. پس از بررسی بیشتر مشخص می‌شود که این‌بار عمل «بارگذاری سبد خرید» برای مشتری نیز تاخیر قابل توجهی دارد که پیش‌تر قابل استخراج نبود [گلوگاه 2] و پس از رفع آن، مجددا تاخیر دیگری در ثبت تراکنش مالی در دیتابیس پس از بازگشت از درگاه پرداخت نیز دیده می‌شود [گلوگاه 3].  تصویر زیر یک نمایش انتزاعی [و نه کاملا منطبق] مرتبط با این مساله است.علت اصلی این نوع مساله، پنهان‌شدن گلوگاه‌ها در پشت عملیات اصلی به صورت آبشاری (cascaded) است و تا زمانی‌که تعداد سفارشات بالا نباشد، تعداد «بارگذاری سبد خرید/واحد زمان» و «تعداد پرداخت‌های موفق برگشتی/واحد زمان» نیز ترافیک بالایی را تجربه نخواهد کرد تا بتوان تاخیر آن‌ها را نیز به صورت مجزا احساس کرد.در عمل، گلوگاه‌ها همیشه در سطح اول ظاهر نمی‌شوند و ممکن است چند سطحی بوده و به نوعی ارتباط عِلّی داشته باشند؛ مثل آن‌چه که در تصویر بالا نمایش داده شده‌است؛ پیدا کردن گلوگاه B و C که پشت گلوگاه A به اصطلاح قایم شده اند، همیشه سر راست نیست و آشکارشدن اش نوعاً پیامدی (consequence) از رفع گلوگاه n-1 سطح قبلی است.عدم پیکربندی درست و پایین‌بودن توان connection pool یک نوع رایجی از گلوگاه‌ها، محدود بودن توان عملیاتی یک مولفه میانی مثل connection pool بین دو زیرسیستم یا مولفه قدرتمند است. محدود بودن شاید ویژگی ذاتی این مولفه نباشد و ممکن است Pool size با مصالحه (Trade-off) درستی تنظیم نشده است.به طور کلی مشابه تصویر بالایی، در یک طرف، App ای وجود دارد که به شکل خوبی بهینه شده است و در مقابل تلاش می‌کند به منابع قدرتمندی [مثل دیتابیس رابطه‌ای یا غیر رابطه‌ای، سرویس‌دهنده ایمیل، ذخیره‌ساز ابری یا object storage و غیره] که در دسترس است متصل شود و با داشتن انتظار بالایی از توان عملیاتی، ترافیک بالایی را نیز هندل کند. اما با توجه به محدودیت‌های connection pool این انتظار برآورده نمی‌شود.+اینجا یک نمونه از این مساله مطرح شده است.به طور کلی، +این‌جا طبقه‌بندی خوبی از 20 نوع مرسوم گلوگاه‌ در لایه‌های مختلفی از جمله پردازنده، دیسک، حافظه اصلی، دیتابیس‌ها، چارچوب‌های نهان‌سازی (Caching)، شبکه و... آورده شده است که هر کدام از آن‌ها جزئیات و ویژگی‌های خاص خودش را دارد.پی‌نوشت:برای اینکه خواندن این نوشته حوصله‌ سربر نباشه، سعی می‌کنم در چند پست مجزا موارد دیگر رو بنویسم.برخی از این موارد، به نوعی تجربی است و در جریان فعالیت‌ام به همراه تیم توسعه فنی [High-performance app در حوزه مالی] از نزدیک دیده ام. فکر می‌کنم طرح «مسائل» جذاب‌تر از خود راه‌حل‌ها باشه بنابراین در خصوص «راه‌حل»ها سعی کردم بحثی رو باز نکنم.در مواردی ممکنه که برداشت من ناقص و اشتباه باشه، مشتاقم در بخش نظرات دیدگاه خودتون رو مطرح کنید و در خصوص این موارد و هر آن‌چه که مرتبط است صحبت کنیم.</description>
                <category>میثم | Maysam</category>
                <author>میثم | Maysam</author>
                <pubDate>Sat, 24 Apr 2021 23:05:04 +0430</pubDate>
            </item>
            </channel>
</rss>