@vetsmen

Почему через некоторое время не работают все mysql-сесии?

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

Сам модуль
socket.on('sell', async (id) => {
      try {
        id = parseInt(id, 10);

        if(!socket || !socket.userid) {
          return;
        }

        if(!id) {
          return;
        }

        let transaction = await connection.prepareTransaction();
        
        try {
          await transaction.beginTransaction();

          let item = await transaction.query('SELECT * FROM Items WHERE id = ? FOR UPDATE', [id]);

          if(!item || !item[0]) {
            await transaction.rollback();
            transaction.release();

            return;
          }

          if(!item[0].userid) {
            await transaction.rollback();
            transaction.release();

            return;
          }

          await transaction.query('UPDATE Items SET ? WHERE id = ?', [{status: 0, userid: null, timestamp: 0}, id]);

          await transaction.commit();
          transaction.release();
        } catch (e) {
          await transaction.rollback();
          transaction.release();
        }
      } catch (error) {
        throw error;
      }
    });
mysql обработчик
const mysql = require('mysql');
const { promisify } = require('util');

const pool = mysql.createPool({
  host: config.host,
  user: config.user,
  password: config.password,
  database: config.database,
  socketPath: '/var/run/mysqld/mysqld.sock',
  connectionLimit: 100
});

exports.prepareTransaction = () => {
    return new Promise((resolve, reject) => {
        pool.getConnection((err, connection) => {
          if (err) throw err;

          const query = promisify(connection.query).bind(connection);
          const commit = promisify(connection.commit).bind(connection);
          const rollback = promisify(connection.rollback).bind(connection);
          const beginTransaction = promisify(connection.beginTransaction).bind(connection);
          const release = connection.release;

          resolve({beginTransaction, query, commit, rollback, release});
        });
    });
};

Через определенное время (зависит от активности пользователей) mysql отваливается, при чем никакая ошибка не прилетает. Единственная версия - забиваются все доступные коннекты, т.к. не делается connection.release(), но в моем случае он вроде бы везде есть. Тем самым при подключении клиент ждет доступную сессию, а ее никогда уже и не будет.
После перезагрузки все снова работает нормально и через час-несколько часов mysql снова падает. До обновления такого не было.

На момент, когда умирают запросы в приложении (по всей видимости которые находятся в постоянном ожидании), PROCSSLIST показывает:
466d4b06bd.jpg
И таких процессов чуть больше 100 штук.
После рестарта приложения их всего навсего становится:
c830cf1d01.jpg
И после этого приложение работает адекватно 2-5 часов.
В htop вижу такие процессы:
ea95d3c29c.jpg
Но они не имеют никакого отношения к работе базы, как я понял.
  • Вопрос задан
  • 109 просмотров
Решения вопроса 1
@BorisKorobkov Куратор тега MySQL
Web developer
До недавнего времени все было нормально. Сейчас перешел с пива на водку. На утро сильно болит голова (зависит от количества выпитого). Единственная версия - интоксикация. После через некоторое время после опохмела прихожу в себя. Но после нескольких литров выпитой водки опять начинает кружиться голова. До перехода с пива на водку голова так сильно не болела.

Коннекты создаются, но не закрываются. Когда их кол-во достигает лимита - mysql падает.
transaction.release() не срабатывает, потому что у вас каша из попыток писать синхронный код на асинхронном языке. Await на каждой строчке - это говнокод. Понапихать еще await'ов в connection.release() - это не решение проблемы, а костыль. В таком стиле можно писать на PHP, но для использования Node.JS сначала разберитесь с асинхронностью.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы