Q4MにてSELECT COUNTで件数がとれるがSELECT *もdequeueもできない場合の強引な対処
某日Q4Mが動いているサーバがダウンしまして。
再起動後、Q4Mを立ち上げなおした所、Worker(Perl製。参照 http://perl-users.jp/articles/advent-calendar/2009/data-model/22.html)がQueueを受け取れなくなってました。
mysql> SELECT COUNT(*) FROM queue_table; +----------+ | COUNT(*) | +----------+ | 365474 | +----------+ 1 row in set (0.00 sec)
と件数がとれるんですが、
mysql> SELECT * FROM queue_table LIMIT 2; Empty set (0.01 sec)
と中身がとれないという、おかしなことに。
もちろんqueue_wait()もできません。
ただ、enqueueはできています。
今回の環境は
CentOS 6.2 + MySQL 5.1.48 + Q4M 0.9.4 ※Q4Mコンパイル時のconfigureはディレクトリ指定以外デフォルト
です。
今回は、消えても復旧できるログだったので力技で解決する事に。
同じ構成でテーブル作って、実データであるQ4Mファイルをコピーすれば同様に動くんですよ…
対応方法1
対象テーブルは
queue_table
- Worker停止、enqueueも停止
- 移行先テーブル作成
CREATE TABLE `queue_table_` ( `id` char(255) DEFAULT NULL, `job_data` blob, `priority` tinyint(4) unsigned DEFAULT '10' ) ENGINE=QUEUE DEFAULT CHARSET=sjis;
- ファイル確認
cd /usr/local/mysql_q4m/var/project ls -la queue_table.Q4M queue_table_.Q4M
- 実データコピー
cp -ap queue_table.Q4M queue_table_.Q4M
- MySQLからのアクセス確認
mysql> SELECT * FROM queue_table_ LIMIT 2; mysql> SELECT COUNT(*) from queue_table_; mysql> SELECT queue_wait('queue_table_'); mysql> SELECT * FROM queue_table_; mysql> SELECT queue_abort(); mysql> SELECT COUNT(*) FROM queue_table_; ※データが取得できればOK
- テーブルリネーム
ALTER TABLE `queue_table` RENAME `queue_table_bak`; ALTER TABLE `queue_table_` RENAME `queue_table`;
- 確認できたら古いテーブルを消す
DROP TABLE `queue_table_bak`;
- Worker開始、問題なければenqueueも開始
対応方法2
対象テーブルは
queue_table2
こちらは
- 対応1やっても無理(表題の事象が起こる)
- select count(*)は取れるがselect *は取れない
- Workerを回している間はselect *投げて帰ってきたり返ってこなかったりする
どうもWorkerのqueue_runningで1件dequeueしている間は、select *でとれるようだ!?
そんなバカな。だが目の前にある現実。
- enqueue停止
- Workerを動かす
ただし、挙動的にはqueue_wait()、queue_abort()を繰り返している
- 移行先テーブル作成
CREATE TABLE `queue_table2_` ( `id` char(255) DEFAULT NULL, `job_data` blob, `priority` tinyint(4) unsigned DEFAULT '10' ) ENGINE=QUEUE DEFAULT CHARSET=sjis;
- 実データコピー
mysql> INSERT INTO `queue_table2_` (`id`,`job_data`,`priority`) SELECT * FROM `queue_table2`; 0件ならもう一度試す
- MySQLからのアクセス確認
mysql> SELECT * FROM queue_table2_ LIMIT 2; mysql> SELECT COUNT(*) from queue_table2_; mysql> SELECT queue_wait('queue_table2_'); mysql> SELECT * FROM queue_table2_; mysql> SELECT queue_abort(); mysql> SELECT COUNT(*) FROM queue_table2_; ※データが取得できればOK
ただし、
mysql> SELECT COUNT(*) FROM queue_table2; +----------+ | COUNT(*) | +----------+ | 365474 | +----------+ 1 row in set (0.00 sec) mysql> SELECT COUNT(*) FROM queue_table2_; +----------+ | COUNT(*) | +----------+ | 365473 | +----------+ 1 row in set (0.00 sec)
多分Workerでdequeueしている分がないんだと思う。
データが1件欠損する。
- Worker停止
- テーブルリネーム
ALTER TABLE `queue_table2` RENAME `queue_table2_bak`; ALTER TABLE `queue_table2_` RENAME `queue_table2`;
- 確認できたら古いテーブルを消す
DROP TABLE `queue_table2_bak`;
- Worker開始、問題なければenqueueも開始
とまあ、力技で解決しました。
テーブル構造が壊れてたのかなあ。
オススメできない対処方法です。