ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

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

چه باید کرد؟ اینجاست که هوش مصنوعی به کمک ما می آید. مقاله در مورد صحبت خواهد کرد تعمیرات قابل پیش بینی (تعمیرات قابل پیش بینی). این رویکرد به طور فعال در حال افزایش محبوبیت است. تعداد زیادی مقاله از جمله در هابره نوشته شده است. شرکت های بزرگ به طور کامل از این رویکرد برای حفظ عملکرد سرورهای خود استفاده می کنند. پس از مطالعه تعداد زیادی مقاله، تصمیم گرفتیم این روش را امتحان کنیم. چه نتیجه ای حاصل شد؟

معرفی

سیستم نرم افزاری توسعه یافته دیر یا زود وارد عمل می شود. برای کاربر مهم است که سیستم بدون خرابی کار کند. اگر یک اورژانس رخ دهد، باید با کمترین تاخیر برطرف شود.

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

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 1. رابط نظارت گرافانا

متریک ها نشانگرهای مختلفی از یک سیستم نرم افزاری، محیط اجرای آن، یا رایانه فیزیکی هستند که سیستم تحت آن در حال اجرا است با یک مهر زمانی از لحظه دریافت معیارها. در تحلیل استاتیکی به این معیارها سری زمانی می گویند. برای نظارت بر وضعیت سیستم نرم افزار، معیارها به شکل نمودار نمایش داده می شوند: زمان در محور X است و مقادیر در امتداد محور Y هستند (شکل 1). چندین هزار معیار را می توان از یک سیستم نرم افزاری در حال اجرا (از هر گره) گرفت. آنها فضایی از متریک ها (سری های زمانی چند بعدی) را تشکیل می دهند.

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

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

ابزار اصلی برای اجرای تعمیر و نگهداری پیش بینی، وظیفه جستجوی ناهنجاری ها در سری های زمانی است زمانی که یک ناهنجاری رخ می دهد در داده ها احتمال زیادی وجود دارد که بعد از مدتی یک شکست یا شکست وجود خواهد داشت. ناهنجاری یک انحراف معین در عملکرد یک سیستم نرم افزاری است، مانند شناسایی کاهش سرعت اجرای یک نوع درخواست یا کاهش میانگین تعداد درخواست های ارائه شده در سطح ثابتی از جلسات مشتری.

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

روش‌هایی برای جستجوی ناهنجاری‌ها هنگام پیش‌بینی خرابی‌های سیستم‌های نرم‌افزاری

اول از همه، شایان ذکر است که ایده پیش بینی شکست ها از مقاله الهام گرفته شده است "یادگیری ماشین در پایش فناوری اطلاعات". برای آزمایش اثربخشی رویکرد با جستجوی خودکار ناهنجاری ها، سیستم نرم افزاری Web-Consolidation که یکی از پروژه های شرکت NPO Krista می باشد، انتخاب شد. پیش از این نظارت دستی بر اساس معیارهای دریافتی برای آن انجام می شد. از آنجایی که سیستم بسیار پیچیده است، تعداد زیادی معیار برای آن در نظر گرفته شده است: نشانگرهای JVM (بار جمع‌آوری زباله)، نشانگرهای سیستم عاملی که کد تحت آن اجرا می‌شود (حافظه مجازی، % بار CPU سیستم عامل)، نشانگرهای شبکه (بار شبکه). خود سرور (بار CPU، حافظه)، معیارهای wildfly و معیارهای خود برنامه برای همه زیرسیستم‌های حیاتی.

تمام معیارها با استفاده از گرافیت از سیستم گرفته شده است. در ابتدا، پایگاه داده whisper به عنوان یک راه حل استاندارد برای grafana مورد استفاده قرار گرفت، اما با افزایش پایگاه مشتری، گرافیت دیگر نمی توانست با آن مقابله کند، زیرا ظرفیت زیرسیستم دیسک DC را تمام کرده بود. پس از این تصمیم گرفته شد که راه حل موثرتری پیدا شود. انتخاب به نفع انجام شد گرافیت + خانه کلیککه امکان کاهش بار روی زیرسیستم دیسک را به نسبت بزرگی و کاهش فضای اشغال شده دیسک بین پنج تا شش برابر فراهم می کرد. در زیر نموداری از مکانیسم جمع‌آوری معیارها با استفاده از گرافیت+کلیک‌هاوس نشان داده شده است (شکل 2).

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 2. طرحی برای جمع آوری معیارها

نمودار از اسناد داخلی گرفته شده است. این ارتباط بین grafana (واسط کاربری نظارتی که استفاده می کنیم) و گرافیت را نشان می دهد. حذف معیارها از یک برنامه توسط نرم افزار جداگانه انجام می شود - jmxtrans. او آنها را در گرافیت قرار می دهد.
سیستم Web Consolidation دارای تعدادی ویژگی است که مشکلاتی را برای پیش بینی خرابی ایجاد می کند:

  1. روند اغلب تغییر می کند. نسخه های مختلفی برای این سیستم نرم افزاری موجود است. هر یک از آنها تغییراتی را در بخش نرم افزاری سیستم ایجاد می کند. بر این اساس، به این ترتیب، توسعه‌دهندگان مستقیماً بر معیارهای یک سیستم معین تأثیر می‌گذارند و می‌توانند باعث تغییر روند شوند.
  2. ویژگی پیاده سازی و همچنین اهدافی که مشتریان از این سیستم برای آنها استفاده می کنند، اغلب باعث ایجاد ناهنجاری بدون تخریب قبلی می شوند.
  3. درصد ناهنجاری ها نسبت به کل مجموعه داده ها کوچک است (< 5٪).
  4. ممکن است در دریافت اندیکاتورها از سیستم خللی وجود داشته باشد. در برخی از دوره های زمانی کوتاه، سیستم نظارت در به دست آوردن معیارها شکست می خورد. به عنوان مثال، اگر سرور بیش از حد بارگذاری شده باشد. این برای آموزش شبکه عصبی بسیار مهم است. نیاز به پر کردن شکاف ها به صورت مصنوعی وجود دارد.
  5. موارد با ناهنجاری اغلب فقط مربوط به یک تاریخ / ماه / زمان خاص (فصلی) است. این سیستم دارای مقررات مشخصی برای استفاده کاربران است. بر این اساس، معیارها فقط برای یک زمان خاص مرتبط هستند. این سیستم را نمی توان به طور مداوم استفاده کرد، اما فقط در چند ماه: به طور انتخابی بسته به سال. موقعیت‌هایی به وجود می‌آیند که رفتار یکسان معیارها در یک مورد می‌تواند منجر به خرابی سیستم نرم‌افزاری شود، اما در مورد دیگر نه.
    برای شروع، روش‌های تشخیص ناهنجاری در پایش داده‌های سیستم‌های نرم‌افزاری مورد تجزیه و تحلیل قرار گرفت. در مقالات مربوط به این موضوع، زمانی که درصد ناهنجاری‌ها نسبت به بقیه مجموعه داده‌ها کم است، اغلب استفاده از شبکه‌های عصبی پیشنهاد می‌شود.

منطق اصلی برای جستجوی ناهنجاری ها با استفاده از داده های شبکه عصبی در شکل 3 نشان داده شده است:

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 3. جستجوی ناهنجاری ها با استفاده از شبکه عصبی

بر اساس نتیجه پیش بینی یا بازیابی پنجره جریان فعلی متریک ها، انحراف از دریافتی از سیستم نرم افزاری در حال اجرا محاسبه می شود. اگر تفاوت زیادی بین معیارهای به‌دست‌آمده از سیستم نرم‌افزاری و شبکه عصبی وجود داشته باشد، می‌توان نتیجه گرفت که بخش داده فعلی غیرعادی است. مجموعه ای از مشکلات زیر برای استفاده از شبکه های عصبی ایجاد می شود:

  1. برای کارکرد صحیح در حالت پخش، داده‌های مربوط به آموزش مدل‌های شبکه عصبی باید فقط شامل داده‌های «عادی» باشد.
  2. داشتن یک مدل به روز برای تشخیص صحیح ضروری است. تغییر روندها و فصلی بودن معیارها می تواند باعث ایجاد تعداد زیادی مثبت کاذب در مدل شود. برای به روز رسانی آن، لازم است که زمان قدیمی بودن مدل را به وضوح مشخص کنید. اگر مدل را دیرتر یا زودتر به روز کنید، به احتمال زیاد، تعداد زیادی مثبت کاذب به دنبال خواهد داشت.
    ما همچنین نباید جستجو و جلوگیری از وقوع مکرر موارد مثبت کاذب را فراموش کنیم. فرض بر این است که آنها اغلب در شرایط اضطراری رخ می دهند. با این حال، آنها همچنین ممکن است نتیجه یک خطای شبکه عصبی به دلیل آموزش ناکافی باشند. لازم است تعداد موارد مثبت کاذب مدل به حداقل برسد. در غیر این صورت، پیش‌بینی‌های نادرست زمان زیادی را که مدیر برای بررسی سیستم در نظر گرفته شده است، تلف می‌کند. دیر یا زود، مدیر به سادگی از پاسخگویی به سیستم نظارتی "پارانوئید" خودداری می کند.

شبکه عصبی مکرر

برای تشخیص ناهنجاری ها در سری های زمانی می توانید استفاده کنید شبکه عصبی مکرر دارای حافظه LSTM تنها مشکل این است که فقط برای سری های زمانی پیش بینی شده قابل استفاده است. در مورد ما، همه معیارها قابل پیش بینی نیستند. تلاشی برای اعمال RNN LSTM به یک سری زمانی در شکل 4 نشان داده شده است.

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 4. نمونه ای از یک شبکه عصبی بازگشتی با سلول های حافظه LSTM

همانطور که از شکل 4 مشاهده می شود، RNN LSTM توانست با جستجوی ناهنجاری ها در این دوره زمانی کنار بیاید. در جایی که نتیجه دارای خطای پیش بینی بالایی است (خطای میانگین)، در واقع یک ناهنجاری در اندیکاتورها رخ داده است. استفاده از یک RNN LSTM به وضوح کافی نخواهد بود، زیرا برای تعداد کمی از معیارها قابل استفاده است. می تواند به عنوان یک روش کمکی برای جستجوی ناهنجاری ها استفاده شود.

رمزگذار خودکار برای پیش بینی شکست

رمزگذار خودکار - اساسا یک شبکه عصبی مصنوعی. لایه ورودی رمزگذار است، لایه خروجی رمزگشا است. عیب تمام شبکه های عصبی از این نوع این است که ناهنجاری ها را به خوبی بومی سازی نمی کنند. یک معماری رمزگذار خودکار همزمان انتخاب شد.

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 5. مثالی از عملیات رمزگذار خودکار

رمزگذارهای خودکار بر روی داده های معمولی آموزش می بینند و سپس چیزی غیرعادی را در داده های تغذیه شده به مدل پیدا می کنند. فقط چیزی که برای این کار نیاز دارید. تنها چیزی که باقی می ماند این است که انتخاب کنید کدام رمزگذار خودکار برای این کار مناسب است. از نظر معماری ساده ترین شکل رمزگذار خودکار یک شبکه عصبی رو به جلو و بدون بازگشت است که بسیار شبیه به پرسپترون چند لایه (پرسپترون چند لایه، MLP)، با یک لایه ورودی، یک لایه خروجی، و یک یا چند لایه پنهان که آنها را به هم متصل می کند.
با این حال، تفاوت‌های بین رمزگذارهای خودکار و MLP در این است که در یک رمزگذار خودکار، لایه خروجی دارای تعداد گره‌های یکسانی با لایه ورودی است و به‌جای آموزش برای پیش‌بینی مقدار Y هدف داده‌شده توسط ورودی X، رمزگذار خودکار آموزش داده می‌شود. برای بازسازی Xs خود. بنابراین Autoencoder مدل های یادگیری بدون نظارت هستند.

وظیفه رمزگذار خودکار یافتن شاخص های زمانی r0 ... rn مربوط به عناصر غیرعادی در بردار ورودی X است. این اثر با جستجوی خطای مربع حاصل می شود.

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 6. رمزگذار خودکار همزمان

برای رمزگذار خودکار انتخاب شد معماری سنکرون. مزایای آن: توانایی استفاده از حالت پردازش جریان و تعداد نسبتاً کمتر پارامترهای شبکه عصبی در مقایسه با سایر معماری ها.

مکانیزم برای به حداقل رساندن مثبت کاذب

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

الگوریتم برای تبدیل پویا خط زمانی (الگوریتم DTW، از تاب خوردگی زمانی پویا انگلیسی) به شما امکان می دهد مطابقت بهینه بین دنباله های زمانی را پیدا کنید. اولین بار در تشخیص گفتار استفاده شد: برای تعیین اینکه چگونه دو سیگنال گفتاری یک عبارت گفتاری اصلی را نشان می دهند استفاده می شود. متعاقباً کاربرد آن در مناطق دیگر پیدا شد.

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

در نتیجه، بر اساس روش‌های شبکه عصبی که در بالا توضیح داده شد، یک برنامه آزمایشی برای پیش‌بینی خرابی‌های سیستم «تجمیع وب» ساخته شد. هدف این برنامه، با استفاده از آرشیو موجود از داده های نظارتی و اطلاعات مربوط به خرابی های قبلی، ارزیابی شایستگی این رویکرد برای سیستم های نرم افزاری ما بود. طرح برنامه در شکل 7 در زیر ارائه شده است.

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 7. طرح پیش بینی شکست بر اساس تحلیل فضای متریک

در نمودار، دو بلوک اصلی را می توان تشخیص داد: جستجوی دوره های زمانی غیرعادی در جریان داده های نظارتی (سنجش ها) و مکانیسم به حداقل رساندن مثبت کاذب. توجه: برای اهداف آزمایشی، داده ها از طریق یک اتصال JDBC از پایگاه داده که گرافیت آن را در آن ذخیره می کند، به دست می آید.
زیر رابط سیستم نظارتی است که در نتیجه توسعه به دست آمده است (شکل 8).

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 8. رابط سیستم نظارت تجربی

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

نمونه ای از تشخیص ناهنجاری بر اساس عملکرد CPU با استفاده از شبکه عصبی RNN LSTM (شکل 9).

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 9. کشف RNN LSTM

یک مورد نسبتاً ساده، اساساً یک حالت پرت معمولی، اما منجر به شکست سیستم، با استفاده از RNN LSTM با موفقیت محاسبه شد. شاخص ناهنجاری در این دوره زمانی 85-95٪ است؛ هر چیزی بالاتر از 80٪ (آستانه به صورت تجربی تعیین شد) یک ناهنجاری در نظر گرفته می شود.
نمونه ای از تشخیص ناهنجاری زمانی که سیستم قادر به بوت شدن پس از به روز رسانی نبود. این وضعیت توسط رمزگذار خودکار شناسایی می شود (شکل 10).

ما با استفاده از شبکه های عصبی به دنبال ناهنجاری ها و پیش بینی خرابی ها هستیم

شکل 10. نمونه ای از تشخیص رمزگذار خودکار

همانطور که از شکل می بینید، PermGen در یک سطح گیر کرده است. رمزگذار خودکار این موضوع را عجیب می‌دانست، زیرا قبلاً چنین چیزی را ندیده بود. در اینجا ناهنجاری 100% باقی می ماند تا زمانی که سیستم به حالت کار بازگردد. یک ناهنجاری برای همه معیارها نمایش داده می شود. همانطور که قبلا ذکر شد، رمزگذار خودکار نمی تواند ناهنجاری ها را بومی سازی کند. اپراتور برای انجام این عملکرد در این شرایط فراخوانی می شود.

نتیجه

PC "Web-Consolidation" چندین سال است که در حال توسعه است. سیستم در وضعیت نسبتاً پایداری قرار دارد و تعداد حوادث ثبت شده اندک است. با این حال، می توان ناهنجاری هایی را که منجر به شکست می شود، 5 تا 10 دقیقه قبل از وقوع شکست پیدا کرد. در برخی موارد، اطلاع از خرابی از قبل به صرفه جویی در زمان برنامه ریزی شده برای انجام کار "تعمیر" اختصاص داده شده است.

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

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

من از همکارانم که به من در نوشتن و حفظ ارتباط این مقاله کمک کردند تشکر می کنم: ویکتور وربیتسکی و سرگئی فینوگنوف

منبع: www.habr.com

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