Время ожидания прерывистой блокировки Laravel Транзакция БД (с 5 повторными попытками) - PullRequest
0 голосов
/ 17 февраля 2020

У нас были периодические ошибки блокировки (примерно 1-2 в день из ~ 250).

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

Пример нашего кода (не совсем то же самое, но достаточно близко):

DB::transaction(function () use ($paymentMethod, $singleUseTokenId, $requiresPayment, $chargeAccount) {
    // create order locally
    $order = Order::create([
        'blah' => $data['blah'],
    ]);

    // handle payment
    $this->handlePayment();

    // update order with new status (with a secondary transaction for safety)
    DB::transaction(function () use ($order) {
        $order->update([
            'status' => 'new status',
        ]);
    }, 5);

}, 5); // Retry transaction 5 times - this reduced the lock timeout errors a lot

И периодически возникающая ошибка, которую мы получаем ( фактические значения удалены):

SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction (SQL: insert into `orders` (`user_id`, `customer_uuid`, `type_uuid`, `status_uuid`, `po_number`, `order_details`, `cart_identifier`, `cart_content`, `cart_sub_total`, `cart_tax`, `cart_grand_total`, `payment_type_uuid`, `shipping_address`, `uuid`, `updated_at`, `created_at`) 

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

Из того, что я могу сказать из крошек базы данных, создание заказа иногда занимает много времени (например, видел один в 3 с, другой в 23 с по какой-то причине, как правило, это вставка 50 мс), а затем другой что-то происходит, и он пытается обновить заказ, но строка все еще заблокирована из create ().

Примечания:

  • У нас есть 4 внешних ключа в таблице заказов (customer uuid , пользователь uuid, тип заказа uuid, статус заказа uuid) - я чувствую, что это может вызывать проблемы.
  • Некоторые красноречивые создания берут 3 секунды, другие 23 (только проверенные проблемы). Для большинства заказов максимальный запрос составляет 500 мс, поэтому это выбросы.

Есть предложения?

Решение: первичного ключа в заказах нет. Очень глупая ошибка. Заставил InnoDB создать 6-байтовый ключ для индекса. И заблокируйте от последовательной вставки, затем обновите ..

1 Ответ

1 голос
/ 17 февраля 2020

Если вы видите ошибки «время ожидания блокировки», посмотрите другие транзакции. Особенно вредны длительные транзакции. Вы можете найти их в SHOW ENGINE INNODB STATUS\G. Восхождение на список истории InnoDB также указывает на то, что они есть. Выполняемые в данный момент длинные транзакции будут перечислены в information_schema.INNODB_TRX.

Обратите внимание: если транзакция получила эксклюзивную блокировку, она не освобождается до конца транзакции, а не до конца запроса.

First , исключить длительные запросы. Например, медленное UPDATE будет удерживать блокировку на время выполнения.

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

...