Рефакторинг, вторая часть (с цифрами)

16.10.2010

Данный материал будет интересен только технарям, это продолжение целого цикла заметок, касающихся эволюции методов чтения и записи данных в рекламном движке Daos. О повышении сбросоустойчивости при высоких нагрузках и вообще оптимизации кода.

Цикл начинается 1) задачкой для программистов, 2) продолжается заметкой про нагрузочное тестирование PHP-скриптов с помощью Apache Benchmark, 3) далее статья про этапы рефакторинга функций чтения/записи в Daos и, пожалуй, 4) завершается уже сейчас.

Надеюсь, дальше эту тему поднимать не придётся, и так голова уже пухнет от новых знаний, да и достигнуты вполне приличные результаты.

НИОКР вокруг ФЧЗ в PHP :)

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

Для тестирования я отобрал четыре варианта реализации ФЧЗ:

  1. Собственные старые ФЧЗ (далее ФЧЗ-1, код здесь.), заведомо плохой вариант, так как допускает иногда сброс данных. Именно из-за сбросов и начались эти исследования на более серьезном уровне, чем то было раньше.
  2. Собственную новую реализацию (далее ФЧЗ-2, исходники). Не один день думал, делал и переделывал, в результате последние изменения внёс уже сегодня перед написанием этой заметки. Хотя опытные образцы уже тестируются на очень нагруженном сайте и хорошо себя показали.
  3. Вариант от Jungle (далее ФЧЗ-Д, код тут). На мой взгляд несколько избыточное решение, но почему бы не проверить? Хотя, сравнивать эти функции с предыдущим и следующим вариантом не совсем корректно, т. к. они написаны не с нуля, а основаны на несовершенных ФЗЧ-1 с добавлением функций Jungle.
  4. Извращённый вариант, основанный на идее от Alek$ (далее ФЧЗ-А, см. код), он предложил нестандартно использовать сессии для блокировки файлов. Пусть изврат, но очень интересный. Признаюсь, это извращение мне нравится.

Тестирование

Зарядил все ФЧЗ в копии дистрибутивов, и поехали! Интересные получились результаты, смотрите сами. Только учитывайте, что эти результаты получены не в боевых условиях работающего в сети сервера, а на моей старенькой машинке, то есть вообще не учитывайте абсолютные значения, интерес представляют исключительно сравнительные данные.

Тест ФЧЗ-1 ФЧЗ-2 ФЧЗ-А
Ночное стресс-тестирование для выявления случаев повреждения данных. Общее количество запросов — 50 тыс., и 50 строчек в ротации (большой файл статистики).
ab -n 50 -c 3 do/test/JSblock.php (x 1000)
25 сбросов сбросов не было сбросов не было
Проверка скорости выполнения скрипта при умеренной нагрузке и отсутствии конкурентных запросов. В отчёте время в мс и количество выполненных запросов/отказов.
ab -n 1000 do/test/JSblock.php
150 мс (1000/780) 180 мс (1000/0) 160 мс (1000/0)
А теперь добавим конкурентных запросов. Формат отчёта аналогично предыдущему тесту.
ab -n 1000 -с 3 do/test/JSblock.php
490 мс (1000/190) 520 мс (1000/0) 490 мс (1000/0)
Работа под нагрузкой у всех ФЧЗ оказывает эффект занижения статистики показов. В идеале после теста количество показов в Daos должно точно соответствовать количеству запросов ab. В отчёте показан процент соответствия. 93% 95% 98%

Итоги

Явно видно преимущество варианта Alek$ (ФЧЗ-А), сессии действительно работают надёжнее всего, и код получается гораздо проще. Не говоря уж о том, что у ФЧЗ-2 есть параметры $limit и $sleep, которые очень сильно влияют на показатели скорости отклика и количества отказов. Самая большая сложность — подобрать оптимальное соотношение, ведь оно различается от сервера к серверу. Сессии лишены этого недостатка, так что решено.

Почему в таблице нет ФЧЗ-Д? Вариант не заработал с первой попытки, времени на разбирательства нет, тем более, такой способ мне всё же совсем не нравится. Уж слишком избыточные функции, я уверен, что они не принесут никакого выигрыша ни в чём. Но всё равно спасибо за попытку!

Дополнительная оптимизация

А потом ещё попробовал в файлике, который непосредственно выдаёт JS-код в браузер (JSblock.php), убрать подключение сборника-функций daos.php и внедрить в него функции чтения/записи напрямую (дублирование кода в угоду производительности). Результаты в таблице ниже. Для сравнения часть одной колонки скопирована из предыдущей таблицы.

Тест ФЧЗ-А в JSblock.php ФЧЗ-А
Проверка скорости выполнения скрипта при умеренной нагрузке.
ab -n 1000 do/test/JSblock.php
150 мс (1000/0) 160 мс (1000/0)
То же с конкурентными запросами.
ab -n 1000 -с 3 do/test/JSblock.php
510 мс (1000/0) 490 мс (1000/0)
Процент соответствия. 100% 98%
Попробуем тест пожёстче, имитируем семёрку гиперхолериков.
ab -n 1000 -c 7 do/test/JSblock.php
1,14 сек. (1000/0) 1,15 сек. (1000/0)
Атака сумасшедшей семёрки окончена. Какой процент соответствия запросов и показов в статистике? 100% 97%

Результаты меня удивили. Я ожидал, что время выполнения должно существенно сократиться, а влияние на процент соответствия будет минимальным. Вышло наоборот! Как, почему? Пока не понимаю.

Зато скептики, которые призывали не экономить на спичках могут торжествовать, вы, наверно, были правы. И, конечно, прав Стив Макконнелл, который в книге Совершенный код категорически протестовал против преждевременной оптимизации. Код нужно просто писать, заботясь прежде всего об удобстве и читаемости, а оптимизировать уже после, и то, лишь в том случае, если производительность приложения оказалась недостаточной.

Впрочем, как поступить в данном случае — пока не знаю. Необходимо провести дополнительные тесты, и если расхождение в процентах соответствия не окажется статистической ошибкой, всё же частично дублировать в JSblock.php код из daos.php.

А по времени исполнения, у меня такая теория — похоже, подключаемые файлы PHP кэширует всё же, а значит бояться дополнительных include() не нужно, если это предоставляет в проекте дополнительные удобства. Производительность не падает.

Двойная надёжность

Несмотря на отличные результаты ФЧЗ-А, в в новой версии Daos (планирую выпустить завтра) всё же появится дополнительная возможность восстановить статистику из резервных копий вручную, потому что все вышеперечисленные ФЧЗ не гарантируют работу после сбоя «железа» хостера. Например, если в результате аварии файл запишется лишь наполовину, PHP при подключении такого файлика через include() может немножко сойти с ума.

И это ещё не всё!

Вообще, есть много всяких решений проблемы блокировки файлов при чтении/записи. Но эти ссылки я пока не смотрел, да и закруглиться хочу уже. Кстати, о предлагаемых комментаторами решениях…

У меня замечательные читатели!

Спасибо вам за то, что вы есть, за то что часто приходите на помощь, советуете, подсказываете, критикуете. Я вам очень благодарен. Вы у меня самые лучшие :)

Комментарии

  1. # aktuba

    Коды не смотрел, но не понимаю, почему нельзя вынести общие фрагменты кода в отдельный файл и подключать его?

  2. # Тормоз

    Можно… но тогда в index.php придётся подключать два ))

  3. # quantum

    Возможна такая ситуация, когда include_flock одного клиента заблокировал файл сессии, а в это время вызвался vw другого клиента и все порушилось? Файлы сессий у разных клиентов-то разные, поэтому блокировки не работают.

    А вообще, использование механизмов для того, для чего они не предназначены дурной тон, хоть решение и рабочее и в какой-то степени красивое.

  4. #  Тормоз

    Файлы сессий не разные, ID сессии прямо прописывается в скрипте, посмотри код. Так что ничего не порушится, как раз для таких случаев оно всё и делается.

    И использование такого механизма — это прекрасный пример программирования с использованием языка, а не программирования на языке (с ограничениями). Никто бы про сессии и не вспомнил, если бы предназначенный для блокировок flock работал как надо.

  5. # aktuba

    Ну подключай 2 – ничего страшного.

    P.S.: кстати, ты знаешь, что твои комментарии на почту не приходят, а чужие приходят. Баг ;)

  6. #  Тормоз

    Нет, не знал такого. Нифига себе :( Спасибо что сказал, надо будет разбираться, что за ерунда творится.

  7. # quantum

    По одной сессии – да, код быстро просмотрел и только в некоторых местах.

    А про программирование с использованием языка не согласен. Это всего лишь попытки воссоздать семафоры другими, не предназначенными для этого методами, пусть и удачными (как в сессиями).
    И от того, что механизм с сессиями рабочий, и того, что рабочий везде (в отличие от не включенных по дефолту семафорных функций http_://www.php.net/manual/en/sem.installation.php) это не становится менее дурным тоном.

  8. #  Тормоз

    Я не религиозный фанатик, меня дурность тона мало волнует, если решение превосходно работает. Да и тем более, что сам дурным тоном это не считаю.

  9. # quantum

    Собственно, это с самого начала было понятно. Просто не смог не высказать свое фи;)

  10. #  Тормоз

    На кой чёрт ты прочерк в http ставишь? Активная ссылка удобней, вообще-то. И распознаётся автоматически — www.php.net/manual/e…

    Вот такая линкофобия точно дурнейший тон.

  11. # quantum

    Мало ли. За спам посчитается, потеряется коммент. А я так много редко пишу – жалко:)

  12. #  Тормоз

    Спам — это когда человек комментирует ради ссылки на продвигаемый говносайт. С чего бы я тебя-то банил? :) Каким-то злодеем считаешь меня.

  13. # quantum

    Автоматически конечно:) За php.net ты сам банить никогда не будешь:)

    Вобщем в любом случае я рад, что не будет постов «Я опять где-то просчитался и опять файлы сбрасываются» и рабочее решение найдено, хоть и немного обходное.

  14. #  Тормоз

    Ох, хоть бы так и было :) А то вдруг ещё что-то пропустил. Но всё же 0 сбросов на стресс-тестах в сравнении с 25 прошлого варианта заставляет меня поверить в надёжность.

    P.S. Автоматического бана у меня вообще нет, от автоматики защищает предпросмотр.

  15. #  Тормоз-тестер

    Так, подписываюсь. Извините, кому приходят лишние сообщения, но мне нужно протестировать.

  16. #  Тормоз

    Этот комментарий должен отправиться на мыло прошлому… и всем.

  17. #  Тормоз

    Хм, ну пришло сообщение. Интересненько.

Комментирование этой статьи закрыто.

Интересное Покупки ТехникаРазное Отдых Статьи Строительство Услуги Общество Хобби Культура Советы Уют