آشنایی با ۱۲-فاکتور اپلیکیشن (The twelve-factor app) فاکتور های دهم الی آخر

دوازده فاکتور اپلیکیشن
دوازده فاکتور اپلیکیشن - صادق خان

با سلام و درود، با قسمت چهارم از آشنایی با فاکتورهای ۱۲ گانه اپلیکیشن در خدمتتان هستم (۱۲-فاکتور اپلیکیشن یا The twelve-factor app ) . در قسمت اول با فاکتور های اول تا چهارم و در قسمت دوم با فاکتورهای چهارم تا هفتم و در قسمت سوم با فاکتورهای هفتم تا دهم آشنا شدیم که به شرح زیر بودند:

فاکتور اول: codebase – پایگاه کد

یک codebase در کنترل revision ردیابی می شود و بسیاری از آنها مستقر (deploy) می شوند.

به طور خلاصه، یه کدبیس خواهیم داشت و همان را در چند جا مستقر می کنیم.

فاکتور دوم: Dependencies – وابستگی ها

به صورت صریح . ایزوله، dependency ها مشخص می شوند

فاکتور سوم: config – کانفیگ

کانفیگ در محیط هر استقرار نگه داری شود، ترجیحا از متغیرهای محیط استفاده شود.

برای مطالعه کامل تر روی ۳ فاکتور نخست از فاکتورهای دوازده گانه اپلیکیشن، پیشنهاد می کنم قسمت اول ( آشنایی با ۱۲-فاکتور اپلیکیشن (The twelve-factor app) فاکتور های اول تا سوم ) از این مطلب را حتما نگاه بندازید.

فاکتور چهارم: Backing services -سرویس های پشتی

خدمات پشتیبان، به عنوان منابع پیوستی تلقی شوند.

فاکتور پنجم: Build, release, run ، ساخت، انتشار، اجرا

مراحل ساخت و اجرا را کاملا جدا کنید

فاکتور ششم: Processes -فرآیندها

app را به عنوان یک یا چند فرآیند بدون حالت (stateless) اجرا کنید.

برای مطالعه کامل تر روی ۳ فاکتور دوم از فاکتورهای دوازده گانه اپلیکیشن، پیشنهاد می کنم قسمت دوم ( آشنایی با ۱۲-فاکتور اپلیکیشن (The twelve-factor app) فاکتور های چهارم تا هفتم) از این مطلب را حتما نگاه بندازید.

فاکتور هفتم: Port bindinge

export کردن سرویس ها را با استفاده از Port Binding انجام دهید.

فاکتور هشتم: Concurrency – همزمانی

توسط مدل فرآیند، مقیاس پذیر کنید.

فاکتور نهم: Disposability – یکبار مصرف

با راه‌اندازی سریع و خاموش شدن برازنده، استحکام (robustness) را به حداکثر برسانید.

برای مطالعه کامل تر روی ۳ فاکتور سوم از فاکتورهای دوازده گانه اپلیکیشن، پیشنهاد می کنم قسمت سوم ( آشنایی با ۱۲-فاکتور اپلیکیشن (The twelve-factor app) فاکتور های هفتم تا یازدهم) از این مطلب را حتما نگاه بندازید.

در ادامه به فاکتورهای دهم الی آخر می پردازیم:

فاکتور دهم: توازن بین توسعه/تولید – X. Dev/prod parity

تا جایی که میشه مراحل توسعه دادن، staging و Production را مشابه نگه دارید.

از لحاظ تاریخی، شکاف‌های قابل توجهی بین توسعه – development (یک توسعه‌دهنده, ویرایش‌های زنده – live – برای استقرار محلی برنامه را انجام می‌دهد) و تولید- production (استقرار در حال اجرا برنامه که کاربران نهایی به آن دسترسی دارند) وجود داشته است. این شکاف ها در سه حوزه ظاهر می شوند:

  • فاصله زمانی: یک توسعه دهنده ممکن است روی کدی کار کند که تولید آن روزها، هفته ها یا حتی ماه ها طول می کشد.
  • شکاف پرسنل: توسعه دهندگان کد می نویسند، مهندسان عملیات آن را مستقر می کنند.
  • شکاف ابزار: توسعه دهندگان ممکن است از پشته ای مانند Nginx، SQLite و OS X استفاده کنند، در حالی که توسعه تولید از Apache، MySQL و Linux استفاده می کند.

برنامه دوازده عاملی برای استقرار مداوم با کوچک نگه داشتن فاصله بین توسعه و تولید طراحی شده است. با نگاهی به سه شکاف توضیح داده شده در بالا:

  • فاصله زمانی را کم کنید: یک برنامه‌نویس ممکن است کد بنویسد و ساعت‌ها یا حتی چند دقیقه بعد آن را مستقر کند.
  • شکاف پرسنل را کوچک کنید: توسعه دهندگانی که کد نوشتند از نزدیک در استقرار آن و مشاهده رفتار آن در تولید نقش دارند.
  • فاصله ابزارها را کم کنید: توسعه و تولید را تا حد امکان مشابه نگه دارید.

خلاصه موارد فوق به صورت جدولی به شرح زیر است:

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

سرویس های پشتیبان، ماننده پایگاه داده ها، سیستم های نوبت دهی، یا کش، یکی از جاهایی است که تشابه تولید/توسعه مهم می باشد. خیلی از زبان های برنامه نویسی کتابخانه هایی را پیشنهاد می دهند که به سادگی به سرویس های پشتیبان ، شامل آداپتورهای انواع مختلف سرویس ها را ارائه می دهند. بعضی از مثال ها به شرح زیر می باشد:

نوعزبانکتابخانهآداپتورها
پایگاه دادهRuby/RailsActiveRecordMySQL, PostgreSQL, SQLite
صف (نوبت دهی)Python/DjangoCeleryRabbitMQ, Beanstalkd, Redis
کشRuby/RailsActiveSupport::CacheMemory, filesystem, Memcached

توسعه دهندگان گاهی اوقات استفاده از یک سرویس پشتیبان سبک وزن در محیط های محلی خود پیدا می کنند، در حالی که یک سرویس پشتیبان قویتر و جدیتر در محیط تولید انجام می شود. برای مثال استفاده از SQLite به صورت locall و PostgreSQL به هنگام تولید& یا استفاده از local process memory برای کش کردن در محیط توسعه و Memcached در محیط تولید.

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

خدمات محلی سبک – lightWeight کمتر از قبل قانع کننده هستند. نصب و اجرای سرویس‌های پشتیبان مدرن مانند Memcached، PostgreSQL و RabbitMQ به لطف سیستم‌های بسته‌بندی مدرن، مانند Homebrew و apt-get، دشوار نیست. از طرف دیگر، ابزارهای تدارکات اعلامی مانند Chef و Puppet همراه با محیط های مجازی سبک مانند Docker و Vagrant به توسعه دهندگان اجازه می دهد تا محیط های محلی را اجرا کنند که به محیط های تولید تقریب نزدیک دارند. هزینه نصب و استفاده از این سیستم ها در مقایسه با مزیت برابری dev/prod و استقرار مداوم پایین است.

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

فاکتور یازدهم: لاگ ها – Logs

لاگ ها را به‌عنوان جریانهای رویداد (event streams) در نظر بگیرید

لاگ ها امکان مشاهده رفتارهای برنامه در حا اجرا را فراهم می کنند. در محیط های مبتین بر سرور& آنها معمولا روی فایل روی دیسک نوشته می شوند logfile ، فقط یه فرمت خروجی می باشد.

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

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

در استقرار staging یا تولید، هر جریان فرآیند توسط محیط اجرا ضبط می‌شود، با تمام جریان‌های دیگر از برنامه ترکیب می‌شود و برای مشاهده و بایگانی طولانی‌مدت به یک یا چند مقصد نهایی هدایت می‌شود. این مقصدهای بایگانی برای برنامه قابل مشاهده یا تنظیم نیستند و در عوض کاملاً توسط محیط اجرا مدیریت می شوند. روترهای لاگ منبع باز (مانند Logplex و Fluentd) برای این منظور در دسترس هستند.

جریان رویداد برای یک برنامه را می توان به یک فایل هدایت کرد یا از طریق realtime tail در یک ترمینال تماشا کرد. مهمتر از همه، جریان را می توان به یک سیستم نمایه سازی (log indexing) و تجزیه و تحلیل گزارش مانند Splunk یا یک سیستم انبار داده همه منظوره مانند Hadoop/Hive ارسال کرد. این سیستم‌ها قدرت و انعطاف‌پذیری زیادی را برای بررسی رفتار یک برنامه در طول زمان فراهم می‌کنند، از جمله:

  • یافتن رویدادهای خاص در گذشته
  • نموداری در مقیاس بزرگ از روندها (مانند درخواست در دقیقه).
  • هشدار فعال (Active alerting) با توجه به اکتشافی های تعریف شده توسط کاربر (مانند هشدار زمانی که تعداد خطاها در دقیقه از یک آستانه خاص فراتر رود).

فاکتور دوازدهم و آخر: فرآیندهای مدیریت – Admin processes

وظایف ادمین/مدیریت (admin/management) را به عنوان فرآیندهای یکباره اجرا کنید

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

  • اجرای migrationهای پایگاه داده (مانند manage.py migrate در جنگو یا rake db:migrate در Rails).
  • اجرای یک کنسول (همچنین با PERL shellهم شناخته می شود) جهت اجرای کد دلخواه یا رسیدگی کردن به ماژول های app در برابر پایگاه داده زنده. اکثر زبان ها با اجرای مفسر بدون هیچ آرگومانی (مانند پایتون یا پرل) یک PERL ارائه می کنند یا در برخی موارد دستور جداگانه ای دارند (برای مثال irb برای Ruby و rails console برای Rails)

فرآیند های ادمین باید در یک محیط مشابه با فرآیند های طولانی مدت برنامه اجرا شوند. آنها در مقابل یک release اجرا می شوند و از code base یکسان استفاده می کنند و ماند هر فرآیندی که رد مقابل releaseاجرا می شود، کانفیگ می شوند. Admin code باید همراه با application code ارسال شود تا از مشکلات همگام سازی جلوگیری شود.

تکنیک های جداسازی وابستگی یکسانی باید برای تمامی انواع فرآیند ها استفاده شود. برای مثال، اگر Ruby web process از دستور bundle exec thin start شروع می کند، سپس یک migration دیتابیس باید با دستور bundle exec rake db:migrate انجام شود. به همین ترتیب، یک برنامه پایتون که از virtualenv استفاده می کند باید از vendored bin/python برای اجرا کردن جفت Tornado webserver و هر فرآیند ادمین از manage.py استفاده کند.

در یک استقرار محلی (local deploy)، توسعه دهندگان از دستور مستقیم shell درون پوشه checkout از app ، برای فراخوانمی یکباره فرآیند های ادمین استفاده می کنند. در استقرار تولید (production deploy)، توسعه دهندگان یم توانند از ssh یا هر مکانیسم فرمان ریموت که توسط محیط استقرار فراهم شده است، برای اجرای چنین فرایندی استفاده کنند.