Постараюсь быть максимально подробным.
До сих пор я использовал только 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