MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話

63
MySQL 4.09年動き続けたサーバを リプレイスしてバージョンアップした話 OKUMURA Takahiro MySQL Casual Talks vol.7

Transcript of MySQL 4.0で9年動き続けたサーバを リプレイスしてバージョンアップした話

MySQL 4.0で9年動き続けたサーバを!リプレイスしてバージョンアップした話

OKUMURA Takahiro MySQL Casual Talks vol.7

OKUMURA Takahiro!

@hfm @tacahilo!

2013年ペパボ新卒入社の2年目インフラエンジニア

今日の話MySQL 4.0.25で9年動き続けたサーバを,新しいサーバへリプレイスし,MySQL 5.0.96にバージョンアップした話!

ホントはもっとバージョンを上げたかったけど,他の仕事の兼ね合いで間に合いませんでした😞

背景

2013年度新卒採用でペパボに入社!

7/15からhetemlにインフラエンジニアのOJT!

ITインフラのことは何一つ分かってなかった

MySQLとの馴れ初め

MySQLとの馴れ初め

MySQLとの馴れ初め

規模がよくわかっておらず,ノリノリで応答している

SELECT ????????? FROM ????????

しかし課題は山積み…

当初はSELECT文すらろくに書けなかった(↓を埋められない)

知識不足経験不足,勉強も並行するとして,まずは現状の把握から…

passport0

heteml の顧客管理DB

2005年から投入されてるサーバ (hetemlサービスリリース時点で投入されたサーバの1つらしい)

よぼよぼ

passport0# uname -a Linux passport0.heteml.jp 2.6.17-1.2142_FC4 #1 Tue Jul 11 22:41:06 EDT 2006 x86_64 x86_64 x86_64 GNU/Linux !

# cat /etc/redhat-release Fedora Core release 4 (Stentz) !

# mysql --version mysql Ver 12.22 Distrib 4.0.25, for unknown-linux-gnu (x86_64)

passport系DBの構成MySQL !4.0.25!

!MASTER

MySQL!5.1.49!

!SLAVE

MySQL !4.0.25!

!SLAVE

passport系DBの構成MySQL !4.0.25!

!MASTER

MySQL!5.1.49!

!SLAVE

MySQL !4.0.25!

!SLAVE

masterに(無い|有る)DBやユーザがいたりしてデータが不安

masterに(無い|有る)DBやユーザがいるし,独自パッチが当たっているし,あと一部DBの中身がぶっ壊れたままレプリケーションしてた

masterしか信用出来ない…

ハードウェアがいつ死んでもおかしくないソフトウェアも古く扱いづらい!

CentOS6, MySQL X.Y.Z ( > 4.0.25) にハードウェアリプレイス&ソフトウェアアップグレードしたい!!

MySQL 4.0からレプリケーション可能なバージョンは?

各バージョンのMySQLをビルドして,4.0.25からレプリケーション出来るか各バージョン毎に調べたりhttps://github.com/kamipo/mysql-build (神)

途中,道を外してただひたすらチェインレプリケーションを行ったりも

MySQL 4.0!!

port 3306

VagrantのVM (1個)

MySQL 4.0!!

port 3306

MySQL 4.1!!

3307

VagrantのVM (1個)

MySQL 4.0!!

port 3306

MySQL 4.1!!

3307

MySQL 5.0!!

3308

VagrantのVM (1個)

MySQL 4.0!!

port 3306

MySQL 4.1!!

3307

MySQL 5.0!!

3308

MySQL 5.1!!

3309

VagrantのVM (1個)

MySQL 4.0!!

port 3306

MySQL 4.1!!

3307

MySQL 5.0!!

3308

MySQL 5.1!!

3309

MySQL 5.5!!

3310

VagrantのVM (1個)

MySQL 4.0!!

port 3306

MySQL 4.1!!

3307

MySQL 5.0!!

3308

MySQL 5.1!!

3309

MySQL 5.5!!

3310

MySQL 5.6!!

3311

VagrantのVM (1個)

途中成果物

https://speakerdeck.com/hfm/27https://github.com/tacahilo/mysql-allstar

MySQL 5.0化へ

そんなこんなで検証を続け,最終的にはMySQL 5.0へのアップグレードを計画することにした.

MySQL 5.0化へ

社内でMySQL 4.0 -> 5.0へのアップグレード経験があった(ので不安も少なめ)

CentOS 6用のMySQL 5.0.86 rpmが社内yumリポジトリにあった(昔ビルドしたらしい)

passport系DBの構成MySQL !4.0.25!

!MASTER

MySQL!5.1.49!

!SLAVE

MySQL !4.0.25!

!SLAVE

masterに無いDBやユーザがいたりしてデータが不安

masterに無いDBやユーザがいるし,独自パッチが当たっているし,あと一部DBの中身がぶっ壊れたままレプリケーションしてた

masterしか信用出来ない…

(再掲)

リプレイス概要

MySQL !4.0.25

リプレイス概要

MySQL !4.0.25 dump

リプレイス概要

MySQL !4.0.25

MySQL !5.0.86dump

リプレイス概要

MySQL !4.0.25

MySQL !5.0.86!

!MASTER

dump

MySQL !5.0.86!

!SLAVE

6/20 リプレイス夜間メンテナンス

MySQL 4.0からのdump,そしてMySQL 5.0へのリストアが成功し,無事メンテは成功したかに思えた…

!! INSERT breaks bin-log !!

レプリケーションを作ろうとして発覚!

INSERTクエリが実行されたときのみ,bin-logが壊れる現象に遭遇

!! INSERT breaks bin-log !!

use testdb; INSERT INTO a_data (id, create_date) VALUES ('1', NOW());

!! INSERT breaks bin-log !!ERROR: Error in Log_event::read_log_event(): 'read error', data_len: 66899, event_type: 41 Could not read entry at offset 881:Error in log format or read error # at 575 #140620 3:59:32 server id 1 end_log_pos 642 Query thread_id=575 exec_time=0 error_code=0 !

BEGIN /*!*/; -- use SYSTEMtestdb/*!*/; etstdbINSERT INTO a_data (id, create_date) VALUES ('1', /*!*/;

!! INSERT breaks bin-log !!ERROR: Error in Log_event::read_log_event(): 'read error', data_len: 66899, event_type: 41 Could not read entry at offset 881:Error in log format or read error # at 575 #140620 3:59:32 server id 1 end_log_pos 642 Query thread_id=575 exec_time=0 error_code=0 !

BEGIN /*!*/; -- use SYSTEMtestdb/*!*/; etstdbINSERT INTO a_data (id, create_date) VALUES ('1', /*!*/;

1. 途中挟まっている「SYSTEM」という文字列はタイムゾーン

2. 「use <database>」の間にタイムゾーンの文字が割り込む

3. INSERT文行頭に「1文字削れたDB名」がくっつき,VALUES以降が消失してしまう

4. flushすれば再開するが,結局INSERT毎にbin-logが破損してしまう

切り戻し(メンテ失敗)

bin-log問題の調査

@hiboma先生に助けを求めた

MySQL 5.0系のsourceとGCCバージョンの相性に問題?

• http://bugs.mysql.com/bug.php?id=48357

• https://gcc.gnu.org/bugzilla/show_bug.cgi?id=38562

MySQL 5.0系のsourceとGCCバージョンの相性に問題?

log_event.cc:

!write_str_with_code_and_len((char **)(&start), catalog, catalog_len, Q_CATALOG_NZ_CODE); !!(*dst)+= len;

MySQL 5.0系のsourceとGCCバージョンの相性に問題?該当箇所では char * を Log_event::Byte* ( = unsigned char) として扱っている

これは strict aliasing に違反するコードになる(難しくてよく分かってない)http://d.hatena.ne.jp/yohhoy/20120220/p1

strict aliasing に違反(あるいは有効にしている場合?)は,異なる型でポインタを操作すると動作が未定義になるらしい

=> 未定義の結果として、ポインタのサイズが期待通りに計算されなくて binlog のポジションがズレて物故割れた

MySQL 5.0系のsourceとGCCバージョンの相性に問題?MySQL 5.0にバグがあった? => NO

GCCにバグがあった? => NO

GCCの特定バージョン (4.3.3~4.4.0あたり) でMySQL 5.0をビルドしようとするとバグってしまうという,組み合わせの問題っぽい

• -O1でビルドするとmysqlのテストスイートがコケる • -O2でビルドするとbinlog周りのテストがコケる • -O2 -fno-strict-aliasingならテスト通る

MySQL 5.0系のsourceとGCCバージョンの相性に問題?

@hiboma先生の調査メモに再現方法つきで更に詳細が載っております(僕自身がちゃんと問題を把握しきれてなくてすみません…)

https://github.com/hiboma/hiboma/blob/master/mysql/bug-48357-binlog-corruputed.md

gccが悪かったのか!yum updateと-O2 -fno-strict-aliasingで解決だ!

やった!これで行ける!!と思ったら

新しいGCCでrpmbuildしたら!別の場所でコケた

MySQLをrpmbuildする過程specファイルを見ると,2回ビルドしていることが分かる

1. DEBUG=1をつけてビルドする

• mysql-debugバイナリを生成する

• 1回目のテストを走らせる

2. DEBUG=0をつけてビルドする

• 2回目のテストを走らせる

• mysqldバイナリを生成する

MySQLをrpmbuildする過程specファイルを見ると,2回ビルドしていることが分かる

1. DEBUG=1をつけてビルドする

• mysql-debugバイナリを生成する

• 1回目のテストを走らせる

2. DEBUG=0をつけてビルドする

• 2回目のテストを走らせる

• mysqldバイナリを生成する

この時点でmysqld-debug.sym というファイルが生成される

何故か途中でmysqld-debug.symが消えてビルドがコケる

そのとき出ていたエラー

RPM build errors: File not found: /home/vagrant/rpmbuild/BUILDROOT/MySQL-community-5.0.96-1.rhel5.x86_64/usr/sbin/mysqld-debug File not found: /home/vagrant/rpmbuild/BUILDROOT/MySQL-community-5.0.96-1.rhel5.x86_64/usr/lib64/mysql/mysqld-debug.sym

redhat-rpm-configの罠

Development Toolsに同梱されているrpmパッケージ

/usr/lib/rpm/redhatにマクロやヘルパスクリプトを用意してる!

本当ならきっとイイヤツ

/usr/lib/rpm/redhat/macros#=================================================================== # ---- Build policy macros. # # #------------------------------------------------------------------- # Expanded at beginning of %install scriptlet. # !%__spec_install_pre %{___build_pre}\ [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "${RPM_BUILD_ROOT}"\ mkdir -p `dirname "$RPM_BUILD_ROOT"`\ mkdir "$RPM_BUILD_ROOT"\ %{nil}

/usr/lib/rpm/redhat/macros#=================================================================== # ---- Build policy macros. # # #------------------------------------------------------------------- # Expanded at beginning of %install scriptlet. # !%__spec_install_pre %{___build_pre}\ [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "${RPM_BUILD_ROOT}"\ mkdir -p `dirname "$RPM_BUILD_ROOT"`\ mkdir "$RPM_BUILD_ROOT"\ %{nil}

%install前にディレクトリ消してる…

yum remove redhat-rpm-macros!でビルド通ったーーーーーーーー

こうしてCentOS 6用!MySQL 5.0.96 rpmが生まれた

CentOS6 (Vagrantがオススメ) で走らせるとMySQL 5.0.96 rpmが出来上がるshellscript

https://gist.github.com/tacahilo/321657c75722a24204fa

MySQL !5.0.96!

!SLAVE

8/22 リベンジメンテ

MySQL !4.0.25!

!MASTER

MySQL !5.0.96!

!MASTER

8/22 リベンジメンテ

MySQL !4.0.25!

!

MySQL !4.0.25!

!

MySQL !5.0.96!

!SLAVE

MySQL !5.0.96!

!MASTER

MySQL !5.0.96!

!SLAVE

8/22 リベンジメンテ

8/22 リベンジメンテ

バッチ処理や利用時間帯を考えて,2回目は早朝メンテになった.

1回目のメンテで取ったdumpのおかげで,具体的な作業はマスタ昇格のみ.すぐ終わった.

メンテ終わりに,朝日に照らされながら飲んだ珈琲が美味しかった☕

before afterMySQL !5.0.96!

!MASTER

MySQL!5.5.40!

!SLAVE

MySQL !5.0.96!

!SLAVE

MySQL !4.0.25!

!MASTER

MySQL!5.1.49!

!SLAVE

MySQL !4.0.25!

!SLAVE

実は100%成功ではなかったり…

MySQL 4.0にMovable Typeのデータ (UTF-8) が入っていた.

手を変え品を変えてデータリカバリに取り組んだが,どうしてもMTのDBだけが壊れてしまう…

一応現在はmiddlemanをベースにリプレイス作業が進行中.

passport0は今

リプレイスから約一ヶ月後の9/24,サーバから応答が無くなり引退

謝辞

当時の自分にとっては難易度が高く,何度も挫けそうになりましたが,先輩方の支えがあって,ここまで漕ぎ着けることが出来ました.

やることはまだ残っていますが,ひとまずここで感謝させてください.

ご清聴!ありがとうございました