Pull to refresh
55

Sr. PHP developer

7
Subscribers
Send message
Через какое-то время вы будете при тестировании новых фич видеть результаты предыдущих тестов, часто смешанных и запутанных.

Для законченных тестов все пользователи видят один и тот же вариант сайта. Спустя какое-то время эти тесты вряд ли будут как-то значительно влиять на текущие тесты.

Так же есть возможность посчитать KPI-показатели для вариантов теста, начиная с того момента, как пользователям были выданы сплит-группы. Если показатели будут сильно различаться, значит есть какая-то проблема.
Исправил, спасибо!
При таком подходе у каскадной очереди не запуститься будет еще меньше вероятность:)
Да, еще один момент хотел спросить.
Как я понимаю рассылка пушей должна начинаться на каком-то сервере. Что если упал этот сервер? Тогда рассылка вообще не начнется, так же как и в случае каскадной очереди.
Как я понимаю решить проблему можно так же, как и в случае с каскадной очередь.
В нашем случае мы не выбираем данные с очередей на соседних серверах намеренно.

Согласен, такую оптимизацию сделать можно, и она так же будет работать в каскадной очереди.

По поводу падения сервера. Маленькое сообщение отправляется перед обработкой пачки.
Если «соседний» сервер упал, то сообщение будет отправлено на следующий доступный сервер.

Я вижу здесь следующий тонкий кейс.
Что если сообщение было успешно отправлено на следующий сервер, но не было там обработано из-за того, что сервер упал? Ведь от получения сообщения до его обработки может пройти относительно не маленький промежуток времени.
В этом случае поднятие этого сервера будут ждать все остальные.

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

По поводу «падает очередь», Tarantool Queue не падает, работает надежно!

Так не бывает. Во первых баги есть везде, возможно с ними вы просто еще не сталкивались. Во вторых здесь может быть элементарно человеческий фактор. Так что совсем исключать такой сценарий я бы не стал.
Для этого на одном из серверов необходимо выбрать «пачку», в очередь на «соседнем» сервере добавить маленькое сообщение с информацией о последнем id-пользователя из текущей «пачки». При обработке маленького сообщения на втором сервере мы должны получить «новую пачку» начиная с указанного id, сформировать аналогичное сообщение «серверу-соседу», и т.д., пока не переберем всю базу. Текущую «пачку» нужно всегда обрабатывать локально в своей очереди. Таким образом, мы «как бы» переместим код к нашим данным, распараллелим генерацию «пачек» по серверам и не будем гонять данные по сети.

Зачем так все усложнять с это эстафетной палочкой и делать отдельные локальные очереди?
Что произойдет, если один из серверов не сможет достать пачку и передать эстафету дальше? Цепочка может оборваться в любом месте. Что один из серверов упал? Будет отправлена только часть пушей, а маленькое сообщение даже не сможет попасть в очередь?

Я вижу решение этой проблемы в виде каскадной очереди (цифры взяты из головы, должны настраиваться, их нужно подобрать для своего проекта):

Для инициализации отправки нужно либо сделать крон-скрипт, который будет запускаться раз нужный промежуток времени, либо специальную очередь, которая для примера, описанного в статье будет иметь 1 сообщение "подготовить пуши пользователям", после обработки этого сообщения для него (этого сообщения) будет выставляться delay (если нужно отсылать раз в сутки):
+(24 часа - время обработки)

Эта очередь может использоваться и для инициализации и других каскадных очередей. Назовем эту очередь Очередь1.

Когда сообщение «подготовить пуши пользователям» берется в обработку, обработчик извлекает минимальный и максимальный id пользователя, делает, допустим 10000 диапазонов, и создает 10000 сообщений в Очередь2 с сообщением "подготовить пуши пользователям, у которых id от n до m". Когда сообщение "подготовить пуши пользователям, у которых id от n до m" из очереди Очередь2 берется в обработку, обработчик делит диапазон, допустим, еще на 10000 диапазонов и создает еще 10000 сообщений в эту же очередь. Так происходит до тех пор, пока диапазоны не станут достаточно маленькими.

Когда диапазоны становятся достаточно маленькими, то создаются сообщения на непосредственно саму отправку пушей (для iOS в Очередь3 для Android в Очередь4) с сообщением, содержащим id пользователя. Соответственно при обработке очередей Очередь3 и Очередь4 происходит непосредственно отправка пушей. Для iOS и Android сделано разделение затем, что для них нужен как минимум разный коннект, который можно использовать для нескольких сообщений.

Теперь о серверах. Где будет находиться и обрабатываться очередь Очередь1 — не принципиально, но важно мониторить то, что тачка живая и если что создавать и обрабатывать эту очередь на другом сервере. Для очередей Очередь2, Очередь3 и Очередь4 можно использовать хоть все доступные сервера очередей, при этом решать, на какой сервер записать сообщение для очереди Очередь2 можно хоть просто случайным образом, а для Очередь3 и Очередь4 можно, например, использовать остаток отделения user_id на кол-во серверов.

Где обрабатывать Очередь2, не принципиально, а очереди Очередь3 и Очередь4 лучше на разных группах серверов, что бы было проще контролировать нагрузку. Обработку очередей не обязательно делать на тех же серверах, где крутится сервер очередей.
При обработке сообщений сообщения можно брать из доступных серверов по пачками по очереди. Допустим обрабатываем Очередь3, у нас доступно 5 серверов, мы достаем 1000 сообщений из первого, обрабатываем, 1000 из второго, обрабатываем и так по кругу.

Получается что у есть только одна точка отказа — сервер, где крутится Очередь1. С остальным проблем нет — падает очередь на одном из серверов — сообщения с этого сервера временно не обрабатываются, зато сам сервер может использоваться для обработки. Либо на сервере может по каким-то причинам упасть обработчик, но сообщения с этого сервера будут забираться другими серверами, на которых обработчики работают.

Надеюсь понятно объяснил.
На сколько я понял правильная ссылка www.joedog.org/siege-home/.
Так же можно установить в ubuntu через apt-get.
Именно поэтому я написал это в конце начиная со слов «Так же», т.е. это не имеет конечно сильное значение.
Ещё раз, это геттеры и сеттеры не будут работать во всяких setAttributes и прочих местах, например при использовании хелпера CHtml::activeTextFiled() и т.д. И получается не понятно, какой прок от них.
Такое писать в базовом классе не правильно:
    public function getId()
    {
        return $this->id;
    }

Далеко не все таблицы имеет поле id и могут иметь составной PK.

Так же мне кажется довольно сомнительным использовать для всего геттеры и сеттеры в описанном в статье виде, ибо setAttributes эти геттеры и сеттеры использовать не будет. Что бы этот подход работал нужно использовать название поле например, начинающиеся с символа '_' — а это тот ещё изврат.

Так же лишние вызовы методов — это увеличение времени работы приложения, и поэтому такие вызовы должны быть оправданы.
Сеть иногда отваливается, приходится F5 нажимать
Редко, не редко, но я писал именно демон и считаю, что если есть возможность писать весь проект на одном языке, то лучше писать на одном языке, хотя кто-то может со мной и не согласиться.
Спасибо большое за информацию, добавил её в конец статьи.
В водах статьи я уже написал, что declare(ticks=1); — это зло, и в 5.3 его можно использовать, а вызывать pcntl_signal_dispatch() в начале или в конце итерации основного цикла.
По хорошему итерация основного цикла демона должна проходить не прерываясь, т.к. внутри может идти работа с несколькими разными типами БД, и если прервать итерацию в середине и вызвать exit(), то эти БД будут неконсистентны. Конечно использование pcntl_signal_dispatch() не спасет от kill -9 и консистентность нужно обеспечивать как-то по другому, но зачем усложнять свой код вызовами обработчиков из любого места?
При вызове pcntl_signal_dispatch(); обработка сигнала идет постфактум в отличии от использования declare(ticks = 1), поэтому мне не понятно, чем отличаются эти два вариант. Можно ли по подробнее? Так же не понятно, почему новый запущенный экземпляр не сможет получать/обрабатывать сигналы, ведь через system запускается отдельный независимый процесс.
Это уже оскорбление, осторожнее на поворотах!
Я подозреваю мы говорим о разном
Идеального кода не бывает, всегда есть реальность, и если твой идеальный код работает медленно, грош ему цена.
Код должен быть читаемый и выполнять свою функцию. И ещё раз повторяю, есть фреймворки с закрытым исходным кодом, даже для php в виде расширения.
Задача фреймворка не идеальный код, а дать ядро, на котором можно удобно решать какие-то задачи, например писать сайты. И API фреймворка должно быть хорошо описано.

Код же вообще может быть закрытым, и там могут быть оптимизации кода, которые не с идеальным для чтения кодом рядом не стоят.
Да, согласен, не совсем по теме ответил.
Если по теме, то почему не лепить собственный велосипед если есть желание? Конкуренция всегда нужна:)
Это же не какой-то коммерческий проект, где изобретение велосипеда может стоить проекту жизни.
И если yii будет разбираться и собираться как симфони, то получится почти тот же симфони. Зачем это нужно?

Information

Rating
Does not participate
Registered
Activity