Я постараюсь быть максимально подробным.
До сих пор я использовал только 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][''];
EDIT: я обнаружил, что этот запрос блокируется, похоже, что 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 - тот же
Вот некоторые подробности, которые я могу получить при блокировке:
- Состояние задачи: ПРИОСТАНОВЛЕНА
- Команда: SELECT
- Приложение: HTTP-сервер Apache
- Время ожидания (мс): 115163
(и увеличивается)
- Тип ожидания: LCK_M_S
(я погуглил, не помогло)
- Ожидание ресурса: keylock hobtid = *** dbid = * id = ** и так далее
- Заблокировано идентификатором: 204 (это идентификатор JoinServer)
Что еще делать? Есть предложения?
Попробуйте приготовить ("ВЫБРАТЬ Счетчик (член ___ id) ИЗ MEMB_STAT с (nolock) WHERE ConnectStat = '1'");
Но посмотрите документы на nolock, он недостатки, но, думаю, для этой цели они приемлемы. https://stackoverflow.com/questions/686724/what-is-with-nolock-in-sql-server