MySQL: Slave could not parse relay log event entry

Рубрика: Development, MySQL | 17 September 2009, 10:09 | Vadim Voituk

При использованиии MySQL Master-Slave (или же Master-Master) репликации бывает ситуация что по разным причинам версия слейва ниже чем версия мастера.
Если при этом используется опция binlog_format=MIXED, в результате возможна ситуация когда мастер запишет в свой binlog запись вида:
BINLOG 'XMawShMEAAAARwAAAEp5UwUAAGkAAAAAAAAACHNhblahblahblah'
Которую слейв не сможет выполнить, ибо он ее попросту “еще не умеет”.

Первой ласточкой того, что это произошло станет сообщение “SLAVE DOWN” от мониторинговой системы и запись в MySQL-логе слейва сродни этой:

090917 14:55:51 [ERROR] Error in Log_event::read_log_event(): 'Found invalid event in binary log', data_len: 71, event_type: 19
090917 14:55:51 [ERROR] Error reading relay log event: slave SQL thread aborted because of I/O error
090917 14:55:51 [ERROR] Slave: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' o
n the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL
code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave. Error_code: 0
090917 14:55:51 [ERROR] Error running query, slave SQL thread aborted. Fix the problem, and restart the slave SQL thread with "SLAVE START". We stopped at log 'bin-us1.000022' position 17007149

Попытки пропустить неугодные записи старым добрым методом:
slave stop;
set global sql_slave_skip_counter=1;
slave start;

в данном случае не помогают.

Как вариант решения предлагаю:

  1. Останавливаем slave: “SLAVE STOP;”
  2. “Выуживаем” из текста ошибки имя бинлога и позицию, на которой произошла ошибка.
    В данном случае это bin-us1.000022 и позиция 17007149
  3. На мастере выполняем запрос “FLUSH LOGS;”
  4. Делаем дамп бинлога начиная с найденной позиции:
    mysqlbinlog --start-position=17007149 bin-us1.000022  >  bin-us1-from17007149.sql
  5. Загружаем полученный дамп на слейве с ключем “–force”
    mysql --force -uuser -ppassword database < bin-us1-from17007149.sql
  6. Выполняем на слейве “FLUSH LOGS;”
  7. В data-директории находим relay-log с максимальным номером и размером около 100 байт (в моем случае это mysqld-relay-bin.000037)
  8. В той же директории в файле relay-log.info
    первую строку заменяем на имя только что найденного relay-log-а, во вторую вписываем 0, в третью – следующий после “испорченного” бинлог, в четвертую – 0
    Получится что-то вроде:
    /var/lib/mysql/mysqld-relay-bin.000037
    0
    bin-us1.000023
    0
  9. Дальше на слейве выполняем:
    CHANGE MASTER TO MASTER_LOG_FILE='bin-us1.000023', MASTER_LOG_POS=0;
    SLAVE START;
  10. Ну и потом чтоб удостоверится что все “завелось”
    SHOW SLAVE STATUS\G

Должно работать.
Подозреваю что пункты 4 и 5 можно обьеденить в один, более простой и элегантный.
Но как это сделать – не гуглил.

MySQL: Single row lock implementation

Рубрика: Development, MySQL | 24 June 2009, 16:01 | Vadim Voituk

При разработке приложений с использованием баз данных, часто возникает сценарий “insert if not exists”:

if ( <row exists in table> )
   then <insert new record into table>

Из-за того, что данный блок псевдо-кода не выполяняется атомано, может возникнуть ситуация, когда между проверкой <row exists in table> и выполнением действия <insert new record> паралельный поток (клиент)  выполнит добавление новой записи и в итоге в БД окажется 2 одинаковых записи (или произойдет ошибка “duplicate key”).

Такой, не самый приятный case, в книгах по паралельному программированию называют race condition и обходят путем создания синхронизирующих блокировок , использованием “выпрямителей” и тд.
[Далее...]

MySQL: Archive Storage Engine

Рубрика: Development, MySQL | 13 March 2009, 20:56 | Vadim Voituk

Все очевидно, что любая современная информацонная система занимается хранением и анализом любого рода данных.  Аналитики утверждают что в среднем, обьем этих данных для среднестатистичекой компании растет на 42% в год.
В результате проблема хранения этих данных постепенно приобретает бОльшую актуальность.

Из своего опыта работы с достаточно большими массивами данных, хранимых в современных реляционных СУБД (по большей части в MySQL) могу сказать что не менее 50% данных в любой системе – это данные которые представляют собой только “историческую” ценность. [Далее...]

MySQL: Определение размера таблицы

Рубрика: MySQL | 8 January 2009, 18:11 | Vadim Voituk

Вот такой вот интересный запрос случайно выудил из документации MySQL:

SELECT
    table_name AS table_name,
    engine,
    ROUND(data_length/1024/1024,2) AS total_size_mb,
    table_rows
FROM
    information_schema.tables
WHERE
    table_schema=DATABASE();

Показывает обьем и количество строк в таблицах MySQL.
Результат выглядит приблизительно так:

+-------------------+--------+---------------+------------+
| table_name        | engine | total_size_mb | table_rows |
+-------------------+--------+---------------+------------+
| categories        | MyISAM |          0.00 |         17 |
| downloadlinks     | InnoDB |         13.02 |      19158 |
| errors            | InnoDB |         15.02 |      84104 |
| lastdownloads     | MEMORY |          3.19 |        524 |
| providers         | MyISAM |          0.00 |         17 |
| starstags         | InnoDB |          1.52 |      14323 |
| tagids            | InnoDB |         35.59 |     759694 |
| tags              | InnoDB |       2036.00 |   21971934 |
| vars              | InnoDB |          0.02 |         51 |
| videocategories   | InnoDB |         49.58 |    1583675 |
| videos            | InnoDB |       1864.00 |    1954427 |
| videos_deleted    | MyISAM |         56.33 |      75889 |
| videostats2       | InnoDB |        271.88 |    3417776 |
| videostats2_daily | InnoDB |          0.02 |        266 |
+-------------------+--------+---------------+------------+

Правда есть один нюанс: на InnoDB-таблицах показывает количество незалоченных в данный момент строк.

P.S. А кто-то пробовал использовать ARCHIVE storage engine?
Как он в плане fail-over и repair?
Поделитесь good/bad experience?

MyISAM and InnoDB auto_increment difference

Рубрика: MySQL | 22 August 2008, 09:53 | Vadim Voituk

Заметил интересную особенность автоинкрементного поля в InnoDB MySQL Engine

В отличии от MyISAM, значение автоинкрементного счетчика может повторяться. [Далее...]

PHP, MySQL и FOUND_ROWS() bug

Рубрика: Development, MySQL | 5 June 2008, 11:53 | Vadim Voituk

“Словил” сегодня пренеприятнейший баг, который стоил мне более часа потерянного времени.

Выполняем в консольном mysql-клиенте такой запрос:
SELECT SQL_CALC_FOUND_ROWS FROM tablename LIMIT 5;

Получем resultset из 5ти результатов (предполагается, что в таблице tablename больше 5ти записей)

Теперь в этом же соединении выполняем:
SELECT FOUND_ROWS();
Получаем значение, равное количеству строк в tablename – ничего сверхъестественного, все как и ожидалось.

Самое интересное начинается если повторить выполнить эти SQL-запросы из PHP-скрипта (при определенных условиях, но о оних ниже) – второй запрос будет всегда возвращать 0.

Причиной всему – ошибка в модуле php_mysql.so (BUG#33021), которая наблюдается при включенной опции
mysql.trace_mode=true

Дабы не поулчить подобную неприятность в своих проектах рекомендую пока установить mysql.trace_mode в false.

При тестировании использовался PHP 5.2.1 и с модулем mysql client API 5.1.16-beta.

Знак зодиака средствами MySQL

Рубрика: Development, MySQL | 13 February 2008, 13:45 | Vadim Voituk

Что-то давно я ничего про MySQL не писал – буду исправляться.

Часто на развлекательных сайтах приходится приходится “вычислять” знак зодиака пользователя по его дате рождения. Задача решена уже тысячу раз, и интереса не представляет – проверка попадания даты в интервал релизуется на любом популярном языке программирования в 5-7 строк.
А теперь представьте себе, что нужно написать SQL-запрос в MySQL БД, который выбрает из таблицы всех пользователей с определенным знаком зодиака.

Тут на помощь приходит оператор CASE.
С его использованием запрос, который выводит из таблицы users id-пользователя и его знак зодиака выглядит приблизительно так:
[sql]

SELECT id,
  stat_birth,
  @d:=DAY(FROM_UNIXTIME(stat_birth)) AS stat_birth_day,
  @m:=MONTH(FROM_UNIXTIME(stat_birth)) AS stat_birth_month,
  CASE
    WHEN (@m=3 AND @d>20) OR (@m=4 AND @d<21) THEN 'Oven'
    WHEN (@m=4 AND @d>20) OR (@m=5 AND @d<22) THEN 'Taurus'
    WHEN (@m=5 AND @d>21) OR (@m=6 AND @d<22) THEN 'Gemini'
    WHEN (@m=6 AND @d>21) OR (@m=7 AND @d<23) THEN 'Cancer'
    WHEN (@m=7 AND @d>22) OR (@m=8 AND @d<24) THEN 'Leo'
    WHEN (@m=8 AND @d>23) OR (@m=9 AND @d<24) THEN 'Virgo'
    WHEN (@m=9 AND @d>23) OR (@m=10 AND @d<24) THEN 'Libra'
    WHEN (@m=10 AND @d>23) OR (@m=11 AND @d<23) THEN 'Scorpion'
    WHEN (@m=11 AND @d>22) OR (@m=12 AND @d<22) THEN 'Sagittarius'
    WHEN (@m=12 AND @d>21) OR (@m=1 AND @d<21) THEN 'Capricorn'
    WHEN (@m=1 AND @d>20) OR (@m=2 AND @d<19) THEN 'Aquarius'
    WHEN (@m=2 AND @d>18) OR (@m=3 AND @d<21) THEN 'Fish'
  END AS zodiak
FROM users

[/sql]

По хорошему определение знака зодиака нужно оформить как хранимую процедуру, но в таком случае теряется совместимость с MySQL версий ниже 5-й.

10 cекретов консольного клиента MySQL

Рубрика: MySQL | 19 October 2007, 13:24 | Vadim Voituk

Всем известно, что в пакете с СУБД MySQL поставляется примитивный консольный клиент.
Но при этом мало кто им всерьез пользуется, предпочитая GUI- и WEB-аналоги (например MySQL Front, phpMyAdmin). Большинство аргументирует это тем, что консольный mysql неудобен.
После 2х лет работы исключительно с консольным клиентом, я с ними категорически не согласен, и уверен что консольный mysql – это мощный и удобный инструмент, как vim, только в своей нише. [Далее...]

MySQL: As Small As Possible

Рубрика: MySQL | 27 September 2007, 12:13 | Vadim Voituk

Do you know how to create minimal storage table field?
How to store single bit value in most optimized way?

Just do it:
[sql]

CREATE TABLE dummy (
  id int unsigned auto_increment primary key,
  ...
  bitField CHAR(0), # Only "" and NULL values
  ...
);

SELECT bitField="" AS checked, ISNULL(bitField) AS unchecked FROM dummy;

[/sql]

… или пособие о том, как не нужно делать :)

Предположим у нас есть MySQL master-slave репликация, в которой мастер работает на MySQL 4.0, а все слейвы на MySQL 4.1 и выше.

В принципе нормальная ситуация, т.к. в подобных системах мастер появляется первым, и возможно на тот момент версии MySQL 4.1 ещё попросту небыло.

Теперь выполняем примитивный запрос: [Далее...]

Страница 1 из 3123