Badoo перейшли на PHP7 і зекономили $1M

Badoo перейшли на PHP7 і зекономили $1M

Ми зробили це! Кілька сотень наших application-серверів переведені на PHP7 і прекрасно себе почувають. Наскільки нам відомо, це другий перехід на PHP7 проекту такого масштабу (після Etsy). В процесі ми знайшли кілька дуже неприємних багів в системі кешування байт-коду PHP7, але вони виправлені. А тепер — ура! — добра звістка для всього PHP-спільноти: PHP7 дійсно готовий до продакшену, стабільний, споживає значно менше пам'яті і дає дуже хороший приріст продуктивності. Нижче ми докладно розповімо, як ми перейшли на PHP7, з якими труднощами зіткнулися, як з ними боролися і які результати отримали. Але почнемо з невеликого введення.

Думка про те, що вузьким місцем у веб-проектах є база даних — одне з найбільш поширених помилок. Добре спроектована система збалансована — при збільшенні вхідної навантаження удар тримають всі частини системи, а при перевищенні порогових значень гальмувати починає все: і процесор, і мережева частина, а не тільки диски на базах. У цій реальності процесорна потужність application-кластера є чи не найважливішою характеристикою. У багатьох проектах цей кластер складається з сотень або навіть тисяч серверів, тому «тюнінг» процесорної навантаження на кластері додатків виявляється більш ніж виправданим економічно (мільйон доларів у нашому випадку).

Процесор в веб-додатках PHP «з'їдає» стільки ж, скільки й будь-високорівневий динамічний мова — багато. Але у PHP-розробників роками була особлива печаль (і привід для найсильнішого «троллінгу» з боку інших співтовариств) — відсутність в PHP «чесного» JIT або хоча б генератора в компільований текст на мовах типу С та С++. Нездатність спільноти надати подібні рішення в рамках основного проекту породило неприємну тенденцію: великі гравці стали придумувати власні рішення. Так з'явилися HHVM в Facebook, KPHP у «Вконтакте», напевно, були й інші «саморобки».

На щастя, в 2015 році зроблено перший крок до того, щоб PHP став «дорослішими»: вийшов PHP7. JIT у PHP7 так і не з'явився, однак результат змін у «движку» важко переоцінити: тепер на багатьох задачах PHP7 навіть без JIT не поступається HHVM (див., наприклад, бенчмарки з блогу LiteSpeed і бенчмарки з презентації розробників PHP7). Нова архітектура PHP7 також спрощує подальше додавання JIT.

Платформні розробники Badoo пильно стежили за цими пристрастями останні кілька років і навіть зробили пілотний проект з HHVM, але вирішили дочекатися PHP7, оскільки вважали його більш перспективним. І нещодавно ми запустили Badoo на PHP7! Це був епічний проект як мінімум з-за розміру: у нас більше 3 мільйонів рядків коду на PHP і 60 000 тестів. Про те, як ми з усім цим впоралися, попутно придумавши новий фреймворк для тестування PHP-додатків (вже випустили в open source — схожий на Go! AOP) і заощадили цілий мільйон — читайте далі.

Досліди з HHVM

Перед переходом на PHP7 ми деякий час шукали інші способи оптимізувати наш backend. Звичайно, першим ділом ми вирішили «погратися» з HHVM.

Витративши пару тижнів на дослідження, ми отримали вельми гідні результати: після прогріву JIT на нашому фреймворку виграш по швидкості і використання CPU становив сотні відсотків.

Однак HHVM володів неприємними недоліками:

  • складний і повільний деплой. При деплое необхідно обов'язково прогрівати JIT-кеш. У момент прогріву машина не повинна бути навантажена продакшен-трафіком, тому як все працює досить повільно. Прогрівати паралельними запитами теж не рекомендується. Коротше, фаза прогріву великого кластера — операція нешвидка, плюс на великий кластер в кілька сотень машин треба навчитися викладати порційно. У підсумку отримуємо нетривіальну архітектуру і процедуру деплоя з непередбачуваним часом роботи. А ми хочемо мати максимально простий і швидкий деплой: важливою частиною нашої девелоперської культури є викладка двох планових релізів в день і можливість швидко «розкачати в бій» хотфікси;
  • незручність тестування. Для юніт-тестування ми активно використовували розширення runkit, яке відсутнє в HHVM. Ми детальніше розповімо про це далі, але якщо ви раптом не в курсі, то це таке розширення, яке дозволяє на льоту змінювати поведінку змінних, класів, методів, функцій практично як завгодно, і робиться це через вельми «хардкорную» інтеграцію з «нутрощами» PHP. Ядро HHVM лише віддалено схоже на ядро PHP, так що ці самі «нутрощі» там абсолютно різні. Тому реалізувати runkit поверх HHVM самостійно — hells працю: з-за особливостей розширення нам довелося б переписувати десятки тисяч тестів, щоб переконатися, що HHVM правильно працює з нашим кодом. Нам це здалося недоцільним. Якщо бути чесними, це було проблемою будь-якого з варіантів, і при переході на PHP7 нам все одно довелося переробити дуже багато, в тому числі викинути runkit, але про це пізніше;
  • сумісність. В першу чергу це неповна сумісність з PHP 5.5 (див. github.com/facebook/hhvm/blob/master/hphp/doc/inconsistencies github.com/facebook/hhvm/issues?labels=php5+incompatibility&state=open) і несумісність з уже написаними розширеннями, а у нас їх десятки. Обидві несумісності випливають з очевидного структурного недоліку проекту: HHVM розробляється не співтовариством, а відділом всередині Facebook. У таких випадках компаніям значно простіше поміняти внутрішні правила і стандарти, не озираючись на співтовариство і тонни вже написаного коду. Їм простіше переробити все під себе, вирішити проблему своїми ресурсами. Тому, щоб успішно працювати при таких же обсягах завдань, треба мати порівнянний по потужності ресурс і для первинного етапу впровадження, і для подальшої підтримки. Це ризиковано і потенційно дорого — ми так ризикувати не хотіли;
  • перспективи. Незважаючи на те, що Facebook — велика компанія з класними програмістами, у нас були великі сумніви в тому, що відділ розробки HHVM може виявитися могутніше PHP-спільноти. Ми вважали, що як тільки всередині PHP з'явиться щось схоже, всі доморощені проекти почнуть повільно, але вірно вмирати.
І ми стали чекати PHP7.

Перехід на нову версію інтерпретатора — важливий і складний процес, тому ми готувалися до нього, склавши чіткий план переходу. Він складався з трьох етапів підготовки:

  • зміна інфраструктури для складання і деплоя PHP і адаптація безлічі написаних нами розширень;
  • зміна інфраструктури та оточення тестування;
  • зміни PHP-коду додатків.
Розповімо про всі етапи докладніше.

Виправлення в ядрі і розширення

У нас є власна, активно підтримувана і дорабатываемая гілка PHP. Ми розпочали проект з переведення на Badoo PHP7 ще до його офіційного релізу, тому нам треба було плавно забезпечити регулярний rebase PHP7 upstream в наше дерево, щоб мати можливість отримувати оновлення кожного реліз-кандидата. Всі патчі і кастомізації (див. секцію «Патчі» нашого техсайта tech.badoo.com/open-source), які ми використовуємо в повсякденній роботі, також повинні були бути портируемыми між версіями і працювати коректно.

Ми автоматизували викачування і складання всіх залежностей, экстеншенов і дерева PHP під 5.5 і 7.0. Це не тільки спростило роботу, але й дало хороший заділ на майбутнє: коли вийде версія 7.1, у нас вже все буде готово.

Над экстеншенами теж довелося попотіти. Ми подерживаем близько 40 розширень, причому більше половини — зовнішні розширення open source з нашими напрацюваннями.

Для максимально швидкого переходу ми вирішили запустити паралельно два процеси. Перший — переписати самостійно найкритичніші для нас розширення: шаблонизатор Blitz, кеш даних APcu в Shared memory, збір статистики Pinba і деякі кастомні для роботи з внутрішніми сервісами (в результаті близько 20 розширень).
Другий — активно позбавлятися від розширень, які використовуються в некритичних частинах інфраструктури. Легко позбутися нам вдалося від 11 розширень — чимало!

І, звичайно, ми почали активно спілкуватися з людьми, які підтримують основні відкриті розширення, використовувані нами, на предмет сумісності з PHP7 (окреме спасибі Деріку Ретансу (англ. Derick Rethans), який розробляє Xdebug).

Далі ми трохи докладніше зупинимося на технічних деталях портування розширень під PHP7.

У 7-й версії PHP-розробники змінили багато внутрішніх API, що викликало необхідність редагування великої кількості коду в экстеншенах. Найважливіші зміни наступні:
  • zval * → zval. Раніше, при створенні нової змінної, структура zval завжди аллоцировалась, а тепер використовується структура з стека;
  • char * → zend_string.В PHP7 використовується агресивне кешування рядків в ядрі PHP, тому в новому ядрі повсюдно перейшли із звичайних рядків на структуру zend_string, в якій зберігається рядок і її довжина;
  • зміни в API масивів.Тепер використовується zend_string в якості ключа, в імплементації масивів замінили double linked list на звичайний масив, який виділяється одним блоком замість безлічі маленьких.
Все це дозволило кардинально зменшити кількість невеликих аллокаций пам'яті і в результаті прискорити ядро PHP на десятки відсотків.

Потрібно відзначити, що всі ці зміни спричинили за собою необхідність якщо не переписувати, то активно правити все экстеншены. Якщо у випадку з вбудованими экстеншенами ми могли розраховувати на їх авторів, то наші розробки могли правити тільки ми, а правок потрібно було багато: з-за зміни внутрішніх API деякі частини коду було простіше переписати.

На жаль, введення нових структур, що використовують збір сміття, одночасно з прискоренням виконання коду ускладнює сам движок проблем і знаходження в ньому. Однією з них стала проблема в OPcache, яка полягала в наступному: при очищенні кеша байт-код закешированного файлу руйнувався в той момент, коли він ще міг використовуватися в іншому процесі, що призводило до падіння процесу. Зовні це виглядало так: рядки (zend_string) у назвах функцій або констант раптом руйнуються і замість них з'являється сміття.

Оскільки у нас використовується значна кількість экстеншенов власної розробки, багато з яких активно працюють з рядками, то в першу чергу підозра впала на неправильне використання рядків у них. Написали багато тестів, провели багато експериментів, але все безрезультатно. У підсумку довелося звернутися за допомогою до основного розробника ядра PHP — Дмитру Стогову.

В першу чергу він запитав, очищався чи кеш. З'ясували, що, дійсно, в кожному випадку так і було. Стало зрозуміло, що проблема все-таки не у нас, а в OPcache. Ми швидко відтворили проблему і Дмитро виправив її в протягом пари днів. Без цього виправлення, яке увійшло у версію PHP 7.0.4, використовувати її стабільно в продакшені було не можна!

Зміна інфраструктури тестування

Тестування в Badoo — наша особлива гордість. PHP-код ми викладаємо в продакшен 2 рази в день, кожну викладку у нас потрапляє 20-50 завдань ми використовуємо feature branch у Git і автоматизовану збірку білдів з тісної JIRA-інтеграцією). При такому графіку і обсязі завдань без автотестів ніяк.

На сьогоднішній день у нас близько 60 тисяч юніт-тестів приблизно з 50%-м покриттям, які проходять в середньому за 2-3 хвилини в хмарі (про це ми вже розповідали на Хабре). Крім юніт-тестів, ми використовуємо автотесты більш високого рівня — інтеграційні та системні тести, selenium-тести для веб-сторінок і calabash-тести для мобільних додатків. Все це різноманітність дозволяє нам в найкоротші терміни зробити висновок про якість кожної конкретної версії коду і прийняти відповідні рішення.

Перехід на нову версію інтерпретатора — кардинальна зміна. Можливих проблем може бути скільки завгодно, тому вкрай важливо, щоб всі тести працювали. Для того, щоб стало зрозуміло, що, як і чому ми робили, необхідно зробити невеликий екскурс в історію і розповісти про еволюцію розвитку тестів у нашій компанії.

Часто люди, замислюються про тестування своїх продуктів, стикаються в процесі експериментів (а деякі вже при впровадженні) з тим, що їх код до цього не готовий. Дійсно, розробник повинен пам'ятати про те, що його код повинен бути тестованим. Архітектура повинна дозволяти юніт-тестів підміняти виклики та об'єкти зовнішніх залежностей, щоб ізолювати досліджуваний код від зовнішніх умов. Треба сказати, що вимога це ускладнює життя, і багато програмісти з принципу не хочуть писати код так, щоб його можна було тестувати — нав'язувані обмеження вступають в нерівну боротьбу з іншими цінностями «хорошого коду» і зазвичай програють. І часто, уявивши собі обсяг наявного коду, написаного не за правилами, експериментатори просто відкладають тестування до кращих часів або намагаються задовольнятися малим, покриваючи тестами тільки те, що можна покрити (в результаті тести не завжди дають очікуваний результат).

Наша компанія — не виняток. Ми теж почали впроваджувати тестування далеко не відразу після старту проекту. Було вже написано чимало рядків коду, який цілком собі працював в продакшені і приносив хороші гроші. Переписувати весь цей код заради можливості покрити його тестами так, як рекомендується, вийшло б надто довго і дорого.

На щастя, на той момент вже був відмінний інструмент, який дозволяв вирішити більшість проблем з нетестируемым кодом — runkit. Це розширення для PHP, який дозволяє під час виконання скрипта змінювати, видаляти, додавати методи, класи та функції, які використовуються в програмі. Він може ще багато чого, але інші функції розширення ми не використали. Інструмент розроблявся і підтримувався протягом кількох років (з 2005 по 2008 роки) Сарою Гоулман (англ. Sara Golemon), яка зараз працює в Facebook, в тому числі і над HHVM. А з 2008 року і по сьогоднішній день проект підтримує наш співвітчизник Дмитро Зенович (працював керівником відділів тестування в «Бігуні» і Mail.Ru). І ми теж трошки «наконтрибутили» в проект.

Сам по собі runkit — дуже небезпечний экстеншен. З його допомогою можна змінювати константи, функції та класи прямо під час роботи скрипта, який їх використовує. По суті, це інструмент, за допомогою якого можна перебудувати ваш літак прямо під час польоту. Runkit лізе в самі нутрощі PHP на льоту; одна помилка або недоробка в runkit — і літак красиво вибухає в повітрі, PHP падає, або ви проводите багато годин в пошуку витоків пам'яті та іншої низькорівневої налагодження. Тим не менш, це був для нас необхідний інструмент: впровадити тестування в проект без серйозного переписування можна тільки так, через зміну коду на льоту, просто замінюючи його на потрібний.

При переході на PHP7 runkit виявився великою проблемою — цю версію PHP він не підтримував. Був варіант спонсорування розробки нової версії, але цей шлях не здавався нам самим надійним в довгостроковій перспективі. Паралельно ми розглядали кілька інших варіантів.

Одним з перспективних рішень було перейти з runkit на uopz. Це теж розширення PHP c схожою функціональністю, що з'явилося в квітні 2014 року. Його нам запропонували колеги з «Мамби», давши дуже хороші відгуки в першу чергу швидкості роботи. Проект підтримує Джо Уоткінс (англ. Joe Watkins) з First Beat Media (UK). Виглядав цей проект більш живим і перспективним порівняно з runkit. Але, на жаль, перевести на uopz всі тести у нас не вийшло. Десь траплялися фатальні помилки, десь сегфолты — ми завели кілька репортов, але за ним, на жаль, руху немає (докладніше див. наприклад цей баг на github). Обійтися переписуванням тестів в цьому випадку вийшло б дуже дорого, та і не факт, що не виявилося б щось ще.

В результаті ми прийшли до очевидного для нас рішення: раз нам і так необхідно переписати безліч коду і при цьому все одно залежати від зовнішніх проектів типу runkit або uopz, з якими у нас постійно з'являються проблеми, які дуже дорого або неможливо вирішувати самостійно, то чому б вже не переписати код так, щоб по максимуму всі залежно прибрати? Та так, щоб подібних проблем у нас більше ніколи не виникало, навіть якщо ми захочемо перейти на HHVM або будь-який інший подібний продукт. І тоді у нас з'явився свій фреймворк.

Система отримала назву SoftMocks. Слово soft підкреслює, що система працює на чистому PHP замість використання розширень. Це проект open source, він доступний у вигляді підключається бібліотеки і знаходиться в відкритому доступі. SoftMocks не зав'язаний на особливості реалізації ядра PHP і працює за допомогою переписування коду на льоту, за аналогією з фреймворком Go! AOP.

В нашому коді тестів в основному використовуються наступні речі:
  1. Підміна реалізації одного з методів класу.
  2. Підміна результату виконання функції.
  3. Зміна значення глобальної константи або константи класу.
  4. Додавання методу в клас.
Всі ці можливості прекрасно реалізуються з допомогою runkit. При переписуванні коду це стає можливим, але з деякими застереженнями.

Опис роботи SoftMocks — матеріал для окремої статті, яку ми найближчим часом напишемо. А поки обмежимося лише коротким описом роботи цієї системи:

  • користувальницький код підключається через функцію-обгортку rewrite. Після цього всі оператори include автоматично рекурсивно підміняються на обгортки;
  • всередину визначення кожного користувача методу додається перевірка на існування підміни, і якщо вона є, то виконується відповідний код. Прямі виклики функцій замінюються на виклик через обгортку — це дозволяє перехоплювати як вбудовані, так і користувальницькі функції;
  • звернення до констант в коді також динамічно підміняються на виклик обгортки;
  • SoftMocks в роботі використовує PHP-Парсер Микити Попова. Ця бібліотека не дуже швидка (парсинг приблизно в 15 разів повільніше token_get_all), але надає зручний інтерфейс для обходу синтаксичного дерева і дає зручний API для роботи з синтаксичними конструкціями довільної складності.
Повернемось до нашого завдання — переходу на PHP7. Після того як ми стали використовувати в проекті SoftMocks, у нас залишилося близько 1000 тестів, які потрібно «полагодити» вручну. Це можна вважати непоганим результатом, якщо врахувати, що спочатку у нас було 60 000 тестів. Швидкість їх прогону порівняно з runkit не зменшилася, так що в плані продуктивності серйозних втрат від використання SoftMocks немає. Справедливості заради відзначимо, що uopz все-таки повинен працювати помітно швидше.

Утиліти і код програми

Крім безлічі нововведень, PHP7 приніс з собою і деякі зворотні несумісності. Перше, з чого ми почали вивчення проблеми — це читання офіційного migration guide. Швидко стало зрозуміло, що без виправлення наявного коду ми ризикуємо отримати в продакшені фатальні помилки, так і зіткнутися з зміною поведінки, яке не буде відображено в логах, але призведе до неправильної логіки роботи програми.

Badoo — це кілька репозиторіїв коду на PHP, найбільший з яких містить більше 2 мільйонів рядків коду. Причому на PHP у нас реалізовано безліч речей: починаючи від бізнес-логіки веба і бек-ендом мобільних додатків і закінчуючи утилітами тестування і викладки коду. Крім цього ситуація ускладнювалася тим, що Badoo — проект з історією, йому вже 10 років, і спадщина PHP4, на жаль, все ще присутній. Відповідно, метод «пильної вдивляння» непридатний. Застосовується і «бразильська система», тобто викласти в продакшен як їсти і дивитися, що зламається, надто збільшує ризики зламати бізнес-логіку для занадто великого відсотка користувачів. Тому ми почали шукати можливість автоматизувати пошук несумісних місць.

Спочатку ми спробували використовувати найбільш популярні серед розробників IDE, але, на жаль, на той момент вони просто не підтримували синтаксис і особливості PHP7, або виявляли підозріло мало проблем, пропускаючи, очевидно, небезпечні місця в коді. Після невеликого дослідження було вирішено спробувати утиліту php7mar. Це такий нескладний статичний аналізатор коду, реалізований на PHP. Дуже простий у використанні, працює досить швидко, результат надає у вигляді текстового файлу, вимагає наявності PHP7. Звичайно, дана утиліта не є панацеєю, є як помилкові спрацьовування, так і пропуски особливо «хитрих» місць в коді. Але близько 90% проблем з її допомогою вдалося виявити, що суттєво прискорило і полегшило процес підготовки коду до роботи під PHP7.

Найбільш часто зустрічаються і потенційно небезпечними проблемами для нас були:
  • зміна поведінки функцій func_get_arg() і func_get_args(). У п'ятій версії PHP ці фунції повертали значення аргументів функцій на момент їх передачі, а в сьомій версії — на момент виклику func_get_args(). Таким чином, якщо всередині функції до виклику func_get_args() змінна агрумента змінюється, то є ризик отримати поведінка, відрізняється від п'ятої версії. Це той самий випадок, коли в логах буде порожньо, а бізнес-логіка програми може виявитися зламаною;
  • непряме звернення до змінним, властивостей і методів об'єктів. І знову небезпека в тому, що поведінка може змінитися «мовчки». У документаціїдосить докладно описано, в чому саме полягають відмінності;
  • використання зарезервованих імен класів. У PHP7 стало не можна використовувати bool, int, float, string, null, true і false в якості імені класу. Так-так, у нас був клас Null. На щастя, цей випадок вже простіше, бо призводить до помилки;
  • дуже багато було знайдено потенційно проблемних конструкцій foreach, які використовують посилання. Але практично всі з них вели себе однаково у п'ятої та сьомої версії, так як ми і раніше намагалися всередині foreach не змінювати итерируемый масив і не розраховувати на його внутрішній покажчик.
Інші випадки несумісності або зустрічалися вкрай рідко (як, наприклад модифікатор 'e' для регулярних виразів), або виправлялися простою заміною (наприклад, тепер всі конструктори повинні називатися __construct(), використовувати ім'я класу заборонено).
Але, перед тим як розпочати виправлення коду, ми подумали, що поки одні розробники вносять необхідні для сумісності зміни, інші будуть продовжувати писати несумісний з PHP7 код. Для вирішення цієї проблеми ми додали pre-receive hook в кожен Git-репозиторій, який виконував на змінюваних файлах php7 -l, тобто перевіряв їх на відповідність синтаксису PHP7. Це не гарантує повний захист від несумісності, але вже усуває ряд проблем. В інших же випадках розробникам просто доводилося бути трохи уважніше. Крім того, ми стали робити регулярний прогін повного набору тестів під PHP7 і порівнювати результати з прогонами під PHP5. При цьому використовувати будь-які нові можливості PHP7 розробникам було заборонено, тобто старий pre-receive hook з php5 -l ми не вимикали. Це дозволило нам у певний момент отримати код, сумісний як з сьомою, так і з п'ятою версією інтерпретатора. Чому це важливо? Тому що крім проблем з PHP-кодом, при оновленні на нову версію можливі проблеми з самим PHP7 і його розширень (власне, як сказано вище, ми з цими проблемами і зіткнулися). І, на жаль, не всі з них відтворювалися в тестовому оточенні, деякі ми змогли побачити тільки під значним навантаженням в продакшені.

«Запуск в бій» і результати

Очевидно, нам потрібен простий і швидкий спосіб змінювати версію PHP на будь-яку кількість будь-яких серверів. Для цього у всьому коді шляху до CLI-інтерпретатору були замінені на /local/php, який, у свою чергу, був симлинком або на /local/php5, або на /local/php7. Таким чином, для зміни версії PHP на сервері потрібно змінити посилання (операція атомарна — це важливо для CLI-скриптів), зупинити php5-fpm і запустити php7-fpm. Можна було б мати в nginx два upstream для php-fpm, запускати php5-fpm і php7-fpm на різних портах, але цей варіант нам не сподобався усложеніе конфігурації nginx.

Після того як все перераховане вище було виконано, ми змогли перейти до прогону selenium-тестів у препродакшен-оточенні, що дозволило нам виявити ряд проблем, не помічені раніше. Вони стосувалися як PHP-коду (наприклад, довелося відмовитися від застарілої глобальної змінної $HTTP_RAW_POST_DATA на користь file_get_contents(«php://input»)), так і розширень (різного роду помилки сегментації).

Виправивши виявлені на попередньому етапі проблеми та закінчивши переписування юніт-тестів (в ході якого нам теж вдалося виявити кілька багів в інтерпретаторі, наприклад, такий), ми нарешті приступили до «карантину» в продакшені. «Карантином» ми називаємо запуск нової версії PHP на обмеженому числі серверів. Почали з одного сервера в кожному великому кластері (бекенд інтернету і мобільних додатків, хмара), поступово збільшуючи кількість, якщо помилок не виникає. Першим великим кластером, повністю перейшли на PHP7, стало облако. Причиною цього стало відсутність на ньому потреби в php-fpm. Тим же кластерах, де працює fpm, довелося почекати до тих пір, поки ми не виявили, а Дмитро Стогів не виправив проблему з OPcache. Після цього ми вже переклали і fpm-кластер.

Тепер про результати. Якщо коротко, то вони більш ніж вражають. Нижче наведені графіки часу відповіді, rusage, споживання пам'яті і використання процесора в найбільшому (263 сервера) мають у нас кластерів, а саме — бек-ендом мобільних додатків в празькому дата-центрі:

Розподіл часів відповіді:


RUsage (CPU time):


Memory usage:


CPU load (%) на всьому кластері:


Таким чином, процесорний час скоротилося в 2 рази, що покращило загальний час відповіді приблизно на 40%, оскільки деяка частина часу при обробці запиту витрачається на спілкування з базами і демонами, і з переходом на PHP7 ця частина ніяк не прискорюється, що очікувано. Крім того, ефект дещо посилюється тим, що загальне навантаження на кластер впала нижче 50%, що вказує на деякі особливості в роботі технології Hyper-Threading. Грубо кажучи, при збільшенні навантаження вище 50% починають працювати HT-ядра, які не настільки корисні, як ядра фізичні, але це вже тема для іншої статті.
Споживання пам'яті, хоча ніколи і не було для нас вузьким місцем, знизилась приблизно у 8 разів! І, нарешті, ми заощадили на обладнанні — тепер ми можемо на тій же кількості серверів витримувати набагато більше навантаження, що, по суті, знижує витрати на його придбання і обслуговування. Результати на інших кластерах відрізняються незначно, хіба що виграш на хмарі трохи скромніше (близько 40% CPU) з-за відсутності там OPcache.

Скільки ми заощадили в грошах? Давайте порахуємо. Кластер серверів додатків у нас складається з 600 з гаком серверів. Знизивши використання CPU в два рази, ми отримуємо економію приблизно в 300 серверів. Додавши початкову ціну такого «заліза» (близько 4000$ за кожен) і амортизацію, отримуємо близько мільйона доларів економії плюс близько ста тисяч в рік на хостингу! І це не рахуючи хмари, продуктивність якого також зросла. Вважаємо, що це — відмінний результат!

А ви вже перейшли на PHP7? Будемо раді почути вашу думку і питання в коментарях.

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.