‘mysql’ タグのついている投稿


仕事関連で確認したメモ。ちょっと変わった手法なので、まぁそういうこと、といった程度の内容。

シーケンス代わりにAUTO_INCREMENTを使う

mysqlでは、シーケンスオブジェクトがなく、その代わりにAUTO_INCREMENTをカラムに指定する。AUTO_INCREMENTは、1テーブルに1カラム指定出来て、CREATE TABLEやALTER TABLEでも指定できる。
これを利用して、データは空なのだけどシーケンス値を取得するというトリックが使えないかと考えた。

CREATE TABLE test_nextval (
  order_id int(11) NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (order_id)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8;

とテーブルを作成し

SHOW TABLE STATUS LIKE 'test_nextval';

でシーケンス値を取得し

ALTER TABLE test_nextval AUTO_INCREMENT=シーケンス値+1;

とする。

AUTO_INCREMENTがリセットされる

一見、上記の方法はアリなように思えるけれど、AUTO_INCREMENTがリセットされるタイミングがある。mysqlを再起動した時だ。

mysql> SHOW CREATE TABLE test_nextval;
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table             | Create Table                                                                                                                                                          |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_nextval      | CREATE TABLE `test_nextval` (
  `order_id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> \q
# service mysqld restart
# mysql test
mysql> SHOW CREATE TABLE test_nextval;
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table             | Create Table                                                                                                                                                          |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_nextval      | CREATE TABLE `test_nextval` (
  `order_id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`order_id`)
) ENGINE=InnoDB HARSET=utf8 |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

データベース内の整合性としては、中身が空なのにAUTO_INCREMENTが設定されているのはおかしいということか。
もしかしたらリセットされないオプションなどあるのかも知れないが、そもそもトリッキーな手法だし、そういうこともあるよねと納得した方が良いと思う。というかそういうオプションを用意するならば、シーケンスオブジェクトの実装をした方がまっとうな気がする。

もちろん値があればリセットされない

当然、AUTO_INCREMENTカラムに値があれば、その値+1に設定される。

mysql> INSERT INTO test_nextval (1000);
Query OK, 1 row affected (0.00 sec)

mysql> SHOW CREATE TABLE test_nextval;
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table             | Create Table                                                                                                                                                          |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_nextval      | CREATE TABLE `test_nextval` (
  `order_id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> \q
# service mysqld restart
# mysql test
mysql> SHOW CREATE TABLE test_nextval;
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table             | Create Table                                                                                                                                                          |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_nextval      | CREATE TABLE `test_nextval` (
  `order_id` int(11) NOT NULL auto_increment,
  PRIMARY KEY  (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8 |
+-------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

結局古典的手法にもどる

つまりは、test_nextvalテーブルで最新のシーケンス値を実際に持って管理する、昔からある採番テーブルの手法でやるのがまっとうということに落ち着く。
当たり前といえばそれまでのお話。

なんでこんなことをやったかというのは、また時間が出来たら是非とも書きたい。そのくらいには苦労した。


WebARENA CLOUD9、解約しようとしたら、3ヶ月無料キャンペーンは、1年契約になるので3ヶ月経過後すぐには解約出来なかった。がーん。
仕方が無いので、あんまり落ちてくれるなよと祈りつつ色々実験機として使うことにした。

クラウドストレージの登場で、外部バックアップがしやすくなった

バックアップデータは曜日単位でバックアップを取るなどすると掛け算で容量が増えるのでストレージを結構圧迫する。また、同一ストレージ上にあるよりは、別ストレージに逃がした方が当然良い。
Dropboxなどクラウドストレージは、上記要件の解として有効なもののひとつだと思う。問題点は、ストレージの速度とセキュリティの問題か。プライベートクラウドなど、今後はより安全で安定なサービスも増えると思うが、今回はwordpressの記事データをバックアップするという単純な用途なので、あまり難しく考えずDropboxにmysqlのダンプを退避してみる。

参考サイト

http://wiki.dropbox.com/TipsAndTricks/TextBasedLinuxInstallを参考にした。
日本語で個人の方が書いている方法もあったが、その当時よりも対応が進んでいて、より簡単に出来た。この記事だって数ヶ月もしたら、もっと簡単な方法に置き換わると思われる。

Pythonのインストール

CentOSにデフォルトでインストールされているPythonは、2.4.3。DropboxのCLIは2.5以上を要求しているので、現時点で2.X系で最新の2.7.1をインストールした。
その際、すでにインストールされているPythonとぶつからないようにした。

#wget http://www.python.org/ftp/python/2.7.1/Python-2.7.1.tgz
#tar -zxvf Python-2.7.1.tgz
#cd Python-2.7.1
#./configure --prefix=/usr/local/bin/Python-2.7.1
#make
#make install
#ln -s /usr/local/bin/Python-2.7.1/bin/python /usr/bin/python2.7.1
#python2.7.1 -V
Python 2.7.1

Dropboxのインストール

dropbox.pyからDropbox本体をインストール出来るので、dropbox.pyを先にダウンロードする。

#wget -O dropbox.py "http://www.dropbox.com/download?dl=packages/dropbox.py"
#python2.7.1 ./dropbox.py start -i
Starting Dropbox...
Dropbox is the easiest way to share and store your files online. Want to learn more? Head to http://www.dropbox.com/

In order to use Dropbox, you must download the proprietary daemon. [y/n] y
Downloading Dropbox... 100%
Unpacking Dropbox... 100%
Done!
#python2.7.1 ./dropbox.py start
To link this computer to a dropbox account, visit the following url:
https://www.dropbox.com/cli_link?host_id=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

表示されたURLにブラウザからアクセスし、すでに持っているアカウントでログインすると同期完了。ホームディレクトリ上にDropboxディレクトリが作成され、同期が開始される。これで設定は終わり。Dropboxは動いている。

シェルでmysqldumpを実行して、Dropboxで同期する

Dropboxを常時デーモンとして動かしても良いのだけど、見たところ200MBくらいメモリを使う。CLOUD9の基本プランではメモリは1GBなので、出来るだけメモリは節約したい。バックアップ目的なので、バックアップ処理時だけDropboxを起動して、処理終了時にはDropboxも終了するようにする。
以下のようなシェルスクリプトで定期実行する。

#!/bin/bash
prog="python2.7.1 Dropboxをインストールしたディレクトリ/dropbox.py"

mysqldump --user=root --all-databases --password=パスワード > ホームディレクトリ/Dropbox/mysqldump/dump
tar czvf ホームディレクトリ/Dropbox/mysqldump/dump`date '+%w'`.tgz ホームディレクトリ/Dropbox/mysqldump/dump
rm -rf ホームディレクトリ/Dropbox/mysqldump/dump
$prog start
status=`$prog status`
while [ "$status" != "Idle" ]
do
status=`$prog status`
echo $status
sleep 3 ← Dropboxの状態を次に確認するまでの秒数
done
$prog stop

mysqldumpのパラメータは、使うデータベースを限定したり、状況に合わせて変更する。稼働中、Dropboxのステータスを表示するようにしたので、どのくらいの時間で同期できたかもざっくりわかる仕組み。
データセンターからのアップなので結構なスピードが出るのかと思ったら100KB/sec以下になることも多い。これはこちらの回線というよりもDropbox側の問題だと思われる。

と、ここでCLOUD9は回線速度のことを書いていないことに気づいた。SuitePROは1Gbpsと書いている。なんというか、全体にこんな印象なんだよね、CLOUD9。説明があるようで無いようである。探せばどこかに書いてあるのだろう。


指定のレンタルサーバにwordpressを設置する作業で少しだけ特殊な例に当たった。
設置するサーバが決まる前に、別のテスト環境で作ったデータを流し込む必要があり、さてサーバの用意が出来たので作業しますか、という段階でmysqlがUNIXソケット設定なのを知った。
用途がローカルからのアクセスだけであれば、UNIXソケットで全然構わないのだけど、phpMyAdminもwordpressもデフォルト設定がTCP/IP前提だったのでちょっとつまづいた。

phpMyAdminの設定

config.inc.php で

$cfg['Servers'][$i]['connect_type'] = 'socket'; //デフォルトでは tcp となっているのを変更する
$cfg['Servers'][$i]['socket'] = 'UNIXソケットのファイル名';

を設定する。

wordpressの設定

wp-config.php で

define('DB_HOST', 'localhost:UNIXソケットのファイル名');

を設定する。
 
デフォルト設定がTCP/IPであるから、全体としてUNIXソケットであることの方が少ないのかも知れない。とはいえ設定変更はそんなでも無いので大きな問題では無かったのだけど、そういえばこういう問題があるなと思った。


フューチャースピリッツ 共用レンタルサーバにデータベースを標準提供でも書いたように、www.mybenjo.net で運用しているwordpressは、mysqlのサーバを別サーバで運用している。現状は、WebARENA SuitePRO V2なのだが、WebARENA CLOUD9へ移行したのでメモ。

そもそもwordpressでmysqlを別サーバで運用するのは、いわゆるレンタルサーバを利用する層では一般的で無く、そういったケースは少ないのだろうけれど、よかったら参考にしてください。

ただし、以下は少しだけテクニカルな内容を一般論的に記述しているので、実施する場合、詳細は各自で検討するか、もしくはお仕事として依頼していただければと思います。

  1. WebARENA SuitePRO V2サーバで mysqldump を使ってwordpress用データベースのデータをエクスポート。

    その際、 –default-character-set=binar の指定で生データとして出力する。

  2. WebARENA CLOUD9サーバで、wordpress用データベースとアカウントを作成。

    その際、webサーバのIPからのみアクセスできるよう設定する。権限などに注意。

  3. WebARENA CLOUD9サーバのデータベースに、 mysql を使ってエクスポートしたデータファイルをインポート。

    その際、 –default-character-set=utf8 を指定してUTF-8のデータとして取り込むようにする。

  4. WebARENA CLOUD9サーバが、外部IPからmysql接続できるよう、ポートマップの設定を実施する。
  5. webサーバからWebARENA CLOUD9サーバへ、mysql接続できるよう、ポートなどの設定を実施する。
  6. wordpressの設定ファイル、wp-config.phpのDB_HOSTをWebARENA CLOUD9サーバのIPに変更する。

WebARENA SuitePRO V2は、mysql4.1.22、WebARENA CLOUD9は、5.0.77とバージョンが異なるが、上記の流れで問題なく移行は完了した。WebARENA CLOUD9の方がメモリが少なく、それ以外でもスペックが異なるので、これから様子を見つつ、チューニング出来るところはいじっていく必要があるかも知れない。


mybenjo.netのサーバには、フューチャースピリッツのレンタルサーバを使用しています。

フューチャースピリッツには、映画情報サイト ミニパラがスタートした当初サーバを提供していただいていおり、サポートなどの品質面について、信頼性が高いという評価を持っており、お仕事でサーバ選定案を出す場合には、ほぼ必ず選択肢に出させていただいています。
今回、共用サーバで今までオプションだったデータベースが標準提供となり、wordpressなどのCMSサービスを簡単に始めることが出来るようになりました。

SaaS型メールフォーム作成サービス 「フォームメーラ-」の独自ドメイン版をリリース ~レンタルサーバー「FutureWeb2」に標準搭載~
http://www.futureweb.jp/news/press/20100824.html

ということで、www.mybenjo.netもwordpressに置き換えてみようかと、ちょっと手を動かしてみたのですが、契約が古い共用サーバプランのままで、そちらにはデータベース提供はされていなかった模様。古いプラン自体がサイトを探しても情報が無く、現行プランに切り替えないとならないかも知れない…という状況でした。

今はVPSなどで安いサーバなども数多くあるのですが、仕事で使っているメールアドレスの遅延や未達が怖く、やはり継続して面倒を見てもらえればと考えていて、次回契約更新時に新プランに切り替えようかと思った次第。

とはいえ、ちょっと悔しかったのでmysqlは別サーバで用意して、wordpressを動くようにしてみました。
wordpressは、ちょっとした設定ですぐ動かすことが出来る便利なCMSですので、コンピュータやネットワークの知識がそんなになくても始められますが、以下は、ちょっとだけテクニカルな事柄を一般論的な記述で書いていますので、実施する場合には、詳細は各自で検討するか、お仕事として依頼していただければと思います。

  1. mysqlの動くサーバでwordpress用のデータベースとアカウントを作成する。その際に、特定サーバのIPからのみアクセスできるよう設定する。権限などに注意。
  2. mysqlの動くサーバが、外部IPからmysql接続できるよう、ポートなどの設定を実施する。
  3. wordpressの設定ファイル、wp-config.phpのDB_HOSTをmysqlを準備したサーバのIPにする。
  4. mysqlの動くサーバへ、mysql接続できるよう、ポートなどの設定を実施する。
  5. wordpressのファイル一式をアップして、index.phpにアクセスし、wordpressの設定を完了する。