Мой Blog или что интересно web разработчику

Mysql и HandlerSocket

Oracle

Недавно я на блоге Токарчука Андрея, русского IT шника, работавшего на Оракл нашел его перевод статьи Yoshinori Matsunobu.

По сути эта статья является не новостной. Тут я лишь хочу дать свои результаты тестирования этого плагина.

Японец получил в своем тесте 750 тыс. чтений в секунду из mysql таблицы. По сути это в 2 раза больше чем удается забрать с memcache сервера. Основной прирост производительности происходит за счет экономии времени процессора на этапе парсинга sql. Сегодня я хотел бы попробовать его повторить. Конечно я не добьюсь такого же результата на десктопе, но сравнение мы увидим.

В целом опыт японца выглядел так. Миллион записей в InnoDb таблице. innodb_buffer_pool_size такой чтобы вся таблица в нем поместилась. Плагин для Mysql HandlerSocket. С ним можно собрать обычный mysql но я использовал форк mysql — Percona. Там он уже есть — его надо только включить. Системные параметры японца — Detailed specs were as follows.

   Model: Dell PowerEdge R710
   CPU: Nehalem 8 cores, E5540 @ 2.53GHz
   RAM: 32GB (all data fit in the buffer pool)
   MySQL Version: 5.1.50 with InnoDB Plugin

Мои системные параметры

Core I7, 6 гигов памяти. Под buffer pool выделено около 2 гигов.

Ряд особенносте работы плагина — в 3 раза меньше сетевой трафик, работа только с индексами, всегда открытые сетевые подключения. Поддерживает опреации INSERT/UPDATE/DELETE. Есть LIMIT.
Почему — это интересно — нет дублирования кеша. Данные всегда актуальны. Остаются все наработки с мусклем — mysqladmin и прочее. Ничего не надо менять — это просто плагин.
Из минусов — нет авторизации на его портах. Надо помнить об этом на продакшне.
Нет выигрыша при нагрузке на файловую систему. Тут могут облегчить муки только ssd диски.

Подготовка плацдарма. Таблица

CREATE TABLE `test` (
  `testid` int(11) NOT NULL AUTO_INCREMENT,
  `testname` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`testid`)
 ) ENGINE=InnoDB AUTO_INCREMENT=1300092 DEFAULT CHARSET=utf8

Вставляем туда миллион md5 хешей для поиска. Код приведен для примера, если хотите повторить — придется адаптировать

require_once "common.php";


$db  = sqlFactory::create("mysql://localhost:testuser:domains:testuser");

$start = microtime(true);
echo "start " . $start . "\n" ;
for ($index = 0; $index < 1000000; $index++) {
    $new_rec = array();
    $new_rec['testname'] = md5($index);
    $db->insert( 'domains.test', $new_rec );
}
$stop = microtime(true);
echo "stop " . $stop . "\n";

Замерять будем родным инструментом для mysql:

mysqladmin extended-status -uroot -i 1 -r -p | grep "Innodb_rows_read"

Теперь сделаем 2 файла. Один будет работать через sql:

ini_set('memory_limit', '8000M');

require_once "../common.php";

$db  = sqlFactory::create("mysql://localhost:testuser:domains:testuser");

$start = microtime(true);
echo "start " . $start . "\n" ;
for ($index = 0; $index < 5000000; $index++) {
    $id = mt_rand(300092, 1300091);
    $res = $db->Row("SELECT testid,testname FROM test WHERE testid = $id");
}
$stop = microtime(true);
echo "stop " . $stop . "\n";

echo 'Sql '.($stop - $start) . "\n";

Второй — напрямую, через сокет

ini_set('memory_limit', '8000M');

require_once "../common.php";

$host = 'localhost';
$port = 9998;
$port_wr = 9999;
$dbname = 'domains';
$table = 'test';
$hs = new HandlerSocket($host, $port);
if (!($hs->openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'testid,testname')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

$start = microtime(true);
echo "start " . $start . "\n" ;

$search_arr = array();
for ($index = 0; $index < 5000000; $index++) {
    $hs->executeSingle(1, '=', array( mt_rand(300092, 1300091) ), 1, 0);
}
$stop = microtime(true);


echo "stop " . $stop . "\n";
echo 'No sql '. ($stop - $start) . "\n";

unset($hs);

Тут я использовал mt_rand именно в пределах первичных ключей всего моего диапазона.

Результаты тестирования прикрепляю в виде скринов. Первый — sql вариант. Все мои 8 ядер загрузились по полной уже при 8-10 потоках.

Sql

Sql

Второй вариант — более успешный Nosql вариант. Как ни странно говорить это слово по отношению к mysql. Успешно выдержал 15 потоков, и количество извлекаемой информации — в 3 раза больше (циферки на скрине — количество отданных строк в секунду движком mysql).

Nosql result

Nosql result

В обоих случаях количество потоков запрашивающих данные поднято до полной нагрузки процессора и аппроксимирующего прекращения роста количества отдаваемых данных.

Вывод: очень хороший плагин. Конечно же, мемкеш никуда не уйдет. Но просто необходимо использовать такие вещи в составе фреймверка. Конечному разработику ведь совсем не обязательно знать, как достается по первичному ключу запись — через sql или напрямую из индекса и пула. Так что, содержание этого подарка в Doctrine, например в магических find, было бы прозрачно и очень полезно.

Об авторе mudruy

Занимаюсь WEB разработкой с 2007. Оновной язык PHP. Плотно работал с Agile методологиями, первый толчок под руководством - http://www.scrumguides.com/search/label/krivitsky . Интересуюсь адаптацией систем под высокие нагрузки. Есть широкий опыт внедрения автоматического тестирования. Хочу чтобы в любой компании Симферополя хотелось работать.

Все посты автора mudruy

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

  • RSS
  • Gmail
  • LinkedIn
  • Skype
e-mail: mudruy@mail.ru
skype: mudruy
Copyright © 2012 / iMiracle
Powered by WordPress