سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید

در اکوسیستم PHP در حال حاضر دو رابط برای کار با سرور Tarantool وجود دارد - این افزونه رسمی PECL است. tarantool/tarantool-php، نوشته شده در C، و tarantool-php/client، به زبان PHP نوشته شده است. من نویسنده دومی هستم.

در این مقاله، من می خواهم نتایج تست عملکرد هر دو کتابخانه را به اشتراک بگذارم و نشان دهم که چگونه با حداقل تغییرات در کد، می توانید به افزایش عملکرد 3-5 دست یابید (در تست های مصنوعی!).

چه چیزی را آزمایش خواهیم کرد؟

موارد ذکر شده در بالا را تست خواهیم کرد همزمان اتصال دهنده هایی که به صورت ناهمزمان، موازی و ناهمزمان-موازی اجرا می شوند. 🙂 همچنین نمی خواهیم به کد خود کانکتورها دست بزنیم. در حال حاضر چندین افزونه برای دستیابی به آنچه می خواهید وجود دارد:

  • سول - یک چارچوب ناهمزمان با کارایی بالا برای PHP. توسط غول های اینترنتی مانند علی بابا و بایدو استفاده می شود. از نسخه 4.1.0 یک روش جادویی ظاهر شده است SwooleRuntime::enableCoroutine()، که به شما امکان می دهد "کتابخانه های شبکه PHP همزمان را با یک خط کد به کتابخانه های ناهمزمان تبدیل کنید."
  • Async تا همین اواخر یک پسوند بسیار امیدوارکننده برای کارهای ناهمزمان در PHP بود. چرا تا همین اواخر؟ متأسفانه، به دلیل ناشناخته من، نویسنده مخزن را حذف کرد و سرنوشت آینده پروژه نامشخص است. من باید از آن استفاده کنم одним از چنگال ها مانند Swoole، این افزونه به شما این امکان را می‌دهد تا به راحتی شلوار خود را با یک حرکت مچ باز کنید تا با جایگزین کردن اجرای استاندارد جریان‌های TCP و TLS با نسخه‌های ناهمزمان آنها، ناهمزمانی را فعال کنید. این کار از طریق گزینه «async.tcp = 1".
  • موازی - یک پسوند نسبتاً جدید از جو واتکینز معروف، نویسنده کتابخانه هایی مانند phpdbg، apcu، pthreads، pcov، uopz. افزونه یک API برای چند رشته ای در PHP ارائه می دهد و به عنوان جایگزینی برای pthread ها قرار می گیرد. محدودیت قابل توجه کتابخانه این است که فقط با نسخه ZTS (Zend Thread Safe) PHP کار می کند.

چگونه آزمایش خواهیم کرد؟

بیایید یک نمونه Tarantool را با غیرفعال کردن ثبت پیش از نوشتن (wal_mode = هیچ) و افزایش بافر شبکه (Readahead = 1 * 1024 * 1024). گزینه اول کار با دیسک را حذف می کند، گزینه دوم خواندن درخواست های بیشتر از بافر سیستم عامل را امکان پذیر می کند و در نتیجه تعداد تماس های سیستم را به حداقل می رساند.

برای معیارهایی که با داده ها کار می کنند (درج، حذف، خواندن و غیره)، قبل از شروع معیار، یک فضای memtx (دوباره) ایجاد می شود که در آن مقادیر شاخص اولیه توسط یک تولید کننده مقادیر صحیح مرتب شده ایجاد می شود. (توالی).
فضای DDL به شکل زیر است:

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

در صورت لزوم، قبل از اجرای معیار، فضا با 10,000 تاپل فرم پر می شود.

{id, "tuplе_<id>"}

تاپل ها با استفاده از یک مقدار کلید تصادفی قابل دسترسی هستند.

خود بنچمارک یک درخواست واحد به سرور است که 10,000 بار (انقلاب) اجرا می شود که به نوبه خود در تکرار اجرا می شود. تکرارها تا زمانی تکرار می شوند که تمام انحرافات زمانی بین 5 تکرار در خطای قابل قبول 3٪ * باشد. پس از این، میانگین نتیجه گرفته می شود. یک مکث 1 ثانیه ای بین تکرارها وجود دارد تا از انقباض پردازنده جلوگیری شود. زباله جمع کن Lua قبل از هر بار تکرار غیرفعال می شود و پس از اتمام آن مجبور به کار می شود. فرآیند PHP تنها با برنامه‌های افزودنی لازم برای معیار، با بافر خروجی فعال و جمع‌آوری زباله غیرفعال راه‌اندازی می‌شود.

* تعداد دورها، تکرارها و آستانه خطا را می توان در تنظیمات بنچمارک تغییر داد.

محیط آزمایش

نتایج منتشر شده در زیر بر روی MacBookPro (2015)، سیستم عامل - فدورا 30 (نسخه هسته 5.3.8-200.fc30.x86_64) ساخته شده است. Tarantool در داکر با پارامتر " راه اندازی شد--network host".

نسخه های بسته:

Tarantool: 2.3.0-115-g5ba5ed37e
داکر: 19.03.3، ساخت a872fc2f86
PHP: 7.3.11 (cli) (ساخته شده: 22 اکتبر 2019 08:11:04)
tarantool/client: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ پچ برای 7.3)*
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
موازی بیرونی: 1.1.3

* متأسفانه کانکتور رسمی با نسخه PHP > 7.2 کار نمی کند. برای کامپایل و اجرای پسوند روی PHP 7.3، مجبور شدم از آن استفاده کنم پچ.

یافته ها

حالت همزمان

پروتکل Tarantool از یک فرمت باینری استفاده می کند بسته پیام برای سریال سازی پیام ها در کانکتور PECL، سریال سازی در اعماق کتابخانه پنهان شده است و بر فرآیند رمزگذاری از کد کاربر لند تأثیر می گذارد. ممکن به نظر نمی رسد. برعکس، یک رابط PHP خالص، توانایی سفارشی کردن فرآیند رمزگذاری را با گسترش رمزگذار استاندارد یا با استفاده از پیاده‌سازی خودتان فراهم می‌کند. دو رمزگذار خارج از جعبه موجود است، یکی بر اساس msgpack/msgpack-php (پسوند رسمی MessagePack PECL)، دیگری روشن است rybakit/msgpack (در PHP خالص).

قبل از مقایسه کانکتورها، عملکرد رمزگذارهای MessagePack را برای کانکتور PHP اندازه‌گیری می‌کنیم و در آزمایش‌های بعدی از یکی که بهترین نتیجه را نشان می‌دهد استفاده خواهیم کرد:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
اگرچه نسخه PHP (Pure) از نظر سرعت پایین تر از پسوند PECL است، اما در پروژه های واقعی من همچنان استفاده از آن را توصیه می کنم. rybakit/msgpack، زیرا در پسوند رسمی MessagePack مشخصات فرمت فقط تا حدی پیاده سازی شده است (به عنوان مثال، پشتیبانی از انواع داده های سفارشی وجود ندارد، بدون آن شما نمی توانید از Decimal - یک نوع داده جدید معرفی شده در Tarantool 2.3) استفاده کنید. تعدادی دیگر چالش ها و مسائل (از جمله مشکلات سازگاری با PHP 7.4). خب، به طور کلی، پروژه رها شده به نظر می رسد.

بنابراین، اجازه دهید عملکرد کانکتورها را در حالت همزمان اندازه گیری کنیم:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
همانطور که از نمودار مشخص است، کانکتور PECL (Tarantool) در مقایسه با کانکتور PHP (Client) عملکرد بهتری را نشان می دهد. اما این تعجب آور نیست، با توجه به اینکه دومی، علاوه بر پیاده سازی در زبان کندتر، در واقع کار بیشتری انجام می دهد: با هر فراخوانی یک شی جدید ایجاد می شود. درخواست и واکنش (در مورد Select - همچنین ضوابطو در مورد Update/Upsert - عملیات)، نهادهای جداگانه اتصال, بستهبند и مربی سربار را نیز اضافه می کنند. بدیهی است که انعطاف پذیری بهایی دارد. با این حال، به طور کلی، مفسر PHP عملکرد خوبی را نشان می دهد، اگرچه تفاوت وجود دارد، اما ناچیز است و شاید در هنگام استفاده از پیش بارگذاری در PHP 7.4 حتی کمتر از JIT در PHP 8 باشد.

بیایید ادامه دهیم. Tarantool 2.0 پشتیبانی SQL را معرفی کرد. بیایید سعی کنیم عملیات Select، Insert، Update و Delete را با استفاده از پروتکل SQL انجام دهیم و نتایج را با معادل های noSQL (باینری) مقایسه کنیم:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
نتایج SQL چندان چشمگیر نیستند (اجازه دهید یادآوری کنم که ما هنوز در حال آزمایش حالت همزمان هستیم). با این حال، من زودتر از این بابت ناراحت نمی شوم؛ پشتیبانی SQL هنوز در حال توسعه فعال است (به عنوان مثال اخیراً پشتیبانی اضافه شده است. بیانیه های آماده شده) و با قضاوت در لیست مسائل، موتور SQL در آینده تحت تعدادی بهینه سازی قرار خواهد گرفت.

آسیک

خوب، اکنون بیایید ببینیم که چگونه افزونه Async می تواند به ما در بهبود نتایج بالا کمک کند. برای نوشتن برنامه‌های ناهمزمان، افزونه یک API بر اساس برنامه‌های مشترک ارائه می‌کند که ما از آن استفاده خواهیم کرد. ما به طور تجربی متوجه می شویم که تعداد بهینه کوروتین ها برای محیط ما 25 است:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
10,000 عملیات را در 25 برنامه مشترک "گسترش" کنید و ببینید چه اتفاقی می افتد:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
تعداد عملیات در ثانیه بیش از 3 برابر برای tarantool-php/client!

متأسفانه کانکتور PECL با ext-async شروع نشد.

در مورد SQL چطور؟

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
همانطور که می بینید، در حالت ناهمزمان، تفاوت بین پروتکل باینری و SQL در حاشیه خطا قرار گرفت.

سول

دوباره تعداد بهینه کوروتین ها را، این بار برای Swoole پیدا می کنیم:
سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
بیایید روی 25 توقف کنیم. بیایید همان ترفند را با افزونه Async تکرار کنیم - 10,000 عملیات را بین 25 کوروتین توزیع کنید. علاوه بر این، یک تست دیگر اضافه می کنیم که در آن تمام کارها را به 2 دو فرآیند تقسیم می کنیم (یعنی هر فرآیند 5,000 عملیات را در 25 کوروتین انجام می دهد). فرآیندها با استفاده از SwooleProcess.

نتایج:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
Swole در یک فرآیند در مقایسه با Async نتیجه کمی پایین‌تر نشان می‌دهد، اما با 2 پردازش تصویر به‌طور چشمگیری تغییر می‌کند (عدد 2 تصادفی انتخاب نشد؛ در دستگاه من، 2 پردازش بود که بهترین نتیجه را نشان داد).

ضمناً ، افزونه Async یک API برای کار با فرآیندها نیز دارد ، اما در آنجا تفاوتی با اجرای بنچمارک در یک یا چند فرآیند مشاهده نکردم (ممکن است جایی بهم ریخته باشم).

SQL در مقابل پروتکل باینری:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
همانند Async، تفاوت بین عملیات باینری و SQL در حالت ناهمزمان حذف می شود.

موازی

از آنجایی که پسوند Parallel در مورد کوروتین ها نیست، بلکه در مورد رشته ها است، اجازه دهید تعداد بهینه نخ های موازی را اندازه گیری کنیم:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
روی دستگاه من 16 است. بیایید بنچمارک های رابط را روی 16 رشته موازی اجرا کنیم:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
همانطور که می بینید، نتیجه حتی بهتر از برنامه های افزودنی ناهمزمان است (بدون احتساب اجرای Swoole روی 2 فرآیند). توجه داشته باشید که برای کانکتور PECL، عملیات Update و Upsert خالی است. این به دلیل این واقعیت است که این عملیات با یک خطا شکست خورده است - نمی دانم آیا تقصیر ext-parallel، ext-tarantool یا هر دو بوده است.

حالا بیایید عملکرد SQL را با هم مقایسه کنیم:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید
به شباهت با نمودار برای اتصال دهنده هایی که به طور همزمان اجرا می شوند، توجه کنید؟

با یکدیگر

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

* راه اندازی کوروتین های Swoole با Parallel امکان پذیر نبود؛ به نظر می رسد این افزونه ها ناسازگار هستند.

بنابراین، نتایج نهایی:

سرعت اتصالات Tarantool PHP را با Async، Swoole و Parallel افزایش دهید

به جای یک نتیجه گیری

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

منبع: www.habr.com

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