かじゅあるしてますか?(挨拶)
この記事はMySQL Casual Advent Calendar 2011の20日目の記事です。
19日目は @n0ts さんでした。
たいていの方ははじめまして。sohgohといいます。守備範囲は主にサーバー&DB管理ですが、歴史的背景から(?)アプリ開発も一部兼任してたりしてます。...といいつつ最近はチーム全体のマネージメント業務の割合が多くなってきていて、どうやって遊ぶ時間を捻出するか現場業務に携わり続けるかが悩みです><
さて、今回はMySQLのUDF(UserDefinedFunction)でファイルのput/deleteをチーム内でカジュアルに実装した話です。
ソースは https://github.com/sohgoh/mysql/tree/master/file_functions にあります。
■作ったきっかけ
数年前、とあるサービスでアップロードされたファイルのput/delete処理を、別ロケーションにあるサーバー群にも定常的に複製する必要が出てきました。

別ロケーションにあるサーバーへのコピーが必要
ちまたに存在するプロダクト(queue系のアプリとか)を探したりしてたのですが、
導入コストとか運用時の周囲への学習コスト考えると二の足を踏む状況でした。
そんな時、Scaling Out(Facebookエンジニアのノート)(※当時はブログで読んだような…記憶違いかな)とかFacebookのデータセンターに見るMySQL活用事例 - MySQLカンファレンス(松信さんが書いたマイナビニュース記事)などを読んで、その流れでMySQLのUDFの存在を知ったのでした。MySQLなら普段から操作に慣れているし、レプリケーションの機構がうまく使えればやりたいことが実現できるのではないかと思ったわけです。

MySQLを使ったファイルput/delete処理のレプリケーションイメージ
■ファイルをput/deleteするUDF
ということで作られたのが以下のようなもの。
file_put('出力先ファイルのフルパス','ファイルの中身',パーミッション)※ファイルのオーナーはmysql起動ユーザ
※返戻値はファイルサイズ
file_delete('削除するファイルのフルパス')※返戻値はtrue/false値
■導入方法
Master-Slave構成を組み、それぞれのMySQLに対して以下の手順を実施します。
(1)コンパイルとインストール
[oogou@dev tmp]$ git clone git@github.com:sohgoh/mysql.git
Cloning into mysql...
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 5 (delta 0)
Receiving objects: 100% (5/5), done.
[oogou@dev tmp]$ cd mysql/
[oogou@dev mysql]$ ls
file_functions
[oogou@dev mysql]$ cd file_functions/
[oogou@dev file_functions]$ ls
file.c Makefile
[oogou@dev file_functions]$ make
gcc -Wall -I/usr/include/mysql -fPIC -shared -o file.so file.c
[oogou@dev file_functions]$ make install
sudo cp -p file.so /usr/lib64/mysql/plugin/
[oogou@dev file_functions]$
(2)UDFの登録
mysql> CREATE FUNCTION file_put RETURNS STRING SONAME 'file.so';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION file_delete RETURNS STRING SONAME 'file.so';
Query OK, 0 rows affected (0.00 sec)
(3)処理用テーブル作成
作成した独自関数の実行をslaveにも流すためにはバイナリログに記録される必要がある=実在のテーブルに対して更新処理が必要になる、ということなのでテーブルを作成します。ただテーブルには何もデータを書き出す必要は無いのでBlackHoleストレージエンジンを使うと良いと思います。※masterとslave双方に必要です。
mysql> CREATE TABLE test.ret(id INT(11)) ENGINE=BLACKHOLE;
Query OK, 0 rows affected (0.02 sec)
(4)logbin-formatをMIXかSTATEMENTにする
今回のUDFはテーブルに対して値をセットすることが目的ではないので、行レベルレプリケーションにするとうまく動作しません。なので、MIXかSTATEMENTである必要があります。デフォルトでどちらかなので問題はないと思います。詳細は本家マニュアルを見てください:5.1.2.1. レプリケーション フォーマットのセッティング。
■実際に実行してみる
テキストだと伝わらないので、実際に実行した様子をキャプチャしてみました。
ホスト名testdb1がMaster、testdb2がSlaveとして構築しており、クエリはMaster上で実行しています。
put/deleteが出来ている様子がわかるかと思います。
※画質が汚くてすいません
やってることはreplace文でファイルの書き込み、削除の実行です。
mysql> replace test.ret set id=file_put("/home/ec2-user/tmp/hello","Hello,World!\n");
Query OK, 1 row affected (0.00 sec)
mysql> replace test.ret set id=file_delete("/home/ec2-user/tmp/hello");
Query OK, 1 row affected (0.00 sec)
■さいごに
で、実はこのUDF、テストタイプとして作ったのですが、諸般の事情で日の目を見ることはありませんでした。
なので、色んな意味でソースがかじゅあるな状態です!w
お蔵入りをこうして公開する機会を与えてくれた(?)
MySQL Casual Advent Calendarと発起人の @myfinder さんに感謝!
※UDFについて興味がわいた方は以下の本とかよろしいかと。
ということで、つぎ(21日目)は @oranie さんです!
この記事はMySQL Casual Advent Calendar 2011の20日目の記事です。
19日目は @n0ts さんでした。
たいていの方ははじめまして。sohgohといいます。守備範囲は主にサーバー&DB管理ですが、歴史的背景から(?)アプリ開発も一部兼任してたりしてます。...といいつつ最近はチーム全体のマネージメント業務の割合が多くなってきていて、どうやって
さて、今回はMySQLのUDF(UserDefinedFunction)でファイルのput/deleteをチーム内でカジュアルに実装した話です。
ソースは https://github.com/sohgoh/mysql/tree/master/file_functions にあります。
■作ったきっかけ
数年前、とあるサービスでアップロードされたファイルのput/delete処理を、別ロケーションにあるサーバー群にも定常的に複製する必要が出てきました。

別ロケーションにあるサーバーへのコピーが必要
ちまたに存在するプロダクト(queue系のアプリとか)を探したりしてたのですが、
導入コストとか運用時の周囲への学習コスト考えると二の足を踏む状況でした。
そんな時、Scaling Out(Facebookエンジニアのノート)(※当時はブログで読んだような…記憶違いかな)とかFacebookのデータセンターに見るMySQL活用事例 - MySQLカンファレンス(松信さんが書いたマイナビニュース記事)などを読んで、その流れでMySQLのUDFの存在を知ったのでした。MySQLなら普段から操作に慣れているし、レプリケーションの機構がうまく使えればやりたいことが実現できるのではないかと思ったわけです。

MySQLを使ったファイルput/delete処理のレプリケーションイメージ
■ファイルをput/deleteするUDF
ということで作られたのが以下のようなもの。
file_put('出力先ファイルのフルパス','ファイルの中身',パーミッション)
※返戻値はファイルサイズ
file_delete('削除するファイルのフルパス')
■導入方法
Master-Slave構成を組み、それぞれのMySQLに対して以下の手順を実施します。
(1)コンパイルとインストール
[oogou@dev tmp]$ git clone git@github.com:sohgoh/mysql.git
Cloning into mysql...
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 0), reused 5 (delta 0)
Receiving objects: 100% (5/5), done.
[oogou@dev tmp]$ cd mysql/
[oogou@dev mysql]$ ls
file_functions
[oogou@dev mysql]$ cd file_functions/
[oogou@dev file_functions]$ ls
file.c Makefile
[oogou@dev file_functions]$ make
gcc -Wall -I/usr/include/mysql -fPIC -shared -o file.so file.c
[oogou@dev file_functions]$ make install
sudo cp -p file.so /usr/lib64/mysql/plugin/
[oogou@dev file_functions]$
(2)UDFの登録
mysql> CREATE FUNCTION file_put RETURNS STRING SONAME 'file.so';
Query OK, 0 rows affected (0.00 sec)
mysql> CREATE FUNCTION file_delete RETURNS STRING SONAME 'file.so';
Query OK, 0 rows affected (0.00 sec)
(3)処理用テーブル作成
作成した独自関数の実行をslaveにも流すためにはバイナリログに記録される必要がある=実在のテーブルに対して更新処理が必要になる、ということなのでテーブルを作成します。ただテーブルには何もデータを書き出す必要は無いのでBlackHoleストレージエンジンを使うと良いと思います。※masterとslave双方に必要です。
mysql> CREATE TABLE test.ret(id INT(11)) ENGINE=BLACKHOLE;
Query OK, 0 rows affected (0.02 sec)
(4)logbin-formatをMIXかSTATEMENTにする
今回のUDFはテーブルに対して値をセットすることが目的ではないので、行レベルレプリケーションにするとうまく動作しません。なので、MIXかSTATEMENTである必要があります。デフォルトでどちらかなので問題はないと思います。詳細は本家マニュアルを見てください:5.1.2.1. レプリケーション フォーマットのセッティング。
■実際に実行してみる
テキストだと伝わらないので、実際に実行した様子をキャプチャしてみました。
ホスト名testdb1がMaster、testdb2がSlaveとして構築しており、クエリはMaster上で実行しています。
put/deleteが出来ている様子がわかるかと思います。
※画質が汚くてすいません
やってることはreplace文でファイルの書き込み、削除の実行です。
mysql> replace test.ret set id=file_put("/home/ec2-user/tmp/hello","Hello,World!\n");
Query OK, 1 row affected (0.00 sec)
mysql> replace test.ret set id=file_delete("/home/ec2-user/tmp/hello");
Query OK, 1 row affected (0.00 sec)
■さいごに
で、実はこのUDF、テストタイプとして作ったのですが、諸般の事情で日の目を見ることはありませんでした。
なので、色んな意味でソースがかじゅあるな状態です!w
お蔵入りをこうして公開する機会を与えてくれた(?)
MySQL Casual Advent Calendarと発起人の @myfinder さんに感謝!
※UDFについて興味がわいた方は以下の本とかよろしいかと。
![]() | Mysql 5.1 Plugin Development |
Andrew Hutchings,Sergei Golubchik | |
Packt Publishing |
ということで、つぎ(21日目)は @oranie さんです!