Posterous theme by Cory Watilo

Filed under: MySQL

My fail with MySQL

Сегодня сделал глупость – поторопился. И уложил MySQL. А дело было так…

Создал таблицу test1 с хранилищем InnoDB, и начал делать в нее load data infile. Но процесс затянулся, и я решил убить его. Зря. Убить процесс в мускуле не удалось, и я злостно его перезапустил.

После перезапуска MySQL запусти фоновое восстановление таблицы, и не отзывался ни на что. Потому был потушен еще раз.

Затем вместо того чтоб прописать в my.cnf

innodb_force_recovery = 4

я остановил его и… грохнул test1.frm. Руками, на диске.

После перезапуска ничего не изменилось. И я уже запустил MySQL с указаной опцией. И тут я понял свою ошибку. А ведь надо было не удалять файл, а п ерезапуститься с innodb_force_recovery и сделать уже оттуда

DROP TABLE test1;

В результате поисков было найдено решение: дампить БД, убивать БД, выкатывать БД из дампа. Так tablespace в InnoDB почистится.

Вывод: не торопиться и не пороть гарячку. Доки прийдется читать в любом случае, зато не нервничая при этом.

UPD: еще большей глупостью было убить логи не дожидаясь clean shutdown. Теперь лишь mysqldump –all-databases, убить, restore…

UPD2: удалением БД дело не ограничилось. Пришлось дампить все InnoDB таблицы, затем удалять /var/lib/ib*, в том числе и ibdata (при остановленом мускуле), запускать его и вкатывать дамп обратно.

На заметку:

forcing-recovery Recovery howto

LVM Rocks

Давно заметил что в Ubuntu (server edition) во время инсталляции начали предлагать использовать LVM. Но я все не решался поставить production на него. Затем пообщался со теми кто его использовал, почитал доку - и последний год стал его использовать, так как постиг скрытую в нем мощь :) Допустим, у нас есть простенький бюджетный сервер. Мы развернули новое приложение, и его база стала расти весьма стремительно. Итого - база, веб-файлы и система живут на одном физическом диске. Был куплен диск WD Razor, и на него перенесли базу. Нагрузка диска (iostat -x -m 1) составила 1-2%. Решено перенести туда же и веб-файлы, однако решение это пришло лишь через пару дней. Так что получилось наглядно продемонстрировать возможности LVM.

Part1. Creating...

Когда поставили разор на нем создали один раздел - LVM: [cc lang="bash"] # fdisk -l Disk /dev/sdb: 74.3 GB, 74355769344 bytes 255 heads, 63 sectors/track, 9039 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0x00000000 Device Boot Start End Blocks Id System /dev/sdb1 1 9039 72605736 8e Linux LVM [/cc] Пару слов об организации LVM. Уровень 1: volume group (vg). Это наивысший уровень абстракции, объединяющий в себе logical volumes и physical volumes. Уровень 2: physical volume (pv). Это некое блочное устройство, способное хранить данные (HDD, RAID, ...) Уровень 3: logical volume (lv). Это эквивалент раздела на жестком диске. Таким образом в группу добавляются физические тома (pv), и потом во всем этом пространстве свободного места создаются разделы (lv), на которых уже создается файловая система. Итак, сначала создавался pv: [cc lang="bash"] pvcreate /dev/sdb1 [/cc] Затем vg: [cc lang="bash"] vgcreate sys_vg /dev/sdb1 [/cc] И затем на все свободное место указанного pv (/dev/sdb1) создали lv с именем var_lib_mysql: [cc lang="bash"] lvcreate -L 100%PVS -nvar_lib_mysql sys_vg /dev/sdb1 [/cc] Дело за малым: [cc lang="bash"] mkreiserfs /dev/mapper/sys_vg-var_lib_mysql mount /dev/mapper/sys_vg-var_lib_mysql /mnt /etc/init.d/mysql stop mv /var/lib/mysql/* /mnt/ mv /var/lib/mysql/.* /mnt/ umount /mnt mount /dev/mapper/sys_vg-var_lib_mysql /var/lib/mysql chown -R mysql:mysql /var/lib/mysql /etc/init.d/mysql start [/cc] Вот собственно и почти все. Последний штрих - прописать монтирование раздела в fstab, дабы это происходило при загрузке автоматом. Можно скучно сделать это через blkid, увидеть там нужный UUID (например, f6946e54-c7d6-4688-8fac-05dcb1bf9973), скопировать его, открыть /etc/fstab и вставить туда строку вида: [cc lang="bash"] UUID=f6946e54-c7d6-4688-8fac-05dcb1bf9973 /var/lib/mysql reiserfs defaults 0 2 [/cc] а можно сделать так: [cc lang="bash"] printf "\nUUID=`blkid | grep sys_vg-var_lib_mysql | sed -r 's/.*UUID="([^"]*).*/\1/i'`\t/var/lib/mysql reiserfs defaults 0 2\n" >> /etc/fstab [/cc] Да, если сделать umount /var/lib/mysql && mount /var/lib/mysql до ребута - то /dev/disk/by-uuid/f6946e54-c7d6-4688-8fac-05dcb1bf9973 (или какой там получится) там еще не будет. Для того чтоб появился до ребута надо перезапустить udev: [cc lang="bash"] /etc/init.d/udev restart [/cc]

Part2. Resizing...

Как я говорил раньше, с опозданием пришла мысль о том, что неплохо бы вынести и статические файлы на этот же винт. И сделать это совсем просто! Для этого от того lv что был создан раньше (и именуется var_lib_mysql) откусим немного места. Сначала остановим все службы (говорят, reiserfs увеличивается/уменьшается без проблем налету, но я этого пока не пробовал на себе): [cc lang="bash"] /etc/init.d/mysql stop umount /var/lib/mysql [/cc] Затем уменьшим файловую систему, а затем и lv на 20ГБ: [cc lang="bash"] resize_reiserfs -s-20G /dev/mapper/sys_vg-var_lib_mysql lvreduce -L-20G /dev/mapper/sys_vg-var_lib_mysql [/cc] На всякий случай я предпочел проверить фс на ошибки (а вдруг!): [cc lang="bash"] reiserfsck /dev/mapper/sys_vg-var_lib_mysql [/cc] Ну и возвращаем обратно MySQL: [cc lang="bash"] mount /var/lib/mysql /etc/init.d/mysql start [/cc] Теперь создадим lv для веб-файлов, и так как их намного меньше 20ГБ, я решил оставить 5ГБ про запас, никому их не присвоив. Потом можно будет налету добавить туда где закончится место. [cc lang="bash"] lvcreate -L 15G -nvar_www sys_vg mkreiserfs /dev/mapper/sys_vg-var_www [/cc] Далее - перенос файлов: [cc lang="bash"] /etc/init.d/nginx stop /etc/init.d/apache2 stop mount /dev/mapper/sys_vg-var_www /mnt mv /var/www/* /mnt/ mv /var/www/.* /mnt/ umount /mnt mount /dev/mapper/sys_vg-var_www /var/www /etc/init.d/apache2 start /etc/init.d/nginx start [/cc] И опять не забываем про fstab: [cc lang="bash"] printf "\nUUID=`blkid | grep sys_vg-var_www | sed -r 's/.*UUID="([^"]*).*/\1/i'`\t/var/lib/mysql reiserfs defaults 0 2\n" >> /etc/fstab [/cc] По материалам:
  1. http://wiki.linuxquestions.org/wiki/LVM#example
  2. http://www.tldp.org/HOWTO/LVM-HOWTO/reducelv.html
PS: после изменения размера мог измениться UUID для lv var_lib_mysql, хотя я и не уверен в этом. Но проверить не помешает. PS2: если работаете удаленно - не забывайте про screen. PS3: писалось по памяти, так что могут быть некоторые неточности. Тупой копипаст без вовлечения мыслительного процесса чреват боком. Я предупредил ;)

Server moving adventures

Второй день занимаюсь переездом содержимого одного сервера на другой. Другой - VPS под FreeBSD (привет, ДЦ Воля). В общем, это последний раз когда я до оплаты сказал что он неплох. Теперь только реальные сервера. Ну и может VDS под Linux... В общем, именно эта реализация ужасна. Меня мало интересует как и что - факт налицо.
Первая ласточка - mysql. Сообщение о нехватке памяти в логах: [cc lang="text"] 080806 13:39:10 [ERROR] /usr/local/libexec/mysqld: Out of memory (Needed 1043824 bytes) [/cc] Судя по найденому в гугле и попыткам что-либо изменить, это вылазит из-за дефолтного в i386 FreeBSD значения максимального количества памяти на процесс. И изменить его у меня не удалось. В результате куцые буфера, и веселые запросы толпятся в очереди, а MySQL уверенно пухнет. И опухает: [cc lang="text"] [root@vps ~]# ps axu | grep mysql bash: fork: Cannot allocate memory [/cc] Причем, такое поведение я уже встречал ранее. Дважды. Тогда еще и файловые дескрипторы заканчивались (привет phpbb с кучей плагинов). Но все был бы ничего, однако базы в большинстве своем живут в MyISAM, но самая тяжелая - как и полагается, в InnoDB. И вот любой запрос с джоинами на ней ложил тачку. Во время разборок с мускулем был применен киллер, найденый в темном переулке на форумах мускуля: [cc lang="php"] #!/usr/local/bin/php 10 && $row['User']!='root' ) { $sql="KILL $process_id"; mysql_query($sql); } } ?> [/cc] Теперь появилось время на мысли. mtop помог отследить, что во всем виновата одна эта БД. После запора в ней более-менее тяжелые запросы в других БД тоже застряют. Результатом был переезд этой большой базы на другой хост, и использование ее оттуда. Сервер с двухядреным оптероном и 4ГБ памяти не заметил появления балласта: запросы пролетали мгновенно. И это без попыток тюнинговать мускуль.
Далее начались проблемы с милой связкой nginx+apache. Как описано у Алексея, все заработало. Но некоторые странички отказывались показываться - браузер ругался на невозможность понять что же ему пришло. Такой ошибки я не встречал, и как оказалось никто из моего контакт-листа тоже. А получилось следующее: обожаемый ExpressionEngine (и тебе привет) пытался все отдать за-gzip-леное. Апач справедливо отдавал это как HTTP/1.1 Transfer-Encoding: chunked. Но это в ответ на запрос HTTP/1.0 от nginx! Последний нифига не понимал и результирующий фарш доставлялся браузеру. Еще бы, он не хотел это нечто отображать... Выключением опции gzip-сжатия в ExpressionEngine 1.5.3 это полечилось, однако...
... приключения с этим белым и пушистым зверьком не закончились. В форуме при публикации сообщения символы кириллицы отсутствовали. Долго я искал помощи через гугль, пока не полез в код. А в коде методом тыка нашел, что это все виноват xss_clean в версии 1.5.3. Заменив строки с [cc lang="php"] ... $str = preg_replace('#(&\#*\w+)[\x00-\x20]+;#u',"\\1;",$str); ... $str = preg_replace('#(&\#x*)([0-9A-F]+);*#iu',"\\1\\2;",$str); ... [/cc] на [cc lang="php"] $str = preg_replace('#(&\#?[0-9a-z]+)[\x00-\x20]*;?#i', "\\1;", $str); ... $str = preg_replace('#(&\#x?)([0-9A-F]+);?#i',"\\1\\2;",$str); [/cc] проблему вылечил. С нетерпением жду что обнаружится дальше...