EC2/S3

2011年8月10日 (水)

PythonでのAmazon S3プログラミング

ちょっとした事情があり、PythonでAmazon Web Servicesを操作するプログラムを作ることになりました。PythonでAWSを操作するにはbotoがよさそうです。

PythonでAWSプログラミングの手始めにメジャーなサービスであるAmazon S3でbotoの使い方を学習してみました。

■ botoについて

botoはAWSの公式SDKではありませんが、以下のAWSのAPIに対応したライブラリです。

  • Simple Storage Service (S3)
  • SimpleQueue Service (SQS)
  • Elastic Compute Cloud (EC2)
  • Mechanical Turk
  • SimpleDB
  • CloudFront
  • CloudWatch
  • AutoScale
  • Elastic Load Balancer (ELB)
  • Virtual Private Cloud (VPC)
  • Elastic Map Reduce (EMR)
  • Relational Data Service (RDS)
  • Simple Notification Server (SNS)
  • Identity and Access Management (IAM)
  • Route53 DNS Service (route53)

公式SDKに迫るような対応サービスの多さですね。
それだけではなく、Google Storageにも対応しています。PythonとGoogle関連サービスとの相性がよいからでしょうか...。単純にS3とインタフェースが近しいからというのもありそうですが。

まあ、とにかくしっかりAWSプログラミングができそうなライブラリです。

■ botoインストール

Linux、Mac OS Xなどではeasy_installがあれば以下のような感じで簡単インストールです。オススメです。

% sudo easy_install boto

あるいは、ここからダウンロードして、展開して
以下のような感じでインストールでもよいかと。(easy_installつかったほうが簡単だと思いますが・・・)

% wget http://boto.googlecode.com/files/boto-2.0.tar.gz
% cd boto-2.0
% sudo python setup.py install

■ S3への接続とアクセスキー、秘密キーについて

環境変数としてAWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEYをあらかじめセットしておけばプログラム中にアクセスキー、秘密キーを記述する必要はありません。以下のような感じで接続できます。

from boto.s3.connection import S3Connection
conn = S3Connection() # プログラム中にキー情報は書かない

もし、プログラム中に記述する場合は以下のようにAWSとのAWSAuthConnectionを継承したクラス(この場合S3Connection)のインスタンスを作成するのですが、そこで引数にキー情報を入れます。

from boto.s3.connection import S3Connection
conn = S3Connection('アクセスキー', '秘密キー')

■ バケット情報取得とバケット作成

すべてのバケット情報を取得して、バケット名を出力すると以下のような感じになります。簡単ですね。

from boto.s3.connection import S3Connection

conn = S3Connection()

# すべてのバケットを取得する。
buckets = conn.get_all_buckets()

# バケット名出力
for bucket in buckets:
    print bucket.name

続いて、バケットの有無を判定して、あればバケットオブジェクト取得、なければバケットオブジェクトを作成する、というのは以下のようにすれば動きます。ちなみにバケットのリージョンは東京リージョンを指定しています。

bucket_name = 'flect-bucket-tokyo'

# バケットがあるかどうかを調べる、なければ作成する。
if bucket_name in conn:
    bucket = conn.get_bucket(bucket_name)
else:
    bucket =  conn.create_bucket(bucket_name, location=Location.APNortheast) # 東京リージョン指定

補足ですが、リージョン情報を取得するのは以下のように書けばできます。

from boto.s3.connection import Location
print dir(Location)
# 出力例→ ['APNortheast', 'APSoutheast', 'DEFAULT', 'EU', 'USWest', '__doc__', '__module__']

■ オブジェクトの作成と削除

続いて、先ほど作成したバケットにオブジェクトを出し入れしてみます。
まずは単純なテキストから。以下のように出し入れできます。

# キーからオブジェクトの取得/保存操作には以下のインポートが必要
from boto.s3.key import Key

# 中略

k = Key(bucket)
k.key = 'text_content' # キー指定
k.set_contents_from_string('text content') # テキストをオブジェクトとして保存
text_content = k.get_contents_as_string()  # 保存したオブジェクトのテキスト取得

また、ファイルとしてアップロード/ダウンロードも簡単です。
以下はローカルの画像ファイルをアップし、別名でダウンロードする例です。
(bucketはバケットオブジェクトが取得されているものとします)

# ファイルをS3に保存する
k = Key(bucket)
k.key = 'sample_image.jpg'
k.set_contents_from_filename('./sample.jpg')

# ファイルをS3から取得して、指定したファイル名に保存
k.get_contents_to_filename('./download.jpg')

■ まとめと次の課題

内容が著しく浅い、という感はぬぐえないですが、今回はPythonでAWSを触る感触を学習してみたかった、ということでS3を操作するプログラムを通してbotoの使い方になじんでみました。

よく使っているからという理由でS3から学習してみたのですが、今回はAmazon SESなどほかに動かしたいサービスのウォーミングアップなので次回以降いろいろなサービスを動かしてみたいと思います。

2011年1月27日 (木)

セールスフォース、Google、AmazonのPaaSの比較とSIer視点からの印象

最近、Amazon Beanstalkが発表されて、PaaS領域が一段と盛り上がってきました。

業務系に強いForce.com、ソーシャルアプリなどコンシューマ系サービスに強いGoogle App Engineあたりが有名でしたが、最近は選択肢がかなり増えました。
この記事を書いている最中にもちょうど以下のような記事がでていて、PaaSに対する注目度が高いことがうかがえます。

http://www.publickey1.jp/blog/11/google_app_engine_paas.html

http://www.publickey1.jp/blog/11/_java_paas.html

上記の記事でだいたいよいところ、難しいところがまとまっているのですが、今日はGoogle App Engine、Force.com、AWSのサービス、それぞれ実サービスの運用や受託開発で使った経験や、SIerでマネージャをする立場から、自分なりの比較と印象を書いてみようと思います。まず、セールスフォース、Google、Amazonが提供、あるいは関連が強いPaaSについて言語、利用するDB、インフラ運営元、そしてサービス提供会社を一覧にしてみました。

◆ 各プラットフォームと言語、DBなどの比較

名前言語DBインフラ環境サービス提供会社
Google App Engine(GAE) Python, Java BigTable Google Google
Force.com Apex, VisualForce Force.comのDB(Database.com) Force.com(セールスフォース) セールスフォース
VMForce Java(Spring Framework) Force.comのDB(Database.com) Force.com(セールスフォース) セールスフォース
Heroku Ruby(Ruby on Railsなど) PostgreSQL(標準)など Amazon セールスフォース
Amazon Beanstalk Java Amazon RDS(MySQL), Amazon SimpleDBなど Amazon Amazon
Engine Yard Ruby(Ruby on Railsなど) MySQL(標準)など Amazon Engine Yard(いずれAmazon?)

注目すべきはGAEはDBが独自であること、Force.comはApex、VisualForceという独自の言語でアプリケーション構築をする必要があることでしょう。(Force.comのDBは独自といえば独自ですが、RDBの考え方でだいたい操作できます)

それに対して、Amazon上で動くPaaSは言語、DBともに、オンプレミス環境からの差分はかなり少ないと思ってよさそうです。こういった特徴を踏まえたうえで、「よいところ」と「気をつけるべきところ、気になるところ」を私の所感でまとめてみました。

◆ 特徴まとめ

PaaS分類よいところ気になるところ
Google App Engine(GAE) ・アプリケーションサーバだけでなく、データベースまで自動スケールするところ。

・Java/Pythonといった汎用性の高い言語で開発できること

・非常に安い。1日あたりのQuota制限があるが、ある程度のボリュームまでは無料と考えてもよい。範囲を超えても安い。

・個人で勉強しやすい。情報も多いし、安い。
・物理的にどこにデータが置かれているかなどブラックボックス(悪いこととは限らない)で、どう動いているか見通しがきかないことがあること

・BigTableという、RDBとは違う考え方が求められるデータベースを使うため、使いこなすにはかなりの学習コストが発生すること。開発者の確保もやや難しいこと
Amazon系(Heroku、Engine Yard、Beanstalk) ・Java(Tomcat)やRuby on Railsなど、オンプレミスの環境で培われた技術を用いてアプリケーションが構築できること。

・開発者が確保しやすい。

・Amazon EC2、RDS、S3、CloudFrontなどPaaSの構成要素となるコンポーネントが独立したサービスとなっており、自由自在に組み合わせられる。
・GAE、Force.comと比べるとRDBやストレージなどのバックアップ等、ミドル、インフラの運用面的なことを多少意識しないといけないこと

・アプリケーション部分についてはForce.comのように何かベースとなる強力な機能があるわけではないので、その開発コストはオンプレミスに近い感じになること
Force.com系 ・GUI操作(Point&Click)だけで、かなりのカスタム機能が作成でき、型にはまると生産性がかなり高いこと。

・認証系の機能、ユーザの権限制御、ワークフローなどスクラッチ実装をするとけっこう面倒な機能が既に存在すること。

・国内、海外問わずたくさんの大手企業が業務システムに使っており、セキュリティ含め、実績面では信頼しやすい
・Apexなど独自技術の学習コストがかかる

・ストレージ容量やレコード件数、外部からのAPI呼び出しの最大数の制限など、「容量の大きいデータ」、「件数の多いデータ」への制限は強いこと

・ライセンス費用がユーザ単位であり、GAEやAmazon系の課金と違うのは注意が必要なこと

上の色をつけているところが、もっともメリットとして特色があるところです。

◆ 用途に合うと高い効果を出すGAEとForce.com

GAEとForce.comは「制約は強いが、型にはまると高い効果を出す」と考えるとよいと思います。

GAEはデータベースが独自なので「Joinをさける」「集合関数は使わないで、レコードに持つ」などRDBとは違う考え方で開発が必要です。しかし、アプリケーションサーバだけでなく、データベースまでもが自動スケールするので、アクセス量が読めないアプリケーション(ソーシャルアプリなど) では、独自技術を習得するコストを払ってもメリットを得られる可能性があります。

Force.comについては、GAEに比べると書籍等少なく、個人で勉強する人も少なそうなので、知らない人も多そうですが、GAEと同じく型にはまると強いPaaSと考えています。
GAEやAmazon系のPaaSが提供している機能はデータストアやストレージのAPIなど、どんなアプリケーションでも共通で使いそうなものが中心です。それに対して、Force.comは会社などの組織で使うアプリケーション構築に必要な機能が最初から揃っています。たとえば、ユーザの発行、権限管理、ワークフローなど。認証処理とか権限制御など、受託案件では「毎度おなじみ」の機能ですが、けっこう作るのは毎度面倒、な機能です。そういったものが最初からそろっていて、しかも簡単にカスタマイズできるというのは、はまるとすごい生産性です。

実際、フレクトでも案件管理や勤怠管理、経費申請などいくつかの業務アプリをバンバン作っていった実績があります。セールスフォースが得意とするCRMだけでなく、多くの業務系アプリの開発が高い生産性でできる実感を持っています。

一方でForce.comはユーザごとにライセンス費用がかかったり、CPUやストレージをちょっと使うと意外と早く制限がくるなど、特有の制約事項があり、注意しながらの開発が必要です。

両方とも制約が強く、はまると効果テキメンっといった感じですが、学習コストがかかるので開発者のアサインが意外と難しい、といったデメリットがあります。

◆ 既存のオープンな技術をベースにスピーディに作れるAmazon系

HerokuやBeanstalkなどのPaaSはRuby on Rails、Java(Tomcat)、PostgreSQL、MySQLなどのオンプレミス環境でも存在しているオープンな技術をベースとしていて、それらを使ったシステムをすばやく作れるというメリットがあります。アプリケーションサーバ、RDB、ストレージなどはAWSや各PaaSが提供してくれているサービスをそのまま使えばいいので、インフラ、ミドルの心配をせずに、Web開発のスタンダードな技術であるJava、Ruby、MySQLなどを使って開発できるというのがGoodです。オンプレミス環境と同じで、なおかつオープンな技術をベースにしているものが多いので学習コストも低く、開発者のアサインも容易です。

コンシューマが使うWeb系のシステム構築で、とにかく早くリリースしたい、早く作りたい、という場合には、Amazon系のPaaSが有力な選択肢になります。

実際、フレクトでもPaaSではありませんが、Amazon EC2、S3などを使ってモバイルサイト(http://bhmb.jp/)を開発、運用しており、開発時のプラットフォーム選択の決め手はクラウドの恩恵をうけつつ、既存技術をベースにすばやく開発したい、というものでした。

◆ SIer視点からの認知度、信頼度の印象

SIerである私たちにとって、多く接するお客様はユーザ企業の情報システム部門の方々です。そういった企業の方々からも選択肢として認知されているのはセールスフォースがやはり一番という印象です。多くの企業で導入されたということはコンプライアンス観点などからもクリアした案件が多いということで、この辺はお客様に提案するプラットフォームとしてはSIer的にはGoodです。

Amazon系のサービスやGoogle App Engineもまったく認知されていないというわけではないのですが、積極的に選択肢にあがってくるケースが多いかというと必ずしもそうではなさそうな気もします。Amazon系やGAEの事例もサービス企業が内製でそのメリットを活かして作っているケースが多く見受けられます。企業の情報システム部門からの認知度、信頼度という点は、今後の向上に期待というところです。

もちろん、私が知る範囲でもお客様によってはAmazon系やGAEなどの技術に長けていて、すごく活用されているというケースもあります。ただ、全体で見るとまだ低い割合なのかな、と思います。

◆ 今後の気になるところはPHPのPaaS

SI案件というとJava系が多いと思いますが、Web絡みになるとPHPの比重が高くなります。そういう点ではPHP系のPaaSは有名なものは見当たらないですね。注目としてはPHP Fog(http://www.phpfog.com/)が、Heroku的立ち位置を目指しているようなので今後どうなるか気になるところです。

※ 【追記】 AzureでPHPできるとご指摘いただきました。ちょっと調べてみます。

◆ まとめと中途採用募集のお知らせ

VMForceなどリストアップしていながら、あまり言及していないものがあり、すみません。また今度調査してみます。

最後に、フレクトはセールスフォースのプラットフォームやAWSを使ったインテグレーション事業を拡大中です。最新のPaaSを使った開発に興味のある人はぜひご連絡いただければと思います。採用エントリーは以下からです。お待ちしております。

http://www.flect.co.jp/recruit/

2010年9月30日 (木)

Amazon SQSに入門してみました

こんにちは。大橋です。

今日はAmazon SQSについてです。

サイトを運営していると、ときどきメッセージキューで非同期に
処理をしたいなという箇所がよくあります。

また、最近、当社ではセールスフォースとAmazon EC2の併用など、異なる
クラウド環境を使ったシステムをを扱っており、その連携方法を日々調査しています。

1箇所のサーバ環境だけならば、GearmanやQ4Mなど自前インストール型のキュー
使えばよいかと思うのですが、クラウド環境間の連携などを考えると、
グローバルに利用できるメッセージ伝達方式の方が望ましいケースもあります。

そこで、今回Amazon SQSに触手を伸ばし、入門してみました。
今日は、その記録を残します。

【Amazon SQSを利用開始する】

Amazon Web サービスのアカウントにサインアップし、
Amazon SQS
のページで「Amazon SQSの利用を申し込む」
をすればOKです。

【料金はすごく安い】

課金はリクエスト数によるものととデータ転送量によるものの2系統です。

リクエスト課金は 10,000回のAmazon SQSリクエストに付き0.01ドル。
ほとんどお金かかりません。

データ転送量は米国&欧州とアジア(シンガポール)で異なりますが、
たとえば、米国&欧州では10TB(テラバイト!!)までのデータ受信で
0.15ドル。同一RegionでEC2と送受信するものは課金されません。

すごくすごく気軽に使える値段です。(個人で利用しても気にならない価格です)

【少ないAPIで使えるシンプルな設計】

機能が少ないともいえますが、シンプルに使えます。

だいたいのことはには、以下の4つを使ってできます。

(1) CreateQueue    :  メッセージキューを作成する
(2) SendMessage   : メッセージキューにメッセージを送信
(3) ReceiveMessage  : メッセージキューからメッセージを受信
(4) DeleteMessage  : メッセージキューからメッセージを削除

もちろん、他にもAPIはいろいろありますが、ちょっと試すだけならば
これでOKです。

キューを作成したあと、以下の絵のような流れで処理をすることになります。
Amazon SQSではメッセージは8192バイトが最大なので、もし大きなデータを
渡したい場合はAmazon S3やAmazon SimpleDBなど外部のデータストアに置いて
おき、そのポインタをメッセージに入れるのがよいです。

Sqs

【メッセージ保存期間と視認性について】

メッセージは4日間、キューに保存されます。

また、あるクライアントがReceiveMessageしたあとは、他のクライアントは一定期間、
同一のメッセージが見えなくなります。

見えなくなる時間(視認できなくなる時間)はAPI経由で設定でき、30秒から12時間まで
設定できます。

もしAというクライアントがメッセージαを取得したあと、なにかしらの処理に
失敗した場合、メッセージαは、一定期間(30秒~12時間)のあとに、他のクライアントから
見えるようになります。

もちろん、そのAというクライアントが処理に成功し、メッセージ削除APIを
キューに対して呼び出した場合は、その後、他のクライアントから見えなくなります。

【使い方 ~Perlで実際に使ってみる~】

PHP編やJava編はいずれ機会があったら書きます。
とりあえず、Perlから使ってみます。

先ほどの絵でいうところのSendMessageする側(Process1)が「メッセージ送信側」、ReceiveMessageする側が「メッセージ受信側」(Process2)とします。

やりとりするメッセージはサンプルなので「Hello, World」とします。
メッセージ送信側がキューに対して'Hello, World'とメッセージをいれ、
メッセージ受信側はそのメッセージをキューから取得、画面に表示して
キューからメッセージを削除しています。

実運用ではメッセージは処理を依頼する内容やデータのポインタになります。
また、メッセージ受信側では、時間がかかる処理をするなど、なにかしらの
処理をします。

なお、Perlから使うにはモジュールのインストールが必要です。Amazon::SQS::SimpleというモジュールがCPANにありますので、サンプルプログラムを使うには以下のモジュールをインストールしてから実行する必要があります。

Amazon::SQS::Simpleモジュール

以下、サンプルプログラムです。

・メッセージ送信側

#!/usr/bin/env perl                                                                                                                       
# sqs_msg_sender.pl                                                                                                                       

use strict;
use warnings;

use Amazon::SQS::Simple;

my $access_key = $ENV{AWS_ACCESS_KEY};
my $secret_key = $ENV{AWS_SECRET_KEY};

# SQSオブジェクトを作成します。                                                                                                           
my $sqs = new Amazon::SQS::Simple( $access_key, $secret_key );

# キューを作成します。作成済みの場合に実行してもそのままキューがある状態になります。                                                      
my $q = $sqs->CreateQueue('sample_flect_queue');

# キューにメッセージを送付します。                                                                                                        
$q->SendMessage('Hello World');

exit 0;

・メッセージ受信側

#!/usr/bin/env perl                                                                                                                       
# sqs_msg_receiver.pl                                                                                                                     

use strict;
use warnings;

use Amazon::SQS::Simple;

my $access_key = $ENV{AWS_ACCESS_KEY};
my $secret_key = $ENV{AWS_SECRET_KEY};

# SQSオブジェクトを作成します。                                                                                                           
my $sqs = new Amazon::SQS::Simple( $access_key, $secret_key );

# キューオブジェクトを取得します。                                                                                                        
my $q = $sqs->CreateQueue('sample_flect_queue');

# キューからメッセージを取得します。                                                                                                      
my $msg = $q->ReceiveMessage();

# メッセージの内容を出力してみます。                                                                                                      
print $msg->MessageId() . "\n";
print $msg->MessageBody() . "\n";

# キューからメッセージを削除します。ReceiptHandleというのを使います。                                                                     
$q->DeleteMessage( $msg->ReceiptHandle() );

exit 0;


【すぐに使えて高い信頼性があることについて】

メッセージキューは機能は非常にシンプルですが、同じようなキューを
自前で構築して、Amazon SQS並みの信頼性を保とうと思うとけっこう大変です。

たとえば、Q4MのようにMySQLを使うタイプのメッセージキューを自前で
構築した場合、1台くらいサーバが落ちてもメッセージをロストすることなく、
なおかつ、クライアントからのメッセージ送受信のリクエストをさばきつづける、
となると、必要な構築コストはかなり大きいです。

複数台のサーバが必要で、MySQLのレプリケーションをしたり、あるいは
DRBDで複数台のデータを同期させたり・・・、とかとか。ちょっと手間がかかりますね。

その点、Amazon SQSはAmazonが複数のサーバやデータセンターで冗長化していて大量のリクエストが来ても、ちゃんと止まらずにさばいてくれます。

そういったメッセージキューシステムを自前で作らなくても
すぐに本番システムレベルの信頼性で使える、というのは場合によっては
大幅なコスト削減になるんではないかと思います。

もちろん、パフォーマンス面など適合しないケースもあるかと思いますが、
クラウドな環境ではひとつの選択肢になるのではないかと考えています。

【制限や注意事項もあります】

基本的な注意事項は「メッセージ保存期間と視認性について」のところで
書いたとおりのこと、それと、メッセージが8192バイトが最大なので、
大きいデータの受け渡しが必要なときはS3などにデータをおき、その
ポインタ情報(URL)をやりとりするように、ということがあります。

その他に重要なポイントとしては

 (1) 同一のメッセージが複数回受信できてしまうことがある。
 (2) メッセージはキューに入れた順番どおりには受信できない。

ということです。

これはAmazon SQSが複数のサーバや複数のデータセンターを使って
運営されているためのようですが、注意が必要です。

(1)については場合によっては、Amazon SQS以外のデータストア
(Amazon SimpleDBなど)にどこまでのメッセージ処理ができたか、
などの情報を持っておく必要があります。
その辺はシステムの要求などによりケースバイケースだと思いますが、注意が必要です。

【まとめ&今後取り組むこと】

初期調査、入門だけなのに、記事が少しながくなってしまったので、今日は
これくらいにしておきます。

現在、私が行っているAmazon SQSの調査の最終ゴールは当社が現在力を入れている
Saleforceのシステムと連携させてみることです。

ちゃんと連携できたらまた記事にしますので、待っていてください。

なお、当社はAmazon Web Servicesに力を入れると同時に、Salesforce事業も
展開中です。現在、こういったいろいろなクラウドプラットフォームを使って
お客様によいソリューションを提供したい、というエンジニアの方を
大募集中です。もし、興味のある方は以下からご連絡いただけると幸いです。

http://www.flect.co.jp/recruit/index.html

2010年9月22日 (水)

EC2でEBS上のMySQLのデータをバックアップ

こんにちは。フレクトの大橋です。

ベターホームレシピ(http://bhmb.jp)では、MySQLを会員やレシピデータ用の
インスタンスと、Cicindela用のインスタンスを同一のサーバにそれぞれ
データをEBSに置いて運用しています。

レプリケーションなど信頼性向上のための施策をしているのですが、
運用上大事なのはバックアップです。

そこで、今日はEBS上のMySQLのデータのスナップショットを
整合性を失わずにバックアップする方法についてベターホームレシピでの
実運用の事例をもとに紹介します。

■ 本題の前に・・・、Amazon RDSについて

そもそも直接MySQLをEC2上にインストールしなくても、日々機能が強化されている
Amazon RDSを使えばよいのではないか、という考えもあります。はい、その通りです。
特に最近はMulti-AZ機能なども提供され、安心感があります。

ただ、ベターホームレシピを検討していたときには、RDSは冗長化機能が弱い、
バックアップでIOフリーズがあったりする、など現在より課題も多かったので
EC2上で自前運用としました。

また、運用にかけられる予算が少なかったので、EC2とは別に複数のインスタンスでの
RDSの費用が発生するのが嫌だったというのもあります。

RDSを選ぶかは、みなさまの環境によると思います。

■ EBS上にMySQLデータを置いて動かす

では、EC2上で自前でMySQLを運用する場合について進めます。
普通にインストールすると、EC2のローカルストレージにデータを置くことになりますが、
EC2のインスタンスが落ちた場合、データ消えてしまうので怖いです。

したがって、MySQLのプログラム自体はEC2のローカルストレージでも
いいのですが、データディレクトリはEBS上に置くことにします。

肝心の方法ですが、以下に書いてある通りですんなりできます。   

http://d.hatena.ne.jp/shibataism/20080822/1219422913
http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1663&categoryID=100

■ ファイルシステムは xfs

ポイントはファイルシステムをxfsで作ることできます。

xfsはファイルシステムのフリーズフリーズ解除(freeze/thaw)機能があり、
EBSスナップショット取得中に書き込みをロックすることができ、
一貫性を持ったファイルシステムのスナップショット取得ができます。

freezeのコマンドはシェルからできるので、運用上、自動化することもでき、
今回の用途にはよいです。なので、以下に続く例もxfsにします。

■ 手動でフリーズ、スナップショット取得を実行してみる

前提としてmysqlのデータファイルは
  /vol/****/mysql/data
にあるものとします。(****は当社の場合はプロジェクト名です)

手順は以下の順番です。

 (1) MySQLのデータをFLUSHし、READロックをかけます。つまり、書き込みできないようにします。これでDBへの書き込みはできなくなります。
 (2) xfs_freezeコマンドでファイルシステムを凍結。ファイルシステムに書き込みをできなくすると同時に、ファイルシステム上のキャッシュやメタデータなどをディスクに書き込んでしまいます。
  (3) EBSのスナップショットを取得する。
 (4) xfsの凍結を解除します。ec2-create-snapshotでできます。
 (5) MySQLのロックを解除します。

DBやファイルシステムの状態が不整合を起こさないようにする工夫は(1)、(2)です。
(1)でMySQLのキャッシュのデータをFLUSHし、全部ディスクに退避させ、その上でREADロックです。
これでMySQLに追加書き込みはできません。その上で(2)を実施して、ファイルシステムに書き込みできなくします。
ディスクに追加書き込みできなくしてからEBSのスナップショット取得、そしてロックを順次解除していきます。具体的には以下のようにmysqlのコンソールに入ってコマンドを実行していくとできます。

----------------------------

 # mysql -u root --password=xxxx --port=xxxx --host=xxx.xxx.xxx.xxx     # mysqlのコンソールへ。

mysql >FLUSH TABLES WITH READ LOCK;                  # (1)MySQLをロック
mysql >SYSTEM xfs_freeze -f /vol                    # (2)ファイルシステムをロック
mysql >SYSTEM ec2-create-snapshot -d xxxxx vol-xxxxxx                  # (3)EBSのスナップショット
mysql >SYSTEM xfs_freeze -u /vol                    # (4)ファイルシステムのロック解除
mysql >UNLOCK TABLES;                      # (5)MySQLのアンロック

----------------------------
 

■ バックアップのプロセスを自動化する

上記のプロセスをスクリプトで自動化しておくと、定期的なスナップショット
取得ができて便利です。以下に簡単なPerlでのスクリプト例も書いておきます。
なお、xfsを使わない場合も想定して、xfs_freezeの前にsyncを入れていますが、
それ以外は上記のプロセスの自動化となっています。

#!/usr/bin/env perl

use strict;
use warnings;

use DBI;

my $use_xfs         = 1;
my $xfs_mount_point = '/vol';

my $use_mysql      = 1;
my $mysql_username = 'xxxx';
my $mysql_password = 'xxxx';
my $mysql_host     = 'xxx.xxx.xxx.xxx';
my $mysql_port     = 3306;
my $mysql_dsn      = [
    "DBI:mysql:;host=$mysql_host;$mysql_port", $mysql_username,
    $mysql_password
];

my $dbh = undef;

# connect and lock mysql
if ($use_mysql) {
    $dbh = connect_db($mysql_dsn);
    flush_tables_with_read_lock($dbh);
}

# commit buffer to disk
run_command( ['sync'] );

# freeze file system
if ($use_xfs) {
    run_command( [ 'xfs_freeze', '-f', $xfs_mount_point ] );
}

# snapshot ebs
run_command( [ 'ec2-create-snapshot', '-d', 'xxxxxx', 'vol-xxxxx' ] );


# thaw file system
if ($use_xfs) {
    run_command( [ 'xfs_freeze', '-u', $xfs_mount_point ] );
}

# unlock and disconnect
if ($use_mysql) {
    unlock_tables($dbh);
    disconnect_db($dbh);
}

exit 0;

sub run_command {
    my ($command) = @_;
    eval { system(@$command) and die "failed($?)\n"; };
    warn "ERROR: @$command: $@" if $@;
}

sub connect_db {
    my $dsn = shift;
    my $dbh = DBI->connect(@$dsn)
      or die "cannot connect database " . $!;
    return $dbh;
}

sub disconnect_db {
    my $dbh = shift;
    $dbh->disconnect();
}

sub flush_tables_with_read_lock {
    my $dbh = shift;
    $dbh->do('FLUSH TABLES WITH READ LOCK;') or die $dbh->errstr;
}

sub unlock_tables {
    my $dbh = shift;
    $dbh->do('UNLOCK TABLES; ') or die $dbh->errstr;
}

■ 注意点、制限事項など

ベターホームレシピで運用しているときはだいたい1回5秒くらいかかります。
特にEBSスナップショットに時間がかかります。その間、書き込みがブロックされるので
注意が必要です。書き込みに待ちが発生してもよい環境(スレーブ環境)などで取得するか、
マスタ環境で取得する場合は、書き込みブロックが許容できる環境で実施するのが
よいと思います。

なお、EBSスナップショットの取得はec2-create-snapshotコマンドではなく、APIを直接
たたけばもう少し高速になるはずです。それはまた今度実施してみます。

あと今回はxfsにしましたが、ext3,ext4など他のファイルシステムでもxfs_freeze的なことが
できるのかは、ちょっと調べましたが、見当たりませんでした。できるのかもしれませんが、
他のファイルシステムでもこういったバックアップ運用ができるのか、今後調べてみたいです。

■ 参考資料

今回の記事は以下の記事をもとに作りました。

・EBSでMySQLのスナップショットを取るための手順等の資料等
http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1663&categoryID=100
http://alestic.com/2009/09/ec2-consistent-snapshot

■ まとめ

このような手順を踏めば、定期的に整合性の取れた状態でスナップショットを
作っておけて便利です。今度はリストアの方法なども記載したいです。

フレクトではEC2を使ったインフラ運用に興味のあるエンジニアを
募集しています。興味のある方は以下からご連絡ください。

 

http://www.flect.co.jp/recruit/index.html

 

2010年9月11日 (土)

CloudFrontのエッジサーバ上にキャッシュされているオブジェクトを更新する

こんにちは。フレクトの大橋です。

私たちが運営しているベターホームレシピ(http://bhmb.jp)では、画像などの静的コンテンツ
の配信にCloudFrontを使っています。

CloudFrontはAmazonが用意しているS3上のオブジェクトを高速に配信する仕組みです。
CloudFrontを使うと、S3のオブジェクトがエンドユーザに対して近くに配置されている
サーバ(エッジサーバ)から配信されるようになり、高速のコンテンツの配信ができます。アメリカ西海岸にあるS3の画像が日本国内のエッジサーバにキャッシュされて、高速に配信できたりします。CDN(Contents Delivery Network)の一種です。

CloudFrontのエッジサーバはオブジェクトへのアクセスがあったときに、もしエッジサーバ上に
オブジェクトがあれば、それを配信し、なければ、S3にアクセスしにいき、
配信します。S3から取得したオブジェクトはエッジサーバ上にキャッシュされます。

キャッシュされる時間はS3のメタデータ(HTTPヘッダなど)にTTLを設定すれば制御できます。
以前は24時間が最短でしたが、現在は1時間を最短にできます。
Expireヘッダに1時間後の時間を設定するなどすれば、1時間ごとにエッジサーバのオブジェクトは
更新されるようになるはずです。詳しくは以下を参考にしてください。

http://aws.typepad.com/aws/2010/04/amazon-cloudfront-object-ttl-slashed.html

■ キャッシュが1時間単位だとけっこう面倒

さて、前置きが長くなりましたが、ベターホームレシピではデザイナが
直接S3にアップして静的コンテンツを確認したりします。(もちろん、開発用環境からやりますが)
しかし、以下のような問題によくぶつかっていました。

 ・静的コンテンツ(画像、CSS)などを更新しても、HTML内はCloudFrontのURLを
  指しているので、1時間以上待たないと更新が確認できない。
 ・デザイナがExpireヘッダなどいちいち意識するのはとても面倒

うちのデザイナは技術力もあるため、S3を直接触るような運用になっている事情もあるのですが、
何かとこのキャッシュのタイミングは面倒な作業が発生していました。

そのため、

「CloudFront上のコンテンツをゴリゴリ編集できるようにしたい、もうキャッシュ切れを待つのは面倒」

という不満がチーム内(デザイナだけですが)にただよっていました。

■ CloudFrontのInvalidation機能

そうしたら、最近以下のような記事を見つけました。
英語の苦手な私は早速スルーしようと思いましたが、ちょっとだけ読んでみると、
どうやら、CloudFront上のエッジサーバのキャッシュを無効にできる機能が
CloudFront API上に実装されたようです。

http://aws.typepad.com/aws/2010/08/new-cloudfront-feature-invalidation.html

用途としては

 ・まれに実施するCSSやJavaScriptの更新
    → ただし、1時間とか1日待つのは面倒ですよね
 ・間違ってエンコードしたビデオファイルをキャッシュから削除

などなどがあがっています。

■ CloudBuddy PersonalでInvalidation機能の使う

「APIが用意されているので、そちらでどうぞ。」

http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=213

と言いたいところですが、現実的にはうちのデザイナはそこまでは
やってくれませんし、そんなことを要求したら喧嘩になりそうなのでやめておきます。
以下の2つのツールが現状は対応しているようです。

   ・CloudBuddy Personal
   ・CloudBerry Explorer

前者で実施してみました。

まずは CloudBuddy Personalをインストールします。

  http://m1.mycloudbuddy.com/downloads.html

メールアドレスなど入力が必要ですが、画面に出てくる指示のままに
進めます。

ダウンロード、インストール後、S3のアクセスキー、秘密キーなどを
入力して、CloudBuddy Personalのエクスプローラ画面を開いてください。

CloudFrontに対応したバケットを選択し、右クリックを押して
以下のように「Object Invalidate」を押してください。

Cf_inv_01

次の画面で、「Distribution」のURLとInvalidateしたいオブジェクトを選択し、
「Create New Invalidation」を押します。

Cf_inv_02

そうすると、たぶん、5分から10分くらいでキャッシュが無効になっているはずです。
リアルタイムじゃないのでご注意ください。
Invalidationする前に、該当のオブジェクトを更新するなりしておくと
ちゃんと確認できます。

CloudBuddy Personalのエクスプローラの右上のCloudFrontボタンから
たどれるCloudFront Consoleでも、Invalidation Listで無効にしたキャッシュオブジェクトの
リストが以下のように確認できます。

Cf_inv_03

はい、このエントリは若干長いですが、CloudFront上のキャッシュオブジェクトの更新は
けっこう簡単です。そして、実際に使うときも技術的なことはほとんど考えなくてよいです。

まだ開発者の私しか試していないので、来週、うちのデザイナに試してもらおうと
思います。きっとこれまでの不満を解消できることでしょう。

フレクトではCloudFrontやS3を使ってデザイナと一緒にコンテンツ運用の
「よりよい仕組み」を作っていけるエンジニアを募集しています。
興味のある方は以下からどうぞ。

 

http://www.flect.co.jp/recruit/index.html

 

2010年8月19日 (木)

PerlでAmazon S3の操作をする方法

今日はPerlとS3についてです。

EC2上で稼働しているベターホームレシピ(http://bhmb.jp/)では
サーバ側の細かい運用ツールにPerlを使っているケースが多いです。

また、静的コンテンツの公開やログデータのバックアップなどには
Amazon S3を使っています。

s3syncなどS3を使うツールはありますが、プログラム経由で操作したい
ケースもそれなりにあり、Perlのモジュールを使ってAPI経由で
S3を操作し、各種運用をしています。その方法について簡単に紹介します。


[モジュールの選定]

PerlでS3を使うには

 ・Net::Amazon::S3
 ・Amazon::S3

あたりのモジュールが代表的なようです。この2つで検討しました。
Net::Amazon::S3の方がドキュメント、機能、パフォーマンスはよさそうすが、

  「依存モジュールが少ないこと。インストールしやすいこと。」

を重視したいので、Amazon::S3の方が私たちのケースではよさそうでした。

Net::Amazon::S3はAmazon::S3の3倍くらい依存モジュールがあり、XML::LibXMLやMooseなど
ブツブツいうほどでもないですが、ちょっとインストールが面倒なケースがあったり、重量級モジュール
だったり、と「お手軽感」という点では少しマイナスかな、と思いました。

ドキュメントみたら、やっぱりNet::Amazon::S3よりポータブルにするという思想があるみたいですね。

http://search.cpan.org/~tima/Amazon-S3-0.45/lib/Amazon/S3.pm

XML::LibXMLを使わないなどパフォーマンス面は少し劣るようですが、「ポータブルな実装」っていうのは
Goodです。パフォーマンスはとりあえず、気にしないことにしました。

ただ、Amazon::S3はちょいとドキュメントがゆるいというのが欠点はあります・・・。
まあ、中身を読んだりすれば何とかなるだろう、ということで、
よしあしはありますが、私のケースではAmazon::S3に決定して、
ベターホームレシピではPerlでS3の操作をしています。

では、簡単ですが、使い方サンプルを。


[インストール]

最近はもっぱらcpanminusでモジュールインストールです。

 cpanm Amazon::S3

とかでOKです。

以下あたりを参考にすると、cpanminusの簡単な使い方が書いてあります。

http://www.omakase.org/perl/cpanm.html


[S3への接続]

まず、接続編。以下のようにAmazon::S3クラスのコンストラクタを
アクセスキー、秘密キーを指定して呼び出せば、S3を操作するオブジェクトを
取得できます。

#!/usr/bin/perl

use strict;
use warnings;

use Amazon::S3;

# S3のアクセスキーの指定                                                                                 
my $aws_access_key_id     = 'それぞれの環境ごとに指定してください。';
# S3の秘密キーの指定                                                                                     
my $aws_secret_access_key = 'それぞれの環境ごとに指定してください。';

my $s3 = Amazon::S3->new(
    {
        aws_access_key_id     => $aws_access_key_id,
        aws_secret_access_key => $aws_secret_access_key
    }
);

my $res = $s3->buckets;

# 成功していればownwer_idなどが取得できます
print $res->{owner_id} . "\n";
print $res->{owner_displayname} . "\n";

[S3のバケット一覧の取得]

ドキュメントに記載されていないように見えましたが、
取得したS3オブジェクトを使ってバケット名一覧を取得できるみたいです。

my @buckets = @{$s3->buckets->{buckets}};

for my $bucket ( @buckets ) {
    print $bucket->bucket . "\n";

}


[S3のバケット作成]

これはドキュメントにサンプルがあるとおりですが、バケット作成は
こんな感じみたいです。バケット名を指定すればOKですね。

my $new_buekct = $s3->add_bucket( { bucket => 'flect_test_buekct' } )
    or die $s3->err . ": " . $s3->errstr;


[S3へのデータのアップロード]

データをアップロードするだけならば、サンプルにもあるとおり
以下のような感じです。

# バケットオブジェクト( Amazon::S3::Bucketのオブジェクト )を取得                                          
my $bucket = $s3->bucket('flect_test_buekct');

# キーを指定                                                                                             
my $keyname = 'test.txt';

# 値を指定                                                                                                
my $value   = 'T';
$bucket->add_key(
                  $keyname,
                  $value,
                  {
                      content_type        => 'text/plain' # コンテンツタイプなど設定を指定                                                                        
                  }
                  );

ローカルディスクにあるファイルを指定してアップする場合は以下のように
add_key_filenameを使います。

my $filepath = './testfile.txt';
$bucket->add_key_filename( 'testfile.txt', $filepath )
  or die $s3->err . ':' . $s3->errstr;

ファイル指定してアップロードというユースケースもけっこうあるので
よく使います。


[S3の指定したバケット内のキーリストを取得]

ファイルをアップしたりすれば、当然取得したくなります。
これもサンプルどおりですが、一応書いておきます。

# バケットオブジェクト( Amazon::S3::Bucketのオブジェクト )を取得                 
my $bucket = $s3->bucket('flect_test_buekct');

# キーリストを取得。                  
my $res = $bucket->list
    or die $s3->err . ": " . $s3->errstr;

# キーリストを表示                  
for my $key (@{ $res->{keys} }) {
    print $key->{key} . "\n";
}


[S3のバケット内に指定したキーが存在するかの確認]

既に同一キーでオブジェクトがアップされていないか、など確認したくなる
ケースがあります。そんな場合は以下のような感じで。

# バケットオブジェクト( Amazon::S3::Bucketのオブジェクト )を取得                  
my $bucket = $s3->bucket('flect_test_buekct');

# head_keyでキーの存在確認ができます。                  
if ( $bucket->head_key("testfile.txt") ) {
    print "key is found\n";
} else {
    print "key is not found\n";
}


[S3からデータのダウンロード]

S3に退避しておいて、別の場所でダウンロードしたい、なんてことありますよね。
ベターホームレシピではログファイルをEC2からS3にアップし、社内のデータ解析用サーバに
ダウンロードしていろいろ処理しています。

データをダウンロードし、その値をPerl内でごにょごにょ処理したい場合は
以下のように。

# バケットオブジェクト( Amazon::S3::Bucketのオブジェクト )を取得
my $bucket = $s3->bucket('flect_test_buekct');

# キーを指定してPerlの変数に取得。                  
my $data = $bucket->get_key('testfile.txt');
# 値を表示。valueを指定。                  
print $data->{value} . "\n";

データをローカルのファイルシステムに保存したい場合は以下のように。

# バケットオブジェクト( Amazon::S3::Bucketのオブジェクト )を取得
my $bucket = $s3->bucket('flect_test_buekct');

# 最後の引数にダウンロードするパスを書く。
$bucket->get_key_filename( 'testfile.txt', 'GET', './donload_file.txt' )
    or die $s3->err . ':' . $s3->errstr;


[S3からキーを削除]

アップしてあるデータを削除するには

my $bucket = $s3->bucket('flect_test_buekct');
$bucket->delete_key('testfile.txt')

みたいにしましょう。簡単です。


[最後に]

アクセス権制御や、各種メタデータの格納などは今回はカバーしていませんが、
次回以降、どこかでまたまとめて書きたいと思います。

Google Storageなど対抗のサービスもありますが、S3はいろいろな用途で
大活躍できるので、もっと調査、活用を考えてみたいです。

なお、フレクトではAmazon EC2/S3を利用した開発、案件をこれから
たくさんやっていきます。興味のある方はぜひ中途採用にご連絡ください。

http://www.flect.co.jp/recruit/index.html

2010年8月 4日 (水)

Amazon EC2/S3, Google AppEngine, Google Appsで開発、運用するモバイルレシピサイト

フレクトの大橋です。このブログではフレクトで運営しているサービスについての
開発情報をなるべくオープンに公開しきたいと思います。

1回目はAmazon EC2/S3, Google Appsなどを使って開発したモバイル3キャリア公式サイト
のシステム構成について紹介します

サイトはお料理教室のレシピが携帯でチェックできる「ベターホームレシピ」です。

システムとしては携帯からレシピコンテンツを各種検索機能やランキング機能を
使って探すことができるサイトとお考えください。

今後、システム開発に使った技術は当ブログで詳細を紹介していきますが、
今日のところはどんな要素でシステムを組んだのか、参考になる方も
いらっしゃるかも、ということで公開してみます。

まず、システム構成の概略図を。

Bh_arch

【インフラ】

・Amazon EC2(アメリカ西海岸)
   開発中にシンガポール版が出たのですが、リリースが近かったので
   検証できず、アメリカ西海岸でスタートとなりました。

【OS】

・Linux(CentOS)

【Web/APサーバ】
 ・Apache
 ・Tomcat

【アプリケーション実装】

 ・主にJava、一部Perl/Pythonです。
 ・WebアプリのフレームワークにはSAStruts/S2JDBCを使いました。
 ・また、携帯用処理にはmobyletを使いました。mobylet便利です。

【データベース】

 ・MySQL
   特段かわったことはしていませんが、
   データファイルはAmazon EBSにおいて運用し、
   そのスナップショットを定期的にS3にアップするよう
   運用しています。

【検索サーバ】

 ・Apache Solr
  ⇒ 何かと高性能な検索エンジンです。今度ブログ記事を
    記載したいと思いますが、形態素解析でやっています。
    網羅性より精度重視で構築しました。

【レコメンドサーバ】

 ・Cicindela
  ⇒ ライブドアさんが作ったOSSのレコメンドエンジンです。
    Perlでできていて、一部フレクトでフィルタ等追加して
    構築しました。

【メール送信】

 ・Postfix
  ⇒ いたってノーマルな使い方をしています。

【空メールの受信】

 ・GoogleAppEngine
  ⇒ smtp2webじゃないですが、同じようなことをするために
    メール受信のハンドリングはGoogleAppEngineで行いました。
    Pythonでアプリ部分は実装しています。

【画像配信】

  ・Amazon CloudFront

【運用監視】
  ・muninや自作ツールなど

【バックアップ用ストレージ】

・各種バックアップはAmazon S3を使っています。データベースのバックアップや
 ログのバックアップに使っています。

【効果測定、ログ集計・視覚化】

  ・Google Analytics
  ・自作ツール+ Google Spreadsheets

EC2/S3, GAEを使っているところがポイントですが、もう事例も多いので
目新しくないかもですね。

ちょっと珍しいかも、というのはログ集計・視覚化にGoogle Spereadsheets API
を使って集計値を更新したり、グラフを更新したりして、チームみんなで
アクセス状況、コンテンツの人気度の分析など行っていることでしょうか。

今後、詳細をいろいろ公開していきます。

最後にPR。

フレクトでは、Amazon EC2/S3を使ってシステムを作ってみたい!Google Appsを
使ってちょっと便利なツールを作ってみたい!という意欲あふれるエンジニアを
募集しています。興味のある方はぜひ以下からご連絡ください。

中途採用応募はこちら

採用情報

株式会社フレクトでは、事業拡大のため、
・Salesforce/Force.comのアプリケーション開発
・HerokuやAWSなどのクラウドプラットフォーム上での
Webアプリケーション開発
エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみたい方、
是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、セールスフォースパートナーです。
また、heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。

2024年4月

  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30        
ブログ powered by TypePad