TECH PLAY

株式会社ZOZO

株式会社ZOZO の技術ブログ

949

はじめに こんにちは、じゃがいもの皮はもっぱらキレイにむいて食べるエンジニアの村田です。 前回のエントリ iQONのバックエンドの非同期処理について ではざっくりとした方針とかを書きましたが今回は具体的な実装方法や運用方法などについて紹介したいと思います。 使用技術 iQONではResqueという仕組みを採用して、メール送信やDBの重たい更新処理などを非同期処理しています。 ResqueはRedisにキューを出し入れして遅延処理を実現する仕組みです。シンプルだし導入しやすいと思い採用しました。 このResqueの仕組みをdaemon-spawnというgemでデーモン化して運用しています。 イメージにするとこんな感じです。 導入方法 1.Gemfileに記述 gem ' resque ' gem ' daemon-spawn ' , :require => ' daemon_spawn ' initializersにRailsの環境ごとのredisサーバのホスト設定を記述 config/initializers/load_redis_config.rb require ' resque ' if Rails .env.to_s == " production " Resque .redis = ' redis.production.iqon.jp:6379 ' elsif Rails .env.to_s == " test " Resque .redis = ' redis.test.iqon.jp:6379 ' else Resque .redis = ' redis.dev.iqon.jp:6379 ' end 3.デーモンの起動処理を記述 script/resque_worker #!/usr/bin/env ruby require File .expand_path( ' ../../config/application ' , __FILE__ ) Rails .application.require_environment! class ResqueWorkerDaemon < DaemonSpawn :: Base def start (args) @worker = Resque :: Worker .new( ' default ' ) @worker .verbose = true @worker .work end def stop end end ResqueWorkerDaemon .spawn!({ :working_dir => Rails .root, :pid_file => File .join( Rails .root, ' tmp ' , ' pids ' , ' resque_worker.pid ' ), :log_file => File .join( Rails .root, ' log ' , ' resque_worker.log ' ), :sync_log => true , :singleton => true , :signal => ' QUIT ' } ) このスクリプトにstart/stop/restartなど渡して実行することでデーモンを操作します。 例えばこんな感じです。 起動 script/resque_worker start 停止 script/resque_worker stop キューをredisにエンキューする処理を実装する エンキューする処理はcontrollerでもmodelの中でも好きなタイミングで問題ないと思います。 大切なのはどのworker(あとでキューを処理する処理、つまり非同期で動く処理)にどんなパラメータを投げるかを指定するところです。 #TestResqueWorkerにparamsを渡す Resque .enqueue( TestResqueWorker , params) キューを処理するワーカーを実装する app/worker/test_resque_worker.rb class TestResqueWorker @queue = :default def self . perform (params) #DBの更新処理やメール送信などの重たい処理を実装する end end 具体例 ここまでは導入する最低限の概要でしたが、実際のiQONでどのようにしているかを一部紹介したいと思います。 例として、コーディネートモデルからキューを発行して、コーディネートに使われている各アイテムのブランドのコーディネート数を更新していく処理を見てみます。 キューの発行 コントローラからキューを発行してみます app/controller/coordinate.rb class CoordinateController < ApplicationController def update_brand_coordinate_count #params[:brands]は123,235,12345のようにカンマ区切りの文字列が入っている Resque .enqueue( UpdateBrandCoordinateCountWorker , { :brands => params[ :brands ]}) end end キューを処理する app/worker/update_brand_coordinate_count_worker.rb class UpdateBrandCoordinateCountWorker @queue = :default def self . perform (params) brand_id_list = params[ " brands " ].split( " , " ) brand_id_list.each do | brand_id | #brandテーブルのコーディネート数を更新していく if Brand .where( :brand_id => brand_id, :delete_flag => 0 ).exists? Brand .increment_counter( :coordinate_count , brand_id) end end end end このような形でResque.enqueueで非同期で処理させたい内容(どのworkerクラスに処理させるかを第一引数に、パラメータを第二引数に設定)をキューとしてRedisにエンキューします。 それを受けてUpdateBrandCoordinateCountWorkerがパラメータを受け取り実際の処理をしていくという流れになります。 Redisサーバを用意して、Railsアプリケーションにこれだけ実装すれば非同期処理を実現できるのは手軽で便利ですね。 気をつけること ここまでで導入と具体例を紹介させて頂きましたが、実際に開発、運用をしていく上で困ったことと対応方法を紹介したいと思います。 workerが受け取るハッシュのキーはシンボルではなく文字列になる サンプルコードでも書いてありますが、キューを発行するときにシンボルをキーにしたハッシュを渡していいますが、キューを処理するworkerの中では文字列をキーにしたハッシュとしてパラメータにアクセスしています。 これはResqueがキューを入れるときに内部的にto_jsonをしているからのようです。 開発を始めたときは結構ハマったのでこれから導入を考えている方は気をつけたほうがいいと思います。 workerがキューを処理中にdaemonをリスタートした時に中断されてしまう問題 この問題も最初はハマりましたが最初に紹介させて頂いたResqueWorkerDaemon.spawnで :signal => 'QUIT' という指定することで対応できます。 これはworkerが現在処理している内容をすべて処理し終わってからworkerプロセスを終了するというオプションになります。 特定のキューだけ優先的に処理したい場合 優先度の低い重たいキューがたまりすぎると優先度の高い軽いキューが詰まってしまう問題ですね。 class FirstPriorityWorker @queue = :first_priority #省略 end class SecondPriorityWorker @queue = :second_priority #省略 end class ResqueWorkerDaemon < DaemonSpawn :: Base @worker = Resque :: Worker .new( :first_priority , :second_priority ) #省略 end このように設定するとfirst_priorityのキューを優先的に処理することが可能です。 キューに対して優先度を設定したい場合などはこのように設定すればできると思います。 最後に Resqueはかなり簡単に非同期処理を実現できるので素晴らしいのですが、なんでもかんでも非同期処理にしてしまうと問題になることもあるのでそこは見極めが必要です。 あとは前述した注意点を守れば導入はスムーズに運用していくことができるかと思います。
アバター
  こんにちは最近一日に一回は波紋のビートを刻んでる村田です。 はじめに スマートフォンアプリの開発では回線状況や端末のスペックなど様々な状況下で動作するため、少しでも高速化できる余地があるのであればなんとか頑張りたいところですよね。 今日はサーバサイドとiOSアプリの間のデータのやり取りを高速化する方法をご紹介したいと思います。 サーバサイドはRuby on Railsを前提にすすめさせて頂きます。 こんな感じでできないか? 弊社ではアプリとサーバサイドのデータのやり取りをjsonで行なっていました。 レスポンスを受け取ってからパースする部分を高速化するには? と考えたときパーサ自体を高速なものに置き換えてみたりしましたが、それよりもplistバイナリで直接やり取りすればパースをする処理が省けるので高速化できないかという仮説に達しました。 このようなイメージですね。 実際どうなのよ? いきなり結論から行きますが、高速化できました。 以下具体的な実装の一部を紹介していきます。 実装(サーバ側) Rubyでplistのデータを扱うときにはCFPropertyListというgemを使うのが簡単でいいと思います。 Ruby on Railsで使う場合Gemfileに code  gem 'CFPropertyList' /code と追記してbundle installすれば大丈夫です。 実際にサンプルのコードを書いてみました。 code require 'cfpropertylist' class SampleController < ApplicationController def index #こんな感じのレスポンスをサーバサイドから返す response_data = {:info => {:total => 100, :count => 10}, :results => [{:name => "murata", :age => 27}, {:name => "6rats", :age => 28}, ... #省略 {:name => "ozaki", :age => 15} ] } if params[:format].to_s == "plist" #plistでレスポンスを返却 plist = CFPropertyList::List.new plist.value = CFPropertyList.guess(response_data, :convert_unknown_to_string => true) render :text => plist.to_str(CFPropertyList::List::FORMAT_BINARY) else #デフォルトではjsonで返却  render :json => response_data.to_json(:root => 'response', :skip_instruct => true, :dasherize => false, :skip_types => true) end end end /code formatというパラメータにplistが指定されたときにはplistのバイナリをテキストで返すようにしてみました。 最後のテキストにする時にCFPropertyList::List::FORMAT_BINARYを指定するなど少しだけハマりかけたところも有りましたが、これで大丈夫そうです。 サーバサイドではここまで準備できれば完了です。 実装(iOS側) 次にサーバサイドからデータを受け取ったiOSアプリ側の実装になります。 code self.parsedResponse = [NSPropertyListSerialization propertyListFromData:self.responseData mutabilityOption:NSPropertyListImmutable format:nil errorDescription:&aError]; /code self.responseDataにAPIサーバからのレスポンスが入ってself.parsedResponseが実際に扱えるデータになります。 iOS側はこの部分がJSONをパースしてという処理でした。 どれくらい速くなった? 1. APIからのレスポンスのデータ量の比較 ファッションアイテムの一覧を取得するAPIのデータ量の比較 plistバイナリのものは大体16KB jsonのものは大体約30KB 通信する際の容量の点でも結構削減できました 2.iOS内での処理速度の比較 同じくファッションアイテムの一覧を取得するAPIにリクエストした時を想定して計測してみます。 今回はAPIからのレスポンスを実機で100回パース処理を行なってみました。 計測結果 大体10倍くらいは速くなっていますね。 最後に いろいろ思考錯誤を重ねましたが、少なくともこの方法は高速化に貢献できたと思います。 サーバサイドからのデータ量が少し大きくなってしまった場合に、より効果を発揮しています。 エンジニアチームではまだまだやりたいこととできていないことがたくさんあります。 技術的なチャレンジを一緒に楽しめるエンジニアを大募集しています。
アバター
こんにちはiQONのバックエンドシステムを担当している唐揚げエンジニアの村田です。 このTechブログも最後の更新から早一年が経ってしまうのでこれはヤバイと立ち上がりました。 生きてます。 さて早速本題にはいります。 はじめに iQONのバックエンドのシステムは重たい処理をしなければいけないリクエストをAPIが受けた時に、「必ずそのタイミングで処理しなければいけないもの」でない限りできるだけ非同期に処理をしてレスポンスを素早く返すように作られています。 具体的には非同期に処理する内容をキューとしてキューサーバに登録しておき、レスポンスを返してしまって、そのあとAPIとは別のプロセスがキューサーバからキューを受け取り重たい処理を実行するという流れになります。 後で実例も含めて紹介しようと思いますが、ざっと絵にすると下のような感じです。 構成 ここに登場するものを簡単に説明すると スマートフォンアプリ、Webアプリケーション - 実際にユーザに使って頂いてるアプリケーションの部分になります。iOSアプリ、Androidアプリ、Webアプリケーションだったりですね。以下アプリケーションとします。 API - アプリケーションからリクエストを受けるバックエンドシステムのAPIになります。 DBサーバ - iQONのさまざまなデータが格納されているデータベースサーバ。 キューサーバ - APIがその場で処理しない「重たい処理」をキューとして貯めこんでおくサーバです。 Workerサーバ - キューサーバに溜まった「重たい処理」を実行するサーバになります。定期的にキューの状態をチェックしてキューがあれば順番にどんどん処理をしていきます。 メールサーバ - ユーザにお知らせのメールなどを配信するサーバになります。 このような構成で非同期処理を実現しています。 実際のiQONでの使用例 ではiQONの実際の機能ではどんなところに使われているのかを実例を交えて紹介したいと思います。 iQONでひとつコーディネートを公開したら - フォローしている人たちに公開したことをお知らせ - コーディネートに使われたアイテムをお気に入りしている人にお知らせ コーディネートの公開処理以外にもこのような処理が実行されます。 フォロワーが数百人いるユーザもいれば、コーディネートに使われたアイテムが数千人からお気に入りに登録されていることもあります。 とてもじゃないですが、そのすべてを一度のAPIの処理で完了させるのは難しいですよね。 まさにこの2つのお知らせ処理をキューにして非同期処理にしています。 上記の例で絶対に非同期処理にすべきではないのがコーディネートの公開処理ですね。 非同期処理にしてしまったら、きちんとコーディネートが公開されたのかどうかをユーザがその場で知ることができなくなってしまいます。 一方でコーディネートを公開するという処理以外はその場で認識できなくてもそこまで問題ではないですから、非同期処理にすべきです。 最後に 大事なのは非同期処理にしてもいいものとそうでないものをきちんと見極めてバランスよく実装することだと思います。 なんでもかんでも非同期処理にしてレスポンスを速く返せるというのは正しくないですね。 次回はこの仕組の具体的な実装の一部や使用している技術を紹介したいと思います。 アプリもバックエンドもいろいろな技術や方法を積極的に取り入れて常に進化していけるように日々エンジニアが挑戦をしています。 VASILYでは技術的なチャレンジを一緒に楽しめるエンジニアを大募集しています。一緒にファッションの世界を変えましょう。
アバター
こんにちは、この夏はほぼ毎日ガリガリくんを食べていた村田です。 最近無意識的にガリガリ君を食べなくなったことで秋を感じつつあります。 今回のリニューアルではiQONのバックエンド(DB、WebAPI、検索、バッチ処理など)のシステムを担当しました。 今日はファッションアイテムの検索について紹介したいと思います。 Apache/Solrの採用 今回のリニューアルを機にファッションアイテムの検索にApache/Solrを採用しました。   採用に踏み切った理由として 検索速度 今までiQONではファッションアイテムの検索にMySQLを使っていました。 日に日に増えるデータ量に合わせて検索のスピードは落ちて行き、その都度対応するという苦しい日々が続きました。 単純にMySQLを使う従来のやり方よりは確実にスピードは期待出来ると思っていました。 実際にフタを開けてみると約5〜7倍の速度を確保することができたので、速度の確保に関してはうまく行ったのかなと思います。 インデックス更新の柔軟性 ファッションアイテムはユーザもしくは僕たち運営の人間の手によって日々入れ替わっていき、更新されていきます。アプリケーションから動的にインデックスを更新できるのは必須条件でした。インデックスの更新(追加、変更、削除)がシンプルにできる点でSolrは大変使いやすいと思います。事実、実際の処理ロジックに容易に組み込むことができました。 スケーラビリティの確保 Solrはマスタ、スレーブ構成をとることができるので、今後トラフィックが増えた場合にもスケールさせることはそこまで難しくないのではと思います。 導入コスト、実績 オープンソースでわりときちんとメンテナンスされていて、導入に時間や手間がそこまでかからないという点を重視しました。Solrは毎日updateされるくらい頻繁にメンテナンスされているので、安心して導入することができました。また、実際の導入についてもJavaが動く環境さえあればダウンロードして10分もあればサンプルを動かせるほど簡単に動かすことができませんでした。 以前から気になってはいたけど、いろいろな企業での導入実績を知り、導入に踏み切りました。特にRubyKaigiに行った時にCookPadのプレゼンテーションを見てやってみようと決意しました。 ファッションアイテムに関連するバックエンドシステムの構成   処理の大枠の流れ バックエンドに対するリクエストは基本的にはすべてHTTPリクエストによって行われます。 アプリケーションからリクエストを受けてからレスポンスを返すまでの簡単な流れをまとめてみると 1. Varnishにリクエスト キャッシュの設定がされているリクエストであればキャッシュを返す、それ以外のリクエストであればRailsにリクエストを受け流します。 Varnishによるキャッシュについてはまた次回以降紹介したいと思います。 2. Railsアプリケーションによる処理 MySQLやSolrからリクエストされたデータを取得して、XMLやJSONの形でレスポンスを返却します。   これらの処理を高速にするためにMemcacheを活用しています。 Solrには検索に必要なデータのみを格納し、検索処理のあとにファッションアイテムのIDでMemcacheまたはMySQLから必要なデータを取得して最終的にレスポンスとして返却しています。 おわりに キーワード検索の精度などまだ課題はたくさんありますが、検索速度の向上など得られるものもかなり多かったと思います。 次回は実際のどのようにファッションアイテムのデータが検索、追加、削除、更新されているのかをご紹介したいと思います。
アバター
みなさん、おひさしぶりです、キュン(@kyuns)です。 記事を書く時間がすっかり空いてしまい猛省... 先日iQONがリニューアルしました。 今回から数回に渡ってリニューアルまわりの記事を書きたいと思います。 まずはじめはシステムの全体的な構成についてです。 今回のリニューアルでは主に以下の点に絞ってシステムの構成を見直しました。 1.EC2インスタンスの引越し 2.Ruby化 3.内部APIモデルの採用 4.検索システムの見直し 1.EC2インスタンスの引越し 今まではAmazon EC2のUS-WEST (西海岸)で運用していたのですが今回のリニューアルにあたり EC2(東京リージョン)に変更しました。 もともとEC2の西海岸へはstaticなページでもレイテンシーが 400ms-600ms ほどあり、 不満がたまっていたところでした。 結果的に東京インスタンスへの移行は "劇的な" パフォーマンスアップにつながりました。 HA目的以外でまだ西海岸インスタンスを使っている人は今すぐにでも引っ越しするべきです。 EBS、およびS3のデータのコピー サーバー自体を東京インスタンスに移したことによりデータの保存先であるS3やEBSも東京リージョンに移行する必要がありました。 S3については名前を変えて新しく東京のバケットにつくりなおしました。 残念なことにAWSはデータを簡単に移行できるツールなどは用意してくれていないので 自前で西海岸のバケットから東京のS3バケットにコピーするスクリプトを組んで移しました。 EBSについても同様で手動でrsyncしました。 このあたりの作業は非常にめんどくさいですね。 AWSももう少しデータ移行まわりを強化してほしいです。 Cloud Frontの廃止 もうひとつ、AmazonのCDNサービスであるCloudFrontの利用も廃止しました。 今までは画像の配信にCloudFrontを使っていたのですが、S3のみのシステムに変更しました。 CloudFrontはとても便利なのですが、一度キャッシュされたものを削除するのが非常に手間だったのです。 AmazonCDNにはキャッシュを削除するAPIが用意されてはいるのですが そのAPIを実装したクライアントがほとんどないといっても過言ではありません。 現状僕が知るかぎりではCloudberryぐらいでしょうか。(しかもWindowsのみ) S3のみに変更したことによりレイテンシーが気になることは思いますが、 実際に調べてみるとCloudFront経由でS3の画像を取得した場合、一度キャッシュされた画像は 平均50msでレスポンスが返ってくるのですが、S3(東京)でもほぼ同等の速度がでており サービス運用に問題はないと判断しました。 2.Ruby化 今まではシステムのフロントエンドもバックエンドもPHPで構成されていたのですが 独自のPHPフレームワークを用いており、開発人数が増えたことにより メンテナンスおよび学習コストがかかるようになっていたのでRuby on Rails化することによって 複雑になっていた処理の見える化を行いました。 ソースコードは全てgitで管理されており、capistranoを用いてdeploy作業を行なっています。 capistranoについては以前に こちらの記事 で紹介しています。 アプリケーションサーバーはRuby1.9.2 + Rails 3.0.X + Passenger で動いています。 3.内部APIモデルの採用 内部APIモデルの採用の目的としては"データの取りだしやすさ"と"スケールのしやすさ"です。 近年Webアプリケーションではデータの加工部分のロジックは1箇所にまとめておいて データのアウトプット先がiPhoneやスマホ向けサイト等複数になってもデータを取り扱いやすいようにWebAPI化しておく いわゆる「API化」が進んでいると思います。 今回のリニューアルでもいわゆる内部APIモデルを採用しました。 データの取得、書き込みはすべてRESTfulなAPI経由で行っています。 フロントのアプリケーションサーバーにはロジックはほとんどいれず アプリケーションサーバーからAPIサーバーに対して HTTP経由で並列にデータを取得する流れになっています。 アプリケーションサーバーとAPIサーバーを切り離しているため デプロイも別々にでき、また台数も別々に増やすことができるためスケールが容易になっています。 また、キャッシュサーバーとしてMemcachedとVarnishを利用しています。 リアルタイム性が必要でかつデータの粒度が小さいものはmemcachedに入れておき 検索や一覧など、リアルタイム性のやや低いものはVarnishでレスポンスをまるごとキャッシュしています。 アイテムのデータやコーディネートの個別データなどはmemcached、検索一覧などはVarnish、といった感じです。 4.検索システムの見直し 今まではDBから検索するようにしていましたが、データ量が増え、 検索したい軸も増えてきたことにより検索エンジンを用いることにしました。 色々検討した結果、今回はAmebaやcookpadでも使われているSolrを使うことにしました。 これについては次回以降、nakedエンジニアの@6ratsが別途解説する予定です。 次回は 次回はiQONの肝であるエディター機能、および大規模JavaScript開発におけるノウハウなどを書こうと思います!
アバター
こんにちは。 VASILYのエンジニアの福本です。 前回は、 Redmineのbacklogsプラグインの概要とインストール方法 を紹介しました。 今回はインストール後の改善点について、メール設定とストーリ入力画面の改善についてご紹介します。 メール設定 SMTPにGoogleAppsを使用する VASILYではGoogleAppsを利用しているので、Redmineからのメール送信もGmailのSMTPを利用する事にします。 メール関連の設定は下記のファイルを参考に記述するのですが、親切にもGmail用の設定も雛形になっています。 redmine/config/configuration.yml.example GmailにはTLSを使用するので、いくつか作業してねと書いてあり RedmineBlog へのリンクが貼ってあります。 こちらの手順通りにやってみたいと思います。 1. TLS用プラグインのインストール Redmineのインストールディレクトリに行き、下記のコマンドを打つとインストールしてくれます。 ruby script/plugin install git://github.com/collectiveidea/action_mailer_optional_tls.git 2.設定ファイルの編集 先ほどの雛形ファイルを参考に、redmine/config/configuration.yml を作成します。 下記のようになります。 production : email_delivery : delivery_method : :smtp smtp_settings : tls : true address : "smtp.gmail.com" port : 587 domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps authentication : :plain user_name : "your_email@gmail.com" password : "your_password" 3.テストメール送信 管理者権限でログインし、管理>設定>メール通知の一番下に「テストメールを送信」というリンクがあります。 クリックすると自分のアカウントの登録メールアドレスにテストメールが送信されます。 何か問題があれば、エラーメッセージが表示されるようになっています。 これでGmailのSMTPを利用してメール送信をする事ができると思います。 非同期設定 メール送信はできるようになったのですが、バックログ管理画面やタスクボード上でのAjax操作が異様に遅くなりました。 先ほどの設定ではメール送信が同期設定になってしまっていたからです。 これだとメールが実際に送信されるまで処理が進まず、完了までに数秒待たされる事もあります。 非同期にできないかと調べていたら、やはりRedmine.JPにありました。 小技(0.9): 非同期メール送信を設定してチケット登録を高速化 (あとから雛形に書いてあるのを発見しました^^;;;ちゃんと見なきゃダメですね) 先ほどの設定のdelivery_methodのところをsmtpからasync_smtpに変更するだけです。 これで以前のパフォーマンスを取り戻しました! production : email_delivery : delivery_method : :async_smtp # ここを変更 smtp_settings : tls : true address : "smtp.gmail.com" port : 587 domain : "smtp.gmail.com" # 'your.domain.com' for GoogleApps authentication : :plain user_name : "your_email@gmail.com" password : "your_password" メール送信制御 ただ、バックログ画面やタスクボードの操作でいちいちメールが送信されるのもうざいですよね。 少し調べた限り、設定での制御はできないようです。 こちらはコードを見てみて、変更できそうであれば改修してしまおうと思います。 うまくいったら、また紹介させていただきます。 バックログ管理画面のプチ日本語対応 バックログ管理画面のストーリー入力は日本語にやさしくありません。 漢字変換を確定させるEnterで入力が確定してしまいます。 ひとまず下記のJSを修正する事で、入力確定をEnterでは無くCtrl+Enterにすることで対処しました。 redmine/vendor/plugins/redmine_backlogs/assets/javascripts/editable_inplace.js $ diff editable_inplace.js editable_inplace.js.org 23 ,26c23, 28 < if ( event.ctrlKey === true && event.which === 13 ) { // Ctrl + Enter < that.saveEdits () ; & lt ; } else if ( event.which === 27 ) { // ESC < that.cancelEdit () ; --- > switch ( event.which ) { > case 13 : that.saveEdits () ; // Enter > break ; > case 27 : that.cancelEdit () ; // ESC > break ; > default : return true ; ストーリーを入力する部分について全般的にちょっと使いかってが悪いので、時間を取って調整をしようと思っています。 またアウトプットが出てきましたらご報告します。 VASILYではエンジニアを募集しています。 一緒に変化を楽しみませんか? 詳しくは こちら をご覧ください!
アバター
はじめまして。 梅雨で頭がモジャモジャしはじめてきた天パエンジニアの福本です。 さて、VASILYではアジャイル開発の導入を進めています。 前回は、 デプロイ自動化の話 でしたが、今回はタスク管理についてです。 アジャイル開発ではストーリーカードやタスクボードなどを使用する事が多いですが、それらをWEB上で管理できるツールを導入しました。 Backlogsプラグイン アジャイル開発用のタスク管理ツールを探してみると、BacklogsというRedmineのプラグインが評判もよくシンプルで使いやすそうでした。 タスク管理にRedmineを使用していていた事もあり試してみた所、使い勝手が良かったので紹介します。 全体的な操作感としてはAjaxを多用していて直感的でサクサク動くのが気に入ってます。 プラグインを導入すると通常のプロジェクト画面にBacklogsとReleasesというタブがあらわれます。 バックログ画面 主に利用するのはバックログ画面とタスクボードで、Backlogsタブを選択するとバックログ画面に遷移します。 バックログ画面ではプロダクトバックログとスプリントバックログの管理ができます。 右側のプロダクトバックログにストーリーカードを書き出していき、上下にドラッグアンドドロップで移動させる事により優先順位の管理を行えます。 そして、スプリント計画時に左側のスプリントへドラッグアンドドロップで移動させ、スプリントの対象ストーリを決定します。 タスクボード スプリントの対象ストーリーが決まったら、タスクボード上でストーリーに対するタスクを管理していきます。 タスクカードの管理もAjaxを多用した作りになっていて、直感的にタスクの生成、割り当て、進捗の更新などができるようになっています。 その他にもバーンダウンチャートを表示したりと色々な機能があります。 まだ小さなプロジェクトで試験運用している段階ですが、また使用感など出てきましたらレポートしたいと思います。 インストール方法 使ってみたい!と思われた方のためにCentOSへのインストール手順を公開しておきます。 ストーリーカード、タスクボードの登録がうまくいかなくハマってしまうポイントがあるので是非参考にしていただければと思います。 Redmineのインストール Redmine.JPで1.2のわかりやすいインストール方法が公開されましたので、こちらを参照ください。 Redmine 1.2をCentOS5.6にインストールする手順 Redmine自体のインストールについては、Redmine.JPの 「Redmine 1.1をCentOS5.5にインストールする手順」 がとてもわかりやすいので、こちらを参照ください。 ただ最新バージョンが1.2.0に上がっているので、下記2点にご注意ください。 ・rackのバージョンが1.0.1から1.1.0に上がっている gem install rack -v=1.1.0 ・1.2.0のソース wget http://rubyforge.org/frs/download.php/74944/redmine-1.2.0.tar.gz Redmineの基本設定 Redmine上で基本的な設定を行います。 こちらもRedmin.JPの Redmineを使い始めるための初期設定 がわかりやすいので、こちらを参考に必要な設定を行ってください。 Backlogsプラグインインストール トラッカーの登録 管理者アカウントで、管理>トラッカー画面の「新しいトラッカーを作成」ボタンから、ストーリーとタスクというトラッカーを追加しておきます。 この時、「ワークフローをここからコピー」で既存にある「バグ」や「機能」を選択しておいてください。 トラッカーにワークフローが設定されていないと、ストーリーやタスクへの操作が何も許可されない状態になってしまいます。 この状態になるとストーリーカード、タスクボードの登録時にJavaScriptが正常に動かなくハマります。 必要パッケージのインストール gem install icalendar gem install prawn gem install holidays gem install open-uri-cached gem install ruby-units yum install -y libxml2 libxml2-devel libxslt libxslt-devel gem install nokogiri rmagickのインストール rmagickはちょっとややこしいですが、手順通りやっていけば大丈夫です。 ・ImageMagickのインストール yum install ImageMagick ImageMagick-devel -y ・TrueTypeFontのインストール wget http://www.mjmwired.net/resources/files/msttcorefonts-2.0-1.noarch.rpm rpm -ivh msttcorefonts-2.0-1.noarch.rpm /etc/init.d/xfs restart ln -s /usr/share/fonts/msttcorefonts /usr/share/fonts/default/TrueType ・rmagickのインストール # yumで入れられるImageMagickに対応しているバージョンまで下げる gem install rmagick -v 1.15.17 プラグインのインストール プラグインのインストールはGit経由で行います。(GitHubからDLする場合は こちらの手順 を参照してください) cd /var/lib/redmine/vendor/plugins/ git clone git://github.com/relaxdiego/redmine_backlogs.git cd redmine_backlogs git tag # バージョンのリストが表示される git checkout v0.5.2 # 最新バージョンを指定 RAILS_ENV =production export RAILS_ENV cd ../../../ rake generate_session_store rake config/initializers/session_store.rb rake db:migrate rake db:migrate:upgrade_plugin_migrations # Cannot find old migration table - assuming nothing needs to be done # と出るけど新規インストールなのでOK。 rake tmp:cache:clear rake tmp:sessions: clear rake redmine:backlogs:install # ストーリーとタスクをどのトラッカーにするか聞かれるので、先ほど作成したストーリーとタスクのトラッカーを指定します。 # ちゃんと設定されていないとストーリーカード、タスクボードの登録時にJavaScriptが正常に動かなくハマります。 チャート描画のための設定 rake redmine:backlogs:generate_chart_data /etc/init.d/httpd restart プロジェクトの作成 ここまでできれば準備完了です。 プロジェクトの設定で、モジュールのBacklogsのチェックボックスをチェックしましょう。 先ほどのようにBacklogsとReleasesというタブが表示されるはずです。 以上になります。 アジャイルさを大切にする環境で一緒に働きませんか? 詳しくは こちら をご覧ください。 参考サイト Redmine Backlogs公式ページ Redmine 1.1をCentOS5.5にインストールする手順 / Redmine.JP Blog BacklogsプラグインをMac上のRedmineにインストール / RedmineのBacklogsプラグインを入れてみた / プログラマの思索
アバター
はじめまして。 最近結婚しましたVASILYのエンジニア庄司です。 VASILY では最近、アジャイル開発を取り入れ始めました。 アジャイル開発では開発工程の早い段階でのデプロイ自動化が推奨されています。 ・開発の終盤でデプロイスクリプトを書くより安全・安心 ・自動化されていることで細かく頻繁なアップデートが可能 そこで、Rails定番で利用実績の多いCapistranoを選択しました。 今回はRailsアプリケーションの自動デプロイツールCapistranoを紹介します。 Capistranoとは Railsアプリケーションに特化したデプロイ自動化ツールです。 以下のような特徴があります。 ・Rubyで書かれたRails定番のデプロイツール ・デプロイ/リストアがコマンド一発 ・デプロイのバージョン管理 ・複数サーバにインストール可能。 ・配信先サーバには何もインストールしない。 ・配信中コケてもデプロイ実行前の状態にロールバックしてくれる。 ・git,subversion,Mercurialなどのリポジトリのデータをデプロイできる。 ・Rails以外のデプロイなどにも利用可能 (その分設定は複雑になる) 今回テストした環境 ・CentOS release 5.5 (Final) ・ruby 1.9.2p180 ・Rails 3.0.5 ・git 1.7.4 インストール方法 Gemfileに以下を追記し、bundle install を実行 #development環境にのみインストール group :development do gem ' capistrano ' end Capistranoを採用の前提条件 ・git,subversion等のSCMでソースコード管理されていること ・デプロイ先サーバにsshでログインができること デプロイの流れ 以下の流れで、gitから最新のソースコードを取得し、Railsアプリケーションを起動します。 初回の準備 $ cd /home/vasily/test_app #Rails Application Root $ capify . #capistranoのconfigファイル作成 $ vim config/deploy.rb #下記参照 $ cap deploy:setup #デプロイ先サーバに必要なフォルダを作る(初回デプロイ時のみ) デプロイ $ cap deploy #gitから取得 + Railsアプリケーション再起動 $ cap deploy:migrate #DBスキーマに変更があった場合のみ、本番DBへのmigrationを実行 deploy.rb require " bundler/capistrano " #(1) set :application , " test_app " #(2) set :scm , :git #(3) set :repository , " ssh://... " #(4) set :scm_user , “vasily” #(5) set :deploy_to , " /home/vasily/test_app " #(6) set :deploy_via , :copy #(7) set :user , " vasily " #(8) set :use_sudo , true #(9) default_run_options[ :pty ] = true #(10) role :web , " www.exampl.com " #(11) role :app , " www.exampl.com " #(12) role :db , " www.exampl.com " , :primary => true #(13) namespace :deploy do #(14) task :start do ; end task :stop do ; end task :restart , :roles => :app , :except => { :no_release => true } do run "#{ try_sudo } touch #{ File .join(current_path, ' tmp ' , ' restart.txt ' ) }" end end (1) Rails3用の設定 デプロイ後、bundle installを実行してくれます。 (2) Railsアプリケーション名 (3) リポジトリ管理ツール VASILYではgitを使用しています。 (4) リポジトリのURI (5) リポジトリユーザ名 (6) デプロイ先ディレクトリ (7) プッシュ式デプロイ デフォルトでは、デプロイ先サーバでgit cloneを行いますが、VASILYのgitリポジトリは社内ネットワーク内のサーバにあるため、本番環境からgit pullすることができません。 set :deploy_via, :copy と設定することで、git cloneしたソースコードをtarで固めてscpで配布します。 また、プッシュ式デプロイにすることで、デプロイ先サーバにgitをインストールする必要がなくなります。 (8) デプロイ先サーバにsshするユーザ (9) sudoの使用を許可するか (10) pseudo-ttyを利用するかどうか デフォルトはfalse。 リモートでsudoコマンドを実行する際に、「sudo: no tty present and no askpass program specified」というエラーが出る場合、これを設定するといいです。 (11) webサーバ 複数指定する場合は、以下のように設定します。(11), (12)も同様です。 role :web, "web01.exampl.com", “web02.exampl.com”, ... (12) デプロイ先Railsアプリケーションサーバ ほとんどの場合webサーバと同じ (13) migrateを実行するサーバ DBサーバそのものではなく、rake db:migrate を実行するサーバ (14) Railsアプリケーション再起動の設定 デフォルトではコメントアウトされていますが、Passengerを使っている場合はこのコメントを外せばいいです。 その他のcapistranoタスク cap -T でタスクを確認できます。 以下に代表的なタスクをまとめます cap deploy :cold #ソースコード配布 + migration + Railsアプリケーション起動 cap deploy :start #Railsアプリケーション起動 cap deploy :stop #Railsアプリケーション停止 cap deploy :restart #Railsアプリケーション再起動 cap deploy :rollaback #前回のdeploy前の状態にロールバック + Railsアプリケーション再起動 cap deploy :cleanup #デプロイ先の古いソースコードを最新版から5世代分(デフォルト)残して削除 デプロイ先のディレクトリ Capistranoでデプロイした先のサーバでは、バージョン管理の都合上、通常のRailsアプリケーションのディレクトリ構成とは違います。 ・releases バージョンごとのRailsアプリケーションのコードです。 ・current releases以下のいずれかのディレクトリのシンボリックリンク。通常は最新版を指します。 ・shared Railsアプリケーション内の一部のうち、ログファイルやbundlerで管理するgemパッケージなどデプロイの度に更新してほしくないファイルが置かれます。 実際のディレクトリ構成 /home/vasily/test_app/ |-- current -> /home/vasily/test_app/releases/20110603132533 |-- releases | |-- 20110530110205 .... | |-- 20110530121423 .... | |-- 20110530122100 | | |-- app | | |-- config | | |-- db | | |-- doc | | |-- lib | | |-- log -> /home/vasily/test_app/shared/log | | |-- public | | | --- system -> /home/vasily/test_app/shared/system | | |-- script | | |-- spec | | |-- tmp | | | --- pids -> /home/vasily/test_app/shared/pids | | --- vendor | --- 20110603132533 | |-- app | |-- config | |-- db | |-- doc | |-- lib | |-- log -> /home/vasily/test_app/shared/log | |-- public | | --- system -> /home/vasily/test_app/shared/system | |-- script | |-- spec | |-- tmp | | --- pids -> /home/vasily/test_app/shared/pids | --- vendor --- shared |-- bundle | --- ruby |-- log |-- pids --- system その他の機能 ・メンテナンスページへの切り替え ・独自タスクの設定 ・Railsアプリケーション以外での利用 など、便利な機能がありますが、これらはまた今後のエントリーで。 それでは!
アバター
  はじめまして、 iQON を運営しているVASILYのCTOの今村と申します。 この度サイトのリニューアルにあたり、心機一転、個性豊かなVASILYのエンジニア達による 技術ブログをはじめたいと思います。 一発目の記事ということなので簡単に弊社の環境紹介を。 弊社ではエンジニアをはじめとする全社員がMacを使っています。 Windows環境はVmwareFusion内にしかありません。 エンジニアには全員27インチのiMacが支給され、それを用いて開発を行っています。 また、自分が使いたいマウスやキーボードなども支給されます。 ちなみにVASILYのエンジニアのキーボードはRealForce派:HHKB派が4:1となっています。 僕は静音タイプのRealForceを使っています、一度慣れるともう戻れませんね。 マウスは全員トラックボールを使っています。 これも慣れるまでは大変ですが 慣れると普通のマウスにはもどれないぐらい快適です。 Realforce   トラックボールマウス     BOSEのノイズキャンセリングヘッドフォンのQC3       この3つを合わせて社内では エンジニア三種の神器 と呼んでいたりします。 労働環境については、設立当初からこだわりをもっているところですので 今後ともよりよい労働環境の追求をしていきたいと思っています。 さて、そんなVASILYでは、只今僕達と一緒に働ける仲間を募集しています。 詳しくは こちら 僕達と一緒にインターネットを使ってファッションの未来を変えていきませんか?
アバター