隔週連載groonga

第7回 [実録] MySQL向け全文検索エンジン「Tritonn」から「mroonga」への移行ガイド(2)

この記事を読むのに必要な時間:およそ 7.5 分

更新クエリをTritonn・mroonga互換の実装にする

周知の通り,MySQL 5.0およびTritonn専用の更新クエリが発行される状態では,レプリケーションのスレーブとして追加できません。そこでまずは,MySQL 5.0で動く既存システムへ発行される更新系クエリの精査を行います。MySQL 5.6環境でも互換のある実装にしておくことでMySQLバージョン混在でのレプリケーションが可能となり,ダウンタイム最小での移行を果たせます。

それでは,どういったクエリをどのように書き換えることで実現できるのか,具体例と共に紹介します。

プログラムの修正の必要がある実装例

問題となるmroonga非互換のSQLはCREATE TABLE文のFULLTEXTインデックスにあります。厳密には,USING句からのオプションです。例えば,次のようなSQLです。

-- FULLTEXT行のUSINGから括弧までの箇所が,Tritonn依存
CREATE TABLE search_fulltext_ready (
  id INT,
  content TEXT,
  FULLTEXT INDEX ft USING MECAB, NORMALIZE (content)
) ENGINE=MyISAM DEFAULT CHARSET utf8;

Cronでの定期実行タスクなどによりTritonn専用のCREATE TABLE構文などが発行されると,mroongaでレプリケーションエラーが起きてしまいます。私のケースではCronで次のようなSQLを発行していました。

-- 更新中に利用する作業テーブルを作成する
-- これが問題のSQL
CREATE TABLE search_fulltext_ready (... FULLTEXT INDEX ft USING MECAB (content) ...;

-- 作業テーブルへデータをINSERTやLOAD DATAなどを利用して流し込む
LOAD DATA INTO INFILE search_fulltext_ready ...;

-- 2テーブルを入れ替える。1クエリで行うことで,search_fulltextが存在しない瞬間ができることを避ける
RENAME TABLE search_fulltext TO search_fulltext_old, search_fulltext_ready TO search_fulltext;

-- 古くなったテーブルを削除する
DROP TABLE search_fulltext_old

では,このSQLをどのように変えれば解決できるか,追って解説しましょう。

2つのテーブルを入れ替えるという修正方法

mroonga互換の更新系クエリにするには,単純にCREATE TABLE文をCREATE TABLE search_fulltext_ready LIKE search_fulltext;というクエリに置き換えるだけと思いきや,ここに落とし穴があります。それは,Tritonnの制限事項にも記述されている「USING句が落ちる」問題です。

この「USING句が落ちる」とは,オリジナルが何であろうともUSING MECAB, NO NORMALIZE, 512と書き換わる現象です。これはTritonnのデフォルトであるUSING MECAB NORMALIZEとは異なるものです。

「TRUNCATE TABLE t1を実行するとUSING句情報が落ちる」

この問題は,WHERE句を省略したDELETE文を使うことで解決します。

DELETE FROM search_fulltext_ready;

「CREATE TABLE t2 LIKE t1を実行するとUSING句情報が落ちる」

この問題は,事前に用意した2つのテーブルを入れ替える運用で解決します。

RENAME TABLE search_fulltext TO search_fulltext_old, 
  search_fulltext_ready TO search_fulltext, 
  search_fulltext_old TO search_fulltext_ready;

具体的な修正は,次の手順で行います。

-- 更新中に利用する作業テーブルを空にする
DELETE FROM search_fulltext_ready;

-- 作業テーブルへデータをINSERTやLOAD DATAなどを利用して流し込む
LOAD DATA INTO INFILE search_fulltext_ready ...;

-- テーブルの入れ替えを行う
RENAME TABLE search_fulltext TO search_fulltext_old, 
  search_fulltext_ready TO search_fulltext, 
  search_fulltext_old TO search_fulltext_ready;

特に該当するものが無ければ,影響しうるような改修が追加で行わないよう,チームへのコードフリーズの周知を行うだけで事足りるでしょう。

データマイグレーション計画

前項にてMySQLバージョン混在のレプリケーションを行うための互換プログラムへの改修を取り上げました。次は,既存データを何らかの方法でMySQL 5.6に流し込み,MySQL 5.0のスレーブとしてレプリケーションさせる準備を行います。

MySQL 5.0と5.6の作業サーバ,計2台を利用したデータのマイグレーションの手順は次の通りです。

  • 本番稼働中の待機系スレーブを一時的に切り離す
  • 待機系スレーブの内容をMySQL 5.0用の作業サーバに複製する
  • MySQL 5.0用の作業サーバからMySQL 5.6用の作業サーバにデータを流し込む

大まかにはこのような手順を踏むことで,MySQLのアップグレードができます。

それでは次に,具体的なデータマイグレーションを行う2つの方法を紹介します。

なお,事前に次の作業は済んでいるものとします。

  1. MySQL 5.0と5.6の作業サーバを構築する
  2. 本番稼働中の待機系スレーブを一時的に切り離す
  3. 待機系スレーブの内容をMySQL 5.0用の作業サーバに複製する
方法1: 段階的なアップデート

MySQLのアップグレードを行う一般的な手法として,mysql_upgradeコマンドがよく知られています。しかし今回は2つ飛び越えての大幅なアップデートとなるため,次のようにとても手間がかかります。

  1. MySQL 5.0用の作業サーバにて,Tritonn依存のないスキーマに変更する
  2. この作業サーバにて,MySQLを5.1へアップデートする
  3. mysql_upgradeコマンドを用いて データもMySQL 5.0 から 5.1へアップデートする。エラーが起きたら都度修正する
  4. この作業サーバにて,MySQLを5.5へアップデートする
  5. mysql_upgradeコマンドを用いて データもMySQL 5.1 から 5.5へアップデートする。エラーが起きたら都度修正する
  6. この作業サーバにて,MySQLを5.6へアップデートする
  7. mysql_upgradeコマンドを用いて データもMySQL 5.5 から 5.6へアップデートする。エラーが起きたら都度修正する
  8. 全文検索を行いたいテーブルを,ALTER TABLE構文を用いてmroonga化する
方法2: mysqldumpを用いた移行方法

もう一つの方法として,mysqldumpコマンドを用いる手法があります。これは,データベースをSQLファイルに書き出した後に,MySQL 5.6のクリーンなデータベースに流し込むというものです。この場合には次のように,比較的シンプルな方法で移行を行えます。

  1. MySQL 5.0用の作業サーバにて,Tritonn依存のないスキーマに変更する
  2. MySQL 5.6用の作業サーバにて,mysqldumpでMySQL 5.0用の作業サーバよりデータベース毎に吸い出す
  3. MySQL 5.6用の作業サーバにて,吸い出したダンプファイルを自身に流し込む
  4. MySQL 5.6用の作業サーバにて,全文検索を行いたいテーブルを,ALTER TABLE構文を用いてmroonga化する
  5. そのまま移すことができないMySQLユーザを,手動で適宜追加する
今回採用した方法

段階的バージョンアップに手間を感じたことと,InnoDBのibdataファイルの肥大化を解消したいという要件があるため,mysqldumpを用いた移行方法を採用します。

というのもMySQL 5.0ではまだ目新しかったinnodb_file_per_table設定を利用していないため,InnoDBの共有データスペースであるibdata1が数百GBレベルに肥大化していたのです。この肥大化の原因となったテーブルを削除したとしても一度拡張されたらデータサイズが減ることはないため,縮小するにはSQLダンプファイルから作り直すほかに方法はありません。今回のタイミングを機にmysqldumpで生成したSQLダンプファイルより,1から綺麗に作り直しを行うことにしました。

著者プロフィール

吉田健太郎(Kentaro Yoshida)

株式会社リブセンス,Web系インフラの研究開発エンジニア。

ITベンチャー立ち上げに参画し,幅広い領域での経験を積むこと8年目。フルスタックエンジニアを目指して,湧き出るアイディアを形にする日々を過ごしている。

GitHub:https://github.com/y-ken/
ブログ:http://y-ken.hatenablog.com/