Что делать если увеличились тайминги на запись в базу
Что проверяют
Понимаете ли, что запись упирается не в то же самое, что чтение, и умеете ли отделить задержку базы от ожидания внутри своего приложения.
Как отвечать
Первым делом разделить два случая: выросло время самой операции в базе или время ожидания своего пула соединений. В Go это видно по db.Stats(): WaitCount и WaitDuration растут при упёртом MaxOpenConns, база при этом абсолютно здорова.
Причины со стороны базы:
- индексов стало больше: каждая вставка обновляет их все, и «добавили индекс ради отчёта» замедляет запись навсегда;
- блокировки: конкурентные обновления одной строки, длинные транзакции, удерживающие замок, ожидание в очереди блокировок;
- раздувание таблицы и отставший автовакуум после массовых обновлений;
- контрольные точки и сброс журнала на диск: всплески узнаются по периодичности;
- синхронная реплика: коммит ждёт подтверждения второй машины, и виноват канал, а не диск;
- триггеры и проверка внешних ключей без индекса на ссылающейся стороне.
Со стороны приложения: вставлять пачками вместо строки на запрос, в PostgreSQL через COPY; переиспользовать подготовленные выражения; открывать транзакцию как можно позже и не держать её на время внешних вызовов; ставить дедлайн через context, чтобы зависшая запись не копила горутины.
Где спотыкаются
Предлагают лечить запись индексами. Индекс ускоряет поиск и замедляет вставку с обновлением, то есть это ответ ровно в обратную сторону от вопроса.
Называют кэш и реплики на чтение. Ни то, ни другое не разгружает мастер по записи, а реплика добавляет ему работы по отправке журнала.
Смотрят только среднее время запроса в приложении и не замечают, что половина задержки это ожидание свободного соединения. Такая проблема чинится настройкой пула, а в базе искать нечего.