Как стать автором
Обновить

Комментарии 52

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

Конечно, было быпросто замечательно, если бы группа интузиастов выпустила фреймворк, заточеный специально под соцсети, нагрузку и бинарным обменом с флешью, а не адаптировало бы ZF или симфони
да, еще вспомнил случай реализации одного проекта. Взял свой фреймворк, для реализации социгры, далее решили прикрутить PHP-AMF, прикрутили, оказалось 75% функфиональности в корзину… потом отказались от AMF и заменили на протобуф, ну и вообще 90 процентов кода в никуда…
так что решаем спец задачи
MySQL пробовали настроить перед тем, как NoSQL запихивать? Какой там объём данных и рейт запросов хоть?
хз… это облако… так что для нас, смертных — это черный ящик
Ваш код
$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;
}

Впрочем и так и так следующий разработчик посмотрев на этот код запросто сможет написать подобную статью, удивляясь откуда и почему берутся магические цифры в этом коде
потому-что везде в статье псевдокод, для наглядного понимания, реального кода реально больше (больше проверок, больше методов, больше диапозон выбора данных)
ну а если по логике, то на UPDATE_SPIN_COUNT (=1) формируем один запрос, а на UPDATE_USER_BALANCE (=2) выполняем другой,
а судя вашей логике, на 1 и 2 я выполняю один и тот же запрос
Да, но у вас 2 — магическое число. Как и индексы у $res
очепятка, просил же дать инфу в приват, писал уже ночью
сейчас магик моменто исправлю
НЛО прилетело и опубликовало эту надпись здесь
>$this->execSQL( «SELECT * FRAO users WHERE uid=$uid»); // Тут SQL Injection
принципиально ты прав, и молодец что заменил… Думаю, другие это оценят.
про псевдокод — мой коммент выше, а что касается $uid — то проверка на SQL Injection осуществлена еще в контроллере, а не в модели.
в данном случае это было приведение к инту и проверка на ноль. Ну и скажи — какой смысл пускать ноль в модель если можно дать отлуп на более высоком уровне?
И кто тебе сказал, что клиент и сервер общаются по HTTP? Может клиент и сервер общаются по AMF, protobuf или иному бинарному протоколу?
кстати, если вы разрабатываете социальные игры — то советую присмотреться к протобуфу
Ну и скажи — какой смысл пускать ноль в модель если можно дать отлуп на более высоком уровне?


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

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

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

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

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

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

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

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

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

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

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

Почему не Mysql+Handlersocket, чтобы избавиться от дублирования памяти и не изобретать велосипед с синхронизацией и очередями?
во первых, ни какого велосипеда с очередями нет — это устоявшийся паттерн.
во вторых — это виртуальный хостинг, и хостер предоставляет только доступ к БД, без её администрирования. Да, в какой-то степени это большой минус…
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории