Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Тюнинг SQLite для PHP

Anna | 31.05.2014 | нет комментариев
В данной статье оценивается использование SQLite для PHP-планов, рассматриваются особенности многопоточной работы и методы убыстрения работы.


Предисловие

Не так давным-давно мне захотелось сделать свой сервис промо-кодов для одного своего плана. В выборе платформы я не длинно сомневался. Раз у меня есть сервер с развернутым PHP-окружением, то и сам сервис отважно дозволено писать на PHP (тем больше, что я с ним знаком). В качестве СУБД мне захотелось испробовать SQLite (правда на сервере развернуты MySQL и PostgreSQL). Повод — проще переносить на “боевое” окружение (легко скопировать папку), проще разворачивать на “голом” сервере (помимо PHP ничего не необходимо). Добавочно хотелось упростить бэкап (планировал применять снэпшоты диска примитивное копирование получившегося “среза”).

Но раньше, чем применять, нужно проверить применимость и эффективность данного решения.

Сталь

Тестирование происходило на 2х объектах:

  • Рабочая станция. Intel i5. 12GB RAM. SSD HDD (WD Black). Windows 8. Применяется OpenServer для запуска PHP.
  • Облако в Selectel. Debian 6. Здесь будет стоять сервис. Установлен LAMP в дефолтной конфигурации. Разве что Apache еще мощнее урезал, в угоду уменьшения потребления памяти.

Заблаговременная оценка

Для исходной оценки продуктивности был написан примитивный скрипт:

<?php
	// Инициализация БД
	function initDB()
	{
		$guid = '';
		// Имя строим по случайному ГУИДу
		if (function_exists('com_create_guid') === true)
		{
			$guid = trim(com_create_guid(), '{}');
		}
		else
		{
			$guid = sprintf('%04X%04X-%04X-%04X-%04X-%04X%04X%04X', mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(16384, 20479), mt_rand(32768, 49151), mt_rand(0, 65535), mt_rand(0, 65535), mt_rand(0, 65535));
		}
		// Определяем полное имя БД
		$file = "_$guid.db";
		// Открываем БД (либо создаем)
		$db = new SQLite3($file);

		// Создаем таблицу
		$db->exec('CREATE TABLE foo (i INT, i2 INT)');
		return $db;
	}
	// Операция тестирования БД
	function testDB($db, $count)
	{
		for ($i=0; $i<$count; $i  )
			testIteration($db, $i);
	}
	// 1 итерация тестирования
	function testIteration($db, $iteration)
	{
		$db->exec('INSERT INTO foo VALUES ('.$iteration.', 1)');
	}

	// ---------- ИНИЦИАЛИЗАЦИЯ И ЗАПУСК ТЕСТА ----------
	// Определяем число инсертов
	$COUNT = 1000.0;
	if(isset($_REQUEST['COUNT']))
		$COUNT = $_REQUEST['COUNT'];
	// Иницализируем БД
	$db = initDB();
	// Начинаем застыл времени
	$start = microtime(true);
	// Запускаем тест
	testDB($db, $COUNT);
	// Застыл окончен
	$time = microtime(true) - $start;
	// Итог итога
	echo "$COUNT inserts per " . number_format($time, 2) . "sec. " . number_format($COUNT / $time, 2) . " operation per second";
?>

Ступенчато вставляем 1000 записей в таблицу. Замеряем затраченное время. Вычисляем число операций в секунду.
В тезисе, для жесткой оценки большего и не нужно.
Обращаю внимание, что я намеренно не применял транзакции. Всякая операция пойдет в собственной транзакции. Данный режим работы ближе к реальному применению базы в многопоточном режиме.

А сейчас итоги:
Для SSD диска получили оценку в 365 операций в секунду. Хорошо.
Для HDD получили каждого 13 операций. Грустно. Но что же скажет сервер?
А сервер порадовал. 210 операций.
В целом, оценка продуктивности на сервере абсолютно порядочная. Дозволено продолжать тестирование работы PHP с SQLite. Только сразу же делаем отметку, что для сервера нужно применять стремительную файловую подсистему (SSD).
В нашем случае, как я теснее говорил, применяется облако в Selectel. SSD выступает там как кэш между дисками и облачными машинами (во каждом случае, так я осознал по рассказам небезызвестного amarao).

Многопоточный режим работы

Сейчас испробуем ответить на вопрос, сможет ли база трудиться в многопоточном режиме.
Читаем восхитительный цикл статей о SQLite: habrahabr.ru/post/149356/
И видим, что для многопоточного режима нужно включать WAL-журнал. Добавим в инициализацию БД строчку (позже открытия):

$db->exec('PRAGMA journal_mode=WAL;');

И сразу же прогоним тест:
SSD: 2000 транзакций в секунду. Показатель подрос больше чем в 5 раз!
HDD: 42 операции. Рост в 3 раза.
Сервер: 1000 операций. Рост примерно в 5 раз.

Дюже непредвиденные итоги. Примитивное метаморфоза режима журнала дает рост в 5 раз.
Дальнейшим этапом перепишем скрипт на многопоточность.
Многопоточность будем добиваться через вызов PHP-скрипта несколько раз в нескольких потоках (ближе к реальной работе сайтов). Для этого воспользуемся утилитой AB (Apache Benchmark).

ab -n 1000 -c 10 "http://localhost:81/test/benc_sqlite.php"

Получившийся текст скрипта:

<?php
	function openDB()
	{
		// Определяем полное имя БД
		$file = "_TEMP.db";
		// Открываем БД (либо создаем)
		$db = new SQLite3($file);
		// Оптимизация БД
		$db->busyTimeout(5000);
		$db->exec('PRAGMA journal_mode=WAL;');

		return $db;
	}

	// Инициализация БД
	function initDB()
	{
		$db = openDB();
		// Создаем таблицу
		$db->exec('CREATE TABLE foo (i INT, i2 INT)');
		return $db;
	}
	// Операция тестирования БД
	function testDB($db, $count)
	{
		return testIteration($db, mt_rand(0, 1000));
	}
	// 1 итерация тестирования
	function testIteration($db, $iteration)
	{
		return $db->exec('INSERT INTO foo VALUES ('.$iteration.', 1)');
	}

	// ---------- ИНИЦИАЛИЗАЦИЯ И ЗАПУСК ТЕСТА ----------

	// Иницализируем БД
	if(isset($_REQUEST['init']))
		$db = initDB();
	else
		$db = openDB();
	// Запускаем тест
	if(testDB($db, 1))
		echo 'OK';
	else
		echo 'FAIL';
?>

Из скрипта ушел застыл скорости вставки, это нам даст AB. Сейчас инициализация проводится только 1 раз, т.к. идет работа с одной БД.
Добавочно, установил

$db->busyTimeout(5000);

Это нужно для того, Дабы при попытке многопоточной записи, процесс ожидал некоторое время (я задал 5 секунд) своей очереди, а не сразу падал с тем, что “SQLITE_BUSY”.

Итоги:
SSD: 970 операций в секунду. Больше чем довольно.
HDD: 35 операций.
Сервер: 90 операций при тесте с локальной машины и 210 при запуске AB с сервера. Дюже огромная разница с запуском на SSD. Судя по каждому, она обусловлена отличиями в настройке систем (на сервере Apache урезан до потенциального минимума).
Добавочно следует подметить, что локальные показатели дюже крепко плавают, сказывается облачность сервера. От меня до сервера примерно полторы тысячи километров.
В любом случае, даже если брать минимум, 90 операций в секунду, то этого больше чем довольно, на мой взор. К примеру, Прогр имеет в среднем 30 просмотров в секунду (безусловно, крепкие пики днем, но и до Програ расти и расти).

В последующем показатели для SSD и HDD берутся при локальном тесте. А для сервера — с удаленной машины.
Тестирование сервера и SSD происходит путем запуска 1000 запросов в 10 потоках. Для HDD — 100 запросов в 10 потоков.

Усложнение

Напомню, в тесте был 1 примитивный INSERT запрос. В тезисе, отлично иметь сервис, исполняющий 1 операцию на базе. Но это дюже вдалеке от действительности. Усложним до 3 запросов (1 SELECT, 1 UPDATE и 1 INSERT).
Итоговая функция testIteration:

	function testIteration($db, $iteration)
	{
		$rez = $db->querySingle('SELECT count(*) FROM foo WHERE i='.$iteration);
		if($rez > 0)
		{
			$db->exec('UPDATE foo SET i2 = i2 1 where i='.$iteration);
		}
		return $db->exec('INSERT INTO foo VALUES ('.$iteration.', 1)');
	}

?сно, что дозволено обойтись и без SELECT-запроса, но тем не менее, у нас тест, а не соревнования по оптимизации.

Показатели:
SSD: от 420 запросов. От запуска к запуску показатель падает.
HDD: от 20 запросов (и падает).
Сервер: от 65 запросов (и падает).

Оптимизация БД

Падение продуктивности мне ересные. Настоль, что я решил сравнить продуктивность различных СУБД на сервере. Напомню, что применяется Debian 6. На сервере стоят: SQLite (v3.7.3), PostgreSQL (v9.0.4), MySQL (v5.1.66). Все в дефолтной настройке. AB запускался локально, на сервере. 10000 запросов в 10 потоках.
Итоги:
SQLite: 174 запроса в секунду.
PostgreSQL: 104 запроса в секунду.
MySQL: 167 запросов в секунду.

Как видим, такого большого обрыва, как для локальной машины, в показателях нет. Но не стоит забывать, что на сервере применяется SSD (пускай и не в “чистом” виде, а как элемент облачной СХД).

Вывод

Как результат дозволено сказать, что связка PHP и SQLite абсолютно работоспособна для невысоко нагруженных планов. Довольно придерживаться некоторых примитивных правил:

  1. Используем WAL-режим журналирования.
  2. Не забываем устанавливать Busy Timeout.
  3. Запись объединяем в транзакции. Причем не примитивные, а “BEGIN IMMEDIATE”.

Если же план отнести к “небольшим” невозможно, то применение SSD для базы абсолютно может подмогнуть и тут.

Если же говорить о Hi-Load, то ребята, этим занимающиеся, знают что им делать и без моих советов.

Если же сопоставлять SQLite с другими СУБД, то они владеют сравнимой эффективностью на настройках по умолчанию. Во каждом случае при применении SSD диска.
Совместно с тем, простота настройки и администрирования (ничего не нужно настраивать и администрировать), простота переноса на иной сервер (простым копи-пастом) дают некое преобладание для SQLite. В первую очередь для разработчиков. Для работы SQLite с PHP ничего, помимо самого PHP и не нужно.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB