Комментарии 33
Одно плохо, что при «split-brain», оно выдает «Invalid command», а не свою, «родную» ошибку.
Какое то невнятное падение производительности.
Пробовали развернуть на centos?
Пробовали развернуть на centos?
За замечания спасибо. Особенно полезным мне будет второе. А насчёт первого я писал, что при использовании xtrabackup ноды останавливаться не будут на время дампа.
Скажите, вы не проверели случайно?
Осилю конечно. Просто меня интересует кластерное решение mysql. Пока не могу определится на чем остановится или galera или percona. Вроде бы mariadb использует percona.
Может быть порекомендуете, что почитать? Я хотел бы понять, что мне подайдет для моих задач.
Планирую для начала 3 Master-Master сервера.
Может быть порекомендуете, что почитать? Я хотел бы понять, что мне подайдет для моих задач.
Планирую для начала 3 Master-Master сервера.
Если не секрет, на чем остановились?
Ищу товарищей по несчастью, мучаю третью неделю Percona XtraDB Cluster, хочется мнений / отзывов
Ищу товарищей по несчастью, мучаю третью неделю Percona XtraDB Cluster, хочется мнений / отзывов
по п.4. вопрос — при выходе из строя той ноды, на которую идет запись, haproxy сам переключит запись на другие? как это возможно, если мы к примеру жестко вписали ip ноды?
ясно, меня собственно что и удивило — если тупо писать на один жестко заданный узел, то зачем прокси? спасибо за объяснение
А чем обусловлена большая вероятность split-brain, если писать сразу на 3 сервера? Это же мультимастер, и это требование выглядит немного странно
Наткнулся на глюк, которого по идее в кластере возникать не должно.
Сделал прогу, которая сравнивает последние записи в таблицах на двух узлах кластера (третий узел тупо garbd). Так вот частенько (а при нагрузочном тестировании так постоянно) выползают несоответствия между базами. Например, в одной базе одно поле имеет старое значение, в то время как в другой уже обновилось. Или же в одной есть такая запись, а в другой нет вообще.
Это можно было бы списать на то, что запись делалась непосредственно в интервале между проверкой на первом и втором узле, но это не стыкуется с частичным обновлением полей. К тому же я сделал блокироку через транзакцию на таблицы обоих кластеров до их чтения (тоже не панацея, но снижает вероятность существенно)…
Что бы это могло быть?
Сделал прогу, которая сравнивает последние записи в таблицах на двух узлах кластера (третий узел тупо garbd). Так вот частенько (а при нагрузочном тестировании так постоянно) выползают несоответствия между базами. Например, в одной базе одно поле имеет старое значение, в то время как в другой уже обновилось. Или же в одной есть такая запись, а в другой нет вообще.
Это можно было бы списать на то, что запись делалась непосредственно в интервале между проверкой на первом и втором узле, но это не стыкуется с частичным обновлением полей. К тому же я сделал блокироку через транзакцию на таблицы обоих кластеров до их чтения (тоже не панацея, но снижает вероятность существенно)…
Что бы это могло быть?
А можно детали проги приподраскрыть, чтобы можно было воспроизвести у себя?
Я просто повесил прогу, которая в бесконечном цикле проходится по серверам и сравнивает последнюю строку в каждой таблице. Если что-то не совпадает — выдаёт сообщение. И такие сообщения при нормальной работе сайта периодически выдаются. При нагрузочном же тестировании выдаются постоянно.
При следующем проходе (через 10 миллисекунд) этого несоответствия уже не выявляется, но ведь кластер должен обеспечивать соответствие данных всегда.
Потом я сделал блокировку с помощью открытия транзакции и последующего чтения. То есть сначала я прохожусь по всем серверам и ставлю блокировки, потом уже сверяю данные. Это по идее должно было существенно снизить вероятность попадания на несинхронизированные данные, количество сообщений не уменьшилось.
При следующем проходе (через 10 миллисекунд) этого несоответствия уже не выявляется, но ведь кластер должен обеспечивать соответствие данных всегда.
Потом я сделал блокировку с помощью открытия транзакции и последующего чтения. То есть сначала я прохожусь по всем серверам и ставлю блокировки, потом уже сверяю данные. Это по идее должно было существенно снизить вероятность попадания на несинхронизированные данные, количество сообщений не уменьшилось.
Сама программа (PHP)
<?php
require dirname(__FILE__).'/config.php';
while(true)
{
$ts=date('r');
// echo «старт\n»;
foreach ($config['db'] as $key=>$val)
{
if(!$db[$key]=mysql_connect($val['host'], $val['user'], $val['password']))
die(«Ошибка подключения к БД: ». var_dump($val)."\n");
}
// echo «подключено\n»;
$tables=array();
$tables_summary=array();
// считываем названия всех таблиц во всех базах
foreach($config['db'] as $key=>$val)
{
$db_=$db[$key];
if(!mysql_query(«USE {$config['scheme']}», $db_))
echo $ts.' Ошибка выбора таблицы: '.mysql_error($db_)."\n";
mysql_query(«SET names 'utf8'», $db_);
if($res=mysql_query(«SHOW TABLES», $db_))
{
while($row=mysql_fetch_row($res))
{
$tables[$key][$row[0]]=true;
$tables_summary[$row[0]]=true;
}
}
else
echo $ts.' '.mysql_error($db_);
}
// echo «проверка таблиц\n»;
// проверяем наличие таблиц во всех базах
foreach($tables_summary as $key=>$val)
{
foreach($config['db'] as $key0=>$val0)
{
if(!@$tables[$key0][$key])
{
echo "$ts В базе $key0 нет таблицы $key. Таблица исключена из проверки.\n";
$tables_summary[$key]=false;
}
}
}
//system(«clear»);
// echo «проверка данных\n»;
foreach($tables_summary as $key=>$val)
{
if($val)
{
// лочим таблицы
foreach($config['db'] as $key0=>$val0)
{
$db_=$db[$key0];
if(mysql_query(«START TRANSACTION», $db_))
mysql_query(«SELECT 1 FROM $key LIMIT 1», $db_); // чтоб запустилась блокировка внутри транзакции надо что-нибудь прочитать из таблицы
if(mysql_error($db_))
echo $ts.' Ошибка блокировки: '.mysql_error($db_)."\n";
}
//echo "$key\t";
unset($id_summary);
unset($id_name);
foreach($config['db'] as $key0=>$val0)
{
if(!isset($id_name))
{
$db_=$db[$key0];
// получаем имя первой колонки
$res=mysql_query(«DESCRIBE $key», $db_);
$row=mysql_fetch_row($res);
$id_name=$row[0];
//echo "$id_name\t";
}
// получаем максимальный id
$res=mysql_query(«SELECT MAX($id_name) FROM $key», $db_);
$row=mysql_fetch_row($res);
if(is_numeric($row[0]))
{
//echo " $row[0] ";
if(!isset($id_summary))
{
$id_summary=$row[0];
}
else
{
if($id_summary<$row[0])
{
echo "$ts В базе $key0 в таблице $key ключ $id_name опережает другие на ".$row[0]-$id_summary."\n";
}
if($id_summary>$row[0])
{
echo "$ts В базе $key0 в таблице $key ключ $id_name отстаёт от других на ".$row[0]-$id_summary."\n";
$id_summary=$row[0]; // В $id_summary попадает значение id, которое есть во всех базах
}
}
}
else
unset($id_summary);
}
if(@$id_summary)
{
// echo «сравнение данных\n»;
$data=array();
foreach($config['db'] as $key0=>$val0)
{
$db_=$db[$key0];
// считываем по одной строке из каждой базы
$res=mysql_query(«SELECT * FROM $key WHERE $id_name='$id_summary' LIMIT 1», $db_);
$row=mysql_fetch_row($res);
if($data)
{
if(is_array($data) && is_array($row))
$result = array_diff($data, $row);
elseif($data!=$row)
$result=true;
if($result || !$row)
{
echo "$ts Есть расхождения в таблице $key, $id_name='$id_summary':\n";
print_r($data);
print_r($row);
}
}
else
{
if($row)
$data=$row;
}
}
}
// разлочиваем таблицы
foreach($config['db'] as $key0=>$val0)
{
$db_=$db[$key0];
mysql_query(«COMMIT», $db_);
if(mysql_error($db_))
echo $ts.' Ошибка разблокировки: '.mysql_error($db_)."\n";
}
}
}
//echo «закрытие соединений\n»;
foreach($config['db'] as $key0=>$val0)
{
mysql_close($db[$key0]);
}
usleep(10);
}
require dirname(__FILE__).'/config.php';
while(true)
{
$ts=date('r');
// echo «старт\n»;
foreach ($config['db'] as $key=>$val)
{
if(!$db[$key]=mysql_connect($val['host'], $val['user'], $val['password']))
die(«Ошибка подключения к БД: ». var_dump($val)."\n");
}
// echo «подключено\n»;
$tables=array();
$tables_summary=array();
// считываем названия всех таблиц во всех базах
foreach($config['db'] as $key=>$val)
{
$db_=$db[$key];
if(!mysql_query(«USE {$config['scheme']}», $db_))
echo $ts.' Ошибка выбора таблицы: '.mysql_error($db_)."\n";
mysql_query(«SET names 'utf8'», $db_);
if($res=mysql_query(«SHOW TABLES», $db_))
{
while($row=mysql_fetch_row($res))
{
$tables[$key][$row[0]]=true;
$tables_summary[$row[0]]=true;
}
}
else
echo $ts.' '.mysql_error($db_);
}
// echo «проверка таблиц\n»;
// проверяем наличие таблиц во всех базах
foreach($tables_summary as $key=>$val)
{
foreach($config['db'] as $key0=>$val0)
{
if(!@$tables[$key0][$key])
{
echo "$ts В базе $key0 нет таблицы $key. Таблица исключена из проверки.\n";
$tables_summary[$key]=false;
}
}
}
//system(«clear»);
// echo «проверка данных\n»;
foreach($tables_summary as $key=>$val)
{
if($val)
{
// лочим таблицы
foreach($config['db'] as $key0=>$val0)
{
$db_=$db[$key0];
if(mysql_query(«START TRANSACTION», $db_))
mysql_query(«SELECT 1 FROM $key LIMIT 1», $db_); // чтоб запустилась блокировка внутри транзакции надо что-нибудь прочитать из таблицы
if(mysql_error($db_))
echo $ts.' Ошибка блокировки: '.mysql_error($db_)."\n";
}
//echo "$key\t";
unset($id_summary);
unset($id_name);
foreach($config['db'] as $key0=>$val0)
{
if(!isset($id_name))
{
$db_=$db[$key0];
// получаем имя первой колонки
$res=mysql_query(«DESCRIBE $key», $db_);
$row=mysql_fetch_row($res);
$id_name=$row[0];
//echo "$id_name\t";
}
// получаем максимальный id
$res=mysql_query(«SELECT MAX($id_name) FROM $key», $db_);
$row=mysql_fetch_row($res);
if(is_numeric($row[0]))
{
//echo " $row[0] ";
if(!isset($id_summary))
{
$id_summary=$row[0];
}
else
{
if($id_summary<$row[0])
{
echo "$ts В базе $key0 в таблице $key ключ $id_name опережает другие на ".$row[0]-$id_summary."\n";
}
if($id_summary>$row[0])
{
echo "$ts В базе $key0 в таблице $key ключ $id_name отстаёт от других на ".$row[0]-$id_summary."\n";
$id_summary=$row[0]; // В $id_summary попадает значение id, которое есть во всех базах
}
}
}
else
unset($id_summary);
}
if(@$id_summary)
{
// echo «сравнение данных\n»;
$data=array();
foreach($config['db'] as $key0=>$val0)
{
$db_=$db[$key0];
// считываем по одной строке из каждой базы
$res=mysql_query(«SELECT * FROM $key WHERE $id_name='$id_summary' LIMIT 1», $db_);
$row=mysql_fetch_row($res);
if($data)
{
if(is_array($data) && is_array($row))
$result = array_diff($data, $row);
elseif($data!=$row)
$result=true;
if($result || !$row)
{
echo "$ts Есть расхождения в таблице $key, $id_name='$id_summary':\n";
print_r($data);
print_r($row);
}
}
else
{
if($row)
$data=$row;
}
}
}
// разлочиваем таблицы
foreach($config['db'] as $key0=>$val0)
{
$db_=$db[$key0];
mysql_query(«COMMIT», $db_);
if(mysql_error($db_))
echo $ts.' Ошибка разблокировки: '.mysql_error($db_)."\n";
}
}
}
//echo «закрытие соединений\n»;
foreach($config['db'] as $key0=>$val0)
{
mysql_close($db[$key0]);
}
usleep(10);
}
А как распараллеливать запросы на ноды в таком кластере?
Понятно что в приложении можно, но интересует вариант с прозрачным коннектом и балансировкой. Какие есть варианты?
Понятно что в приложении можно, но интересует вариант с прозрачным коннектом и балансировкой. Какие есть варианты?
спасибо
еще вопрос — вот вы пишите о том что тестировали и кластер, и ноды отдельно — имеется в виду, что ноды выкидывались на время из кластера и на стандартном mysql сервере проводился тест?
еще вопрос — вот вы пишите о том что тестировали и кластер, и ноды отдельно — имеется в виду, что ноды выкидывались на время из кластера и на стандартном mysql сервере проводился тест?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Percona XtraDB Cluster. Установка и тестирование