Назад | Перейти на главную страницу

Apache получает ПРИОСТАНОВЛЕНИЕ в MSSQL другим процессом при выполнении более 5-6 запросов через PHP PDO, что приводит к тайм-ауту

Постараюсь быть максимально подробным.
До сих пор я использовал только Stack Overflow и другие подобные сайты, но никогда не публиковал сообщения. Мне всегда удавалось найти ответ на свой вопрос. Но не в этот раз.

У меня есть игровой сервер Mu Online, который настроен и работает нормально. Частью этого сервера является программа под названием «JoinServer». Когда я использую версию, отличную от md5, это нормально, но я хочу использовать версию файла md5.

С версией md5 у меня следующая проблема:
Сервер запускается, работает и все в порядке, пока кто-то не подключится к игре (здесь создаются запросы и начинает загружаться MSSQL). До этого момента Apache выполнял запросы очень быстро, без задержек и все работало идеально. Но когда кто-то подключается (когда JoinServer начинает работу), блокировки начинают происходить. Это постоянно только с md5-версией JoinServer.

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

Игра работает нормально, но когда я вызываю более 5-6 запросов от Apache, процесс Apache блокируется и имеет статус SUSPENDED внутри монитора ресурсов MSSQL.

Возникает вопрос: как предотвратить приостановку Apache?
- можно ли установить приоритет процесса (Apache) на сервере MSSQL?
- можно ли предотвратить блокировку одним процессом других процессов (запретить JoinServer блокировать / приостанавливать процесс Apache)?
- возможно ли, что мои веб-запросы написаны не очень хорошо и создают слишком большую нагрузку, а MSSQL приостанавливает их выполнение? Субъективно их не слишком много и они не создают большой нагрузки на SQL-сервер. Когда игровой сервер отключен, они запускаются мгновенно.
- НЕЛЬЗЯ изменять запросы игрового сервера (JoinServer), у меня нет доступа к его исходному коду

Используемое программное обеспечение
- Windows Server 2012 R2 (пробовал на Windows 7 Pro - то же)
- Microsoft SQL Server 2008 (пробовал с 2012 - то же)
- PHP 7.3 через xampp 7.3.10
- PHP 7.3 и Apache на Ubuntu (то же самое)
- Официальный драйвер Microsoft PDO для PHP 7.3

Вот как я подключаюсь к БД:

$dsn = 'sqlsrv:server='.Config::DB_SERVER.';Database='.Config::DB_NAME;
$dsn_web = 'sqlsrv:server='.Config::DB_SERVER.';Database=ANHIWEB';
$options = [
                PDO::ATTR_EMULATE_PREPARES   => false,
                PDO::ATTR_ERRMODE            => PDO::ERRMODE_WARNING,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
                ];

try {

    $db = new PDO($dsn, Config::DB_USER, Config::DB_PASS, $options);
    $webdb = new PDO($dsn_web, Config::DB_USER, Config::DB_PASS, $options);

}

catch (PDOException $e) {
    die(print_r($e->getMessage()));
}

(Я использую 2 базы данных).

Вот пример запросов, выполняемых PHP через PDO:

//Get online players count
$exec = $db->prepare("SELECT count(memb___id) FROM MEMB_STAT WHERE ConnectStat='1'");
    $exec->execute();
    $result = $exec->fetchAll();
    return @$result[0][''];
//Some rankings
    $exec = $db->prepare("SELECT
    RowNum
      ,C.[AccountID]
      ,[CharacterName]
      ,C.[Class]
      ,C.[cLevel]
      ,C.[Resets]
      ,[Point]
FROM    ( SELECT    ROW_NUMBER() OVER ( ORDER BY C.Class DESC ) AS RowNum, *
          FROM      [EVENT_INFO] as E
          WHERE C.ctlCode=0
        ) AS RowConstrainedResult
         left join Character as C ON CharacterName = Name

WHERE   RowNum >= $start
    AND RowNum < $limit
ORDER BY RowNum");

    $exec->execute();
    $result = $exec->fetchAll();
//Get total accounts
    $exec = $db->prepare("SELECT count(memb_guid) FROM MEMB_INFO");
    $exec->execute();
    $result = $exec->fetchAll();
    return @$result[0][''];

РЕДАКТИРОВАТЬ: Я обнаружил, что этот запрос блокируется, похоже, что JoinServer использует таблицу MEMB_STAT.
Возможно, это единственный запрос, который блокируется.

//Get online players
global $db;
    $exec = $db->prepare("SELECT count(memb___id) FROM MEMB_STAT WHERE ConnectStat='1'");
    $exec->execute();
    $result = $exec->fetchAll();
    return @$result[0][''];

Теперь вопрос: как выбрать этот счетчик, не вызывая блокировки?

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

Мои усилия:
- Отключен IPv6 в Windows
- Отключены именованные каналы на SQL-сервере.
- Поиграл с параллелизмом - не повезло
- Пробовал с Windows 7, все остальное тоже - не повезло
- Пытался запустить Apache на Ubuntu вместо Windows - не повезло
- Пробовал MSSQL 2012 вместо 2008 - то же

Вот некоторые детали, которые я могу получить на замке:
- Состояние задачи: SUSPENDED
- Команда: SELECT - Заявка: Apache HTTP Server
- Время ожидания (мс): 115163 (и увеличивается)
- Тип ожидания: LCK_M_S (Я погуглил, не помогло)
- Подождите ресурс: keylock hobtid=*** dbid=* id=** and so on
- Заблокировано по ID: 204 (это ID JoinServer)

Что еще делать? Какие-либо предложения?

Пытаться prepare("SELECT count(memb___id) FROM MEMB_STAT with (nolock) WHERE ConnectStat='1'"); Но ищите документы на nolock, у него есть недостатки, но я думаю, для этой цели они приемлемы. https://stackoverflow.com/questions/686724/what-is-with-nolock-in-sql-server