Использование дополнительных инструкций CPU в одной из задач на PHP для ускорения производительности

При построении крупных PHP-проектов многие сталкивались с нехваткой производительности, даже на мощных серверах. Даже небольшой участок кода может ощутимо повлиять на весь ресурс в целом: в плане прибыли, и в плане затрат на поддержку и обслуживание данного ресурса. Расскажу Вам мой опыт о нестандартном подходе решения одной задачи.

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

Уже когда все написано, работает, и продолжает дальше разрабатываться, и ни времени, ни бюджета переделывать что-либо – дабы улучшить производительность – нет, а двигаться нужно только вперед, причем как можно быстрее, я получаю очередное задание. Сначала я посмотрел на него как на обычный тикет: вся личная информация пользователя: фамилия, адрес, телефон, идентификационный код – должна храниться в базе в зашифрованном виде, и быть доступна только при запросе с ключами для расшифровки. Так как это мой первый серьезный опыт, связанный с шифрованием данных, я начал искать в гугле возможные пути решения задачи средствами PHP, и, естественно, наткнулся на всем известную библиотеку mcrypt. Не нужно особо много времени, чтобы разобраться, как с ней работать. Библиотека работала – на форумах можно найти много примеров, комментариев, обсуждений. Она показалась мне идеальным вариантом для решения моей задачи, особенно учитывая, что времени было совсем немного.

В итоге, я использовал код, который находится прямо на странице описания функции mcrypt_encrypt:
http://us2.php.net/manual/en/function.mcrypt-encrypt.php
<?php
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
$text = "Meet me at 11 o'clock behind the monument.";
echo strlen($text) . "\n";
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";
?>


Все работает хорошо, за исключением одного маленького НО: 5-ый параметр $iv (он же – IV — вектор инициализации) в функции mcrypt_encrypt не к месту — так как он вообще не используется в режиме шифрования ECB (Electronic codebook). И меня вообще удивляет, почему данный пример присутствует в документации — это сбивает с толку.

Наш Engineer Lead провел code review, и сделал два аргументированных замечания:
  1. IV не используется в режиме ECB (о чем я писал выше) — это что касается безопасности, к производительности дела не имеет.
  2. mcrypt является слишком тяжелым и медленным, чтобы позволить вызывать его на каждом page load, лучше найти куски кода, где действительно нужны эти данные и расшифровывать их только в тех случаях.

Первое – не проблема, погуглив дальше, сразу же натыкаешься на режим CBC (Cipher-block chaining). Но вот что делать со вторым – это ведь нужно перерыть все модули, ведь фамилии пользователей используются почти на каждой странице сайта. Это слишком много, подумал я, учитывая сроки, риски – ведь все еще должно будет пройти QA.

Одним вечером, обсуждая ежедневные проблемы, связанные с работой, попивая пиво с другом, который далек от PHP и «этих» проблем, но очень опытен в низкоуровневом программировании и С++ – это оказалось не только приятным времяпрепровождением, но к тому же очень полезным для работы.
Раскрыл он мне одну тайну (на самом деле только для меня это было тайной, а вот для мира С++ программистов, конечно же это очевидность): если использовать определённые инструкции процессора, то можно поднять в 10-ки раз производительность вычислительных задач, в том числе и задач, связанных с шифрованием данных. Новые процессоры intel уже поддерживают инструкции для ускорения шифрования и расшифровывания данных — Advanced Encryption Standard (AES) Instruction Set. И к счастью, как оказалось, наш проект работает на серверах с процессорами Intel Xeon E5645, которые уже имеют в наличии эти инструкции (AES New Instructions).

Но как все это использовать в PHP?

Мы напишем свой PHP модуль, который будет принимать значение из PHP и шифровать/расшифровывать, используя возможности процессора. После нескольких бессонных ночей, сравнения результатов производительности и вообще – концепции, что должен делать модуль, где и как хранить вектор с данными (ведь он необходим для расшифровки) – получилось нижеследующее.
PHP модуль, состоящий из двух частей:
  1. Botan (http://botan.randombit.net/) открытая библиотека, написанная на С++, которая реализует множество алгоритмов шифрования, в том числе AES256, который нам нужен, и при этом имеет возможность использовать AES-NI.
  2. libaecrypt – уже наша часть – служит переходником C++ интерфейса библиотеки Botan в C интерфейс (функции, а не классы), который можно вызвать из главного С файла модуля.

В модуле мы реализовали три функции:
  1. Генератор случайных ключей — возвращает случайные данные длиной в N байт, которые можно использовать как ключ или вектор.
  2. Шифрование
  3. Расшифровка

Шифрование/расшифровка – использует в качестве параметров:
  • ключ данных – 32 байта, который должен быть создан один раз и храниться скрыто
  • ключ вектора – 32 байта, который тоже должен быть создан один раз и храниться скрыто
  • IV – 16 байт, который создается «генератором случайных ключей»


Алгоритм выглядит примерно так: генерируется случайный IV, потом шифруются данные, используя ключ данных и IV; шифруется вектор с помощью ключа вектора. Зашифрованный вектор добавляется к зашифрованным данным с разделителем # и сохраняется в базе, расшифровка идет в обратном порядке.

Основная особенность Botan:

Я не думаю, что выкладывать листинги кода в статье разумно, потому что их много, поэтому расскажу о инициализации модуля, что и есть самый сок.
В комплекте с библиотекой Ботан, идет вспомогательный инструмент, который позволяет определить процессор и его инструкции (botan/cpuid.h). Для ускорения шифрования/расшифровки проверяется, есть ли у процессора AES-NI; если нет – то есть ли SSSE3.
int Init()
{
// Инициализируем Ботана
pInitObj = new Botan::LibraryInitializer();

// Узнаем какой процессор
CPUID::initialize();

// Узнаем есть ли у процессора поддержка инструкций
if(CPUID::has_aes_ni())
global_state().algorithm_factory().set_preferred_provider("AES-256", "aes_isa");
else if(CPUID::has_ssse3())
global_state().algorithm_factory().set_preferred_provider("AES-256", "simd");
else
global_state().algorithm_factory().set_preferred_provider("AES-256", "core");

return 1;
}


В результате, инструмент для тестирование нагрузок от Apache – ab (Apache Benchmark), показал разницу между нашим модулем и реализацией такого же алгоритма с использованием mcrypt: приблизительно 600 requests/second против 1400 requests/second – в пользу нашего модуля.

Вывод:


OpenSSL, который так же поставляется с PHP, начиная с версии 1.0.1, выпущенной 14 марта 2012 года (после всех наших мучений), уже тоже умеет использовать инструкции AES-NI (и SSSE3), и в производительности схожий алгоритм, написаный на PHP c OpenSSL, уступает нашему модулю всего-то в 200 requests per second (Software supporting AES instruction set, OpenSSL from version 1.0.1 есть в списке).
Лично я, в будущем, буду использовать OpenSSL, вместо MCrypt. Помимо того, что mcrypt медленнее, он в качестве вектора инициализации требует ключ в 32 байта! — что не совсем стандартно, так как OpenSSL, Botan, и как я понимаю, многие другие библиотеки реализующие криптование в режиме AES256-CBC принимают ключ для IV размером в 16 байт. Если использовать mcrypt, то уже только им можно будет расшифровать данные.

UPD1: Насчет примеров кода и ссылки на мой модуль: проблема заключается в том, что я подписал контракт, который не позволяет мне выкладывать публично исходный код проекта, т.к. это может повлиять на безопасность (речь идет о 100-ни тысяч пользователей США). Но я постараюсь сегодня выложить измененный вариант модуля для просмотра, чтобы не нарушать условия контракта.

UPD2: Я был удивлен резкому негативу и минусу в карму, поэтому хочу сказать: я хотел поделиться опытом, рассказать, что если вы работаете на PHP и имеете дело с шифрованием, то mcrypt не самый лучший выбор, поскольку эта библиотека имеет проблемы с производительностью. В комплекте php, так же поставляется OpenSSL, который с версии 1.0.1 (как я уже писал выше), использует инструкции процессора, работает намного быстрее и на отлично выполняет криптование данных. После выхода новой версии OpenSSL, наш самописный модуль уже не имеет значения, но это, к сожалению, было до его выхода, и опять же отмечу, что у нас было слишком мало времени.

UPD3: Еще раз прошу заметить, что 25k Page Views и проблемы с производительностью нашего проекта — не главный смысл, пожалуйста, акцентируйте внимание на главный вывод из моего опыта: использование AES-NI (инструкции процессора для ускорения производительности) и OpenSSL vs. MCrypt. Спасибо всем, кто прокомментировал и высказал свое мнение, я как можно скорее постараюсь переписать статью, дабы уделить больше внимание AES-NI, OpenSSL vs. MCrypt и как написать модуль для PHP.

Similar posts

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 71

    0
    Простите, но где примеры кода, или хотя бы ссылка на Ваш модуль? В чем смысл статьи?
      +9
      Производительность же ускоряется! =)
        +1
        Я дополню статью по просьбе желающих.
          –1
          Кстати дополню свой комментарий-ответ.
          Цель статьи рассказать о нестандартном подходе к улучшению производительности в PHP. Мой друг, который помогал мне с этим делом, работает в организации, где используют этот метод. Определенные части кода, которые требуют значительных ресурсов процессора при высоких нагрузках, они реализуют в Си, создают модули и экспортируют это в PHP.
          Но как я уже сказал, я поспешил. Это моя первая статья, хотел поделиться опытом.
          Я выложу пример кода и модуль, как только придумаю способ, который не будет нарушать условия контракта.
          Спасибо.
            +1
            А почему нельзя написать например демон, провесить его на unix сокет, пуст принимает параметры, делает сложную работу и возвращает результат? Зачем писать именно модуль под ПХП? Есть даже библиотека, не помню как называется, суть такова — описываются структуры данных, далее на основе этого описания генерируется сервер на любом языке (там их много поддерживается) в вашем случае на с++ и клиент в вашем случае на php. И не надо писать модули
              –1
              Ну как я понял, в статье просто описывается один из вариантов решения.
              А так я бы тоже сделал демон, который бы не просто делал постоянный декрипт одних и тех же данных, а к примеру хранил в памяти кеш расшифрованных данных, расшифровав их единожды в момент логина пользователя, и отдающий нужную их часть по запросу с ключем шифрования либо по идентификатору сессии.
              Так оптимальнее.
              Для особо паранойных безопасников есть вариант перешифровывать данные в памяти чем-то более простым типа RC4 — это защита на случай атак переполнения буфферов, когда при косяках в настройках серваков в HTTP-сокеты могут вываливаться дампы произвольных кусков памяти.
                0
                А при чем тут HTTP серваки, я же про unix сокеты говорю, они не доступны извне
                  0
                  А при чем тут канал связи скрипта с демоном?

                  http-процесс может при нарушениях, вызванных к примеру атакой переполнения буффера, тупо выплюнуть во внешний сокет произвольный кусок памяти машины. Я с этим сталкивался раньше. Это так или иначе связано с человеческим фактором, то есть с косяками программистов, и подобные косяки со временем правятся, и они редкие, но тем не менее так бывает. Так вот. Есть вероятность, что туда могут попасть хранящиеся там дешифрованные данные в plain-виде.
                  Конечно, тут все зависит от конфигурации системы — демон можно выкинуть на отдельный сервак и все такое. Правда со всеми вытекающими задержками. Но во многих случаях они приемлемы, да и при распределении нагрузки(балансировке) локальный кеш каждого сервака особого смысла уже не имеет.
                    0
                    Кусок СВОЕЙ памяти. В случае с демоном у него будет, конечно же, своё адресное пространство, и веб-сервер или сервер приложений (php-fpm, например) его память выплюнуть никак не сможет.
                      0
                      Ага. Верьте документации больше )))
                      У меня на фряхе плевался чужой памятью только в путь. В итоге косяк с адресацией был мой собственный и был обнаружен, но выплевывал чужую память в сокет уже не мой код. Там еще были некоторые решения, построенные на шаред мемори, возможно это одна из причин доступности чужой памяти на чтение «не нулей».
                      В общем сути это не меняет: я не говорил, что это обязательно, что явление частое и все такое. Просто предупредил, что такие проблемы тоже возможны и привел навскидку один из вариантов решения. Это так, между делом, к основной теме разговора конечно не относится.
                        0
                        Защищённый режим на x86 архитектуре придумали в далёком 1985 году, там багов точно нет :) А шаред мемори — так она на то и шаред, что в адресном пространстве вашего процесса. В общем, этот плюс для демона не засчитывается :)
                          0
                          Так это не был плюс. Вы перечитайте выше, где я это упомянул ) Это была просто ремарка: «Для особо паранойных безопасников...». Ни к плюсам, ни к минусам она не относится )
                +1
                Про демона мы не подумали.
                Статью я написал именно с целью получить критику, я считаю, что критика всегда полезна. Комментарий от zim32, причем подтвержденный ibigdan — много значит, так как это новость для меня.
                Спасибо за ответ.
                  0
                  Вы очень любите костыли? Чем демон будет лучше? Он будет быстрее работать? нет, будет тратиться доп. время на работу с общение с демоном. С ним будет проще работать? Нет, вызов функции всяко проще, чем логака коммуникации с методом (ну да, тоже можно в функцию/метод завернуть, но проще, тем не менее, не станет).

                  Единственное, что я вижу: если демон течет, то не потянет за собой php. Но это легко проверяется с помощью тестов и бенчмарков, функциональность то простая.

                  Какие преимущества демона?
                    –2
                    Хм. Я то как раз костыли и не люблю. Поэтому и сказал что ест библиотека, которая за вас генерирует код демона, Вам остается только реализовать нужную логику. Причем при таком подходе вам безразлично какой язык у клиента. Сегодня ПХП, завтра это питон или джава
                      +1
                      Ну т.е. вы готовы пожертвовать некоторой долей производительности прямо сейчас ради призрачного шанса что-то сэкономить, если вдруг проект будет переписан на джаве?
                        0
                        Хватить уже троллить. Я ничем не жертвую. У меня себе спокойно крутиться демон на сокете. Причем запущен он от имени спец. юзера, и права за чтение этого демона закрыты у всех. Т.е. если даже сервер ломанут от имени www, то до демона им не достучаться. Ибо в коде демона содержится очень важная информация. А как в этом плане с модулем ПХП? Загрузит ли php библиотеку у него нет прав на чтение? Сомневаюсь
                          +1
                          Вы боитесь, что кто-то без вас будет через демон данные шифровать по открытому алгоритму? Взломщки сами себе не могут поставить mcrypt?
                            0
                            У меня другой сценарий. Алгоритм закрытый. В этом плюс демона — его можно запустить от имени другого пользователя. А по поводу джавы — демон использует не только ПХП, но и джава тоже. Плюс на сколько я знаю, ПХП грузит все библиотеки. Зачем мне доп. библиотека на все процессы ПХП, если шифрование используется только в одном месте у меня?
                              0
                              Зачем вам, я не знаю, у вас какие-то специфически задачи. Но в случае, который описывает автор статьи, отдельный демон под элементартную задачу, это костыли. Такими темпами под вычисление md5 или crc тоже будут отдельные демоны. Или для расшифровки параметров url. И останется в php только функция обращения к демонам и вывода в html. И время ответа от сервера больше 1с станет нормой.
                                0
                                Вывод в html тоже демоном!
                      +1
                      Вы может быть не видите проблему достаточно глобально.
                      Есть множество нюансов как у варианта с демоном, так и у текущего варианта.
                      В каждом конкретном случае нужно эти нюансы рассматривать и уже потом решать.
                      Навскидку:
                      1. В крупных проектах заказчики любят в первую очередь масштабируемость. Им проще докупить серверов в стойки, чем оптимизировать отдельные куски. Особенно, если эти куски требуют такой низкоуровневой оптимизации. Иными словами демон, работающий с тем же стандартным mcrypt, но оптимизирующий само количество дешифраций, будет предпочтительнее в ряде случаев.
                      2. Демоны эти тоже можно сделать масштабируемыми. То есть серверов под них можно плодить сколько угодно и распределять между ними нагрузку.
                      3. Задержки канала связи с демоном, даже если он будет физически на другой машине, не всегда являются узким местом, даже если это кажется очевидным на первый взгляд. При правильном подходе для клиента просто страница будет генериться на доли секунды дольше. Во многих случаях это вполне приемлемо. Но серваки при этом не будут потеть от перегрузок. То есть упомянутое вами доп. время уже не связано напрямую с загрузкой процессоров. Иными словами общение с демоном мало чем будет отличаться от общения с основной БД например.
                      4. Библиотеку, напрямую прилинкованную к тому же PHP, нужно будет прикомпилировать к каждому новому вводимому в строй серверу. Кроме того, нужны будут люди, обслуживающие ее, то есть люди, разбирающиеся в этой низкоуровневой оптимизации и работе с инструкциями процессоров. Что получает заказчик после сдачи проекта и смены комманды разработчиков к примеру? Геморрой. Вот что он получает.

                      Так что тут еще вопрос, какой из вариантов считать костылями. Если серверов один-два, то вариант с бибилиотекой вполне прокатит — он действительно имеет более прямое использование и минимальный latency. Но судя по скудному описанию проекта в посте, проектик здесь достаточно крупный, чтобы дать приоритет масштабируемости.
                        0
                        На половину ваших замечаний можно ответить «используйте пакеты и системы автоматического деплоя!» :) Решение использовать внешний демон или модуль к интерпретатору не так однозначно, надо тестировать и проверять.

                        Low-level программирования в статье, кстати, не было — использовали готовую библиотеку, так что тут с поддержкой всё ок.
                          0
                          >> Решение использовать внешний демон или модуль к интерпретатору не так однозначно, надо тестировать и проверять.

                          Так а я что, разве настаиваю на конкретном решении? ))) Конечно надо расматривать альтернативы, взвешивать и тестировать. Я вроде об этом в основном и говорю.

                          >> Low-level программирования в статье, кстати, не было — использовали готовую библиотеку, так что тут с поддержкой всё ок.

                          Готовую, но чужую. Mcrypt поставляется вместе с PHP. Здесь заюзана чужая разработка(Ботан). В разных случаях это может дать разные нюансы.

                          Кроме того, здесь описана конкретная проблема и обсуждается конкретное решение. А если таких проблем и решений будет еще несколько? Проект обрастет библиотеками и чужими фреймворками… А вот имея уже готовый шаблонный демон, на него можно много чего повесить, учитывая, что он наботает бэкэндом, то есть работает где-то внутри системы на отдельных серверах, в конфигурации которых можно по-своему оптимизировать процессы.
                          Приходим к тому же, что вы и написали — надо садиться, рассматривать, думать, решать в каждом случае. Но при этом для начала полезно вообще видеть эти нюансы. Если люди о них не знают, это же не значит, что их нет. Это только значит, что они вероятно столкнутся с ними позже, возможно в не очень удобный момент )))
                          0
                          1. В Крупных корпоративных проектах. Для массовых сервисов это невыгодно, потому на www.insight-it.ru/highload/ и можно вычитать, сколько кастомных доработок используют сервисы и сколько собственных решений пишут.

                          2. Дело не в масштабируемости, а лишней прослойке. Там нет общих данных из-за которых нужно делать централизированные вызовы.

                          3. Зачем делать задержки, если можно не делать? ну я вот никак не пойму, кому нужно более медленное решение, у которого нет никаких преимуществ?

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

                          Чем больше серверов будут взаимодействовать с демоном, тем выше будут задержки. При том, что их можно было избежать. Т.е. просто так будет работать медленнее, чем могло бы.
                            0
                            1. Проекты бывают разные. Далеко не все из них позволят вам узнать, что они и где используют.
                            2. Называйте как хотите )
                            3. Чем отличается каждый раз при вызове скрипта запрашивать у БД шифрованные данные и расшифровывать их каждый раз в скрипте, и запрашивать у демона уже расшифрованные данные по тому же ключу или ID сессии? С чего вы взяли, что это решение более медленное?
                            4. Зависит от проекта. Некоторые делают исходя из возможности хостинга, некоторые — с расчетом callocation — то есть серваки стоят собственные. Есть проекты, требующие максимальной масштабируемости, есть — не требующие.

                            5.(про задержки) увеличте количество демонов, распределите нагрузку фиксированно и задержки будут более чем приемлемыми.

                            P.S. сколько можно повторять: я не настаиваю на конкретном решении. лишь предлагаю альтернативу, которая будет приемлема конечно же только в ограниченном количестве вариантов.
                              0
                              1. Практически все высоконагруженные проекты стараются минимизировать нагрузку, создаваемую одним посетителем. Правило, что разработка стоит дороже машинного времени тут не работает. Потому что любые оптимизации и задержки масштабируются в миллионы раз. Затормозили работу сервиса с 10К серверов на 1%? готовье 100 серверов.
                              100 серверов это месяц работы немаленькой команды. Т.е. если пожертвовав этим 1% сэкономили неделю работы такой команды, то прибыльность такого решения сомнительна.

                              3. Отличается тем, что нужно делать 2 вызова. Один к базе, другой к демону. Вызов к демону не обязателен, а занимает время. Это справедливо, даже если демон сам берет исходное значение из базы.

                              4. В данном проекте уже 8 неслабых серверов. Вы уверенны, что кого-то будет волновать что некое решение нельзя завести на шаред хостинге? И, кстати, куда прикажете в случае шареда, демон девать? Если на отдельном сервере, то на нем-же лучше и сайт держать, а не играться с шаредами.

                              5. Представьте нагрузку в 100 запросов в секунду. Представим, что на соединение с сервером и получение от него данных нужно 1мс (кроме расчетов, они и так делаются, в том или другом месте). Ваше решение съест просто так 10% ресурсов.
                                0
                                1. Зависит от конкретики проекта.

                                3. Вы под вызовом подразумеваете время коннекта или отдельного запроса в ту же БД?
                                Ок. Конкретный пример. Демон не имеет связи с БД. Скрипт, обрабатывающий страницу логина пользователя, берет данные из БД, пихает их демону на расшифровку и хранение. Остальные скрипты пользовательские данные из БД не берут, запрашивают их только у демона и уже в расшифрованном виде. Ну кроме скриптов, которые меняют эти данные(установить новый пароль, поменять имя и т.п.). Демон работает только со своей оперативкой. БД работает что с файлами, что с кешем, что с кучей скриптов(даже с теми, кому user data не нужны). Проблемы с временем коннектов частично решаемы персистент-коннектами. Тут все весьма неоднозначно и зависит опять же от конкретики проекта.

                                4. Опять упираемся в конкретику. Вот все стремится к одному и тому же )))
                                5. >> (кроме расчетов, они и так делаются, в том или другом месте)
                                То есть мое предложение заниматься расшифровыванием только во время логина пользователя или изменении его данных вы как бы пропустили, да? ))))
                                  0
                                  Одно дело, прогонять через демон все данные от базы, там их кэшировать и обрабатывать. Такое решение имеет смысл, в том числе и для масштабируемости. Да и затрат особых не будет так, как коннект можно держать открытым и по возможности, кормить данные одним пакетом.

                                  Но совсем другое — отдельный демон для шифрования. Когда веб-приложение все равно будет вынуждено ходить за данными в базу, а только некоторые брать из демона. В таком случае, лишние накладные расходы явно будут и их оправдать будет сложно.
                                    0
                                    Трудно спорить о чем либо, с чем частично согласен и так )
                                    Но только частично )))
                                    Никто не мешает снять с демона функцию расшифровки, оставив ее в скрипте логина. В таком случае демон может работать кешем чего угодно статичного. Он становится более универсальным. Учитывая, что он хранит все в своей области ОЗУ, это довольно безопасно.
                                    При разнесении нагрузки демонов по экземплярам(по серверам), например по принципу CRC идентификатора сессии, чтоб по возможности скрипт сразу сам вычислял без доп.запросов, к какому именно демону ему обращаться за данными конкретного юзера, это тоже может добавить плюс к производительности.
                                    В общем при желании рулить можно многими вещами.
                                    И опять же — все зависит от конкретики проекта, я не настаиваю на единственности и правильности решения. Где-то это вполне себе неплохое решение, а где-то оно явно лишнее и не нужное.
                                      0
                                      Я еще раз прошу заметить, что использования само писаного модуля и Ботана, в том числе демонов — уже не уместна, так как такую же производительность показывает OpenSSL, который тоже идет в комплекте с PHP :)

                                      Да и кстати, есть одно различие mcrypt и других библиотек: дело в том, что он в вектор принимает 32 байта ключ — что не есть хорошо, так как OpenSSL, Botan и все другие библиотеки, которые реализуют CBC, принимают 16 байт ключ.
                              0
                              3. Если использовать асинхронные вызовы, то задержки ответа пользователю могут быть и меньше при использовании демонов. Правда у PHP с этим не очень хорошо, но «костыли» есть.
                                0
                                А что у PHP не очень в этом плане?
                                Мож я чего не знаю…
                                У меня есть пара демонов, целиком написанных на PHP и использующих только либы из штатной поставки. Работают в одном потоке(один процесс, один тред), запросы асинхронны — сокеты (и серверный слушающий и акцептированные клиенты) полноценные(не локальные), толпой опрашиваются select'ами без блокировки. Работают и жрать не просят.
                                Там правда не сотня запросов в секунду, на большие нагрузки оно и не расчитывалось, но при паре-тройке сотен запросов в минуту даже не вспотеют(бывают такие пики во время СМС-рассылок по клиентам).
                                Логика внутри не сказать чтоб сложная, но посложнее предложенного варианта для кеширования данных.
                                И как-то на веб-морде никаких видимых задержек не наблюдается.

                                P.S. Я конечно понимаю, что далеко не все PHP-программисты вообще понимают, как на PHP можно написать асинхронный демон(штука нестандартная для PHP, да). Да и писать я его в свое время начал по приколу, сам думал бред на выходе получится. Просто время было, а за Си лень было приниматься. Ан нет. Работает зараза )
                                  0
                                  Не асинхронный демон, а mod_php скрипт, асинхронно обращающийся к серверу с демоном. Типа запросим пока расшифровку ника, чтобы написать «Привет, ВолЧ» в сайд баре, а пока она будет идти сделаем основной для страницы запрос к БД. Кто первый законяит отрендерит свой кусок шаблона и будет ждать второго.
                                    0
                                    Угу… понятно… хотя и не очень…
                                    Так что у PHP-то с этим плохо? Кроме того, что большинство библиотек работы с БД блокируют скрипт на время выполнения своих вызовов? Например от отсылки запроса до момента, когда первый fetch можно будет делать. Дальше fetch'ить можно вроде как вперемежку с чем-то еще, но опять же — каждый fetch будет блокироваться.
                                    Я имею в виду, что нельзя реализовать что-то вроде try_fetch с предварительной проверкой, есть ли уже чего fetch'ить в локальном буффере.

                                    БД вообще самое узкое место получается — это та часть, работу которой контролировать изнутри нельзя. И если база затупила в ответе на любой вызов — придется ждать.
                                    У меня как раз это частично решено выносом работы с БД в отдельный демон — он тупит вместе с базой, если что, а основной продолжает работать. Тут получается такая шняга: пока с асинхронного сокета связи с демоном БД не соберется полноценный ответ, основной демон не блокирован и ничем не ограничен делать любую другую работу.
                                    Получается именно тот случай, когда вышеописанный в соседних ветках метод ввода отдельного демона(демона связи с БД в данном случае) не столько добавляет задержки в работу скрипта, сколько наоборот, спасает от залипаний и тупняков при обращениях к БД.

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

                                    По хорошему, у меня с этими асинхронно-ПХПшными экспериментами накопилось материалов на целую статью, а то и на несколько. Все времени нет заняться этим, заодно и задокументировать свои библиотечки…
                    +1
                    Название топика не очень хорошо выбрали. «Использование возможностей CPU в PHP для ускорения производительности». Замените «возможностей CPU» на «дополнительных инструкций CPU» или что-нибудь такое. А то выходит, что то, что PHP использует CPU — это нечто экстраординарное.
                      0
                      Спасибо, поправил.
                      0
                      Я как-то выкладывал статью с тестированием алгоритмов шифрования. Там получилось, что Twofish более чем в 2 раза быстрее, чем AES. Не могли бы Вы протестировать Botan AES-NI против Mcrypt Twofish?
                        0
                        Довольно интересно. Я не рассматривал другие варианты. Дело в том что мы под давлением, и проект связан с большим кол-вом личных данных пользователей, и в случае ошибок вся организация может пойти под суд, поэтому нас консультировали RSA.com, и их требование было использовать AES-256-CBC.
                        Но так как я очень увлекся всем этим делом, я попробую Twofish.
                        +4
                        То, что вы задумались о производительности шифрования, это хорошо. Предыдущие разработчики не задумывались о производительности, судя по всему. 25к хитов в день — для php это должен быть пустяк, даже на дешёвой виртуалке, не то что на «мощном сервере» (дело ведь не в запросах к БД?). По-моему, если в проекте разросся рак, оставленный поколениями разработчиков, его надо вырезать. Сделать это можно, установив профайлер (например xhprof, который выдаст красивый граф вроде такого и покажет места, которое тормозят). Дальше исправить их или поствить кеши (например apc, memcache). Чем больше костылей добавляется, тем в больший тупик уходит проект. Иногда лучше сделать шаг назад, чтобы потом сделать быстро десять шагов вперёд. Только вот до верхнего начальства эту необходимость донести, и обосновать целесообразность такого «вложения в будущее», к сожалению, бывает крайне сложно.
                          –1
                          APC, Memcache, профайлер — все это мы используем.
                          Проблема у нас:
                          1. Кол-во кода, время, ресурсы разработчиков и то что предстоит сделать еще.
                          2. Безалаберное отношение разработчиков к использованию функций не по назначению, и то что люди написавшие существенное кол-во кода ушли, пришли новые, которые по верх всего пишут свои костыли.
                          3. И все же больше всего страдает БД, у нас есть таблицы с более, чем 20 миллионов записей.
                          Пишем агрегации, кешировании и прочее, но опять же не все задумываются о том как они пишут код и нас давят со сроками.
                            0
                            Понимаю. 25к хитов в день (это в среднем 50 в минуту днём где-то?) могут завалить тяжёлую базу, тем более если данные персонализованы и нельзя толком закешировать. Поскольку используете профайлер, то наверняка видели и циклические запросы, и файловые операции, и прочую нечисть. Если времени на оптимизацию не дают, тогда делать, как говорится, нечего, остаётся только докупать новые сервера.
                              –1
                              Их кстати 8, на каждом такой же Xeon и 64 RAM'а, к тому же многое еще покрывает Акамаи. :) Все очень печально у нас, у меня даже депрессия очень часто по этому поводу, но я один не могу повлиять, команда большая и риски большие.
                                +4
                                простите, 64 ГБ РАМ? 8 серверов, итого около пол терабайта мозгов. И у вас проблемы с производительностью при 25к хитов в сутки ??

                                Я лично Вам реально очень сочувствую. Если Вы остаетесь на этом проекте с таким убогим руководством, значит у Вас явно есть на то серьезные причины. Мой мозг бы это просто убило, я бы пил сутками на таком проекте :)

                                Крепитесь.
                                  +1
                                  В общем-то мы справляемся, серверов было меньше, это на данный момент столько. Руководство хорошее, но вот у них опыт с PHP и Drupal первый. Я ж говорю, у меня депрессии, я тоже пил, у нас были скандалы и много ссор. :) спасибо за сочувствие :)
                                    +3
                                    Это что же за база такая у вас, что 20 лямов записей просто убивают сервера?

                                    у нас сервер 2гб RAM и двухядерный intel e6300. На сервере апач с php как модуль, впн, десяток вордпресов с посещалкой общей под 5-6к, и сайт с Mysql базой под 10 Гб, у которого таблицы по 40-50 млн. записей, кеширование только на уровне самого мускула. и сайт держит по 100-120 запросов в минуту, с учетом перекрёстных выборок по этим большим таблицам. нагрузка на сервер 30-60%, сервер не падает уже год.

                                    может вам стоит выделить 1-2 человек для анализа кода и времени исполнения всех запросов к БД, и донести до руководства что эти 2 человека могут съэкономить компании тысячи долларов на стоимости железа сейчас и десятки тысяч потом. По крайней мере они могут выделить самые узкие места, а у вас их наверно не мало. раз 8 ксеонов с полтерабайтом оперативы еле держут 1 запрос в секунду. и это притом что у вас всего пользователей не так уж и много для такого железа
                                    >>речь идет о 100-ни тысяч пользователей США

                                    Возможно кто то очень косякнул при разработке и это все благополучно просмотрели, например цикл какой-нибудь while который 100 млн раз проходит за каждый запрос и исправление даже одного косяка съэкономит пару тройку серверов.
                                  0
                                  Да уж, вот и получается, что эти сервера ежемесячно жрут зарплату оптимизатора.
                            0
                            >Первое – не проблема, погуглив дальше, сразу же натыкаешься на режим CBC (Cipher-block chaining).

                            Каким образом это решает проблему скорости? Вы видите что в коде зря генерируете вектор, потому что он не используется вашим алгоритмом шифрования, и поэтому ваше решение — использовать другой алгоритм шифрования который будет использовать вектор? И это по вашему будет быстрее чтоли?

                            Хотя криптографически, ECB конечно имеет большие недостатки.
                              0
                              Вы как-то неправильно поняли все.
                              Первое, имелось ввиду что ECB недостаточно секьюрно, поэтому нужно использовать CBC — к производительности вообще отношение не имеет.

                              Второе уже касается производительности, мы подняли ее за счет использования AES-NI в само писаном модуле для PHP. — что уже, как выяснилось потом — не нужно, так как OpenSSL (буквально месяц назад) встроили поддержку этой самой инструкции, которая ускорят шифрование.
                                +2
                                Просто ваша статья — о производительности. Поэтому когда вы пишете «и сделал два аргументированных замечания:
                                Initialization vector не используется в режиме ECB (о чем я писал выше)», «5-ый параметр $iv (он же – вектор инициализации) в функции mcrypt_encrypt не к месту — так как он вообще не используется в режиме шифрования ECB» и подобное, нигде не уточняя что именно в этом месте вы решаете уже проблему секьюрности, а не производительности, это сбивает с толку. Но сейчас понятно что вы всё-таки разобрались.
                                  0
                                  Кстати спасибо за замечание, будет время доработаю тот кусок.
                            • UFO just landed and posted this here
                                +1
                                С радостью напишу статью-пример. Ждите, работы у меня много. :)
                                • UFO just landed and posted this here
                                    0
                                    Так у них прямо на сайте есть туториал: www.php.net/~wez/extending-php.pdf.
                                    0
                                    Я начинал с чего-то подобного: abhinavsingh.com/blog/2008/12/php-extensions-how-and-why/
                                    Имхо, лучше выбрать из PECL или входящих в PHP расширений какое-нибудь простое, равномощное по трудоёмкости тому что нужно будет написать, и посмотреть его код.
                                0
                                Коли задача состояла в хранении зашифрованных данных в БД, то не лучше ли было использовать её нативные средства шифрования? В MySQL есть встроенный AES и DES.
                                  0
                                  Насколько я понимаю, встроенный AES_ENCRYPT в MySQL, не имеет вектора инициализации — что делает зашифрованную строку уникальной.
                                  +3
                                  Вот что хотите делайте, но производительность не ускоряют, а увеличивают.
                                    0
                                    Кто согласен? Поставьте человеку плюсы и тогда я исправлю всю статью :)
                                    Спасибо :)
                                    0
                                    Из названия статьи можно подумать, что речь идёт о сборке PHP с директивами компилятору O3
                                      0
                                      И снова исправил заголовок. Спасибо. :)
                                        0
                                        Да уже написали бы «Используем AES-NI в PHP для ускорения шифрования» :) А то как-то длинно получилось.
                                          0
                                          Плюс AES-NI добавить в теги, я когда статью про алгоритмы шифрования писал, то искал информацию о поддержке AES-NI.
                                            0
                                            уже непонятно будет для тех кто далек от асма >8086
                                        0
                                        У нашей кампании был проект, построенный на Drupal, которому не хватало производительности под нагрузкой примерно в «25K Daily Page Views».
                                        Что это за сайт такой, который валит серваки при 25к просмотрах. Может стоит друпал правильно приготовить?
                                          0
                                          Начать можно с крона и ватчдог почистить :).
                                          Хотя реально, т.с., в каких таблицах у вас миллионы записей?
                                            –1
                                            Убрал строчку параграф, так как все сразу кидаются на это, а суть статьи вообще не в этом.

                                          Only users with full accounts can post comments. Log in, please.