High performance
PHP
NoSQL
Comments 52
+6
Рекомендую поглядеть на MongoDB. Она не так сильно упирается в размер доступной RAM и имеет некоторые другие полезности по сравнению с традиционными key-value хранилищами. Взять хотя бы aggregation framework или caped collections с ttl (это ваш кэш в виде одной опции).

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

Что касается MongoDb — есть опыт внедрения пары проектов. Очень требовательна к ресурсам и много жрет дискового пространства. На виртуальной машине в РАМ 2Гб — на 1М профилях начинает тупить. Для определенного круга задач — идеальное решение. В данном случае — она (монга) значительно проигрывает по скорости.
-1
Расскажите, как мерили разницу по скорости Тарантул/МонгоДБ и каков порядок у «значительно»?

Не понятно, что значит «требовательна к ресурсам»?
Запускать такую бд на виртуалке с 1Г памяти это все-равно, что на телефоне.

Опять же странно читать про «жрет дисковое пространство» в сравнении с «memory only database».

Монга по умолчанию при старте большие файлики создает, но это как бы не проблема, вот названию ключей не надо сильно раскидистые делать — это да.
+1
Расскажите, как мерили разницу по скорости Тарантул/МонгоДБ и каков порядок у «значительно»?
мерил Си клиентом, засылал 100 000 запросов на несколько потоков (от 8- 16)
значительно, это на 30-40%

Запускать такую бд на виртуалке с 1Г памяти это все-равно, что на телефоне.
Это верно, и пытались это вразумить инвестору, что нужен выделенный сервер…

Монга по умолчанию при старте большие файлики создает, но это как бы не проблема,
да там вообще облако, так что настройка монги — это вообще проблема хостера.
UFO landed and left these words here
+3
С годик полтора назад тестировали производительность различных key/value в том числе и монго. Оказался самым медленным.
У нас получилось
mysql+handlersocket
memcahed+mysql (с различными костыликами)
mysql in memory db
redis
mongo

handlersocket > 600Kqps выше не хватило мощности клиентов
на memcahe получили порядка 450Kqps
redis/mongo на порядки медленее были (меньше 100Kqps. с лагами и падениями. при том, что за mongo были девелоперы и они отчаяно пытались её натюнить)

+3
конечно все зависит от локального железа и настроек, но по моим тестам редис был быстрее чем mysql+hs
тут вообще еще очень многое зависит от методике измерения:
— в одном ли коннекте на поток, или на каждый запрос новый коннект,
— во сколько потоков шли запросы
— делали инсерты или уже изменяли зааллоцированные области.
— первоночальный размер карзины хештейбла или таблицы
— Каким клиентом мерили. Желательно, чтоб это был родной сишный клиент.

Но в целом корреляция существует…
0
Сервер с базой
2 или 3 web (php, python, perl) как fcgi с разными клиентскими либами
siege или ab

На каждый клиентский запрос надо было получить от 100 до 500 значений из хранилища.
Только чтение. Запись в один поток и только инсерты (достаточно медленые)
Все данные по которым делается селект помещаются в память.

Для нас было актуально такое тестирование.

Нагрузка спецефичная, получилось так. Пока ещё не жалеем о выборе
+1
Меня интересовала производительность самого хранилища, по этому делалось 10К рандомных запросов (GET/SET) по num PK ключу в n потоков( каждый поток 10K / n ) сишными клиентами, писался специальныйтестировочный софт. Что бы по минимуму исклюить сетевое взаимодействие, то все происходило в одном коннекте. Ели на каждый запрос делать свой коннект, то общее время увеличится на 20-30%.
Все тестирование происходило на локалхосте, что не совсем правильно.
Пример тулзы для memcached протокола github.com/akalend/mcstrass
аналогичные тулзы писались и для redis, для HandlerSocket и для mongo…
+14
От названия статьи аж мороз по коже. Все известные мне говнокодеры мнят себя хайлоадерами.
+3
ну, спасибо за минус… и меня к говнокедерам причислили :)
+2
Не я ))

Мой комментарий был направлен на название статьи.

Говнокодинг — это уже целая культура. Списать просто на глупость людей, судя по их количеству — нельзя. И как-то заметил, что у большинства из них есть общая черта. Они не стремятся писать чистый код. Они стремятся оптимизировать, причем заранее. Причем всегда. Мозги у людей так повернуты, что они бесконечно думают только о том, чтобы код «летал». Т.е. смещена картина мира — они говнокодом называют то, что не быстро работает. Даже если не требуется. А то, что их код — говно, они не замечают совершенно.

В итоге, их код не читается, нельзя менять. И еще в добавок и не летает, а ползает, как недобитое животное. Предварительная оптимизация — такая предварительная.

У Вас вроде всё верно — написали на реляционной базе — работает, деньги приносит. А потом, уже когда код работал, дали оптимизировать.
+2
а я оценил твой юмор плюсом :)
У Вас вроде всё верно — написали на реляционной базе — работает, деньги приносит. А потом, уже когда код работал, дали оптимизировать.

писал код не я, довел до прибыли не я, так что это лавры хозяина проекта…
моя задача — чтобы все это взлетело, когда стало тормозить… и мои изменения были минимальны, просто другой программист стал делать рефакторинг под моим руководством
+1
что-то в коде менял я… но общий рефакторинг сейчас производит другой програмист. Мной лишь привнесены эти 5-ть рецептов.
-1
Да, да, давайте дальше кричать «говнокодеры», «говнокодеры» и писать статьи с советами а-ля первый урок php (извините, дальше части про php не смог читать), от этого карма (не хабровская) должна обязательно улучшиться!
+2
чтоб не писать статьи а-ля первый урок php, я специально завел свой блог. Многих переубедить что и как делать в определенных условиях практически не возможно. А бороться с ветряными мельницами — нет времени
+3
фреймворки заточены под узкий круг типовых задач

Фреймворк (англ. framework — каркас, структура) — структура программной системы; программное обеспечение, облегчающее разработку и объединение разных компонентов большого программного проекта. Употребляется также слово «каркас», а некоторые авторы используют его в качестве основного, в том числе не базируясь вообще на англоязычном аналоге. Можно также говорить о каркасном подходе как о подходе к построению программ, где любая конфигурация программы строится из двух частей: первая, постоянная часть — каркас, не меняющийся от конфигурации к конфигурации и несущий в себе гнезда, в которых размещается вторая, переменная часть — сменные модули (или точки расширения).


Я тут хотел начать кому-то что-то обьяснять, но перехотел. Пустое это.
+2
это верно, иначе бы Баду, Мамба и Контакт были бы реализованы на симфони или джомула.
+3
Нужно было просто уточнить, что речь о публичных фреймворках. Ибо любой нетривиальный проект содержит в себе фреймворк облегчающий команде его поддержку и/или модификацию.
+2
Леша, согласен с тобой — полностью.
У каждого программиста, проработавшее определенное кол-во времени над определенным кругом задач появляется свой наработанный инструментарий в широком смысле этого слова, который принципиально можно назвать фреймворком. У меня есть собственный фреймворк, который я использую в большинстве задач. По этому, в тексте статьи и было написано, что это вечно флеймовый вопрос…: Быть или не Быть?

Конечно, было быпросто замечательно, если бы группа интузиастов выпустила фреймворк, заточеный специально под соцсети, нагрузку и бинарным обменом с флешью, а не адаптировало бы ZF или симфони
+2
да, еще вспомнил случай реализации одного проекта. Взял свой фреймворк, для реализации социгры, далее решили прикрутить PHP-AMF, прикрутили, оказалось 75% функфиональности в корзину… потом отказались от AMF и заменили на протобуф, ну и вообще 90 процентов кода в никуда…
так что решаем спец задачи
+1
ну и чем поможет какой-то фреймворк, общий или свой… если задача специфична…
+4
MySQL пробовали настроить перед тем, как NoSQL запихивать? Какой там объём данных и рейт запросов хоть?
+2
хз… это облако… так что для нас, смертных — это черный ящик
0
Ваш код
$tuple = $res['tuples_list'][0];
switch ($tuple[1]) {
case UPDATE_SPIN_COUNT:
$sql = "UPDATE users SET spinCount ={$tuple[2]}  WHERE uid ={$tuple[3]}";
break;
 
case 2:
$sql = "UPDATE users SET money = money + {$tuple[2]}  WHERE uid ={$tuple[3]}";
break;
 
default:
throw new Exception ('unknow task type');
break;
}


Почему не так:
switch ($res['tuples_list'][0][1]) {
    case UPDATE_SPIN_COUNT:
    case 2:
        $sql = "UPDATE users SET spinCount ={$tuple[2]}  WHERE uid ={$tuple[3]}";
        break;
    default:
        throw new Exception ('unknow task type');
        break;
}

Впрочем и так и так следующий разработчик посмотрев на этот код запросто сможет написать подобную статью, удивляясь откуда и почему берутся магические цифры в этом коде
+1
потому-что везде в статье псевдокод, для наглядного понимания, реального кода реально больше (больше проверок, больше методов, больше диапозон выбора данных)
ну а если по логике, то на UPDATE_SPIN_COUNT (=1) формируем один запрос, а на UPDATE_USER_BALANCE (=2) выполняем другой,
а судя вашей логике, на 1 и 2 я выполняю один и тот же запрос
0
очепятка, просил же дать инфу в приват, писал уже ночью
сейчас магик моменто исправлю
+1
Про тарантул действительно интересно, спасибо.
Но за такие отрывки кода нужно наказывать:

Скрытый текст
class User extends DbModel {
 
  public function getByUid($uid) {
 
        $result = this->getFromCache($uid);
 
        if (!is_null($result)) {
            return $result;
        }
 
        $result = $this->execSQL( "SELECT * FRAO users WHERE uid=$uid"); // Тут SQL Injection
        $this->setToCache($result);
 
        return $result;
  }
....
}


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

$user = User::model()->cache(1000)->findByPk(111);
-2
>$this->execSQL( «SELECT * FRAO users WHERE uid=$uid»); // Тут SQL Injection
принципиально ты прав, и молодец что заменил… Думаю, другие это оценят.
про псевдокод — мой коммент выше, а что касается $uid — то проверка на SQL Injection осуществлена еще в контроллере, а не в модели.
в данном случае это было приведение к инту и проверка на ноль. Ну и скажи — какой смысл пускать ноль в модель если можно дать отлуп на более высоком уровне?
И кто тебе сказал, что клиент и сервер общаются по HTTP? Может клиент и сервер общаются по AMF, protobuf или иному бинарному протоколу?
кстати, если вы разрабатываете социальные игры — то советую присмотреться к протобуфу
+1
Ну и скажи — какой смысл пускать ноль в модель если можно дать отлуп на более высоком уровне?


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

Всё же перед тем как творить что-то своё стоит обратить свое внимание на реализацию тех или иных вещей в современных открытых системах. Хоть в том же yii или Kohana, Меньше лапши в голове будет.
+1
Очевидно у нас разные взгляды на архитектуру и понятия… Это не типовой WEB проект, точка входа одна, парсинга урла нет, один контролер который работает с моделями…
+1
Расскажите про вашу архитектуру с одной точкой входа. Чем это обусловлено, неужели у Flash игр такая специфика? Или у вас что-то вроде постоянного соединения клиента с сервером?
Я писал много разных API.
+2
В данном проекте нет, так как там моего кода — кот наплакал, рефакторинг еще предстоит
но в предыдущем проекте архитектура системы была следующая:
— клиент стучится по сокетному соединению, если оно не проходит, то тогда стучится по HTTP
— сервер запущен как демон, которые принимает сокетные соединения
— все HTTP запросы прокидываются через nginx на демон скрипта
— протокол обмена бинарный

статистика показывала, что из 1000 одновременных подключений, где-то только 30-65 идут по HTTP

преимущество бинарного протокола:
— компактность
— защищенность, хотя это сомнительно, но через протокол ни кто не влез, а флеш взламывали

преимущество сокетного соединения — скорость
+2
преимущество использование демонов:
— инициализация справочниками проходит один раз, во время загрузки
— соединение с БД, кешами и прочими сервисами проходит один раз

возможны проблемы масштабирования, но они просто решаются, да и нагрузок пока таких, чтоб требовалось масштабирование демона — не возникало.
0
Я курсе про демонов, сам пишу сервер на golang сейчас для одного приложения. И проблем с масштабированием быть не должно — шарлинг, реплики, синхронизация между серверами.
Но я всё равно не понимаю — у вас вся обработка происходит в череде if-else и switch-case в одной(грубо говоря) процедуре?

Ну нет у вас парсинга урла, но операций ведь больше чем одна? Даже несмотря на то, что соединение постоянное, есть ведь разные action`ы, есть контроллеры.
+1
> у вас вся обработка происходит в череде if-else и switch-case в одной(грубо говоря) процедуре?
да, есть switch в котором есть вызывается соответствующий метод (action)
Каждый метод делает некоторые действия. Как правило, инстанцирует свой класс модели и вызывает её определенный метод. Результат выполнения присваивается переменной $result, из которой формируетя ответ.
+1
как вариант можно сделать как-то так…
$actionName= $action;
$this->$actionName($args);

но в данном проекте это совсем не катит, пока что реализовано на switch
0
вот про демоны статья была бы интересна, особенно меня интересуют простые сишные вещи, beanstalkd и аналоги
0
если буду писать статью про демоны, то будет про принципы их написание на Си,
а не про конкретные демоны. Если данный вопрос интересен, то могу написать.
0
Автору советую быть проще, и никогда себя не переоценивать, даже если вы очень хороши в проектировании высоконагруженных систем — готовые проекты покажут что вы стоите на самом деле. Ребята из андев делали сайт выборы 2012, вот это реальных хайлоад, одного разработчика я знаю лично. Скромнейший человек кстати. Это делает ему честь. А у вас в статье столько ляпов и дыр в знаниях. Может лучше больше читать и заниматься практикой и не писать такие сложные статьи с горяча?
+1
Архитектор из автора очень даже не плох, а вот о вычитке нужно с ним договориться ;)
Если у вашего знакомого есть желание поделиться своими знаниями и при этом у него нет обременяющих обязательств перед работодателем — то ждем его статьи/заметки/твита об архитектуре его проекта! Будьте добрее!
0
просто те кто работает в очень крутых проектах всегда очень и очень заняты и не всегда хотят делится

обосрасть всегда легче, чем написать хорошую статью
+1
Не всем дано писать статьи, вы об этом не думали? Обычно хороший спортсмен не всегда умеет учить, так как ему не дано внятно излагать информацию ученикам. А тренер же напротив, не всегда хороший спортсмен, но может быть при этом отличным учителем. Про «обосраться» увы не понял вашей мысли.
+1
Скажите, о какой нагрузке идет речь, по подробнее статистику.
+1
Нагрузка была небольшая: при нагрузке на WEB сервер на 50-100 одновременных тестирующих потоках был возврат 35% ошибок (MySQL server has gone away).

после некоторого архитектурного улучшения (рефакторингом это не назовешь, его нужно еще проводить следующим шагом)
сейчас 320-350 rps, Все работает стабильно и MySQL уже точно не падает.
0
Код проекта… В общем у меня осталось впечатление, что писал его недоученный студент… И это, немотря на то, что уже был сделан частичный рефакторинг другим программистом. Единственное, что радовало, то это то, что не использовался какой-либо фреймворк. Конечно, это вечно флеймовый вопрос: Иисус или Магомед? Быть или не Быть?

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

0
Почему не Mysql+Handlersocket, чтобы избавиться от дублирования памяти и не изобретать велосипед с синхронизацией и очередями?
0
во первых, ни какого велосипеда с очередями нет — это устоявшийся паттерн.
во вторых — это виртуальный хостинг, и хостер предоставляет только доступ к БД, без её администрирования. Да, в какой-то степени это большой минус…
Only those users with full accounts are able to leave comments., please.