به نظرتان مدیریت یک میلیون درخواست با استفاده از زبان برنامهنویسی پایتون امکانپذیر است؟ احتمالاً نه، مگر آنکه جدیداً تغییراتی ایجاد شده باشد.
در این اواخر شرکتهای مختلفی از پایتون به سمت زبانهای دیگر برنامهنویسی مهاجرت کردهاند تا بتوانند کارایی بالایی را ارائه کرده و همچنین هزینه کمتری برای سرور پرداخت کنند. اما دیگر نیازی به این حالت نیست چرا که بروزرسانیهای اخیر پایتون نشان از بهبود آن میدهند.
برای مثال اگر نسخه ۳.۶ پایتون را با نسخههای قبلی مقایسه بکنید مشاهده خواهید کرد که کارایی در این حالت افزایش بسیار زیادی داشته، همچنین پایتون ۳.۷ از چنین قاعدهای پیروی کرده و نسبت به پایتون ۳.۶ بهینهتر عمل میکند. در ارتباط با نسخه ۳.۸ نیز باز میتوان این موضوع را گفت.
از طرفی دیگر پایتون برای محاسبات سنگین یک پیادهسازی منحصر به فرد با نام PyPy دارد که به لطف کامپایلر JIT بسیار سریع عمل میکند. با در نظر گرفتن تمام این موارد من تمایل بسیار زیادی به این موضوع پیدا کردم تا در ارتباط با نوآوریهای پایتون در زمینهای که بیشترین استفاده را دارد صحبت کنم: توسعه وب و میکروسرویسها.
Japronto وارد میشود!
Japronto یک میکروفریمورک جدید مبتنی بر پایتون است که برای توسعه میکروسرویسها استفاده میشود. هدف اصلی این فریمورک سریع، مقیاسپذیر و سبک بودن است. با استفاده از این فریمورک میتوانید با کمک asyncio به صورت همزمان و غیرهمزمان برنامهنویسی بکنید. اما موضوعی که واقعاً در ارتباط با این ابزار عجیب است سریع بودن آن است. این فریمورک حتی از نودجیاس و زبان GO نیز سریعتر عمل میکند!
نکته: زمانی که چارت بالا در گیتهاب پروژه منتشر شد کاربر @heppu اشاره کرد که اگر سرور stdlib HTTP مربوط به زبان GO با دقت نوشته شود میتواند ۱۲درصد سریعتر از میزان گفته شده در چارت عمل کند (منظور ۱۲درصد سریعتر از مورد GO) همچنین اشاره کرده که برای زبان Go یک کتابخانه تحت عنوان fasthttp وجود دارد که ظاهراً تنها ۱۸درصد کندتر از Japronto عمل میکند.
اگر به چارت بالا نگاه کنیم (بدون در نظر گرفتن Japronto) میتوان مشاهده کرد که سرور Meinheld WSGI تقریباً با نودجیاس و GO برابر است. فارغ از طراحی Blocking این مورد کارایی بسیار خوبی را نسبت به چهار مورد قبلی که اتفاقاً از برنامهنویسی async برخوردار هستند ارائه میکند. بنابراین هیچوقت به کسی که میگوید برنامهنویسی async همواره سریعتر است اعتماد نکنید. درست است که async تأثیر بسیار زیادی روی سرعت اجرای برنامه خواهد داشت اما این مورد تنها فاکتور کافی نخواهد بود.
برنامهای که من برای بدست آوردن این بنچمارک از آن استفاده کردم صرفاً یک متن Hello World را نشان میداد. این برنامه روی AWS c4.2xlarge با 8 VCPU در منطقه Sao Paulo اجرا شد. سیستم عامل مربوط به این ماشین اوبنتو 16.04.1 با کرنل Linux 4.4.0–53-generic x86_64 بود. براساس گزارش سیستم عامل پردازنده این ماشین Xeon® CPU E5–2666 v3 @ 2.90GHz بود. برای اجرا کردن کدها نیز من از پایتون 3.6 استفاده کردم.
در تست انجام شده تمام گزینههای موجود روی یک پروسه Single-worker اجرا میشدند. برای اجرای این تست من از wrk با یک رشته (thread)، ۱۰۰ ارتباط و ۲۴ درخواست شبیهسازی شده به ازای یک ارتباط استفاده کردم، حالتی که به آن piplining گفته میشود.
HTTP pipelining در این بنچمارک نقش حیاتی را ایفا میکند چرا که در روال بهینهسازی Japronto این مورد یکی از حالتهاست که در نظر گرفته میشود. بیشتر ابزارهایی که برای پیادهسازی یک سرور استفاده میشود روال بهینهسازی مشخصی را برای این موضوع در نظر نمیگیرند. اما این مورد به این صورت نیست.
Piplining تکنیکی است که در آن کاربر نیازی به منتظر بودن برای دریافت جواب در جهت ارسال درخواستی جدید را ندارد.
جزئیات بهینهسازی
زمانی که کاربر چندین درخواست GET را به صورت pipline ارسال میکند احتمال آنکه تمام این موارد به صورت یک بسته TCP ارسال شده و درخواست لازم برای استفاده از منابع سیستم را بکند زیاد است این درخواست با نام system call شناخته میشود. البته انجام چنین کاری چندان آسان نخواهد بود و نیاز به انجام پردازشهای مختلفی دارد.
تعریف system call: هرگاه یک نرمافزار سطح کاربر نیاز به دسترسی به منابع سیستم و سخت افزار را داشته باشد، یکی از توابع درون سیستم عامل را فراخوانی میکند. که به این عمل فراخوان سیستمی (به انگلیسی: System Call یا Syscall) میگویند.
زمانی که Japronto یکسری داده را دریافت کرده و به صورت موفقیت آمیز درخواستهای موجود در آن را تفسیر کرد سعی میکند تا تمام آنها را در سریعترین زمان ممکن اجرا کند. همچنین Japronto از طریق یکسری تکنیک منحصر به فرد روال Syscall را نیز مدیریت میکند.
البته برخی از درخواستها نمیتوانند به سرعت جوابدهی شوند چرا که میزان قابل توجهی از پردازش را نیازمندند. بنابراین نیاز است تا در ارتباط با این موارد هشیار باشید.
Japronto تقریبا به صورت کامل با زبان C نوشته شده است. مفسر، پروتکل، Connection Reaper، روتر، اشیاء درخواست/جواب و... تماما به صورت افزونههای C توسعه یافتهاند.
از طرفی دیگر Japronto برای تفسیر کدهای وضعیت، سربرگها و پیامهای HTTP از کتابخانه picohttpparser که مبتنی بر C است استفاده میکند. picohttpparser به صورت مستیم تمام موارد مورد نیاز برای پردازش متن را به کار میگیرد. این کار برای انطباق یافتن با توکنهای HTTP صورت خواهد گرفت.
پایتون یک زبان garbage collected است از این رو نیاز است زمانی که سیستمی با کارایی بالا را ایجاد میکنید دقت بالایی داشته باشید. طراحی داخلی Japronto سعی دارد تا از reference cycles اجتناب کرده و تا جای ممکن از فرایندهای allocation/deallocation خودداری کند.
مشارکت در پروژه
به مدت سه ماه است که در پروژه Japronto مشارکت دارم و سعی میکنم تا حرفهایتر مسیر برنامهنویسی را ادامه دهم. با این حال اگر بخواهم وضعیت کنونی این کتابخانه را با شما به اشتراک بگذارم باید به موضوعات زیر اشاره کنم.
- در حال حاضر Japronto از ویژگیهای پایدار بسیار مناسبی برخوردار است.
- یک پیادهسازی از HTTP 1.x به همراه پشتیبانی از آپلودهای چندگانه
- پشتیبانی کامل از HTTP pipelining
- توانایی در زنده نگهداشتن ارتباطات همراه با reaperهایی با قابلیت پیکربندی
- پشتیبانی از sync و async
- پشتیبانی از Code Reloading
- روتینگ ساده
- پشتیبانی از مدلهای Multiworker
در پایان
تکنیکهایی که در این مطلب از آنها صحبت کردم همگی به صورت منحصر به فرد به پایتون تعلق ندارند. ممکن است برخی از آنها را از روبی، جاوااسکریپت و یا حتی PHP برداشته باشم. با این حال به نظر میرسد که امتحان کردن این کتابخانه کار جالبی باشد. میتوانید این کتابخانه را از طریق مخزن گیتهاب دریافت کرده و همچنین از آنجا تغییرات را مشاهده کنید.
دیدگاه و پرسش
در حال دریافت نظرات از سرور، لطفا منتظر بمانید
در حال دریافت نظرات از سرور، لطفا منتظر بمانید