Pull to refresh
19
-2
Сергей @wapmorgan

User

Send message

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

большой для php потому что на php исторически не пишут нагруженные бэкэнды. Ну вот так сложилось, это не моя выдумка.
Давайте не буду выделять тут стэк, просто назову бэкэнд с dau 50k средним бэкэндом. Можно? Вы не против?

С чего вы взяли что не люблю или не знаю?) баг в ext-zlib исправил, парочку opensource-библиотек веду, пишу ещё со времён php 5.3.

Перепутал с системными. Изменю. спасибо

Это какой-то кастомный код, который интегрируется с liquibase / flyway для получения итогового хеша миграций? Или отдельная джоба в пайплайне (но тогда как с этим быть локально)?

Это просто скрипт сборки образа, который вызывается как локально, так и в ci/cd.
И всё лежит во время тестов в tmpfs, да. Просто в самом образе БД выключен автоматический запуск, а БД лежит по другому пути, и перед стартом тестов происходит копирование в tmpfs-волюм:

    command:
      - bash
      - -c
      - "cp -r /root/pgdata/* /var/lib/postgresql/data && /docker-entrypoint.sh -c shared_preload_libraries=timescaledb"
    tmpfs:
      - /var/lib/postgresql/data
  1. Делаем базовый образ бд, в котором будут импортироваться sql-дампы.

  2. Берём md5 от списка файлов в папке с миграциями, он же будет тегом образа.

MIGRATIONS_HASH=`find ${ROOT_DIRECTORY}/migrations/ -type f -exec basename {} \; | grep -v .gitignore | sort | paste -sd ' ' | md5sum - | awk '{print $1}'`
  1. Проверяем, если образа с таким тегом (равным хэшу) нет, то собираем: поднимаем все контейнеры обязательные (напр, redis/pgbouncer и само приложение), выполняем миграции, фиксируем контейнер как образ. Пушим в реестр.

  2. В ci/cd на тестах просто считаем опять же хэш от списка файла миграций и указываем его как тег образа БД.

Там ещё есть небольшые игры в прятки с каталогами pgdata чтобы при запуске контейнера для миграций не потерять уже проинициализированную БД на предыдущем шаге.
Если нужно, оформлю в виде статьи ближе к вечеру тк комментарий большой выходит.

Миграции схлопнуть можно просто записав их все в один sql-файл, которым инициализируется бд.
А для тестов можно вообще готовить образ бд с выполненными миграциями и импортированным перед этим sql-файлом.
У нас на каждый коммит тесты выполняются с бд, образ бд меняется только при добавлении новой миграции (тк хэш образа бд считается на основе списка миграций).

Стат. анализ - ну да, ну да, пошёл как я...

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

Ппкс. Автоматическая проверка, единые правила для всех, отсутствие поля для разногласий или разной трактовки.

Немного ресурсов. Выделил бы 1 машину с 4 ядрами и 4гб минимум.
500 уников - это примерно в 100 раз меньше чем dau бэкэнда, на основе которого написаны рекомендации.
Назовём его бэкэнд больших размеров [для php] и средних размеров [для backend'а в целом].

preload даёт максимум 10% ускорения бутстрепа - в моих тестах подтвердилось. opcache включён по умолчанию. Как вначале и писал, не хочу повторяться с сотней других мануалов по ускорению.

А теперь по пунктам:

  • Особенно учитывая, что подавляющее число небольших приложений используют php/mysql Не знаю что там с mysql, но с postgres - обязательная настройка, позволяющая под нагрузкой держать стабильное околонулевое время соединения с пулером/бд.

  • непонятно, как использование редиса для сессий и кэша относится к использованию реплик Шардирование данных между разными редисами позволяет не нагружать один редис, что негативно скажется на его производительности. А реплики - это про БД в основном. Видимо, объединение шардирования и репликации в одном блоке вводит в заблуждение.

  • если кончаются коннекты, то БД долго выполняет запросы. Всё верно. Именно с этим мы и боремся. Открывать по 2к коннектов к postgres - зачем? если можно иметь в четыре раза меньше и выбирать из них только важную связанную информацию, а простые строки выбирать из кэша (что быстрее чем БД и не занимает коннекты).

  • Кэшируем всё. Я думаю, что любой разработчик в свое время приходил к этой идее Сталкивался каждый. И приходилось выбирать: важнее актуальность или быстродействие. Совсем уж важные данные можно вытягивать без кэша либо с очень небольшим временем жизни, а всё остальное - можно кэшировать.

  • Причем внятного объяснения так и нет — зачем открывать несколько соединений, если по максимуму нужно два, на чтение и на запись У нас как раз два и открывается - одно к мастеру на запись и ~30% чтения и один к случайной реплике для чтения остальных данных. Зря я использовал "несколько", видимо, тоже вводит в заблуждение. Причём оба идут через один и тот же пулер, и поэтому 3.6k воркеров php используют всего ~520 коннектов до мастера и 280 коннектов до каждой из реплик (на данный момент их 2). А до кэширования простых записей из БД все коннекты к БД утилизировались и пришлось бы уменьшать work_mem postgres чтобы увеличить кол-во max_connections. А зачем, если можно не тратить время БД на то, чем может заняться кэш (просто выдать данные по ключу)?

  • Используйте память сервера как более быстрый кэш: какой-то совет из прошлого века, который выглядит больше как рекомендация ИИ Зря вы так категорично. Около полугигабайта некритичного к актуальности кэша (которые опять же, выбрали раз в 5 минут из БД, сагрегировали и положили) на каждой из нод приложения очень хорошо хранятся: и не требуют сети для передачи, и очищаются при редеплое, и выбираются очень быстро. Что там "прошловекового" я так и не понял.

Если вас так сильно зацепило "небольшие", то да - это проблема. Заменю на "средний". Я исхожу из того, что несколько серверов - это вполне себе обычный бэкэнд: парочка для бд, штук 5 для приложения, ещё для кэша и s3.
Большинство советов применимы к любому backend, но в огород java/go - я не лезу, не любят они этого.

На момент старта работы над генератором (середина 2020-го) была версия zircote/swagger-php 3.0.5, в которой поддержки атрибутов не было, как и самих атрибутов в стабильной версии языка (php 8 ещё не вышла).

на 20-й версии у каждого контроллера 19 предков

Верно.

Позволю влезть в ветку.
Поставили nginx-proxy перед внешним https-сервисом. Если ранее 3600 воркеров могли выполнять до 900 запросов без ошибок, а потом начинали валиться сетевые ошибки (разного рода - от резолва до коннект таймаутов), то с nginx-proxy, держащим до 1500 открытых коннектов до сервиса, без проблем держатся и 2k rps к внешнему сервису.
Задержки установления https-коннекта сошли на нет.

А винде пробовали?
Там как проводник с 100к файлами в одном каталоге справится?

Ну и про раскрытие звезды в шелле уже написали

В убунте за последние лет 5 понадобилось только 1 раз зафиксировать зависимость - OpenVpn для NM, чтобы флаги старые использовать.
А сколько раз в арче пришлось что-то фиксировать?

Дополнение к размерам:

  1. Размер таблиц и индексов, единым плоским списком по всей СУБД (чтобы понять что кушает больше всего)

SELECT concat(schemaname, '.', tablename, ':', indexname),
       pg_relation_size(concat(schemaname, '.', indexname)::regclass) as size,
       pg_size_pretty(pg_relation_size(concat(schemaname, '.', indexname)::regclass)) AS pretty_size
FROM pg_indexes
UNION
SELECT concat(schemaname, '.', relname),
       pg_table_size(relid) as size,
       pg_size_pretty(pg_table_size(relid)) AS pretty_size
FROM pg_catalog.pg_statio_user_tables
ORDER BY 2 DESC
  1. Размер одной таблицы суммарный и в пересчёте на одну строку (удобно для прикинуть сколько занимает одна запись на диске)

SELECT l.metric, l.nr AS bytes
     , CASE WHEN is_size THEN pg_size_pretty(nr) END AS bytes_pretty
     , CASE WHEN is_size THEN nr / NULLIF(x.ct, 0) END AS bytes_per_row
FROM  (
   SELECT min(tableoid)        AS tbl      -- = 'public.tbl'::regclass::oid
        , count(*)             AS ct
        , sum(length(t::text)) AS txt_len  -- length in characters
   FROM   partners t                     -- заменить здесь на имя таблицы, которую нужно проанализировать
   ) x
CROSS  JOIN LATERAL (
   VALUES
     (true , 'core_relation_size'               , pg_relation_size(tbl))
   , (true , 'visibility_map'                   , pg_relation_size(tbl, 'vm'))
   , (true , 'free_space_map'                   , pg_relation_size(tbl, 'fsm'))
   , (true , 'table_size_incl_toast'            , pg_table_size(tbl))
   , (true , 'indexes_size'                     , pg_indexes_size(tbl))
   , (true , 'total_size_incl_toast_and_indexes', pg_total_relation_size(tbl))
   , (true , 'live_rows_in_text_representation' , txt_len)
   , (false, '------------------------------'   , NULL)
   , (false, 'row_count'                        , ct)
   , (false, 'tuples'                      , (SELECT reltuples::int FROM pg_class WHERE pg_class.oid = x.tbl))
   , (false, 'pages'                      , (SELECT relpages::int FROM pg_class WHERE pg_class.oid = x.tbl))
   ) l(is_size, metric, nr);

Дополнение к статистике:

  1. Получение статистики выполнявшихся запросов - по суммарно потраченному СУБД времени на все запросы / по потраченному на выполнение одного запроса времени.

Для Postgres 13 и выше нужно заменить total_time на total_exec_time.

SELECT round(total_time::numeric, 2) AS total_time,
       calls,
       ROWS,
       round(total_time::numeric / calls, 2) AS avg_time,
       round((100 * total_time / sum(total_time::numeric) OVER ())::numeric, 2) AS percentage_cpu,
       query
FROM pg_stat_statements
ORDER BY total_time DESC -- для сортировки по суммарному времени выполнению всех копий запроса
-- ORDER BY avg_time DESC -- для сортировки по времени выполнения одного запроса
LIMIT 20;  

Нужен хаб "психология" или "здоровье"

Остаётся вопрос - как теперь заказать и доставить эти ПК в РФ

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Registered
Activity