すぐに子供の写真を見れるGoogle Chromeの拡張作った。

※元ネタはこちらです
http://soh335.hatenablog.com/entry/2013/02/10/011039
http://hisaichi5518.hatenablog.jp/entry/2013/02/01/003820


soh335さんのリポジトリをforkし、
DropboxAPIを利用してDropbox内の写真を表示するように改造してみました。

この拡張でやれること

  • Dropboxのアプリフォルダにある写真をシャッフルして表示
  • Dropboxの「Camera Uploadsフォルダ」内の写真を時系列に表示(ペンディング中)

最初は後者をやりたくて始めたんですけど、DropBoxAPIの仕様によりペンディング中です。
理由は後述。

準備(アプリ編)

ダウンロード

適当なフォルダで以下のコマンドを実行して下さい。

git clone https://github.com/toritori0318/chrome-tumblr-tile.git
OAuthライブラリダウンロード

oauth.jsとsha1.jsを同じフォルダにダウンロードします。
https://oauth.googlecode.com/svn/code/javascript/

準備(Dropbox編)

Dropboxアプリ登録

以下のURLからCreateAppします
https://www.dropbox.com/developers/apps

App key / App secret 取得

アプリケーション情報から "App key" と "App secret"をメモしておきます

アクセストークン取得

APIを使うためのアクセストークンを取得します。
Web上で取得する方法が見つからなかったので、
今回はPerlで以下のような簡単なスクリプトを作って実行しました。*1
https://gist.github.com/toritori0318/10553050
実行するとOAuth URLが表示されるので、
ブラウザでURLを表示してアプリの認証を行い、
コンソールに戻ってエンターキーを押すとトークンが表示されます。
これをメモっておきましょう。

準備(写真編)

Dropboxフォルダに写真を置く

上記まで完了していると
/アプリ/
という名前でDropboxフォルダが作成されています。
ここにお気に入りの写真をたくさん突っ込んでおきましょう。

準備(Chrome編)

拡張パッケージの設定

「設定」>「拡張」>「パッケージ化されていない拡張機能を読み込む」
で、ダウンロードしたアプリのディレクトリを指定します。

Chrome拡張オプション設定

最低限以下の項目を入力するだけでOKです。他のはデフォルトでよいでしょう。

  • AppKey
  • AppSecret
  • AccessToken
  • AccessSecret

Chromeでタブを開く

毎回写真がシャッフルされて、いい感じに表示されます。yatta!

内部説明

TumblrAPIとDropboxAPI仕様が異なる部分があるので
中でやっていることを少しだけ説明します。

  1. Dropbox metadata APIでフォルダ内のファイル一覧取得
  2. 20ファイル分のURLをDropbox thumbnail APIで取得し、blobデータをimageに変換し、DOMツリーに追加
  3. 下部にスクロールした時に、次の20ファイルに対して 2. を実行


DropboxAPIにはページングという気の利いた機能が無く、
フォルダ内のオブジェクトをまるっと取得する手段しかありません。
そのため、一気に処理してしまうとフォルダ内全部のサムネイルを取得してしまうので
ブラウザに表示している部分だけを少しずつ画像取得するようにしています。

Camera Uploadsをストリームっぽく表示してみたかった

元々の動機は
「奥さんが撮っている写真をリアルタイムでブラウザに表示出来たりしたら面白いかなー」
というので書き始めたんですが、DropBoxAPIにページングが無いため
「Camera Uploadsフォルダ」が膨れ上がると
タブを開くたびに大きなネットワークアクセスが発生してしまいます。
それがイマイチっぽい感じがしたので実装を断念しました。
ただ、今の仕様でも実装してみたら全然満足しているのでこのままでもいいかなーと思ってます。

まとめ

Chromeのタブを開くだけで幸せな気分になれます。最高。
子供でなくても、ペットや恋人の写真など表示しても捗るのではないでしょうか!

*1:cpanm WebService::Dropbox しておきましょう

microインスタンスはlimitかけると大きくパフォーマンスが向上する(※再追記あり)

※2014/07/02 T2インスタンスタイプとの比較 を追記しました。
※2014/03/13 他インスタンスタイプとの比較/m3.mediumの検証 を追記しました。



こちらの記事の二番煎じです。
cgroupで、お手軽CPU使用率制限


なるほど。
リソースにLimitかけるとstealを防げるためパフォーマンスも上がるというわけですね。
どのくらい変わるのか実験してみました。

cgroup前準備

sudo yum install libcgroup
sudo chkconfig cgconfig on
sudo service cgconfig start

cgroup設定

上記参考URLとほぼ同じ設定です。
実行時はcpu.cfs_quota_usを変動させて比較してみました。

sudo vi /etc/cgconfig.conf

# 以下を追加
group limittest {
 cpu {
   cpu.cfs_quota_us  = 250000;   # Max25%
   cpu.cfs_period_us = 1000000;
 }
 cpuacct {
 }
}

# 変更後はリスタート
sudo service cgconfig restart

定常的に使う時は、memory.limit_in_bytes なども設定して
メモリもlimitかけると良いかもしれません。

比較コマンド

perlのビルドの時間を比較してみました。

リミットなしバージョン
time perlbrew install perl-5.18.2
リミットありバージョン
time cgexec -g cpu:limittest /root/perl5/perlbrew/bin/perlbrew install perl-5.18.2

結果

- real user sys
リミットなし 186m59.721s 127m54.352s 51m52.487s
リミットあり(Max25%) 90m8.645s 15m4.317s 5m31.501s
リミットあり(Max30%) 75m3.421s 15m1.468s 5m24.844s
リミットあり(Max40%) 87m26.738s 23m40.645s 8m50.737s

リミット無しでsteal発生しまくりの時はおよそ3時間かかっていたのが、
リミットあり(Max30%)だと1時間15分ほど。2倍以上速い!!


※以下引用

いくつかの調査をした結果,
 ・直近の100秒のCPU使用率が20%を超えている場合は低速モードに移行する
 ・低速モードはCPU使用率の97%が使えない状態(steal)になる

Amazon EC2 Microインスタンスの挙動について

とあるので、20%ギリギリ超えるくらいがちょうどいいかなと予想していましたが
実際には30%が一番パフォーマンスが良かったです*1


vmstatでstealの値も見ていたんですが、
Max40%だと結構stealが発生していて、
Max30%の場合ごくごくわずかにstealが発生するくらいでした。
常にCPUMaxをつかう処理があるわけではないと思うので、
20%よりも少しばかり高めに設定したほうが
効率が良いのかもしれませんね。

まとめ

cgroupで制限するとmicroインスタンスでは大幅なパフォーマンス向上が見られました。
大きいビルドなど行うときには必須ではないでしょうか!






※追記 他インスタンスタイプとの比較

smallとの比較があったらよいのでは、というコメントを頂いたので
ついでにインスタンスタイプ別に比較してみました。
m1.smallだけでなく、グループ毎の下位クラスも一緒に比較してみました。

- real user sys
t1.microリミットありver 75m3.421s 15m1.468s 5m24.844s
m1.small 46m3.623s 29m54.188s 10m54.853s
m1.medium 25m33.974s 15m17.969s 5m0.599s
m3.medium 31m42.804s 18m45.818s 7m47.473s
c1.medium 25m1.527s 15m16.129s 5m34.785s
c3.large 16m41.832s 9m31.712s 3m25.633s


c3は予想通りの早さですね。
他のインスタンスも軒並み予想通りですが、一つだけ気になる結果があります。
m3.mediumインスタンスです。

m1.mediumとm3.medium

公式のインスタンスタイプを見ると
以下のようになっています。

- ecu vcpu
m1.medium 2 1
m3.medium 3 1


あれれ、数値上はm3.mediumの方が良さそうですね*2
なぜm1.mediumの方が速いのでしょうか?

ビルド時のスナップショット

m3.mediumのビルド時のvmstatのスナップショットです。

stealが40-50%ほど発生しています。
m1.mediumはというと、stealの発生はありませんでした。

予想:CPU共有タイプ?

公式ドキュメントからは確認出来なかったのですが、
おそらくm3.mediumもm1.smallと同じように
「CPU共有型なのではないか」と予想しました。
詳しくは以下のブログをご覧頂くと良いです。
AmazonEC2 m1.smallのCPU配分
http://php6.jp/linux/2012/01/20/amazonec2-m1-small/


vmstatの推移がm1.smallとm3.mediumで同じような挙動をしているので
ほぼ間違いないのではないかと思います。

m3.largeも試してみる

本当は上記インスタンスだけ比較して終わろうと思ったのですが、
m3のグレードを一つ上げたらstealしなくなるか、を確認してみました。

- real user sys
m3.large 17m1.667s 10m1.062s 3m21.857s
ビルド時のスナップショット


stealが消え、ほぼ公式と同じような性能が出ているように見えます*3
やはり、stealが発生するのはm3.mediumだけのようです。

追記:まとめ

単に性能比較して終わる予定だったのですが、
m3.mediumインスタンスで新たな発見がありました。
m1.mediumと比べて、
「m3.mediumの方が安いし性能もいいしこれでいいじゃんヒャッハー!!!」
と思っていましたが、mediumだけでみると「m1.mediumの方が速い」という結果でした。
ほげぇ。


匿名さん、コメントありがとうございました。


再追記:T2インスタンス

バーストありとバーストなしで追試しました。
バーストあり時は t2.micro/t2.small/t2.medium であまり変わらなかったので
どちらもt2.microの値です。

- real user sys
t2.micro(バーストあり) 14m46.383s 8m53.064s 0m26.884s
t2.micro(ベースライン:10%) -(※注1) -(※注1) -(※注1)

バースト時にはc3インスタンスと遜色ないですね。


また、以下はt2.microのバーストあり時の残高クレジットです。

30-22で、およそ8クレ消費しているようですね。


※注1
【悲報】ベースラインビルド、なんと
 2週間回し続けても一向に終わる気配がありませんでした!!!
 (途中で強制終了しました)
 もしかしたら実測としてはベースラインを大きく下回っているのかも…

*1:途中ネットワークアクセスなども発生していたり、というのもあると思います

*2:自分もこの辺りの性能比較を過去記事に書いています http://d.hatena.ne.jp/toritori0318/20140203/1391445479

*3:c3.largeと比較して

チャットを面白おかしくするおもちゃ箱

SkypeIRCなど、チャットツールは
サービス開発のコミュニケーションツールとしては無くてはならないものである。
しかし時として、場の空気が重くなることもあるだろう。
そんな時、一筋の光をもたらすようなbotがいたなら。。。


時に笑いを提供し、時には場の空気を読まない悪戯小僧のような存在。
そんなライブラリ書いた。

リポジトリ

https://github.com/toritori0318/p5-toy

基本的には「おもしろ画像URL」をランダムに返すだけのライブラリなので、
どのチャットツールでもご利用可能です。
unazusanを利用していれば、exampleをコピペするだけですぐに投入できるでしょう。
プルリクも大歓迎!

画像取得用サービス一覧
独自ライブラリ
  • フリーBox(定義済みの定型文から、適当にピックアップするだけ)
  • ++ユーザランキング


やり過ぎると遊んでるだけになるので、ここぞという時に使うとよいでしょう。
チャットに幸あれ。

*1:エロ的な意味で

M3インスタンスを使わない手はない

最近、また新たにEC2のインスタンスサイズが増えましたね。
【AWS発表】M3インスタンスの新サイズおよび新機能 + EBSの値下げ + S3の値下げ


M3インスタンスはM1インスタンスの後継にあたる汎用インスタンスです。
今回新たに追加された m3.medium / m3.large は価格帯も性能もバランスよく、
非常に使いやすいインスタンスなのではないでしょうか。

本題

ふとM1/M3の料金表を見比べてみたんですが、
同じグレードで比較するとM3の方が料金安いんですよね。
しかも数値上はM3の方が性能も高そうです。
比較表にしてみましょう。*1 *2

インスタンス vCPU ECU RAM(GB) インスタンスストレージ (GB) EBS 最適化 ネットワークパフォーマンス 時間あたりの料金(東京リージョン)
m3.medium 1 3 3.75 1 x 4 SSD - $0.171
m1.medium 1 2 3.75 1 x 410 - $0.175
インスタンス vCPU ECU RAM(GB) インスタンスストレージ (GB) EBS 最適化 ネットワークパフォーマンス 時間あたりの料金(東京リージョン)
m3.large 2 6.5 7.5 1 x 32 SSD - $0.342
m1.large 2 4 7.5 2 x 420 $0.350
インスタンス vCPU ECU RAM(GB) インスタンスストレージ (GB) EBS 最適化 ネットワークパフォーマンス 時間あたりの料金(東京リージョン)
m3.xlarge 4 13 15 2 x 40 SSD $0.684
m1.xlarge 4 8 15 4 x 420 $0.700

まとめ

M1シリーズ、大容量のインスタンスストレージが欲しい以外は
選択する意味があまり無さそうですね。
これはもう「M1を捨ててM3を使え」というAmazonさんからのメッセージと受け取って
M3を使いまくりましょう〜

*1:表はこちらから抜粋させて頂いております http://aws.amazon.com/ec2/instance-types/ http://aws.amazon.com/ec2/pricing/

*2:比較する対象のないm1.smallとm3.2xlargeは除外しています

pip1.5に注意

とある日、素のインスタンスにchef走らせたらpip installで何故かエラーになりました。
デプロイ周りで特にレシピ変更してないし全く身に覚えがない。。。


差分chefインストールだとpipエラー出ないし何でだー?とトレース追ってみると

argparse==1.2.1

でエラってる。そんなバージョンないよって言われる。

pipのバージョン

いろいろ調査した結果、pipのバージョンが怪しいということになって
確認してみると確かに違う。エラーが出るのはpipバージョン1.5だ。
どうやらpip1.5では外部にホストされているモジュールは
デフォルトでインストール出来なくなっているようである。*1

回避策

pip installのオプションで
--allow-all-externalを付けるとうまくインストールされました。
--allow-external PROJECT_NAME で個別にURLを指定することもできるようです。

ということで

pipの最新バージョンを使うと
デフォルトの挙動が変わってしまうので注意しましょう、というお話でした。
他にもいくつか下位互換が失われている変更があるようです。
http://www.pip-installer.org/en/latest/news.html#id1


つかリリース日2014/1/1って。。。

*1:確かに、argparseの1.2.1だけgooglecodeに置かれてる。https://pypi.python.org/simple/argparse/

2013年振り返りと2014年

年末年始バタバタしてたので今頃振り返ってみます。

仕事

DevOps頑張ってた。
監視自動化とか、開発運用共通化とか。


改善前は各モジュールで独自の開発フローや秘伝のタレ化したデプロイツールなど、
担当者がいないと誰も管理できなくなってしまうという
「担当者SPOF」になってしまっていて、
それを改善したいなーと思い
vagrant + chef + cloudformation」という構成で
インフラ構築/運用/開発フローを共通化するためにいろいろ頑張ってた。


現在はこれを拡張して

  • AMIの作成
  • image-idを自動でcloudformationのテンプレートに適用
  • そのままcloudformationのstack作成/更新/削除

という一連のフローを同じrakeタスクで実行できるようにした。


その結果、どのシステムでも全く同じ手順で

  • デプロイ
  • インフラ構築
  • クラスタ構築
  • スケールアウト/スケールイン/スケールアップ/スケールダウン

などが実現できるようになった。

これ実現出来たのは地味にでかいと思ってる。

趣味コーディング

ひょんなことからCPAN Authorになれた。嬉しい。
しかし書きたかったコードはたくさんあったんだけど
それほど書けてなかったような気がする。

プライベート

上の子が幼稚園に入った。
いまだに朝嫌がることはあるが、実際に登園すると普通に楽しんでるようなのであんまり心配してない。女の子にモテてるらしい。くやしい。
下の子はどんどんかわいくなってる。うへぇ
あと結婚10周年でした。美味しいもの食べた。

2014年

仕事関係ではソケットサーバパワーアップさせないと辛いなーって感じになってきてるので
本気でチューニング始める予定。予定は未定。


あと気になってるソリューションがたくさんあるので
徐々に勉強復活させたい。
以下とか。イミュータボー?

  • Docker
  • Serf
  • Mesos
  • Graphite
  • Sensu


yogaコマンドも追加機能したいタスクがどんどん溜まってきてるので消化したい。
やりたい。やらねば。

nginx-lua-moduleでLuaスクリプト書いてみた

プロダクトでWebサーバ上の現在時刻出したい要件がありました。
これぐらいの処理ならアプリケーション介さずともnginxだけでやりたいですね。
現在時刻ヘッダーにつけるならnginx標準機能で出来そうなんですが、
深淵なる理由からコンテンツとして欲しいとのこと。


今後、Nginx+Lua試してみたいなーという要件もありましたし、
せっかくなのでこの機能をLuaスクリプトで書いてみることにしました。


NginxでLuaを動かす環境

まず環境整えるのが若干大変でした。*1
以下のような手順でインストールするようです。

ライブラリのパスなど気をつけないとハマるかもしれませんね。

nginxレシピ

opscodeのnginxクックブックにはluaをインストールするレシピもありました。
しかし、例のごとくそのままでは動かせなかったので
一部オーバーライドしたクックブックを書いてみました。
AWSの生AMIにこれをそのままプロビジョニングするとNginx+Luaが起動することを確認しています。
https://github.com/toritori0318/chef-nginx-lua-sample

直したところ

recipes/lua.rbにパッチを当てたのと、
recipes/source.rbluaをインストールする処理を差し込んだくらいです。
ちなみにcjsonを入れているのは、今回json形式でレスポンスさせたかったからです。
Luaを動かすだけであればcjsonを入れる必要はありません。

サンプルアプリ仕様

  • /current_timeにアクセスすると、plainテキストでdatetimeが返却される
  • df=epoch が指定されていると、エポック秒が返却される
  • rf=json が指定されていると、json形式で返却される

サンプル実装

/etc/nginx/sites-available/lua_current_time

nginxのコンフィグです。
特に語るところはありません。

# Lua soライブラリのパス指定。今回はcjsonのため(ファイルパターンも指定が必要らしい)
lua_package_cpath "/usr/local/lib/lua/5.1/?.so";

server {
  listen   80;

  access_log  /var/log/nginx/access.log;

  location /current_time {
    # 外部Luaスクリプト読み込み
    content_by_lua_file /etc/nginx/lua/current_time.lua;
  }

  location / {
    default_type 'text/plain';
    # コードもそのまま書ける
    content_by_lua "ngx.say('Hello,lua!')";
  }
}
/etc/nginx/lua/current_time.lua

パラメータを受け取ってゴニョゴニョしています。
特に語るところはありません。

local cjson = require "cjson"
local ctime = ""

local args = ngx.req.get_uri_args()
if args.df == "epoch" then
    ctime = os.date("%s")
else
    ctime = os.date("%Y-%m-%dT%H:%M:%S %z")
end
if args.rf == "json" then
    ngx.header.content_type = "application/json";
    ngx.print(cjson.encode({current_time = ctime}))
else
    ngx.header.content_type = "text/plain";
    ngx.print(ctime)
end


非常に簡単ですね。

ベンチマーク

abしてみました。
コマンドパラメータはこんな感じです。

ab -n 20000 -c 2 http://127.0.0.1/xxxx
/ (Hello Lua)
Server Software:        nginx/1.4.3
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /
Document Length:        11 bytes

Concurrency Level:      2
Time taken for tests:   2.018 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Total transferred:      3060000 bytes
HTML transferred:       220000 bytes
Requests per second:    9912.15 [#/sec] (mean)
Time per request:       0.202 [ms] (mean)
Time per request:       0.101 [ms] (mean, across all concurrent requests)
Transfer rate:          1481.02 [Kbytes/sec] received
/current_time
Server Software:        nginx/1.4.3
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /current_time
Document Length:        25 bytes

Concurrency Level:      2
Time taken for tests:   2.339 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Total transferred:      3340000 bytes
HTML transferred:       500000 bytes
Requests per second:    8549.87 [#/sec] (mean)
Time per request:       0.234 [ms] (mean)
Time per request:       0.117 [ms] (mean, across all concurrent requests)
Transfer rate:          1394.36 [Kbytes/sec] received
/static/index.html(静的ファイル配信。このファイルは手動で作りました)
Server Software:        nginx/1.4.3
Server Hostname:        127.0.0.1
Server Port:            80

Document Path:          /static/index.html
Document Length:        6 bytes

Concurrency Level:      2
Time taken for tests:   1.942 seconds
Complete requests:      20000
Failed requests:        0
Write errors:           0
Total transferred:      4680000 bytes
HTML transferred:       120000 bytes
Requests per second:    10298.39 [#/sec] (mean)
Time per request:       0.194 [ms] (mean)
Time per request:       0.097 [ms] (mean, across all concurrent requests)
Transfer rate:          2353.34 [Kbytes/sec] received


静的ファイル配信よりわずかに落ちますが十分早い。


Nginx+Lua、環境設定が若干面倒ですが、
上記クックブックを使うと一発で環境作れますし、
Luaスクリプトもお手軽に書けそうなので試してみてはいかがでしょうか〜
(゚Д゚)オLua!オLua!

*1:※追記 openrestyを使うと楽できるようです! http://openresty.org/