• Быстро и гибко настраиваем  наблюдаемость с помощью канонических строк логов
    0

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

  • Быстро и гибко настраиваем  наблюдаемость с помощью канонических строк логов
    +1
    Валидация отклонит такие данные. Валидация отклоняет валидные логи? Ой.

    Попробую объяснить подробнее то, что я имел в виду. Здесь же речь идёт про конвейер, каждая часть которого делают часть работы:


    Сначала сервис/приложение пишет логи, в текст которых добавляются структурированные данные. Здесь задача положить так, чтобы это потом можно было вытащить.
    Возможная проблема тут — это сформировать какую-то некорректную строку с какими-то лишними данными или без необходимых. Google protobuf тут позволяет проверить, а все ли данные есть. Если чего-то нет, то это не повод не писать логи совсем, а повод дать знать, что есть проблема в запаковке данных (бросить какую-то ошибку, записать специальное сообщение в лог или как-то иначе сигнализировать о проблеме).


    В статье про это сказано так:


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

    В конце эти логи собираются со всех машин и загружаются в какое-то центральное хранилище (в статье сказано про Presto, Redshift и Kafka). И вот тут уже структурированные данные должны извлекаться из текста строк. Данные извлекаются, проверяются той же схемой Google protobuf и пишутся в хранилище распакованными. Если данные тут некорректны, то не получится их распаковать (а значит и записать) и об этой проблеме тоже нужно сигнализировать (т.к. проблема может быть не только в запаковке, но и при передаче "в центральную систему для поиска и анализа", например).


    Понятно, что это всё мои догадки, построенные на базе статьи, а правду знает только её автор и его коллеги...

  • Быстро и гибко настраиваем  наблюдаемость с помощью канонических строк логов
    0

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

  • Быстро и гибко настраиваем  наблюдаемость с помощью канонических строк логов
    0

    Да, это может быть проблемой, но пожалуй её можно решить. Как минимум валидация через google protobuf позволит не пропускать некорректные значения, а наличие ошибок валидации будет сигнализировать о проблемах либо в заполнении данных, либо в их парсинге.

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    +2

    Главная вещь, к которой я призываю — не использовать на автомате время с секундной точностью (потому что "её хватит всем"). Вместо этого стоит задумываться о том, не будет ли пользы от большей точности и если будет, то инструменты для работы с ней уже есть и их можно использовать. Если вам достаточно порядка, то в этом нет ничего плохого, не нужно использовать максимальную точность времени.

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    0
    А есть реальные задачи, где время с такой точностью нужно?

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


    Другой пример — замер времени доставки сообщений чата между базами данных отправителя и получателя. Это физически разные базы и хочется понимать, сколько времени происходит между отправкой сообщений (записью её в базу отправителя) и доставкой (базу получателя). При секундной точности разницу между 0.05 и 0.95 секунды будет не видна, а при повышении точности времени в базе — вполне.

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    +1

    В своём первом комментарии вы говорите про две вещи:


    1. сортировки по времени не нужны, а нужны по ID
    2. непонятно, зачем нужна такая точность времени.

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


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

    Я говорю не про сообщения, а про контакты (главную страницу любого мессенджера). Там записи обновляются много раз (при получении нового сообщения), а создаются (и получают идентификатор) только один раз.

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    +1

    Сортировка по уникальному идентификатору — это очень хорошо и если можно её использовать, то лучше сделать это. К сожалению она не всегда подходит. Вот несколько примеров, где эта сортировка не поможет:


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

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

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    +2

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


    Насколько мне известно, в кодовой базе Badoo нет Yii (но есть немного Laravel и Symfony Components).

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    0

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

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    +1

    Интересно. Кажется, что с помощью такой обёртки можно править баги при работе с временем, если обновить версию PHP нельзя или попался новый еще неисправленный баг.

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    0

    Да, все эти записи будут проигнорированы при выборке. Если же заменить условие created < X на created <= X, то сюда попадёт и та запись, что уже была показана на предыдущей странице.


    Эту проблему тоже можно решить — добавить к сортировке и фильтру по created второе поле, уникальное для каждой записи (тот же автоинкрементный id, например), но придётся усложнять условия выборки. Запрос на выборку страницы тогда будет выглядеть как-то так:


    SELECT id, created
    FROM CommentsTable
    WHERE ((created > :last_shown_created) OR (created = :last_shown_created AND id > :last_shown_id))
    ORDER BY created ASC, id ASC
    LIMIT 10

    Тут в условии (created = :last_shown_created AND id >:last_shown_id) отвечает за корректную обработку случая, когда есть несколько записей в то же время, что и у граничной записи, а (created > :last_shown_created) за обработку случая, когда их нет.


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


    Повышение точности значения времени — самый простой способ уменьшить вероятность появления записей с одним и тем же временем на границе страниц (но совсем избавиться от неё нельзя) без серьёзного изменения кода.


    Есть и другие способы для решения этой проблемы, но они не имеют отношения к времени и это уже совсем другая история...

  • Время высокой точности: как работать с долями секунды в MySQL и PHP
    0

    Не совсем понял пример.


    В моём примере подразумевалось, что если мы делаем пагинацию без оффсетов (при использовании которых есть свои проблемы), а на базе условий вида WHERE created < "2019-10-08 12:13:14" ORDER BY created DESC LIMIT 10 (где 2019-10-08 12:13:14 — это время последнего объекта предыдущей страницы, а 10 — количество записей на страницу), то мы не покажем другие объекты с тем же значением created если они есть, но не попали на предыдущую страницу из-за лимита записей на эту самую страницу.

  • Сыграй в IT-Alias с инженерами Badoo
    0

    Бинго!

  • Сыграй в IT-Alias с инженерами Badoo
    +1

    Способ, позволяющий выкатить новый функционал не на всех пользователей, а только на их часть

  • Сыграй в IT-Alias с инженерами Badoo
    0

    Да, имелось в виду именно это

  • Сыграй в IT-Alias с инженерами Badoo
    +1

    Процесс, после завершения которого пользователям становится доступна последняя версия вашего приложения или сайта

  • Сыграй в IT-Alias с инженерами Badoo
    0

    Он самый

  • Сыграй в IT-Alias с инженерами Badoo
    0

    Верно!

  • Сыграй в IT-Alias с инженерами Badoo
    +2

    Индексы такого типа позволяют компактно хранить набор булевых значений

  • Сыграй в IT-Alias с инженерами Badoo
    +2

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

  • Centrifugo v2 — будущее сервера real-time сообщений и библиотека для Go
    +5
    с помощью Centrifugo работает красивейший дашборд на ресепшн в московском офисе Badoo

    Не только московском, но и лондонском. Спасибо за работу над Центрифугой!

  • Как восемь человек масштабируют highload-проект. Опыт Unsplash
    0

    Значит, как минимум два пользователя очень довольны их продуктом)

  • Проблемы при работе с кэшем и способы их решения
    0

    Что-то подобное есть в дополнительных материалах, которые я приводил:


    Репозиторий на GitHub с описанием и тестами разных способов

    Там в директории samples/ есть log-файлы с результатами теста разных способов (правда никакой визуализации нет и не очень удобно сравнивать способы друг с другом).

  • Проблемы при работе с кэшем и способы их решения
    +1

    Я такой не видел.


    Достаточно просто найти реализацию согласованного хеширования (оно есть, например, в расширении memcached), а вот всё остальное в виде отдельной библиотеки мне не попадалось...

  • Проблемы при работе с кэшем и способы их решения
    0

    По описанию это очень похоже на вероятностные методы, только вместо случайного числа тут тут время обращения

  • Проблемы при работе с кэшем и способы их решения
    +1

    Честно говоря, вариант с мастер-процессом не выглядит проще в реализации, чем фоновое обновление (хотя сложно "лечить по фотографии").


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

  • Проблемы при работе с кэшем и способы их решения
    +1

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


    Я нашёл меньше 20 групп ключей, использующих схему со всеми серверами. Обычно это какие-то счётчики или кэши конфигурации по странам/городам, которые обновляются только фоновыми скриптами (т.е. мы исключаем параллельные обновления). В онлайне эти ключи только читаются и не отличаются от остальных.


    Честно говоря, я не знаю, рассматривались ли решения, про которые вы говорите, но кажется, что проблема не такая большая, чтобы использовать для неё специализированное решение. Memcached у нас уже был, так что мы использовали его.

  • Проблемы при работе с кэшем и способы их решения
    +1

    Спасибо за замечание, добавил еще один вариант названия

  • Проблемы при работе с кэшем и способы их решения
    +1

    Не так важно, какие именно слоты переносятся между серверами, главное добиться правильного соотношения между количеством слотов у работающих серверов (если веса равные, то и количество слотов на каждом должно быть примерно равно друг другу).


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


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

  • Как мы проверяем работоспособность серверного кода без мобильных клиентов
    0

    В принципе это похоже на то, что делаем мы. Разница только в том, что создание пользователя в начале теста и удаление в конце мы делаем неявно — оно происходит "само" и по мере необходимости. У нас есть пул тестовых пользователей, каждый из которых может быть взят любым тестом. За счет этого:


    • нам не нужно тратить время на создание пользователя и его чистку в момент прогона тестов => тесты работают быстрее
    • мы экономим место на дисках: законодательства некоторых стран требуют хранить данные даже удаленных пользователей, поэтому штатно удаление пользователя не означает DELETE записей о нём из базы. У нас несколько тысяч тестов и мы часто их запускаем, поэтому база бы очень быстро росла (особенно это критично на площадках разработчиков, которые используют общие базы)

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


    Еще одно отличие, которое я заметил — вы работаете с локальным объектом (например в вызове user.getCandies()). Мы так не делаем потому, что это не даёт возможность запускать тесты на удалённых площадках.


    Периодически у нас возникает проблема, что тест проходит на площадке разработчика, изменения мержатся в ветку билда, выкладываются на стейджинг (на котором используются боевые базы данных и сервисы) и там тест начинает падать, хотя на девел окружении проходит. В такой ситуации разработчик может сделать checkout ветки билда на своей площадке (в девел окружении) и запускать свой тест в стейджинг окружении (через отправку серверных команд поверх http). При этом можно менять сам тест, добавлять какие-то дебаги, дополнительные вызовы QaApi, которые покажут, что происходит на сервере.


    P.S. Не совсем понял: вы говорите, что у вас по сети ничего не отправляется, но это выглядит как отправка http-запроса


            api().post('/api/v1/buy') // POST запрос на URL покупки
                .set('authtoken', user.getToken()) // задаем заголовки авторизации
                .send(payload) // отправляем запрос
  • Как мы проверяем работоспособность серверного кода без мобильных клиентов
    0

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


    • использование уже имеющихся в коде констант (в приведённом коде есть несколько примеров). Благодаря этому мы можем использовать в тесте семантические значения и нам не нужно делать какой-то маппинг;
    • использование привычного разработчикам инструмента — работать с phpunit умеют чуть ли не все разработчики. За счёт этого снижается порог входа для нового человека;
    • ускорение прогона тестов: при использовании phpunit и локальной площадки разработчика тесты работают в рамках одного процесса без http-запросов. Это важно, ведь таких тестов очень много и они не очень быстрые.
  • Как мы проверяем работоспособность серверного кода без мобильных клиентов
    0
    Нет, assertGiftAddSuccess — это обычный метод класса теста, который делает серию проверок другими assert-методами. Вот его код:
        private function assertGiftAddSuccess($response, $fail_message)
        {
            $this->assertInternalType('array', $response, "{$fail_message}: an array expected");
            $this->assertArrayHasKey('gift_id', $response, "{$fail_message}: gift id expected!");
        }
    


    У нас есть целая пачка подобных asssertSomething, которые мы используем для упрощения самих тестовых методов.

    Magic method здесь — это вызов серверной команды ($ClientGiftSender->ServerGetUser), который собирает из аргументов запрос, отправляет его серверу и разбирает полученный ответ. Тут «магию» мы убирать не пробовали, но думаю, что теряем на ней мы сравнительно немного — ведь в тесте мы работаем с реальной базой и реальными сервисами.
  • Как в Badoo генерируются изображения для «шаринга» в соцсетях
    0
    Вот всё, что есть в паблике: https://github.com/tony2001/leptonica, но это очень старая версия.
  • Как в Badoo генерируются изображения для «шаринга» в соцсетях
    0
    Как вариант я хотел использовать специальный разделитель в лексемах (например, __EOL__), который бы переводчики добавляли в места возможного разбиения тексов на «сложных» языках. При генерации бейджа код бы либо “выкусывал” его (в случае когда текст помещается в одну строку), либо вставлял на его месте перенос строки. Это бы потребовало ручной работы, но совсем немного, ведь используется всего два-три десятка лексем.

    Из очевидных «граблей» — опечатки у переводчиков при вводе спецсимволов, но их можно ловить автоматически: в лексемах с опечатками после разбиения на строки будут символы из двух классов: иероглифов и латиницы, чего в корректных лексемах быть не должно.
  • Как в Badoo генерируются изображения для «шаринга» в соцсетях
    0
    Мы выводим тексты на японском слева направо, так что с этой точки зрения особенностей нет. Проблемы там скорее с разбиением на строки — нет классических пробелов и нельзя разбивать на произвольном месте, чтобы случайно не порвать слово, состоящее из нескольких символов. У меня было пару мыслей на этот счёт, но на практике их реализовывать не пришлось — у нас тексты на японском достаточно короткие и в итоге переводчики просто укоротили 1-2 лексемы, которые не помещались в одну строку.
  • Как в Badoo генерируются изображения для «шаринга» в соцсетях
    0
    К сожалению, я пока не могу прогнать ваш тест — под рукой нет сервера, где одновременно были бы и leptonica, и gmagick.

    В момент поиска графической библиотеки тесты показывали, что leptonica быстрее даже не в 2 раза, а процентов на 25. Было это давно и я не смог найти ни исходников тестов, ни их точных результатов, поэтому сделал новый тест просто чтобы показать (а заодно и самому понять), на каких конкретно операциях leptonica работает быстрее. Я думаю, что тут tony2001 сможет сказать больше меня.
  • Как в Badoo генерируются изображения для «шаринга» в соцсетях
    +1
    Вам правильно ответили — мы используем сессии не в файлах, а в памяти. Технически они доступны на серверах, где происходит генерация изображений, но только если запрос послал пользователь. У ботов нет доступа к данным из этой сессии, поэтому нельзя на неё полагаться и нужно передавать все необходимые параметры в URL бейджа.

    Арабский еще очень тяжело отлаживать — его почти никто не знает и после внесения правок непонятно, правильно они работают или нет. Приходилось после любого изменения готовить примеры картинок, отправлять их переводчикам и ждать от них обратной связи :-)
  • Как в Badoo генерируются изображения для «шаринга» в соцсетях
    +5
    Я сделал еще один вариант теста, в котором используется ваш вариант. resizeImage() работает где-то на 5% быстрее scaleImage(), но в рамках всего теста разница будет не очень заметна.
    Вот дополненная версия теста и его результаты: https://github.com/pryazhnikov/php-image-processing-tests/tree/im_resize_vs_scale
  • Быстрые счетчики в Yii
    0
    UPDATE `banners` SET `id`=1, `name`='test', `info`='long-long description', `hits`=3560, `iduser`='2', `created_at`='2012-02-17 13:14:02', ... WHERE `banners`.`id`=1
    Как я понял из этого запроса, есть таблица с баннерами, в которой хранится информация о баннере (название, какое-то описание, дата создания) + общее число хитов этого баннера.

    Мне было бы интересно вынесение поля hits из этой таблицы, т.е. создание отдельной таблицы banners_hits (banner_id, hits), в которой хранятся те же самые данные, но отдельно от всех остальных данных по баннерам. Логика такая: данные по хитам (скорее всего) нужны не всегда и обновляются гораздо чаще, чем остальные данные, поэтому может иметь смысл хранить их отдельно в сравнительно небольшой табличке.

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