YAPC::Asia2014で儚いクラスタ運用話をしました
http://www.slideshare.net/tsuyoshitorii5/yapcasia2014-2-public
(※一部素材を変更しています)
TV連動サービスの運用ってこんな特徴があって
それに合わせていろいろ運用改善したぜ〜、
という話をしてきました。
結構ボリュームが多くなってしまって
限られた時間でうまく説明できたかどうかいまいち自信がないのですが、
「へぇ〜、そんな感じで運用してるんだ〜」
というニュアンスだけでも伝われば嬉しいです。
足を運んで聞いて下さったみなさま、ありがとうございました!!!
明日もまだまだYAPCは続くので存分に楽しみたいと思います〜
ちなみに株式会社バスキュールは
フロントエンド/バックエンド問わずエンジニアを随時募集しているようです。
もしご興味がある方いれば是非お声がけください!
GitLabとRedmineを連携してみるの巻
はてなブログさんの開発フローのお話
少し前の話になるんですが、GitHubKaigiで
はてなブログさんの開発フローについて発表がありました。
その中で
当初はGitHubとRedmineを併用していたが、 両ツールの連携がイマイチだったので Redmineを止めてホワイトボードでタスク管理するようにした
という内容がありました。
https://speakerdeck.com/shibayu36/hatenaburogutimufalsekai-fa-hurotogithub
「ふむふむ、なるほどなぁ」という感じで非常に勉強になったのですが、
もしかしたら
「"GitLab+Redmine" ならツール自体が連携機能を持っている」
のでもう少しマシになるのかも?とも思いました。
そこで、GitLabとRedmineを使うと
一体どういうことが出来る様になるのか?といったところを紹介してみます。*1
弊社でも連携機能は一応有効にしているんですが、
まだまともには運用していないので
再確認の意味でメモを残しておこう、という意図もありますw
TL;DR
これらの設定を行うと…
事前設定: Redmine
Github Hookプラグインを導入しておく
GitHubという名前ですが、GitLabでも同じように使えます。
インストールは、リポジトリダウンロードして bundle install するだけでOKです。
https://github.com/koppen/redmine_github_hook
事前設定: GitLab
Issue TrackerでRedmine連携が選択できるようにしておく
gitlab.ymlにRedmine連携するための記述をしておく必要があります。
この設定をしておくと、Settingで IssueTracker にRedmineを選択できるようになります。
RPMインストールしているのであれば、
/etc/gitlab/gitlab.rb に以下の記述を追記するだけでOKです。
gitlab_rails['issues_tracker_redmine'] = true gitlab_rails['issues_tracker_redmine_title'] = "Redmine" gitlab_rails['issues_tracker_redmine_project_url'] = "http://<redmine_url>/projects/:issues_tracker_id/issues" gitlab_rails['issues_tracker_redmine_issues_url'] = "http://<redmine_url>/issues/:id" gitlab_rails['issues_tracker_redmine_new_issue_url'] = "http://<redmine_url>/projects/:issues_tracker_id/issues/new"
RedmineからGitLabリポジトリにアクセス出来るようにしておく
これは環境によってやることが異なるのですが、
もしもGitLabとRedmineが同じサーバであれば
GitLabリポジトリへのPermissionが適切に設定されていればよいでしょう。
RPMインストールしているのであれば、
/var/opt/gitlab/git-data/repositories 以下にリポジトリの実体があります。
Redmineを実行しているユーザから、このディレクトリが見えるかどうか確認しておきましょう。
GitLabとRedmine別々のサーバの場合、詳細は割愛しますが
GitLabのwebhookを駆使してRedmineのリポジトリに反映すれば良いでしょう。
プロジェクト発足時、GitLabとRedmineを連携するための最低限の設定
まず、プロジェクトを立ちあげた時に
最低限するべきことをリスト化してみます。
一体何が連携されるの?
GitLabコミットメッセージのissue番号がRedmineのissueとリンクする
コミットメッセージの「#????」という部分が、RedmineのIssueにリンクします。
ただ、少し前のバージョンでは普通にRedmineチケットへのリンクされていたのですが、
現バージョン(6.9.2)ではRedmineのチケットのリンクが上手く作成されないようです。
リンクを復活させるには $RAILS_ROOT/lib/gitlab/markdown.rbのこの行に
以下のようなモンキーパッチを当てます。*2
--- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -178,7 +178,7 @@ module Gitlab end def reference_issue(identifier, project = @project) - if project.used_default_issues_tracker? || !external_issues_tracker_enabled? + if true if project.issue_exists? identifier url = url_for_issue(identifier, project) title = title_for_issue(identifier)
これおそらくJIRA連携を追加した時のバグだと思うのですが
英語力が足りなくて伝えられる気がしない…
Redmineのチケット連携機能がそのまま使える
たとえば、Issueに紐づくコミットの表示や、ステータスの変更/進捗率の変更なども
コミットメッセージから行うことが出来ます。
また、作業時間の連携も行えますので
コミットメッセージに設定した作業時間がチケットに反映され、
そのまま何もしなくてもプロジェクト毎/ユーザ毎の集計結果に反映されます。
実績管理も行っているプロジェクトではとても便利ですね。*3
ダッシュボート/スクラム開発 プラグイン
先のスライドではかんばんについても言及されていました。
そこで、Redmineでも同じようなことを実現するためのプラグインを紹介してみます。
- スクラム開発を支援したり、
- チケットをかんばんで表示したり、
- ドラッグアンドドロップで直感的にチケットを操作したり、
といった機能拡張を提供するものです。
他にも同じようなプラグインがいくつか存在しますが、更新が活発なものを厳選しました。
Redmine Backlogs v1.0.6
Redmineでスクラム開発を支援するためのプラグインです。
Redmineユーザの中では割とメジャーな気がします。
以下、RedmineのBacklogを利用した記事です。
Redmine Dashboard2
プロジェクト毎のタスクボードを提供します。
導入もかなり楽ですし、見た目/操作もわかりやすいので
単純にチケットのかんばんが欲しいだけならオススメ。
※以下、Gifzoで操作感を動画にしてみました
http://gifzo.net/l4gxyO45rI.mp4
Redmine ekanban
こちらもタスクボードを提供するプラグイン。
デモサイトあり。
http://ekanban-demo.herokuapp.com/
account: guest
password: redmine
その他連携プラグイン
Redmine OmniAuth
GitLabのOmniAuthでRedmineを追加します。
こちらを導入すると、GitLabのアカウント管理をRedmineアカウントに集約することが出来ます。
設定手順としては以下の通りです。
弊社でも設定済みですが、導入に結構手間取った記憶が…(※後で追記するかもしれない)
まとめ
GitLabとRedmineを連携するための設定と、
連携するとどういったことが出来るか、
を書いてみました。
もちろん「この機能を使えば何でも解決します!」ということではなく、
こういうやり方もあるんだなぁ、というゆるい感じで
選択肢の一つにしていただければと思います。
続・GitHubクローンのGitLabを5分でインストールした
前回の記事(GitHubクローンのGitLabを5分でインストールした) が
思いのほかブクマされてしまったので補足記事を書くことにしました。
インストールした後に設定したほうが良い項目とミドルウェア競合検証、
その他Tipsなど書いてみました。
公式ドキュメント
以下、記事で書いていることはほぼすべてドキュメントにも書いてあります。
ご参照下さい。
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#configuration
コンフィグファイル準備
事前に /etc/gitlab/gitlab.rb を用意しておきます。
このファイルはGitLabをインストールする前に手動で作ってしまって構いません。*1
sudo mkdir -p /etc/gitlab sudo touch /etc/gitlab/gitlab.rb sudo chmod 600 /etc/gitlab/gitlab.rb
そして、コンフィグ設定後に
sudo gitlab-ctl reconfigure
すると、GitLabに反映するようです。
設定すべきコンフィグ値
SMTP
メール通知などに使います。
gitlab_rails['smtp_enable'] = true gitlab_rails['smtp_address'] = "smtp.server" gitlab_rails['smtp_port'] = 456 gitlab_rails['smtp_user_name'] = "smtp user" gitlab_rails['smtp_password'] = "smtp password" gitlab_rails['smtp_domain'] = "example.com" gitlab_rails['smtp_authentication'] = "login" gitlab_rails['smtp_enable_starttls_auto'] = true
その他コンフィグ値
HTTPS設定
URLのHTTPS化/証明書パスなどを追記します。
external_url "https://gitlab.example.com" nginx['redirect_http_to_https'] = true nginx['ssl_certificate'] = "/etc/gitlab/ssl/gitlab.crt" nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/gitlab.key"
Google, Twitter, GitHub login設定
Omniauth設定を行うことにより、外部認証することが可能です。
gitlab_rails['omniauth_enabled'] = true gitlab_rails['omniauth_providers'] = [ { "name" => "google_oauth2", "app_id" => "YOUR APP ID", "app_secret" => "YOUR APP SECRET", "args" => { "access_type" => "offline", "approval_prompt" => "" } } ]
ちなみに弊社では、Redmine Omniauthで
Redmineアカウントでログイン出来るようにしています。
ミドルウェア混在環境での検証結果
※ 2014/10/10追記分:既存のミドルウェアを利用する方法
そもそも、omnibus-installでミドルウェアをインストールせずに、
既存の環境を使いまわすことも出来るようです。
たとえば、Nginxが既にインストール済みであれば
omnibus-installではインストールせずに
既存のNginxコンフィグを追加するだけで動かすことが出来ます。
ex) 既にインストール済みのPostgresqlを利用する場合
1. /etc/gitlab/gitlab.rb に以下を追記します。
# postgresインストールを無効にする postgresql['enable'] = false # 他のミドルウェアをインストール回避する時はこんな感じ #nginx['enable'] = false #redis['enable'] = false #postgresql['enable'] = false # postgresの情報を入力 gitlab_rails['db_adapter'] = 'postgresql' gitlab_rails['db_encoding'] = 'unicode' gitlab_rails['db_database'] = 'gitlabhq_production' gitlab_rails['db_host'] = '127.0.0.1' gitlab_rails['db_port'] = '5432' gitlab_rails['db_username'] = 'git' # Database owner. gitlab_rails['db_password'] = 'git' # Database owner's password.
2. sudo gitlab-ctl reconfigure を実行してgitlabに反映
3. sudo gitlab-rake gitlab:setup を実行して、初期データを投入
これで、既存の環境にgitlabのDB環境の設定が完了です。*2
ボート競合を回避する方法
前回の記事でも触れましたが、GitLabをRPMインストールすると
NginxやらRedisやらも一緒に同梱されます。
ロケーションは別*3になるので問題ないのですがポートは競合してしまいます。
ただし、それを回避する設定をコンフィグに追記すれば大丈夫そうです。
以下にサンプルを用意しました。
nginx(88)/postgresql(15432)/redis(16379)/unicorn(18080) のポートを指定しています。
redis['port'] = 16379 postgresql['port'] = 15432 unicorn['port'] = 18080 external_url "http://gitlab.example.com:88/"
実際に検証してみましたが、
元からインストールされているミドルウェアに影響させずに
GitLabを起動することが出来ました。
まとめ
取り急ぎですが、前回の補足記事でした。
コンフィグに指定しているキーは
このattributesを変更しているようなので
このファイルを見てキーを確認すれば好きにカスタマイズできそうですね。
では良いGitLabライフを!
*1:というか reconfigure する前には作っておきましょう
*2:参考: http://stackoverflow.com/questions/23580268/gitlab-omnibus-configuration-for-postgres
*3:/opt/gitlab/配下
GitHubクローンのGitLabを5分でインストールした
※2015/6/22 最新版の手順に更新
※2015/1/7 アップグレードについての記事を書きました
http://d.hatena.ne.jp/toritori0318/20150106/1420558625
※2014/5/24 補足記事書きました
http://d.hatena.ne.jp/toritori0318/20140524/1400955383
で、お決まりのパターンでOSSに流れて、
http://d.hatena.ne.jp/rela1470/20140520
GitLabとかやってみたんだけど、むっちゃムズいのねあれ。
まともにインストールできん。
「GitLab インストール」
でググるとたいていまともにインストールしようとしている記事が見つかって
なにこれ使うまで面倒すぎ!
ってなりますよね。かつての自分もそうでした。
しかし最近のGitLabはRPMが提供されているので
これを使うと超絶簡単にインストールすることができます。
素のAmazon Linuxにインストールしてみる
上記手順、ほぼそのままで進めてみます。
RPMダウンロード
ここからRPMダウンロードしましょう。
https://www.gitlab.com/downloads/
以下インストールコマンド
面倒なので一気に貼り付け。
(以下ubuntuバージョンです。他のディストリビューション手順も上記リンクから選択すると表示されます)
# 依存パッケージ sudo apt-get install curl openssh-server ca-certificates postfix # gitlab install curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash sudo apt-get install gitlab-ce # 反映 sudo gitlab-ctl reconfigure # 確認 sudo gitlab-ctl status;
はい、インストール完了です。
http://
※初期ユーザ/パスワードはこちら
- Username: root
- Password: 5iveL!fe
bundlerやDBマイグレーションが実行されるので
元記事のように10秒とは行きませんが、
5分程度で何の問題も発生せずGitLabをインストール/実行することが出来ました。
アップグレードの際もドキュメントに手順が書いてあるので
特に詰まることなく進められると思います。
https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/update.md
GitLabの良いと思うところ
「GitHubクローン」というところを強調されがちですが、
実は「Gistクローン(Snippets)」もついてくるので
社内Gistが欲しいときにも有用だと思います。
また、APIの豊富さ/Hookの種類/Redmine連携のしやすさ といった点もよいですね。
開発がとても活発なのもプラスポイントです*1
注意点
Nginx/PostgreSQL/Redisなどもインストールされるので、
元々環境があるときには
競合しないように素の環境にインストールするのが良いと思います。*2
Dockerなどに構築するのも良いですね。
まとめ
GitLabを簡単にインストールする方法を紹介しました。
かわいそうなのでもう
GitLabのインストールは苦行
とか言わないであげて下さい><
この記事が検索でGoogleトップにくるといいなぁ…(むりぽ)
※2014/7/5 いつの間にかGoogleトップ来てました!みなさまありがとうございます!
*1:毎月下旬、必ずバージョンアップしている
*2:補足記事にも追記しました http://d.hatena.ne.jp/toritori0318/20140524/1400955383
Redisのビットコマンドを用いた高速集計
Redisは様々な型をもっているので
単純な集計(increment)は結構柔軟にできたりします。
ですが、後から条件付きでクロス集計したい時があると思います。
Redisにはビット演算するコマンドがあるので
それを使っていろいろな集計をしてみました。
ビット関連コマンドリファレンス
GETBIT/SETBIT
Redis 2.2.0以降が必要。
ビットのオフセットに対してフラグを取得/設定します。
GETBIT key offset SETBIT key offset value(1/0)
BITOP
Redis 2.6.0以降が必要。
複数のキーに対してビット操作を行うことが出来ます。
集計にはこの操作を使います。
BITOP operation(AND/OR/XOR) destkey key [key ...] BITOP operation(NOT) destkey
簡易Example
127.0.0.1:6379> SETBIT keyA 1 1 (integer) 0 127.0.0.1:6379> SETBIT keyA 2 1 (integer) 0 127.0.0.1:6379> SETBIT keyA 3 1 (integer) 0 127.0.0.1:6379> SETBIT keyB 1 1 (integer) 0 127.0.0.1:6379> BITCOUNT keyA (integer) 3 # keyA のカウント 127.0.0.1:6379> BITCOUNT keyB (integer) 1 # keyB のカウント 127.0.0.1:6379> BITOP AND keyAandB keyA keyB (integer) 1 127.0.0.1:6379> BITCOUNT keyAandB (integer) 1 # keyAandB のカウント 127.0.0.1:6379> BITOP OR keyAorB keyA keyB (integer) 1 127.0.0.1:6379> BITCOUNT keyAorB (integer) 3 # keyAorB のカウント 127.0.0.1:6379> BITOP XOR keyAxorB keyA keyB (integer) 1 127.0.0.1:6379> BITCOUNT keyAxorB (integer) 2 # keyAorB のカウント
ユースケース1:日別集計
ここから具体的なシナリオを考えてみます。
2014/4/1-2014/4/3 に訪れたユーザ数をいくつかの軸で集計してみます。
キーを日別に分けておいて、後でBITOPで演算して集計します。
ビットのoffsetにはユニークユーザID(Integer)を指定します。
登録スクリプト:キーを「2014/4/1〜2014/4/3」に分け、1000ユーザを適当に登録
use strict; use warnings; use Redis; use 5.10.0; my $redis = Redis->new; my @date = qw/ visit:2014-04-01 visit:2014-04-02 visit:2014-04-03 /; sub choice { $_[int(rand(scalar(@_)))] } sub clear { $redis->del($_) for (@date); } sub setbit_all { for my $uid (1..1000) { $redis->multi(); # 適当な確率でvisitする { # 4/1: 9割の確率でvisitさせる if(rand() < 0.9) { $redis->setbit($date[0], $uid, 1, sub {}); } # 4/2: 5割の確率でvisitさせる if(rand() < 0.5) { $redis->setbit($date[1], $uid, 1, sub {}); } # 4/3: 3割の確率でvisitさせる if(rand() < 0.3) { $redis->setbit($date[2], $uid, 1, sub {}); } } $redis->exec(); } } clear(); setbit_all();
集計スクリプト:日付でユーザ集計
A: では日別の結果をORで演算し、3日間全体のユニークユーザ数を集計しています。
B: では4/1と4/3をANDで演算し、2日間どちらも訪れたユニークユーザ数を集計しています。
use strict; use warnings; use Redis; use 5.10.0; my $redis = Redis->new; # 集計する日付 my @date = qw/ visit:2014-04-01 visit:2014-04-02 visit:2014-04-03 /; sub p { my ($key) = @_; printf ("%s %d\n", $key, $redis->bitcount($key)); } sub display { # 全部のbitcount p($_) for (@date); say ''; # bitop # A: 3日間に訪れたユニークユーザ数合計 $redis->bitop('OR', 'visit:total', @date); p('visit:total'); say ''; # B: 2014-04-01 / 2014-04-03 両方に訪れたユーザ数合計 $redis->bitop('AND', 'visit:2day:total', 'visit:2014-04-01', 'visit:2014-04-03'); p('visit:2day:total'); say ''; } display()
ユースケース2:クイズのユーザ集計
クイズを出題し、回答/正解したユーザ数などを集計します。
先程と同じく、ビットのoffsetにはユニークユーザID(Integer)を指定します。
登録スクリプト:キーを「クイズ+選択肢」に分け、1000ユーザを適当に登録
1ユーザに対して性別を登録し、さらに3つの問題をランダムで回答させています。
use strict; use warnings; use Redis; use 5.10.0; my $redis = Redis->new; # 性別 my @genders = qw/man woman/; # 質問に対する回答群 my @option1 = qw/ answer:question1:optionA answer:question1:optionB answer:question1:optionC /; my @option2 = qw/ answer:question2:optionD answer:question2:optionE answer:question2:optionF /; my @option3 = qw/ answer:question3:optionG answer:question3:optionH /; sub choice { $_[int(rand(scalar(@_)))] } sub clear { $redis->del($_) for (@genders, @option1, @option2, @option3); } sub setbit_all { for my $uid (1..1000) { $redis->multi(); { # gender $redis->setbit(choice(@genders), $uid, 1, sub {}); # 3つの問題にランダムで回答 $redis->setbit(choice(@option1), $uid, 1, sub {}); $redis->setbit(choice(@option2), $uid, 1, sub {}); $redis->setbit(choice(@option3), $uid, 1, sub {}); } $redis->exec(); } } clear(); setbit_all();
集計スクリプト:正解したユーザの集計
各問題の正解を定義し、正解したユーザを集計します。
C: では全問正解したユーザを集計しています。
D: では男性の中で全問正解したユーザを集計しています。
use strict; use warnings; use Redis; use Time::HiRes qw/gettimeofday tv_interval/; use 5.10.0; my $redis = Redis->new; # 性別 my @genders = qw/man woman/; # 質問に対する回答群 my @answers = qw/ answer:question1:optionA answer:question1:optionB answer:question1:optionC answer:question2:optionD answer:question2:optionE answer:question2:optionF answer:question3:optionG answer:question3:optionH /; # 以下を正解とする # question1 > optionA # question2 > optionF # question3 > optionH my @collect = qw/ answer:question1:optionA answer:question2:optionF answer:question3:optionH /; sub p { my ($key) = @_; printf ("%s %d\n", $key, $redis->bitcount($key)); } sub display { # 全部のbitcount p($_) for (@genders, @answers); say ''; # bitop # C: 全問正解したユーザ $redis->bitop('AND', 'answer:all:correct', @collect); p('answer:all:correct'); say ''; # D: 男性の中で全問正解したユーザ $redis->bitop('AND', 'answer:man:all:correct', @collect, 'man'); p('answer:man:all:correct'); say ''; } display()
性能評価
BITOPで集計した時の性能評価をしてみました。
環境
サーバ | EC2 |
インスタンスタイプ | c3.large |
Redis | 2.8.9 |
シナリオ:3000万人の集計
先ほどのユースケース2で「3000万人」登録し、BITOPで集計してみました。
結果ログ(Intervalを表示するように改修)
$ perl answer_summary.pl ------------------------------------ man count:14996246 woman count:15003754 answer:question1:optionA count:10003730 answer:question1:optionB count:10001089 answer:question1:optionC count:9995181 answer:question2:optionD count:9999537 answer:question2:optionE count:10002139 answer:question2:optionF count:9998324 answer:question3:optionG count:14998858 answer:question3:optionH count:15001142 ------------------------------------ ------------------------------------ answer:all:correct count:1667467 ---- 0.006544(sec) ------------------------------------ answer:man:all:correct count:833621 ---- 0.006825(sec)
BITOPの結果だけ見ると 6-7ms で終わっています。一瞬ですね。
まとめ
Redisのビットコマンドについて調査してみました。
単純なビット操作なので使い所は限られると思いますが、
Redisだけで高速な集計をしたい場合には有用ではないでしょうか。
すぐに子供の写真を見れるGoogle Chromeの拡張作った。
※元ネタはこちらです
http://soh335.hatenablog.com/entry/2013/02/10/011039
http://hisaichi5518.hatenablog.jp/entry/2013/02/01/003820
soh335さんのリポジトリをforkし、
DropboxAPIを利用してDropbox内の写真を表示するように改造してみました。
この拡張でやれること
最初は後者をやりたくて始めたんですけど、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を表示してアプリの認証を行い、
コンソールに戻ってエンターキーを押すとトークンが表示されます。
これをメモっておきましょう。
準備(写真編)
準備(Chrome編)
Chromeでタブを開く
内部説明
TumblrAPIとDropboxAPI仕様が異なる部分があるので
中でやっていることを少しだけ説明します。
- Dropbox metadata APIでフォルダ内のファイル一覧取得
- 20ファイル分のURLをDropbox thumbnail APIで取得し、blobデータをimageに変換し、DOMツリーに追加
- 下部にスクロールした時に、次の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倍以上速い!!
※以下引用
いくつかの調査をした結果,
Amazon EC2 Microインスタンスの挙動について
・直近の100秒のCPU使用率が20%を超えている場合は低速モードに移行する
・低速モードはCPU使用率の97%が使えない状態(steal)になる
とあるので、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と比較して