TECH PLAY

株式会社LIFULL

株式会社LIFULL の技術ブログ

660

こんにちは、上津原です。 先日Pepperの購入者、または購入予定者が参加できるというPepper Pioneer Club Meetupに参加してきました。 会場は、FreakOutさんのイベントスペースでした。 私はエンジニアというところで、エンジニア目線での今回のイベントで感じたことをお伝えしたいと思います。 乾杯は主役のPepperが まず最初に、恒例らしい(?)Pepperによる乾杯の音頭で始まりました。ちなみに前回はPepperによる乾杯は失敗したとのことで、今回はうまくいき、乾杯の後に拍手がわきあがりました。乾杯ができただけで拍手を受けられるPepper。しかし妙に新鮮でした。 展示されていたPepperや話を聞いて感じた事 Pepperの基本としてはもちろん「会話」が中心になります。なので、会話をしながら記念撮影をしたり、ラジコンのように操縦するスマホアプリが展示されていたり、関西弁でしゃべるPepperなどがありました。 全体を眺めながら感じた点は、まだ柔軟な会話に対応できるPepperアプリケーションを作るノウハウはそりゃあるわけないよねー、という感じでした。「はい」「いいえ」を基本にした会話だったり、数字を選ばせたり、胸元のタブレットで操作したりというかんじで。 いわゆるソフトバンクの発表会で見たようなスムーズな会話を成り立たせるというよりは、Pepper側から選択肢を人間に用意をしてあげて、思った通りのフローを踏ませるといったものが基本だし、ロジックを作る以上はそうなってしまうのはしょうがないのかなと感じます。 CMなどのおかげで、Pepper君は話しかければ大体なんか返事してくれると思っている人が大多数なので、結構その辺で開発者とユーザの間でギャップが起きたりするのでその辺をどう埋めるかというのも課題になりそうです。 まあ、Pepperくんはかわいいので、できなくても大概許してもらえちゃうんですけどね笑 次は開発者イベントがあるといいなあ 今回は「こんな風に使ってます」「作ってみました」というものが多かったので、次開催あたりではもっと開発側に突っ込んだものなどの話があるとうれしいですね。 ロボットを喋らせて、人と会話をするというのは今までソフトウェア開発をしてきてやることはなかった身としては、どうしても普通のソフトウェアに考えが偏りがちで「どうやったら話したくなるか?」「スムーズに会話が進むか?」「違和感のない生きてる感を出せるか?」などいろんなところでつまづく場面があるので、その辺をみんなで共有しあえればもっといいPepper開発につながるんじゃないかなーと思います。 しかし、MeetUpはご飯もおいしく、会場も広く非常に楽しめました。 今後の展開が楽しみです。
こんにちはAndroid開発グループ橋本です。 今回はAndroidStudioで使うlintについて調査する機会があったので内容を記事にします。(lint自体の解説は省略します。) まずは実行をしてみる。 Androidのlintの実行について調べてみると、Android/sdk/tools/の下にあるlintが使用できるようです。 参考: http://developer.android.com/intl/ja/tools/help/lint.html この方法だといちからlintのオプション設定を行わなければいけないため、とても手軽に使えるとは言い難いものです。ではどうしたらいいのか?そもそも開発はAndroid Studioを使う事を前提としていたのでそちらで実行したいところです。 Android Studioから実行 AndroidStudioから実行する場合、実はとても簡単で、メニューからAnalyze→Inspection Scopeで実行できました。 gradleをコマンドラインから実行 Android Studioで作成したprojectフォルダの下にあるgradlewを使用して、以下のコマンドでlintを実行できます。 ./gradlew (モジュール名):lint こちらの方法で実行した場合デフォルトではhtmlとxmlで出力され、実行後に成功していれば出力パスが表示されます。 lintの設定をする。 設定と実行方法はAndroid StudioのGUIに任せるか、手動で行うかのパターンがありますが。GUI上からの設定方法は他文献でいくつかあるようなので、ここでは手動設定の方法を記述します。 build.gradleの設定 作成したprojectファイルにあるbuild.gradleにlintOptionsを追記し必要な項目のオプションを必要に応じて追加する形です。 以下公式から抜粋。 android { lintOptions { // set to true to turn off analysis progress reporting by lint quiet true // if true, stop the gradle build if errors are found abortOnError false // if true, only report errors ignoreWarnings true // if true, emit full/absolute paths to files with errors (true by default) //absolutePaths true // if true, check all issues, including those that are off by default checkAllWarnings true // if true, treat all warnings as errors warningsAsErrors true // turn off checking the given issue id's disable 'TypographyFractions','TypographyQuotes' // turn on the given issue id's enable 'RtlHardcoded','RtlCompat', 'RtlEnabled' // check *only* the given issue id's check 'NewApi', 'InlinedApi' // if true, don't include source code lines in the error output noLines true // if true, show all locations for an error, do not truncate lists, etc. showAll true // Fallback lint configuration (default severities, etc.) lintConfig file("default-lint.xml") // if true, generate a text report of issues (false by default) textReport true // location to write the output; can be a file or 'stdout' textOutput 'stdout' // if true, generate an XML report for use by for example Jenkins xmlReport false // file to write report to (if not specified, defaults to lint-results.xml) xmlOutput file("lint-report.xml") // if true, generate an HTML report (with issue explanations, sourcecode, etc) htmlReport true // optional path to report (default will be lint-results.html in the builddir) htmlOutput file("lint-report.html") // set to true to have all release builds run lint on issues with severity=fatal // and abort the build (controlled by abortOnError above) if fatal issues are found checkReleaseBuilds true // Set the severity of the given issues to fatal (which means they will be // checked during release builds (even if the lint target is not included) fatal 'NewApi', 'InlineApi' // Set the severity of the given issues to error error 'Wakelock', 'TextViewEdits' // Set the severity of the given issues to warning warning 'ResourceAsColor' // Set the severity of the given issues to ignore (same as disabling the check) ignore 'TypographyQuotes' } } 一部よく使うであろうオプションについて解説します。 abortOnError falseを設定することで、build中にlintのエラーが出てもbuild自体に影響を及ぼさない(途中で停止しない)設定に出来ます。コンパイルが通るはずのソースコードをbuild中に止められてしまう可能性があるのでfalseにする事が殆どになると思います。 disable issue IDを設定することで、設定したissue IDを無視できます。実行するモジュールによってはlintが過度の検出をしてしまう為、明示的に設定しlintの検知から除外します。 lintConfig lintの設定ファイルを指定できます。パス設定はgradlewのあるフォルダと同じところからみた相対パスになります。 lintの設定ファイルの記述 基本的には.gradleで設定できる内容と同じ内容が設定できますが、lintConfigで設定したフィアルでは詳細な設定も記述できます。 参考: http://tools.android.com/tips/lint/suppressing-lint-warnings 記述方法:ファイルの個別除外とフォルダ以下全て除外の例です。 <?xml version="1.0" encoding="UTF-8"?> <lint> <issue id="all"> ① <ignore path="src/test/androidtest.java" /> ② <ignore path="src/test/**/*" /> ③ </issue> </lint> issue idを設定します。"all"を設定することで全issue idを対象に出来ます。 ignoreで除外とし、optionのpathで対象ファイルの条件を記述します。(絶対パスの記述例) 2.の相対パスの記述例 調査してみて 今回lintの調査をしてみて、まだまだ調べ切れていない感じがします。 実際に調べ設定してみて設定方法もGUIからがいいのか手動設定がいいのかの判断まではついていませんが、lintの設定だけ考えると個人的には手動がわかりやすかった印象です。 ただ、実際に運用するにあたっては、lintに検知と対応する事を考えるとAndroid StudioのGUI上から設定し修正・運用する方が良さそうでした。 おまけ Android/sdk/toolsのlintコマンドで、オプションに--listをつけ実行する事で検知できるissue idが全て見れます。予想はしていましたが種類が多いのでlint実行時に検知されたissue idの内容を調べ随時対応していくのが効率的だと思いました。
こんにちは。Android 衛藤です。 12/21(日)に Android Bazaar and Conference 2014 Winter に参加してきましたので、今回はその報告を書かせて頂きます。 私が見た講演は下記の通りです。 [開会宣言] Android Link to Next Generation! ~次なる世界を目指して~ [基調講演] 「Project Araと新しいものづくりエコシステム」 [招待講演] Android 5.0とAndroid Wearで広がる最新アプリ開発技法 [招待講演] Microsoft <3 Android [招待講演] ウェアラブルコンピューティングとAndroidの未来 loT時代における開発手法の提案~スマホの次を見据えて~ Material Designの勘所 日本から海外、そして海外から日本、アプリビジネスの海外展開の今後。 歴史は繰り返す+トレンド 裏読みで2015年のモバイルを予測する これらの中で、いくつかピックアップして内容を記したいと思います。 講演内容 Android 5.0とAndroid Wearで広がる最新アプリ開発技法 マテリアルデザイン マテリアルデザインとは異なるデバイス間で一貫した表現をするためのデザイン思想 elevation / ripple / interpolator等の効果により自然に見せる ToolBarを使用する(ActionBarよりも柔軟なカスタマイズが可能) Android Wear 新しくなったNotification。通知をスタックできたりする Watch Face API が公開された Wearアプリを公開する際はGoogle Playのアプリの [価格と販売 / 配布地域] ページで、Google Play の Android Wear コレクションに追加されるように設定することができる Notificationを出しすぎるとアンインストールされるので、本当に必要なときにのみ出すようにする これからアプリを開発するにあたって オレオレUIではなくAndroidらしいものを作る(NavigationDrawerとかActionBar/ToolBarなど) Webのコピーのようなアプリは必要ない サクサク動き、見た目が美しく、電池持ちが良いアプリを作る Android5.0についてなので、当然ながらマテリアルデザインやWearについての話題でした。 この後のマテリアルデザイン講演で詳しく聞いてきたので、詳細はそちらで記載したいと思います。 AndroidらしいUIというところも重要で、やろうと思えばいくらでもUIはカスタマイズ出来ますが、 凝りすぎると返って使いづらいものになる場合もあるので、ユーザが使い慣れたUIがよいですね。 Microsoft <3 Android タイトルの"<3"ですが、ハートを表しているようです。 内容としては Microsoftでは常に1〜3年先のものを開発している(エンジニアの部門) Researchの部門で3年以上先に出るようなものを開発している 開発体制の変更 いままではWindowsを3年単位で開発・リリースしてきたが、アジャイル開発に変えて日〜月単位での開発・リリースをするようにした Visual Studio Communityを発表。C#/C++でAndroid開発をすることができる エミュレータで加速度をエミュレート、バッテリー残量を意図的に減らしたりする事が可能 エミュレータで加速度やバッテリーをいじったりするのはgenymotionのプレミアム会員で出来るみたいですが、 無料で使えるのは魅力的かと思います。 ウェアラブルコンピューティングとAndroidの未来 神戸大学大学院 塚本昌彦教授による講演で、非常に興味深かったです。 Singularity(シンギュラリティ)についての話が冒頭に出てきており、このSingularityは日本語に訳すと特異点というらしいです。 宇宙に関する話でよく出てくるようですがICTの分野だと「技術的特異点」などと訳されます。 Singularityはすぐ近くに来る、と言われていますが、具体的には2045年問題とも呼ばれているようですね。 人工知能が人間の知能を超える時がくる・・・SFの世界のような話で少し怖いですがどうなるのでしょう。 ウェアラブルの未来はというと、 ウェアラブルは単なるバズワードでは終わらない。特に春以降大きく変化していくと思われる SmartWatch3ではWifiもハード的に搭載している スマホが大きくなりすぎたため、スマホに変わる常時身に付けているデバイスになり、単独利用が増える 企業のウェアラブル参入が増加 マルチウォッチ対応してほしい(そもそも二つもWearつける人がいるのか分からない・・・) 最初はどうしても使いづらいのが特徴だが、実世界サービスやビジネス用としてのポテンシャルを膨大に持っている 今のところは通知連携やスマホの補助的ツールとしての使い方がメインかと思いますが、 今後はWear単独での利用が予想されたり、便利なツールが出てきそうですね。 これからどの程度成長してくるかは分かりませんが、HOME'Sでいち早くWear対応出来たのは良かったかな、と思っています。 Material Designの勘所 先ほど少し触れましたが、マテリアルデザインについても聞いてみました。 マテリアルデザインは、ガイドラインというよりは異なるデバイス間でも統一した体験が出来るためのデザイン思想のことです。 少しまとめると Visual Language(視覚的言語)である 紙とインクをコンピュータの世界へ当てはめる あらゆる物体がLayer構造で表現される(Shadowなど) タッチ、ジェスチャーにおいても自然な表現を(Ripple効果など) 要するに、活版印刷の時代に築き上げられた古き良きものをデジタルの世界にも導入しようという思想のようです。 マテリアルデザインを導入するにあたっての3つの原則 1. メタファー 実際の素材のメタファーである 素材との関係を考える 紙やボタンが重なった時の影など 2. Bold, Graphic&Intentional 大胆に活き活きと、意図的に 大きめのボタン等にすることで、ユーザアクションを強調する 3. Motionで意味を提供 モーションに意味を持たせることで、ユーザ体験の継続性を持たせる また、マテリアルデザインを考える上での3つのキーワードは 1. 環境 Z軸を考える フラットデザインが主流になっているが、配置が分かりづらい そのため、光源や環境光などを取り入れ、情報同士の関係性、分かりやすさを強調する 2. 素材の属性 物質としての高さを考える 紙であれば実質的にフラットに見えるが物質として高さが0のものは存在しない 3. 3D空間でのObject配置 http://www.google.com/design/spec/what-is-material/objects-in-3d-space.html 高さが2dpの物体があり、その上に高さ6dpの物体があるなら全体で8dpの高さとなる ActionBar / Floating Action Button / Card UI全てに3D空間として配置する ここに記載したことは、全て Googleのデザインガイドライン に入っています。 とりあえず全部読んだ方が良さそうですね。(私もこれからですが・・・) 最近マテリアルデザインを導入したアプリが増えているようなので、HOME'Sでも導入してみたいです。 歴史は繰り返す+トレンド 裏読みで2015年のモバイルを予測する 携帯コレクター小暮さん&アスキーの遠藤さんによるトークセッション。 タイトル通り、これまでの変遷をもとに今後のトレンドを予測する話でした。 歴史は繰り返す これまでを見る限り、5〜10年サイクルで課金体系が変わってきている 1989年:モバイルインターネットの試行錯誤の時期 ダイヤルQ2による課金が主流 1999年:iモードの出現により課金体系がほぼ確率 2008年:iPhone, Androidの出現によりアプリ内課金が主流に これからはIoTの時代になり、いろんなモノがつながるようになってくる スマホは安定期に入ったのか? これまでもいろんな異形な端末(セッションでは変態端末と言われてました・・・)が出てはすぐに消えていった スマホも実は異形な端末の部類だが、爆発的に普及した異例かもしれない ウェアラブルの今後 ウェアラブル端末にsimが差せ、それだけで通話できるようになる。となるとガラケーの再来では? 心拍数などの身体計測系の機能はこれから欠かせなくなる。ヘルスケア機能が充実し、医療に役立つようになる。 テレビについてはどうなるのか? 現状と変わらず? または最近出てきているスマートテレビにシフト? それともただ表示するだけのモニターとなり、テレビそのものが衰退? テレビなど家電系の今後は気になりますね。 韓国でAndroid冷蔵庫が前に出たらしいですが、1年でなくなったらしいです。結構便利そうですが・・・ 話を聞いていると確かに歴史が繰り返されていると言える部分があると感じました。 これからどうなるのかは誰にも分かりませんが、このような視点での予測も面白いですね。 バザール バザールにも多数出店されていました。 サーバサイドのサービス紹介やMicrosoftのVisual Studioの紹介、Googleの秘密本配布など多数ありましたが、 その中で一点気になったのが、スマホアプリ開発技術検定試験というものがありました。 https://spkentei.jp 受講費用無料でiOS, Android, html5 CSS3などに対応しているとのことです。 学校等でも採用されているらしく、力試し受けてみてもいいかもしれません。 また会社の開発チームで受けることで技術力計測/向上にも使えそうです。 全体的に 初めてABCに参加したのですが、インターネットでの最新ニュースだけでは仕入れられないような話も聞けて、参加した価値があったと思います。 今回は、Android5.0およびAndroid Wearが発表された後に開催されただけあって、 内容もそれに関することが多かったようですね。 Android HOME'Sでも先日 Android Wear対応版 をリリースしましたが、 ウェアラブルが盛り上がって行っているようで、安心しています。 今後も最先端の技術を取り入れつつ、使い勝手の良いアプリを作っていければと思います。 また、最後の懇談会では多数の方とお名刺交換させて頂き、ありがとうございました。 じゃんけん大会でもみごと景品ゲットできたので、大満足です。 次回のABCは、2015/7/20(月・祝) 川崎振興会館にて開催とのことなので、 これからも参加していきたいと思います。
Apple原理主義者であり、Paper原理主義者でもある大坪です。 FacebookのPaperを起動してまず気がつくのがトップ画面のアニメーションでしょう。↓のビデオで親指を下から上に動かすとそれに合わせて、長方形型の写真やら文章がが「ぶわっ」と大きくなるところです。 このように特徴的なUIをもったアプリの発表から、それを再現するコードの公開までの速さには驚かされます。CocoaControlsには同じアニメーションを再現しようとしているプログラムが二つ公開されています。 HAPaperViewController MMPaper 両方とも希望をあたえてくれると共に、Facebook Paperまでの距離の遠さを思い知らされることにもなる。なぜそう考えるのか、そして私の試みがどの程度進んだのかについて書きます。 最近発表されたMMPaperの方を実際に動かしてみましょう。Facebook paperに比べていくつかの部分が気になります。 ズームするときの動きがスムーズではない(To doにもあげられていますが) 指を離した後、自動的にズームしている間、およびそのあと少しの間はジェスチャを受け付けない。つまりジェスチャが時々空振りする。 (他にもありますが、ひとまずここまで) これらの問題を できるだけ 解消することを目指しました。 ーーー コードは GitHub に置きました。実行する前に"Podfile"のあるディレクトリで"pods install"とするのを忘れないでください。 アプリを起動するとこんな風に動きます 起動すると二つボタンが並んだ画面がでてきます。"Responsive"が今回あれこれ工夫した つもり のバージョン、"Standard"が「普通に」実装したバージョンです。"Responsive"のほうが何かとスムーズに動きますよね。ね?ね?(血走った目で懇願) このデモを見てもなお読み続けてくれる心の広い方がいると信じて細かい説明をします。 ーーー Paperトップ画面の動きをみると 「これはUICollectionViewを使ったCustom Transitionだ」 と思う。さて、どのような方式で実装するか?方法は私が思いつくところでは二つあり Layout-to-layout transition(例: taktamur/PAMTransitionSample ) UICollectionViewController-to-UICollectionViewController transition(例: timarnold/UICollectionView-Transition-Demo ) ちなみに先ほど挙げたMMPaperは後者の方式で実装されています。厳密に比較したわけではないのですが、普通に実装すると UICollectionViewController-to-UICollectionViewControllerのほうがスムーズに動くようです。 私も最初UICollectionViewController-to-UICollectionViewControllerで実装したのですが、後述する理由によりLayout-to-layout を使っています。とはいえ普通に実装したのでは"Standard"を選択した時のような動きにしかならない。ではどうするか。 デモプログラムの"Standard"と"Responsive"の違いは二つで "Standard"ではイメージ表示にUIImageViewを、"Responsive"ではASImageNode(in AsyncDisplayKit )を使っている。 UIPanGestureRecognizerがUIGestureRecognizerState.Endedを返してきた後(つまりユーザがスワイプジェスチャを終了した後)"Standard"ではfinishInteractiveTransition()を呼んでいる。"Responsive"ではFacebook Popを使って終了位置までのアニメーションを制御し、その間に新たにタッチが始まった場合にはアニメーションを中断するようにしている。 他の処理は全て同一。ではどのような狙いでこのような「変更」を加えたか。 一点目、レスポンスをあげるため、ジェスチャに対応したセルの変形処理が少しでも軽くなるように、ASImageNodeを用いました。しかし正直に言えば今回のような使い方でどれだけ効果があるのかは今ひとつわかりません。触っていると、確かに少しレスポンスが良いような気がしますが、製作者の贔屓目からもしれません。 ASyncDisplayKitのページ に単にUIImageViewをASImageNodeに置き換えただけでも一部の処理がバックグラウンドで処理されるため効果がある、と記載されていますが... 二点目。"Standard"ではUIPanGestureRecognizerのコールバック関数で、UIGestureRecognizerのstateがUIGestureRecognizerState.Endedだった時にこんな処理を行っています。 if success {  self.collectionView?.finishInteractiveTransition()  self.toBeExpandedFlag = !self.toBeExpandedFlag } else{  self.collectionView?.cancelInteractiveTransition() } 遷移を完了させたければfinishInteractiveTransition()を呼び、キャンセルならばcancelInteractiveTransition()を呼ぶ。コードは簡単明瞭ですがここに問題がある。前掲のサンプルを解説しているページから引用します。 ここで注意するのは、ジェスチャーの終了からアニメーションの完了までに隙間時間(A)がある事です。progressが0.6等の半端な場合にfinishInteractiveTransitionやcancelInteractiveTransitionを呼び出すと、progress1.0になるまでアニメーションして(体感1秒程度かかるときがある)、その後にcompletionブロックが呼び出されます。 この隙間時間に次のtransitionを開始しようとするとクラッシュします。 引用元: UICollectionViewをジェスチャーで拡大縮小したい(iOS7〜) - Qiita このサンプルに習い、クラッシュを避けるため"Standard"ではジェスチャーの終了後UIGestureRecognizerを停止しています。こうすると確かにクラッシュしないのですが、その間ユーザの操作を受け付けることができない。そして時としてこのfinishInteractiveTransition()を呼んだことによるアニメーションは見かけより長くかかる。反応しない画面上をひたすらスワイプするのはどう考えても楽しくない。 というわけで"Responsive"では、ジェスチャーを終了した後のアニメーションを自前で実装しています。(参考にしたのは このサイト ) UIKitDynamicsを使っても いいとは思うのですが、ここは同じくFacebookから公開されているPopを使いました。 *1 今のプログラムは指を離してから拡大または縮小が確定するまでのわずかな時間に再度スワイプを始めた場合、進行中のアニメーションをキャンセルし、ユーザのタッチに反応します。 (わずかな例外を除いて) 正直に書きますが、まだ「不感帯」が残っておりswipeが空振りになることがある。しかし"Standard"より「マシ」になっている、というのはある程度の自信を持って言えます。いや、素直にUICollectionViewController-to-UICollectionViewControllerで実装したの(例えばMMPaper)に比べてどうなんだ、と問われると下を向いてしまいますが.. ーーー Facebook paperチームのエンジニアはプレゼンでこう述べています。 最初にiPhoneに触った時、まるで魔法のように感じた。Appleは表示するコンテンツとユーザの間にあるバリアを取り除き、ユーザが直接コンテンツを操作することを可能にしたからだ。しかしユーザのジェスチャが認識されなかったり、アニメーションが滑らかでないとそうした魔法は消え去ってしまう。 そうして作られたPaperではすべての動きが軽く、そして連続的に動く。それは初めてIPhoneの慣性スクロールに触った時と同じ驚きを与えてくれる。 今回の試みには「不感帯」の他にも大きな問題が存在しています。Paperでは縦方向の拡大ジェスチャと横方向のスクロールジェスチャを両方同時に行うことができる。今のところこれを実現させる方法がわかりません。未だ撲滅できない「不感帯」があることも考えると、ゴールははるか彼方に霞んでいるとしか思えない。 そもそもFacebookが公開したライブラリを使いながら、依然として存在しているこの距離は一体どういうことか、という根源的な問題からは目をそらし、もう少ししつこく 「魔法」 の再現に努力したいと思っています。 *1 : ちなみにUICollectionViewController-to-UICollectionViewControllerで実装すると、指を離した後のアニメーション時にUIGestureRecognizerがそもそも反応してくれません。クラッシュしないのはいいのですが、工夫のしようもない。というわけでLayout-to-layout を使っています。
大坪と申します。先日面白い記事を見つけたので紹介しつつ、つらつらと。 記事の題名は "Design Courage" 。さて、DesignといえばApple。(異論は認めません。私は視野の狭いApple原理主義者なのです)Appleが新しい製品を出すたび(あるいは出さないたび)聞こえてくる "Steve JobsがいなくなったからAppleはもうだめだ” "Steve Jobsが生きていればこんな製品は出さなかった” という声の多さには驚きます。 *1 さて、そうした人たちが言うようにSteve Jobsの存在自体がAppleを他の企業から際立たせていたものなのか?この記事の筆者は違う、と主張します。ではそれは何なのか。 The difference between Apple and many other companies comes down to one word: courage. Everyone thinks they have great ideas. Everyone thinks they’re smart. Everyone thinks they have great designers and engineers. So why is there so much difference between the best and the average? Courage. Not lip service courage, actual courage. It’s rare in software. 引用元: Design Courage — Medium 適当な訳:Appleと他の数多くの企業との違いは一語で表すことができる。「勇気」だ。誰もが自分たちはすごいアイディアを持っていると思っている。誰もが自分たちは賢いと思っている。誰もが自社にはすごいエンジニアとデザイナーがいると思っている。では「最高」と「凡庸」の差異はなんなのか。それは「勇気」だ。ただ口で言っているのではなく本当の「勇気」これはソフトウェア業界では稀なものだ。 では具体的にそれはどのような「行為」に現れてくるのか。例を考えました 未だにApple Watchの発売日は明らかにされません。例えば発売日を決めるにあたり、Appleはこんな考え方もできたはずです。 「他の企業がスマートウォッチを発売する前に売り出し、市場シェアをとってしまおう」 「今年のホリデーシーズンを逃すことはありえない。必ずその前に出荷するべきだ」 しかし彼らはそうしなかった。発売時期を遅らせても完成度を高めることを選択したのです *2 。企業に勤めている人であれば、↑のような声に逆らうことがどれだけ勇気が必要なことが想像できるのではないでしょうか。 とかなんとか考えていて別の記事を思い出しました。 Every aspect of the company's production cycle, from conception to ship date, is calculated. But--and this is a big "but"--what makes Apple different is that it is a company that is willing to move those deadlines. If a product in development isn't ready to be released, the deadline is pushed back. If an idea isn't perfect, or isn't considered truly magical and delightful internally, it's held back, revised, and the product given an entirely new launch date. 引用元: The Biggest Lesson I Learned as an Apple Designer | Inc.com 適当な訳:(Appleの)全ての製品開発サイクル-コンセプト作成から出荷まで-は計算されて設定される。しかし-この「しかし」が大きいのだが-Appleが他の企業と違うのは、そうして設定されたデッドラインを進んで変更することにある。開発中の製品がリリースされるだけの完成度になければ、期限は遅らされる。アイディアが完璧ではなかったり、真に魔法のようだったり楽しくないと考えられれば期限は伸ばされ、スケジュールは改定され、製品の発売日は全く新しく設定される。 なるほどなるほど。話しとしては面白いねえ。でも「期限を決めずに納得のいくまでがんばって!」などといっても怠けて結局何もでてこないのではないか? こうした「当然の疑問」に対して本記事はこう述べます。 That doesn’t mean your design team is always right, or deserves unchecked power. A company needs balance across all disciplines. But the reality of software development today is we put design on a pedestal right up until the moment it threatens to affect our deadline. Then design turns into an unaffordable and unreasonable luxury 引用元: Design Courage — Medium 適ry)訳:これはデザインチームがいつも正しい、とか誰もチェックできないくらいの力を持つべきだ、という意味ではない。企業は全ての面に渡ってバランスを保たなければならない。しかし昨今のソフトウェア開発現場では、デザインをありがたく奉っておき、期限が迫ってきた途端「デザインは理不尽で度を越した贅沢」扱いする。   いやいや、ビジネスなんだから期限が第一。というわけで例えば、プロダクトの開発に関して 「設定したリリース日より1ヶ月前倒しで完成した!グリフィンドールに50点 *3 」 とか 「面白いプロダクトだけど、リリースが2週間おくれちゃったね。スリザリンに-30点」 といったような評価があっても驚きません。こうした「期日を守ったか守れなかったか」を元に判断することは確かに「わかりやすい」し「定量的」でもある。しかしそうした評価方法で「真に素晴らしい製品」を作りあげることができるのか? 「リリースを2週間遅らせたことによる完成度の向上と、ビジネスへのインパクトを秤にかける」 のは難しいし、そのように考えることは確かに「勇気が要る」ことだなと考えたりします。 そんなのは自分でリリースデートを決められる立場にいるからできることだよ、という議論もあるでしょう *4 。 しかしながら、私見ではここで言われている「勇気」は開発における期限に限定されるものではない。 話が膨らみすぎたので、身の丈に戻しましょう。先日iPhone版「 へやくる! 」をリリースしました。 物件一覧画面を見ていただくとナビゲーションバーがないことに気がつくと思います。ここから左右にスワイプすれば条件設定画面、あるいは物件詳細画面がでてくるのですが、果たしてユーザがそれに気がついてくれるか?(初回起動時にインストラクションを出してはいるのですが) ここは社内でも議論になりました *5 。あれやこれやの検討の末現在の形でリリースしたわけですが、リリース後しばらく 「最初の画面から誰も移動できず、アプリがろくに使われないのではないか」 という悪夢に悩まされ続けたのも事実。素直にナビゲーションバーをつけておけばよかったか、あるいは画面遷移を示すボタンだけでもあったほうがよかったのか、とかあれこれ考えました。アプリの利用状況を見てそうした結果になっていないことを知り、最近ようやく安眠できるようになったというのは嘘です(最後の部分だけ)。 これは「Apple Watchのリリースを翌年春まで伸ばす」ことに比べれば、測定限界以下の小さな「勇気」です。しかし製品やサービスのデザイン/設計はこうした「勇気」の積み重ねでもある。小さなステップであっても「勇気」の持ちようによって最終的に表にでてくる製品/サービスは大きく変わってくるのかもしれない、と最近考えています。 *1 : 私のような人間からすると、そうやって自分の頭の中にSteve Jobsを住まわせておくことができる、というのはとてもすごいことだなあと思うのですが *2 : 実際にでてきた製品がひどい出来で「発売伸ばした挙句にこの出来かよ」と思う危険性の存在は無視します *3 : 最近子供がハリーポッターを読む年頃になったのです *4 : 皮肉なことですが、Appleはサプライヤーに対して、 非常に過酷なDeadlineを課す契約 をしていることが明らかになっています *5 : ちなみに私が愛するFacebook Paperはもっと大胆で、最初の画面を上から下にスワイプしない限り設定はおろか新たな投稿も行えないデザインになっています
こんにちは、リッテルラボラトリーの清田です。 11月19日(水)、20日(木)の2日間にわたって芝浦工業大学豊洲キャンパスで開催される WebDB Forum 2014 にて、リッテルラボラトリーのプロダクトの展示・発表を行います! WebDB Forumは、Webおよびデータベースに関する研究発表の場としては国内唯一の査読付き会議で、例年高いレベルの発表が多数行われます。 学生の方は1000円(聴講のみ)で参加できます ので、お近くの方はぜひお越しください。 常設展示ブースおよびポスターレセプションでは、リッテルラボラトリーが新たに開発した 部屋作りシミュレーション『GRID VRICK』 のデモを展示します。 LEGO(R)のブロックを組み替えるだけで、仮想3D空間内に自分好みの部屋を楽しみながら作れるというシステムです。 また、Oculus Riftを着用して、自分で作った部屋の中を自由に歩き回ることができます。ぜひ体験してみてください! 20日(木)午前中の技術報告セッションでは、『不動産・住宅情報サイトHOME’Sにおけるユーザーの「理解」と「支援」の技術』と題して、 2014年5月にリリースした『ホームズくんのこれからシアター』 の運用で得られた知見について発表します。 多数の方のご参加をお待ちしています!
こんにちは。 池田と申します。 本日は、部屋作りシミュレーションシステム「GRID VRICK(グリッドブリック)」についてご紹介しようと思います。 このシステムは、楽しみながら部屋作りを体験できるシミュレーションシステムです。 お部屋を住み替える際には、費用の問題であったり、検討の時間の問題であったり、いろいろな問題があり、結構ハードルが高いものだと思います。 ですが、部屋を住み替えるということは、新しい環境に身を置き、新しい気持ちを持ち、新しい生活を築いていく、とても楽しく素晴らしいことだと思います。 この「GRID VRICK(グリッドブリック)」ではその「楽しい!」という気持ちをより多くの人に感じてもらいたく、作成するに至りました。 今回ここで紹介するのは、LEGO(R)のブロックと組み合わせた体験の例をお伝えしたいと思います。 実際できることは以下です。 ブロックを配置し、間取り作成、家具の配置 ブロックを組み替えることで、リアルタイムに間取り、家具の更新 PC画面上で、部屋の壁紙、扉、窓、家具の種類を変更 「Oculus Rift」を着用し、部屋のウォークスルー体験 実際その流れを実際の利用風景を交えながら、ご紹介していきたいと思います。 間取り作成、家具の配置 ここでは、壁は赤いブロック、扉は薄緑のブロック、窓は青のブロックという設定がされており、このブロックの位置、大きさにより、3Dの部屋空間がPC上に再現されます。 こちらがブロックを配置しているところ。 そしてそれで再現された、3Dの部屋空間。 家具を配置したところ。 間取り、家具の更新 作成した間取り、家具は、ブロックの付け替えにより、リアルタイムで更新ができます。 左下の部屋の窓を増やしてみました。 PC上の画面はこんな感じ。 壁紙、扉、窓、家具の変更 PCの画面上で操作することで、壁紙、扉、窓、家具などを変更できます。 壁紙を変えてみました。 家具(ソファ)を変えてみました。 ウォークスルー体験 「Oculus Rift」を着用することで、 自分が作成した部屋に実際入り込んで、ウォークスルーするような体験をすることができます。 部屋の入口から入るところ。 作ったリビングルーム。 作ったトイレ。 以上が、部屋作りの体験ができるシミュレーションシステム「GRID VRICK(グリッドブリック)」です。 動作している様子は以下の動画でご覧いただけます。 LEGO(R)のブロックで作った室内をOculus Riftでウォークスルー!「GRID VRICK ... 詳細は以下からご覧ください。 「GRID VRICK」(グリッドブリック)おもちゃのブロック等で楽しみながらお部屋作り 株式会社ネクスト リッテルラボラトリー 11月23日(日)、11月24日(月)で開催されるMaker Faireに出展(東京国際展示場・西3ホール 21-6)しますので、気になった方はぜひぜひ遊びに来てください! Maker Faire Tokyo 2014 | Maker Faire Tokyo 2014 | Make: Japan Maker Faire Tokyo 2014 | Maker Faire Tokyo 2014 | Make: Japan
こんにちは。iOS開発Gの石田です。 iPhone6とiOS8が出てしばらく経ちますが、もうすでに入手されたかたも多いかと思います。 iOS8の新機能で僕が注目しているのが、Homekitです。家電をiOSデバイス経由で操作することができる機能で 寒い冬は家に帰る前にエアコンをつけておいてあったかくしておくとか、Siriに「電気消して!」と頼んだら消してくれるようになりそうです。 しかしこのHomeKitなのですが、家電がHomeKitに対応していないと使うことができません。 現状で対応している家電としては こんな室温調節器や http://lyric.honeywell.com/ こんな電球がありますが http://www2.meethue.com/ja-jp/ 海外メーカーしかなく、家電量販店などで我々が目にするメーカーはまだ対応していません。 今後対応機種が発表されていくと思いますが、現在はシミュレータで開発するしかない状況です。 そこでSiriとIRKitという赤外線学習を使えば、HomeKitなしで似たようなことができるのでは・・・と思い立ち 作ってみました。 IRKitについて IRKitとは、Wifi機能がついた赤外線リモコンで、外部からアプリを通してリモコンの信号を送ることができます。 このIRKitはAPIが公開されており、簡単に自分でアプリなどに組み込めるため、様々な方が開発を行っています。 http://getirkit.com/ これを用いれば、赤外線リモコンで操作ができる家電であれば遠隔操作することができます。また赤外線で操作できない家電でもこのようなキットをを使うことで、 家電を赤外線に対応することができます。 http://hitoriblog.com/?p=24191 iOS8でのSiriの新機能 iOS8の新機能として、「Hey! Siri」と呼びかけるとSiriが起動する機能が追加されました。 そこから質問を投げかければ、Siriが質問に答えてくれるようになっています。 ここで重要なのが、画面がロックされていても電源に繋がっている状態であればSiriが起動することです。 しかしながら現在、Siriからサードパーティ製のアプリを操作するといったことはできません。SiriのAPIは公開されていないので appleのアプリであるタイマー、アラーム、天気、メモなどの操作しかできません。 ただアプリ名を言うと、そのアプリを起動することができます。 つまり電源に繋がっているiPhoneに「Hey,Siri アプリ名」と呼びかければ、待機状態のiPhoneのアプリを起動することができるということです。 実現方法 iOS8のSiriとIRKitを組み合わせて、Siriに家電を操作してもらうようにします。 方法以下の通りです。 「電気つけて」など命令形の名前のアプリを作り、そのアプリが起動したらIRKit経由で家の電気がつくようにする。 そのアプリを「Hey Siri」で起動することにより、疑似的にSiriが家電を操作しているようになる! つまり命令の数だけアプリを作り、Siriに命令しているかのように話すと、Siriはアプリを立ち上げるのです。 ここで注意点としては、命令文のアプリを作っても起動してくれないことがあります。 例えば「テレビつけて」という名前のアプリを作って、「Hey,Siri テレビつけて」と言っても 「いいえ、それはできません」と断られてしまいます笑。これは、Siriが「テレビつけて」という言葉をちゃんと命令として 認識してしまうことが原因です。現状でこの現象が起きたのはテレビだけで、「電気つけて」や「電気消して」は大丈夫でした。 いわばSiriの認識の甘さを利用しているだけなので、Siriがもっと賢くなって命令として認識されてしまうとこの手法は使えません。 現状で命令と認識されてしまうものについては、別の言葉にするしかありません。例えば今回は、「テレビ電源」という言葉に置き換えています。 アプリについて Siriで起動して、家電を操作するアプリですが、非常にシンプルなものになります。 初回起動時のみ、家電の赤外線情報を登録する画面が出て、使いたい家電のリモコンをIRKitに向かって押し、登録します。 それ以降の起動では、Wifiに繋がっているIRKitを探し、登録されている赤外線信号を送信、その後すぐにアプリを終了します。 もちろん1アプリ1命令になるため、命令の数だけアプリを作ってiPhoneにインストールします。 IRKitの検索、信号の送信などの機能の組み込みは、SDKが公開されているので非常に簡単に行うことができました。 作って実際にやってみた https://www.youtube.com/watch?v=3df-6wTeDZY Siriで家電を操作してみた 動画では、間接照明のON・OFF、テレビON、チャンネルの変更を行っています。 割と正しく認識して、家電を操作してくれます。Siriの認識、アプリの起動、IRKitの検索、信号の受信という過程があるため、 命令してから実際に操作が完了するまでに少しラグがあります。 またテレビを付けたあとの命令の認識に特に時間がかかっています。 これはテレビの音声をSiriが拾ってしまうことが原因です。なのでチャンネル替えや音量調節といったテレビの操作は 現状では難しそうです。 最近では、テレビに音声認識機能がついたものが相次いで発売されています。リモコンに向かって、 ボタンを押している間だけ認識されるものが多いので、そういったものであれば認識は素早くできそうです。 (リモコンに向かって話しかけるくらいなら、リモコンのボタンを押した方が早いとは思いますが・・) 認識できる距離ですが、iPhoneにある程度の声量が届けば認識してくれるので、隣の部屋くらいであれば大丈夫そうです。 使い方としては、帰宅後に暗くて電気のスイッチがどこにあるのか分からないときに、暗闇に向かって命令すると 電気をつけてくれるのが便利です。 また家を出るときや帰宅後に着換えながら、テレビを消すといった使い方も便利です。手を使えない状況では重宝します。 最後に なんとか使えるレベルにはなりましたが、まだまだSiriが認識してくれるように意識して丁寧に話さないとうまくいきません。 今回作った似非HomeKitでは、「電気つけといて」「電気オン」「ライトつけて」という別名アプリをたくさん作らないと 別の言い回しには対応してくれません。 本物のHomeKitでは、もっと適当に話しても読み取ってくれる高い認識精度を期待します。 とりあえず似非HomeKitの次の機能追加としては、iBeaconを連携させることを考えています。 また本アプリは、名前だけ変えて同じアプリを複数インストールする必要があるため、iOS Developer Programの登録が必要です。 App Storeへの審査・配布は機能的に難しいと思いますので Homekitが待ち遠しい方は、ぜひIRKitを使って開発してみてください。
秋晴れがすがすがしい今日この頃ですが、いかがお過ごしでしょうか。鈴木です。 ネクストのiOS開発Gでは、9月より不定期にて外部の方を交えて 「iOS開発者向けもくもく会」を開催・運営しています。 もくもく会とは 定義は特に決まっていませんが、名前の通り、 エンジニアが集まって、プログラミングを行う、という趣旨のイベントです。 「iOS開発者向けもくもく会」の特徴 もくもくしながらも開発をもっと良くするためにみんなが行っている手法について、 プログラミングで詰まっているところなどを聞き合える雰囲気があることです。 すでに4回行い、それぞれ任意参加の懇親会も実施しています。 運営してみて 本当にいろいろなバックグラウンドのある方々とお話できる機会があり、 技術力向上はもちろん、さまざまなキャリアに触れることができます。 (例) * 普段からiOS開発をしている人 * 普段の業務とは異なる言語としてiOS開発をしている人 * 趣味でiOS開発をしている人 * 会社に属して働いている人 * フリーランスで働いている人 私は文系出身のエンジニアで、マーケティング・営業などを経験していたものの 昔からバリバリ実装型のエンジニアではありません。 似た境遇の方は、どのように学び、キャッチアップしていったのか。 逆に、学生時代からずっと開発をしていた方は何を考えているのか。 そのようなギャップを知ることで、チームの中の一員として貢献するために、 自分が埋めるべきこと、協調するべきことは何か。を自問自答するヒントになっています。 やはり、人と面と向かって話すことは学びがあり、 今の業務を幅広い視野から捉えるための活力になると思います。 告知 今後も不定期ではありますが、ネクストでは 「iOS開発者向けもくもく会」を実施していきたいと考えています。 参加条件など詳細は下記イベント告知サイトにてご確認ください。 もくもくiOS勉強会@ネクスト もくもくiOS勉強会@ネクスト 皆様の参加を心よりお待ちしています。
藤原と申します。 10/18にYahoo!さんで開催された 「iOS8/Swift エンジニア勉強会」 に参加してきました。 この勉強会の内容に関しては、既にいろんな方が書かれていたり、 スライドが公開されたりしていますので、 違った視点からこの勉強会について感じたことを書かせていただこうと思います。 知識の蓄積と適切な選択 今回の勉強会で、iOS8対応に関する様々なTipsを共有していただきましたが、これまで対応してきた中で「あるある!」と思えるようなものばかりで、やはり先行して物事を進めている印象を受けました。 特に印象に残ったのが「iOS8対応の対応方針で適切な優先順位を付けている」と感じた点です。 今回iOS7からiOS8にバージョンが上がる際に必要な対応としては、 「iOS8でアプリが動作する(落ちない)ための対応」 「iPhone6, iPhone6 Plus対応(画面サイズ変更)」 「iOS8での新機能導入」 の3つがあげられ、私達も弊社のアプリである「HOME'S」の対応を、1→2の順でやっていましたが、2.の作業に大きく時間がかかり、3.「iOS8での新機能導入」になかなかチャレンジ出来ない状態でした。 一方Yahoo!さんでは、1→3の順番で対応されていて、まず新機能を優先的に進めており、かつそれまで蓄積していた知識・見識で、短い工数で新機能の導入まで行っていました。 今後は私達も、アプリの効果を出すこと、たくさんの方に使ってもらうことを考えると、最新知識だけではなく、日々の業務におけるノウハウの蓄積を行うだけではなく、そして、適切な優先順位を付けて対応していかなければいけないと感じました。  チャレンジのスピードとモチベーション LTにおいて、正式版が出る前に1ヶ月半前にSwiftでの開発を決め、iOS8正式版リリース日に間に合わせてアプリをリリースされたお話を聞いたり、カスタムキーボードを使用した新たな試みなどの話を伺いました。 あのベータ版の状態でその決心や試みをするのは、ものすごくチャレンジングで勇気のいることだったんだろうな・・・と感じるとともに、自分達も負けていられないという印象を受けました。 日々の業務との兼ね合いというのもありますが、むしろ言ったもん勝ち、言ったからにはやります、というチャレンジ精神を常に持たなければいけないと感じました。 また、セッションをされた新卒エンジニアの方から、ベテランエンジニアの方まですごく楽しそうに話をされていて、本当に日々の業務を楽しく、ポジティブにされているんだろうな、と感じました。 これはYahoo!さんの社員の方だけではなく、社外から参加されている方にも同じ印象・熱意を受けました。   まとめ 今後、自分達が成長するために「知識の蓄積と適切な選択」「チャレンジのスピードとモチベーション」を常に意識し、「物を生み出す、手を動かすところからスタート」を実践しなければいけない、という教訓を得ることが出来ました。 エンジニアである以上、スピード感を持ってものづくりを見せていくことで、この勉強会で得た内容をフィードバック出来るよう心がけたいと思います。 今回このような貴重な機会を提供していただいた、Yahoo!様と刺激的な話をしてくださった、スピーカーの方に感謝を述べて、締めくくらせていただこうと思います。
Apple原理主義者であり、Paper原理主義者とも名乗ろうかと考えている大坪です。 Facebook paperの開発舞台裏の記事を読み「 がびーん 」となったのがほぼ半年前。アニメーションエンジンのpopにも感動したのですが、一番重要な非同期UI部品がなかなか公開されない。最初は是非使いたいと思っていたけどこれ以上待ちきれない、と見切りをつけて開発し始めたアプリが表にでた頃いきなりニュースが飛び込んできました。 The case for AsyncDisplayKit 引用元: Introducing AsyncDisplayKit: For smooth and responsive apps on iOS | Engineering Blog | Facebook Code Facebook paperを触るとすぐに気がつくことですがあの動きの滑らかさは普通ではない。裏で大量の画像をダウンロードし、デコードを行っている。であればCPUは忙しくなり、ユーザは反応の悪さにいらいらしてしまう。 For an app to maintain the gold standard of 60 frames per second, it can only use the main thread for milliseconds at a time. But main-thread-only UIKit views like UIImageView and UITextView can take tens to hundreds of milliseconds to size and display themselves. And while the main thread is decoding an image or rendering text, it can’t respond to user input or keep up with scrolling. 引用元: Introducing AsyncDisplayKit: For smooth and responsive apps on iOS | Engineering Blog | Facebook Code 適当な訳:秒間60フレームという黄金律を守ろうと思えば、メインスレッドを一度に数ミリ秒しか使うことができない。しかしメインスレッドでしか動かないUIImageViewやUITextViewなどのUIKit部品はサイズを変更し表示するのに数百ミリ秒を使ってしまう。メインスレッドが画像をデコードしたり文字を描画している間、アプリはユーザの入力を受け付けたりスクロールしたりすることができない。 しかしFacebook paperはほとんどの場合ユーザ操作に即座に反応する。なぜそういうことが可能なのか? AsyncDisplayKitはメインスレッドでしか操作できないUIViewの代わりにNodeを導入しました。 If you know how to use views, you know how to use nodes. ASImageNode and the Text Kit-powered ASTextNode can be used just like their UIKit counterparts. Unlike UIKit view hierarchies, node hierarchies for entire screenfuls of content can be initialized and laid out on background threads — and nodes make it easy to take advantage of the multicore CPUs in all current iOS devices. 引用元: Introducing AsyncDisplayKit: For smooth and responsive apps on iOS | Engineering Blog | Facebook Code 適ry)訳:Viewの使い方がわかっていれば、Nodeを使うことができる。ASImageNodeやText Kitを使ったASTextNodeはUIKitの同等部品(訳注:UIImageViewとUILabel)と同じように使うことができる。UIKitの階層と違って、Nodeの階層はバックグラウンドスレッドで作成、配置することができる。そのためNodeは最近のiOSデバイスのマルチコアCPUの利点を生かすことができる。 なるほど、わからん。 実際に動かしてみないことにはなにがなんだか、というわけでさっそくサンプルプログラムを作ったわけです。参考にしたのは 本家 のExampleプロジェクトと Startガイド です。 ーーー 最初に言い訳をいくつか。今回文字通り泡食って作ったサンプルなので正しい使い方をしているという保証はありません。おまけにSwiftを使うのも初めて、とあっていろいろおかしなところもあるかもしれませんが私はこの記事を読んでくれる方の心の広さを信じています。 さて今回作ったのはこんなアプリです。 立ち上げると二つのボタンが置かれた画面がでてくる。それぞれ押すと似たような画面に遷移する。それがどうした、と言いたくなるのをぐっと堪えましょう。遷移先の画面には子猫の写真とテキストがずらっと並んでいます。個数はそれぞれ100個。 ソースは Github におきました。Cocoapodsを使っているので、実行前に"pod install"を実行してください。 このプログラムを例えばiPhone4Sで動かすとレスポンスの違いがわかると思います。UIViewと書かれたボタンを押すと、遷移まで「ぐっ」と一呼吸間があります。AsyncNodeを押すと一瞬で遷移する。なぜこのような違いが生じているのか。 ーーー UIViewとかかれたボタンを押すと、普通のUIViewを使った画面へ遷移します。遷移先のUIViewControllerであるところのStdViewControllerを見てもらうと、loadView()の中で必要なビューを作成し、UIScrollView上にずらずら並べ、addSubviewしている。これらの処理は全てメインスレッドで行われるので、ここで時間をとってしまい画面遷移のアニメーションが「もっさり」になるわけです。 AsyncNodeと書かれたボタンを押すと、AsyncDisplayKitを使ったAsyncViewControllerに遷移する。ソースを見てみるとloadViewはこんな風になっています。 ベースとなるUIScrollViewをつけた後にGCDを使い、バックグラウンドスレッドで画面部品の作成、配置を行い、その後にメインスレッドでそれらをUIScrollViewにaddSubviewする。これによって重たい処理をメインスレッドで行うことなく画面遷移のアニメーションがスムーズに動くわけです。 StdViewControllerとAsyncViewControllerを比べてもらうとわかるのですが、処理の流れはほとんど同一です。(GCDを使っているところを除けば)しかし神とか悪魔は常に細部に宿っている。というわけで「細かいところ」を見ていきましょう。 違いその1 UIImageView,UILabelの代わりにASImageNode,ASTextNodeが使われている。 違いその2 文字列を画面幅に収める時、高さがどれだけになるかを計算する必要が有ります。 StdViewControllerでは let tSize = textView.sizeThatFits(vSize) としていますがAsyncViewControllerでは let tSize = textNode.measure(vSize) としています。このmeasureという関数は、sizeThatFitsと似ていますが、計算したサイズの値をASTextNodeのプロパティとして保存してくれる、といううれしさがあります。後で参照するのが簡単ですね。 違いその3 SDWebImageDownloaderを使って画像をダウンロードしています。そのcompletionBlockがAsyncViewControllerのほうが複雑になっています。 データが返ってきたときに、対象となるASImageNodeがロードされていた場合には、メインスレッドでイメージをセットする必要が有ります。これを抜かすとクラッシュです(何度もやったので確信を持って断言できます) 逆に言えば、これだけの修正で時間のかかる処理をバックグラウンドで行うことができる。やれありがたや。 というわけでなんとかこのライブラリをあちこちで使っていきたいと思っている今日この頃。ちょっと待て、UIControlはどうしてくれるとかStoryboardはどうするんだとかAutolayoutはこれとどう共存するのか、とかあれこれ面白い話があるのですが今回はここまで。
こんにちは、上津原です。 UE4.5が来ましたね(リリースされたと思ったらプレビューになったりしましたが) 4.4では正式機能ではなかったUMG(Unreal Motion Graphics)が正式機能として乗っかってきました。 UMGはGUIデザイナーみたいなもので、今までHUDに書いていたものをこっちに書くことでグラフィカルでお手軽にGUIを作成できるようになります。 せっかくなので以下をやって動かしてみました。 Unreal Engine | Unreal Motion Graphics (UMG)のクイック スタート ガイド ※上リンクの内容は4.4の内容なので、2のEditor Preferencesの設定は必要ないです。 上記のやつをやって初歩的な使い方がわかったので、今回はとりあえず適当な場所にボタンを置いて押せるようにしてみたいと思います。 Widgetブループリントを作る コンテンツブラウザの「新規」から「ユーザーインターフェース > Widgetブループリント」を選びます。名前は適当に(今回はButtonUIとつけました) そしてそれを開くとこんな感じに。 真ん中の青色の部分が画面サイズを示していて、これに対応するようにUIを置いていくという感じになります。 ボタンを配置して表示する 左の方にあるパレットから「Common > Button」を選び、画面にドロップします。この辺はレベル作成とおんなじですね。 ボタン配置ができたら保存して、レベルブループリントを開きます。 そしたらUserWidgetの変数を追加して以下のようにBluePrintを組みます。 まとめると、「Create Widget」をして「Add to Viewport」をするだけ。簡単です。今回はボタンなのでクリックできるようにマウスポインタを表示しています。 ここで実行すると画面にこんな感じでボタンが表示されます。 ボタンにアクションを付ける さて、これで表示はできました。 ここからボタンにアクションを付けたいわけですが、先ほど作成したWidgetブループリントに戻ってボタンを選択し、右の詳細を見ると「イベント」という項目があります。 そこの「AddOnClicked」を押すとブループリントにイベントが追加されアクションを付けられるようになります。 そしたらアクションを付けて実行してみれば動作するはずです。 一連やってみて思ったこと HUDと比べてみながらGUIの作成ができるのはとても楽だしわかりやすくていい感じです。 画面サイズを変更すると、それに応じてGUIの位置を変更してくれたりなどスマホや様々な画面サイズへの対応ができるようにもできているし、表示非表示も手軽にできているので使い勝手はとても良いと思います。 ただ、ButtonはClickしかなくてDownとReleaseを分けてアクションを付けられなかったりなどあるので今後のアップデートに期待です。 とっても簡単に伝えてきましたが、上の方で紹介した公式のURLではもっとちゃんとした説明があるのでやってみてもらえればと思います。
クリエイターの日運営委員の松尾です。 前回 と 前々回 に引き続き、第2四半期にあたる7~9月にも様々なチームが クリエイターの日を利用して、ものづくりを行いました。 今回は新卒1年目の社員が2人で進めているものづくりを紹介します。 お二人の名前と、今回の活動について教えて下さい。 東  デザインとフロントエンドのコーディングを担当した東です。普段は駆け出しのデザイナーとして、HOME'SのバナーやLPを作っています。 まずモチベーションとして、普段業務を進める上で、HOME'Sに関わる社内の皆さんが共有して追いかけられる数字が見られると、チームとしての一体感が生まれるのではないかと思いました。そこで、HOME'SのKPIの変化をリアルタイムにブラウザで見られるWebアプリを作りました。 石田  バックエンドを担当した石田です。普段の業務ではHOME'SのiOSアプリを作っています。今回はGoogle Analytics APIを使ってHOME'SのKPIの数値を10分おきに取得する仕組みを作りました。 数値がグラフで表示され、更新時にはエフェクトがかかる ※モックのため、数値は仮のものです 初挑戦ということで、苦労した部分はありますか? 東  フロントエンドでのグラフの描画や動きについて、D3.jsというライブラリを使いました。 ですが、Javascriptをまともに書いたことがなく、教本を読み進めながら作ることになりました。 集中的にがっつり時間を割けるクリエイターの日の制度がなければ出来なかったと思います。 石田  APIにアクセスする処理はPHPで記述しています。 ですが、PHPでGoogle AnalyticsのAPIを扱う情報が少なく、自身のPHPの経験も少なかったため データの取得部分にはとても苦労しました。 苦労しながらも ニヤニヤ もくもくと開発する石田 苦労しつつも成果が出ました。今後も活動しますか? 東  はい。続けます。まだ荒削りなので、次のクリエイターの日では 取れるデータを正確にして、社内で見ても違和感のないものにしたいです。 また、iPhoneやAndroidのウィジェットとして社内で見られるように、改良していきたいです。 (主に姿勢に)苦労する東 他にも感想があれば教えて下さい。 東  ほぼ知識ゼロの状態から新しいことに挑戦できたので、とても良い経験になりました。 この経験を活かして、貪欲にもっと面白いものを追求していきたいです。 石田  始める前は社内の事情も技術的なことも全然分からない状態で焦りましたが 積極的に他部署の人に聞きに行くと、大変丁寧に教えて下さり、実現できました。 社内の人たちの「利他主義」を強く感じたクリエイターの日でした。 報告会で社内でのアピールもバッチリ 2人が語ってくれたように、クリエイターの日には 参加者のキャリア(新卒やベテラン)に関わらず 普段の業務とは直接関連のないものでも 7営業日内で集中して 取り組むことができます。 ものづくりをより活発にするべく、今後もクリエイターの日を盛り上げます。
こんにちは。菊地です。 前回の記事( Android Studio でのメモリ解析の方法 - 株式会社ネクスト エンジニアBlog )で、AndroidStudioにおけるメモリ解析についてまとめましたが、今回はその補足のような記事になります。 AndroidStudio でメモリ関連の調査を行う際に便利だなと思った機能がありましたので、そちらのご紹介になります。 今回は AndroidStudio (Android DDMSかもしれませんが)にある Graphics Acceleration の情報を確認するための Graphics States ActivityManagerの状態を確認するための Activity Manager State という2つの機能について記事にさせていただきます。 ※ここからは、サンプルとして Navigation Drawer Activity を新規プロジェクトとして作成しています Graphics State どうやって使うの? AndroidStudio > Android DDMS で左側のウィンドウに表示されているパッケージ名から調べたいパッケージ名を指定します。 パッケージを指定したあと Android DDMS > System Information > Graphics States で使えます 何がみれるの? Graphics State という名前のとおり、現在のアプリにおける描画の状態が確認できます どのような描画命令が行われたのか? 描画時に使われたメモリ量(現在/最大) 描画されたViewの数、メモリおよび描画フレーム数 Applications Graphics Acceleration Info: Uptime: 610094 Realtime: 610094 ** Graphics info for pid 2096 [jp.nextgroup.myapplication] ** Recent DisplayList operations どのような描画命令が行われたかを一覧で見ることができます Recent DisplayList operations DrawDisplayList DrawPatch DrawRect DrawRect DrawRect DrawPatch DrawPatch SetupShader DrawRect ResetShader DrawDisplayList DrawDisplayList DrawDisplayList Save ClipRect DrawDisplayList DrawDisplayList RestoreToCount DrawRect Save DrawDisplayList DrawRect DrawDisplayList DrawPatch Save ClipRect Translate DrawText RestoreToCount DrawDisplayList Save ClipRect Translate DrawText RestoreToCount DrawDisplayList Save ClipRect Translate DrawText RestoreToCount RestoreToCount DrawPatch DrawDisplayList DrawPatch DrawRect DrawRect DrawRect DrawPatch DrawPatch Caches 描画命令における 現在のメモリ使用量 描画に使用された合計メモリ量 を確認することができます Caches: Current memory usage / total memory usage (bytes): TextureCache 167952 / 25165824 LayerCache 0 / 16777216 RenderBufferCache 0 / 2097152 GradientCache 0 / 524288 PathCache 0 / 10485760 TextDropShadowCache 0 / 2097152 PatchCache 1472 / 131072 FontRenderer 0 A8 524288 / 524288 FontRenderer 0 RGBA 0 / 0 FontRenderer 0 total 524288 / 524288 Other: FboCache 0 / 16 Total memory usage: 693712 bytes, 0.66 MB View Hierarchy Viewの描画に関する 描画されたViewの数 Viewの描画に使われているメモリ使用量 Viewの描画にかかったフレーム数 といった情報を見ることができます Profile data in ms: jp.nextgroup.myapplication/jp.nextgroup.myapplication.MyActivity/android.view.ViewRootImpl@52876bc0 View hierarchy: jp.nextgroup.myapplication/jp.nextgroup.myapplication.MyActivity/android.view.ViewRootImpl@52876bc0 24 views, 2.55 kB of display lists, 19 frames rendered Total ViewRootImpl: 1 Total Views: 24 Total DisplayList: 2.55 kB Activity Manager State どうやって使うの? AndroidStudio > Android DDMS で左側のウィンドウに表示されているパッケージ名から調べたいパッケージ名を指定します。 パッケージを指定したあと Android DDMS > System Information > Graphics States で使えます 何が見れるの? 現在のアプリにおける ActivityManagerの状態を見る事が出来ます Activity の情報 Activity に Attach されている Fragment Fragment の情報 Viewの階層構造 などなど Fragmentの状態なども視覚的に確認することができ、Fragmentが破棄されているのかどうか?といったことも確認することができて、とても便利でした。 TASK jp.nextgroup.myapplication id=4 ACTIVITY jp.nextgroup.myapplication/.MyActivity 52a1a528 pid=2096 Local Activity 52852ee4 State: mResumed=true mStopped=false mFinished=false mLoadersStarted=true mChangingConfigurations=false mCurrentConfig={1.0 ?mcc?mnc en_US ldltr sw360dp w360dp h567dp 480dpi nrml port finger qwerty/v/v dpad/v s.5} Active Fragments in 52852f64: #0: NavigationDrawerFragment{5287b3b8 #0 id=0x7f080002} mFragmentId=#7f080002 mContainerId=#7f080000 mTag=null mState=5 mIndex=0 mWho=android:fragment:0 mBackStackNesting=0 mAdded=true mRemoving=false mResumed=true mFromLayout=true mInLayout=true mHidden=false mDetached=false mMenuVisible=true mHasMenu=true mRetainInstance=false mRetaining=false mUserVisibleHint=true mFragmentManager=FragmentManager{52852f64 in MyActivity{52852ee4}} mActivity=jp.nextgroup.myapplication.MyActivity@52852ee4 mView=android.widget.ListView{528798c8 VFED.VC. ........ 0,0-720,1557 #7f080002 app:id/navigation_drawer} #1: PlaceholderFragment{52862068 #1 id=0x7f080001} mFragmentId=#7f080001 mContainerId=#7f080001 mTag=null mState=5 mIndex=1 mWho=android:fragment:1 mBackStackNesting=0 mAdded=true mRemoving=false mResumed=true mFromLayout=false mInLayout=false mHidden=false mDetached=false mMenuVisible=true mHasMenu=false mRetainInstance=false mRetaining=false mUserVisibleHint=true mFragmentManager=FragmentManager{52852f64 in MyActivity{52852ee4}} mActivity=jp.nextgroup.myapplication.MyActivity@52852ee4 mArguments=Bundle[{section_number=1}] mContainer=android.widget.FrameLayout{5287ad2c V.E..... ........ 0,0-1080,1557 #7f080001 app:id/container} mView=android.widget.RelativeLayout{5285b990 V.E..... ........ 0,0-1080,1557} Added Fragments: #0: NavigationDrawerFragment{5287b3b8 #0 id=0x7f080002} #1: PlaceholderFragment{52862068 #1 id=0x7f080001} Fragments Created Menus: #0: NavigationDrawerFragment{5287b3b8 #0 id=0x7f080002} FragmentManager misc state: mActivity=jp.nextgroup.myapplication.MyActivity@52852ee4 mContainer=android.app.Activity$1@52852fa0 mCurState=5 mStateSaved=false mDestroyed=false ViewRoot: mAdded=true mRemoved=false mConsumeBatchedInputScheduled=false mPendingInputEventCount=0 mProcessInputEventsScheduled=false mTraversalScheduled=false android.view.ViewRootImpl$NativePreImeInputStage: mQueueLength=0 android.view.ViewRootImpl$ImeInputStage: mQueueLength=0 android.view.ViewRootImpl$NativePostImeInputStage: mQueueLength=0 Choreographer: mFrameScheduled=false mLastFrameTime=592749 (15996 ms ago) View Hierarchy: com.android.internal.policy.impl.PhoneWindow$DecorView{52853760 V.E..... R....... 0,0-1080,1776} com.android.internal.widget.ActionBarOverlayLayout{52853f34 V.ED.... ........ 0,0-1080,1776 #1020313 android:id/action_bar_overlay_layout} android.widget.FrameLayout{52855914 V.E..... ........ 0,219-1080,1776 #1020002 android:id/content} android.support.v4.widget.DrawerLayout{528758b8 VFE..... .F...... 0,0-1080,1557 #7f080000 app:id/drawer_layout} android.widget.FrameLayout{5287ad2c V.E..... ........ 0,0-1080,1557 #7f080001 app:id/container} android.widget.RelativeLayout{5285b990 V.E..... ........ 0,0-1080,1557} android.widget.TextView{52875bc0 V.ED.... ......ID 48,48-48,105 #7f080003 app:id/section_label} android.widget.ListView{528798c8 VFED.VC. ........ 0,0-720,1557 #7f080002 app:id/navigation_drawer} android.widget.TextView{52852058 V.ED.... .....A.. 0,0-720,144 #1020014 android:id/text1} android.widget.TextView{52876384 V.ED.... ........ 0,143-720,287 #1020014 android:id/text1} android.widget.TextView{528794ac V.ED.... ........ 0,286-720,430 #1020014 android:id/text1} com.android.internal.widget.ActionBarContainer{52855b94 V.ED.... ........ 0,75-1080,219 #1020314 android:id/action_bar_container} com.android.internal.widget.ActionBarView{5285b218 V.E..... ........ 0,0-1080,144 #1020315 android:id/action_bar} android.widget.LinearLayout{5285b5b0 VFE...C. ........ 0,0-531,144} com.android.internal.widget.ActionBarView$HomeView{5285fb5c V.E..... ........ 0,0-145,144} android.widget.ImageView{5285fdb4 V.ED.... ........ 0,48-48,96 #102025a android:id/up} android.widget.ImageView{528614a4 V.ED.... ........ 37,24-133,120 #102002c android:id/home} android.widget.LinearLayout{52861ee4 V.E..... ........ 145,35-531,108} android.widget.TextView{52862120 V.ED.... ........ 0,0-362,73 #1020265 android:id/action_bar_title} android.widget.TextView{52862790 G.ED.... ......I. 0,0-0,0 #1020266 android:id/action_bar_subtitle} com.android.internal.view.menu.ActionMenuView{5284cd88 V.ED.... ........ 912,0-1080,144} com.android.internal.view.menu.ActionMenuPresenter$OverflowMenuButton{52848a78 VFED..C. ........ 0,0-168,144} com.android.internal.widget.ActionBarContextView{52862afc G.E..... ......ID 0,0-0,0 #1020316 android:id/action_context_bar} com.android.internal.widget.ActionBarContainer{528680e8 G.ED.... ......ID 0,0-0,0 #1020317 android:id/split_action_bar} Looper (main, tid 1) {5284fff0} (Total messages: 0, idling=false, quitting=false) まとめ Graphics Manager は描画命令を視覚的に確認できるほか、メモリ使用量のほか描画にかかったフレームなども見る事ができます。 そのため、 描画が遅い? と思ったときや、 なんか重くなった! 描画重い!? と嘆く前にこれを使い、実際にどういったことが行われて、どの程度の時間がかかっているのかを確認することで、少しでも操作を快適にできるかもしれません。 Activity Manager State もライフサイクルが複雑なFragmentについて、実際の状態を確認することができますし、実は裏でFragmentが生き残っていた!!なんてことも防げるようになると思います。 こういったツールも使いながら少しでもいいアプリを提供できるようにしていけたらと思います。
こんにちは、上津原です。 今回はタイトル通り、UE4にあるDynamic Global Illuminationを試してみたので、そのやり方とどんなふうに変わるかを書きたいと思います。 ※この機能は開発段階のものなので、本番環境での利用準備はできていないものです。 Global Illuminationってなんじゃ? グローバルイルミネーションとは グローバル・イルミネーション(global illumination,大域照明)は、 拡散光を正確に扱うレンダリング技法のことで、 ローカル・イルミネーション(local illumination,局所照明)の対義語。 非常に写実的、つまり物理的に正しい表現が可能である。 レンダリング方程式が考え出された時点で、理論自体は存在していたともいえるが、 当時の貧弱な計算能力や複雑な確率計算に用いるアルゴリズムの不備により、 近年になるまで注目されなかった方法である。 Wikipediaより( グローバル・イルミネーション - Wikipedia ) 僕も詳しくは言えませんが、反射光や拡散光を現実に近い感じでレンダリングしてくれるんですね。 じゃあDynamic Global Illuminationってどういうこと? グローバルイルミネーションに、ダイナミックが付きました。つまり、動的にそれらが計算されるという事です。 通常であれば、ライティングをビルドするときにライトマッピングされてそれぞれにベイクされる感じになるわけですが、これはその処理の必要なく、動的にその処理が行われるというわけです。 わー、なんかスゴそう。そして重そう。 やり方は? ① C:\Program Files\Unreal Engine\4.4\Engine\ConfigのConsoleVariables.iniを開きます。 ② [Startup]の下に「r.LightPropagationVolume=1」を書き足し、保存 ③ Unreal Edirotを開き、プロジェクトのワールド設定内の「Force No Precomputed Lighting」のチェックを外す ④ Directional LightをMovableにし、「Affect Dynamic Indirect Lighting」のチェックを入れる ⑤ おしまい! 動かすとどんな感じになる? Before After かなり違いますね~。反射光があるから中の方まで明るくなってくれて、かなり自然な表現になっています。 右の方にあるCubeのそこには、床になっている芝生の緑色が反射しているのもわかりますね。 FPSはどんなもんか? デフォルトのBP FPSプロジェクトに屋根を追加し、 エディターのビューポートでプレイした結果 Dynamic GI あり:110前後 Dynamic GI なし:115前後 という感じでした。5前後変わってきますね。 ムービーもいくつかあったので載せておきます。 ・チュートリアルムービー ・動かしてみたムービー 開発中のものなので実用性云々を言えるものではありませんが、動かしてみるのは楽しいですね。
こんにちは。Android 衛藤です。 ネクストには クリエイターの日 というものがあり、通常業務から外れて新しい技術等に取り組む機会が与えられます。 非常に魅力的なこの制度、今回初参加させていただくことになりました。 デザイナー1名とエンジニア2名、計3人での取り組みとなります。 取り組む内容 Android Wearアプリの開発 です。 新しい技術は早いうちに学びたい、と思っていたので ちょうどよい機会になりそうです。 様々なメーカーからAndroid Wearが出てきていますが、 どんな使い方が本当に便利なのか? まだ出てきたばかりなだけに、いろんな可能性を秘めているウェアラブルの世界。 今後どんな風に便利になっていくか楽しみです。 Android Wearアプリを開発するときの注意 本家のDocumentはしっかりと書かれていました。 https://developer.android.com/design/wear/index.html こちらに、開発する際のアドバイスがたくさんあります。 また、スマホやタブレットとまったく違うため、デザインに関する注意もあります。 ユーザが操作する際に他の作業を止めるようなことをしない 料理、食事、歩きながら、走りながら等、時計型デバイスは何かをしながら扱うのに最適なので、 デバイス操作のたびに他の作業を止めてしまうのはナンセンス。 たとえば、メールが来てアーカイブする、スケジュールの通知が来てスケジューラにセットする、 などの一連の操作は"5秒以内"に収める。 大き目のジェスチャーに 上記のとおり、何かをしながら操作することが多いウェアラブルデバイス。 少しでも大き目のボタンやリストを作りましょう。 カードを表示する時を第一に考える ウェアラブルは「必要なときに、必要なコンテンツを」が大切。 必要と思われるシチュエーションを整理し、どんなときに見せれば便利かを考えましょう。 あまり必要じゃない時にコンテンツを出しすぎると、ユーザにミュートされてしまいます。 一つの情報で、簡潔に できるだけ見せたい情報に絞っていきましょう。 多いと感じたら、本当にすべての情報が必要か?または複数ページに分離してしまうことを検討しましょう。 視覚的にデザインする どうすれば、ユーザがアプリから素早く情報を得て、作業にすぐに戻れるかを意識してデザインしましょう。 バックグラウンドのイメージが、見せたいメッセージを後押ししているか、など。 肩たたきしない ウェアラブルは常にユーザに触れています。 人と会話しているときに、いきなり後ろから肩を叩かれるとどう思いますか? デバイスのバイブレーションや音で同じようなことをしすぎないようにしましょう。 今回やること 機能は二つ、 通知の連携 道案内(Navigation) 二つだけなのですが、UI考えたり、実際のデバイスとの連携がどんな感じになるのか全くわからなかったため、 思い通りにいかないことが最初はほとんどでした。 何か情報がないか検索してもあまり記事が多くないため、試行錯誤しながらの開発・・・ たぶんAndroidが出たばかりの頃もこんな感じだったんでしょう。 特にUIに関してはどんな見せ方がよいのか、また実装として実現可能かの判断があまりつかず、 UIや画面遷移を考え直すこともしばしばありました。 Handheld(スマホ)とWearの連携 Handheldとペアリングさえしておけば、自動的にWearにも通知が出ます。 Wear側でボタンアクション等追加する場合は、基本的にはHandheld側でPendingIntentを発行します。 これまで通り PendingIntent.getActivity() で画面を開く、 PendingIntent.getBroadcast() でBroadcastすることが可能です。 ただし、WearアプリのActivityを開く場合はWear側からstartActivityさせる必要があります。 この辺りを最初知らないと戸惑いますが、DataApiやMessageApiを使うことで実現が可能になります。 今回実現した内容は 1. PendingIntentを仕込んだNotificationを発行(Handheld) 2. Wear側でのActionを受け取ってWearableとコネクションを張る(Handheld) 3. コネクション確立後にMessageApiを使ってWearableに送信(Handheld) 4. Wear側でメッセージ受け取ったらstartActivity()させる(Wear) 少し面倒くさい方法ですが、これくらいしか方法はなさそうです。 以下、一応サンプルコードです。 Handheld側 Handheld側からWearへ任意のパスを指定してメッセージを送る for (String node : nodes) { PendingResult<MessageApi.SendMessageResult> result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node, "/start/SampleActivity" , null ); result.setResultCallback( new ResultCallback<MessageApi.SendMessageResult>() { @Override public void onResult( final MessageApi.SendMessageResult sendMessageResult) { if (!sendMessageResult.getStatus().isSuccess()) { Log.d(LOG_TAG, "send message failed" ); } else { Log.d(LOG_TAG, "send message success" ); } } }); } いろんなサンプルだと sendMessage().await() してるのが多いですが、await使えないときはsetRersultCallbackで実装しているonResultで結果を受け取ります。 Wearable側 Wear側ではパスで判別して処理を行います。 サービスかリスナーで実装しますが、ここではWearableListenerServiceを継承したクラス内でメッセージを受け取ります。 @Override public void onMessageReceived( final MessageEvent messageEvent) { Log.d(LOG_TAG, "onMessageReceived" ); if (messageEvent.getPath().equals( "start/SampleActivity" )) { Intent intent = new Intent( this , SampleActivity. class ); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } else if (messageEvent.getPath().equals( "start/OtherPath" )) { // 他の処理 // ここからWear自身にNotification発行したり } } ちなみに、Handheld側とWearable側で同じkeystoreで署名しないとメッセージが届かないようで、少しはまりました。 それぞれのbuild.gradleで同じkeystoreを指定してしまえばOKです。 signingConfigs { debug { storeFile fle( ' キーストアのパス ' ) } } MessageApiではパスと一緒にbyte配列のデータを送信することができますが、 DataApiを使うとMapの形式で任意のデータの送信が可能です。 Wear側で出来ること onMessageReceived()やonDataChanged()で受け取ったデータをWearのActivity側に通知する場合、 受け取ったServiceからBroadcastを投げることで実現しました。 ほかにも方法はありそうです。 今回はとある場所までの道案内をカードでWear側で見せる機能があるのですが、 Activty側ではFragmentGridPagerAdapterを使用して、道案内のカードを表示させています。 また、SensorManagerも今まで通り使えるのでコンパス作ったり、自由にViewをカスタマイズすることも可能です。 ただあまり複雑なことをWearでやりすぎると、シンプルさが失われたり電池の消費が激しくなったりと、 よろしくないことがたくさんあるので、出来るだけ複雑な処理はHandheld側で行わせるようにしています。 全体を振り返り Android Wearで何ができるのかを模索しながら活動をしてきましたが、 なかなか良いものが出来上がりました。 やはり今までのAndroidとは使い勝手が違うため、 制約にはまったり、どういう見せ方がよいのか悩みどころがたくさんありましたが、 Android Wearがどんなものなのかがざっと理解できた気がします。 最初の方に書いた注意事項にもありますが、思ったより画面が小さいため見せたい情報を欲張りすぎると見づらくなるし、 複雑な操作をさせるとユーザは離れて行ってしまいます。 シンプル・簡単な操作でユーザの興味を引く、Android Wearを開発する上で一番重要になりそうだと感じました。 Android Wearはまだ新しい技術、これからどんな便利なアプリが出てくるのか楽しみです。 同時に、これからも便利なアプリをいち早く世の中に送り出していきたいと再認識させられた活動でした。
こんにちは。菊地です。 最近、Androidアプリのメモリリークの調査について行う機会があったのですが、 AndroidStudioでメモリリークの調査ってどうやるの? という話が出たので、簡単にですが AndroidStudio でメモリリークの調査をする方法について記事にします。(具体的に解析結果からメモリリーク絞り込むといったことは今回は説明しません) メモリ解析ツール これは、EclipseでAndroid開発をしていた人には、馴染み深い(?) MAT(Memory Analyzer Tool) を使います。 ただし、EclipseではPluginとして存在していますが、AndroidStudioには存在していないようです。(2014/09/30調べ) ですが、Memory Analyzer には Stand-alone が存在しているため、そちらを使います。 ダウンロードはこちら http://www.eclipse.org/mat/downloads.php MAT(Memory Analyzer Tool) の使い方 .hprof ファイルの作成 AndroidStudio の AndroidDeviceMonitor もしくは DDMS を開きます 左側のWindowからメモリを確認したいパッケージ名を探して選択します Initiate GC ボタンがあるので、押して強制的に GC を発生させます Dump Java Heap ボタンがあるので、押して Heap Dump をファイルとして出力します。  (任意の場所/ファイル名.hprof)  今回は、before.hprof, after.hprof という名前にします。 5. アプリの操作を行う 6. 上記の3〜5を繰り返します。 .hprof ファイルの解析 MAT を起動します File > Open Heap Dump > before.hprof を指定する  before.hprof ファイルが読み込まれて、ファイルが作成された時点でのメモリ状況が表示されます。 File > Open Heap Dump > after.hprof を指定する  after.hprof ファイルが読み込まれて、ファイルが作成された時点でのメモリ状況が表示されます。  MAT上に before.hprof と after.hprof の解析結果がそれぞれタブとして表示されているので、解析結果を見比べてメモリリークの疑いのあるオブジェクトを探していきます。 AndroidStudio New Memory Monitor AndroidStudio 0.8.10 から New Memory Monitor という機能が追加されました。 http://tools.android.com/recent/androidstudio0810released MAT のようにオブジェクトのメモリ状態までは調査できないようですが、 リアルタイムにメモリの使用量が確認できるようになりました。 リアルタイムなデータが視覚的にわかるようになるというだけでもだいぶ使いやすいのではないかな?と思います。 New Memory Monitor の使い方 AndroidStudio > Tools > Android > Memory Monitor で、立ち上げることができます。 Allocation Tracker Allocation Tracker とは ある時間とある時間の間を指定することで、その間にどういったオブジェクトが生成されたかを調べるツールになります。 (こちらも Eclipse の頃からあります) Allocation Tracker の使い方 AndroidStudio の AndroidDeviceMonitor もしくは DDMS を開きます 左側のWindowからメモリを確認したいパッケージ名を選択します アプリの操作を行います。 (トラッキングを開始したいタイミングになったら)Start Allocation Tracker ボタンがあるので、それを押します。 アプリの操作を行います。 (トラッキングを終了したいタイミングになったら)Start Allocation Tracker ボタンをもう一度押します。 AndroidStudio 内で、ddms○○○○.alloc というファイルが表示されます。 ddms○○○○.alloc ファイルを解析することで、どのタイミングでどういったオブジェクトが生成されているのか?ということを調べることができます。 Heap Dump と Allocation Tracker の使いどころ Heap Dump の解析を行い、メモリリークの可能性のあるクラスを絞り込んでいきます。 Allocation Tracker はメモリが確保されたタイミングを調べることが可能ですので メモリリークの可能性のあるクラスの中からどのオブジェクトなのかといった絞り込みに有効です。 まとめ AndroidStudio でメモリ解析を行うためのツールの導入方法について説明しました。 Heap Dump の解析、Allocation Trackerなどについて触れました。 今後は、AndroidStudio でリアルタイムにメモリ使用状態を確認できるようになりそうです。 今回は、メモリの節約という基本的な内容ですが、アプリを使っていただいているときに落ちないようにするために重要なポイントだと思っています。 今後も、様々な面でこだわっていいアプリの開発が出来ればと思っています。
こんにちは。新規事業本部・金融グループの金(成奉)です。 前回( PHPコンパイルによる高性能のFastCGIウェブサーバー構築とチューニングに関するお話し(2) - 株式会社ネクスト エンジニアBlog )に引き続き、FastCGI基盤ウェブサーバーのPHPコンパイル構築、チューニング、設定などについてお話したいと思います。 PHPビルド後の簡単な作動確認について テストは「make test」できますが、時間がかかるため、コンパイル・ビルドができているかを確認するため、以下のコマンドを実行して、エラーにならなければ、ビルド構築は成功です。 モジュール確認 php -i | less CGI作動確認 HTMLで出力されます。 php-cgi -i >php_info.htm コマンドラインでの作動確認 エラーなしで、実行できれば、正常にモジュールがロードされて、インストールは完了です。エラーの場合は、ソース修正またはオプションを変更して再コンパイルする必要がある。 php -r 'echo "テスト\n";' php -r 'echo time()."\n";' php -r 'echo md5('test')."\n";' PHP-FastCGIプロセスサーバ(php-fpm)確認 単体では確認できないため、Apacheの設定またはNginxをインストールしてから確認します。 ApacheとPHPモジュール設定(PHP検証のため臨時設定) Apacheとの比較のための臨時設定 サーバネーム追加 echo "ServerName localhost" >> /etc/httpd/conf.d/servername.conf PHPインストール時にApache設定に自動的に追加されるPHPモジュールのコメントにします sed -i 's/LoadModule php5_module/\#LoadModule php5_module/g;' /etc/httpd/conf/httpd.conf PHPモジュールの設定(拡張子:php) cat > "/etc/httpd/conf.d/php.conf" << EOF LoadModule php5_module modules/libphp5.so AddType application/x-httpd-php .php EOF PHPのApacheでの動作確認 cat > "/var/www/html/info_test.php" <<EOF <?php echo phpinfo(); ?> EOF Apache Service Start service httpd start w3mでの確認 yum install -y w3m w3m http://www.example.com/info_test.php w3m終了 Q Apache Bench(apache2+mod_php) PHPモジュールはPreforkモデルでしか動作しません。phpinfo()のベンチマークです。 測定 ab -n 10000 -c 200 http://www.example.com/info_test.php This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.example.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Apache Server Hostname: www.example.com Server Port: 80 Document Path: /info_test.php Document Length: 95999 bytes Concurrency Level: 200 Time taken for tests: 19.618 seconds Complete requests: 10000 Failed requests: 9980 (Connect: 0, Receive: 0, Length: 9980, Exceptions: 0) Write errors: 0 Total transferred: 964672277 bytes HTML transferred: 963357692 bytes Requests per second: 509.72 [#/sec] (mean) Time per request: 392.369 [ms] (mean) Time per request: 1.962 [ms] (mean, across all concurrent requests) Transfer rate: 48019.25 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 37 37.3 26 146 Processing: 13 354 58.5 357 625 Waiting: 3 203 143.0 142 553 Total: 26 391 51.3 388 629 Percentage of the requests served within a certain time (ms) 50% 388 66% 397 75% 406 80% 414 90% 448 95% 477 98% 501 99% 514 100% 629 (longest request) Apache Service Stop service httpd stop mod_fastcgiインストール ソースダウンロード cd /opt/src wget http://www.fastcgi.com/dist/mod_fastcgi-current.tar.gz 解凍とコンパイル tar zxvf mod_fastcgi-current.tar.gz cd mod_fastcgi-2.4.6/ cp Makefile.AP2 Makefile make top_dir=/usr/lib64/httpd make install top_dir=/usr/lib64/httpd インストールバイナリ確認 ldd /usr/lib64/httpd/modules/mod_fastcgi.so linux-vdso.so.1 => (0x00007ffffeeea000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f478e38c000) libc.so.6 => /lib64/libc.so.6 (0x00007f478dff8000) /lib64/ld-linux-x86-64.so.2 (0x0000003b69000000) Apache2/FastCGI設定(PHP-FPM) 性能比較のために拡張子を臨時的に「.fphp」に設定しています。本番運用時には「.php」に戻します。Location設定は、URLへのダイレクトアクセスを防ぐ内容です。Action内部でリダイレクトした後、fcgi-binのURLが使えるようにするために「env=REDIRECT_STATUS」を設定します。 cat > "/etc/httpd/conf.d/php-fpm.conf" <<'EOF' LoadModule fastcgi_module modules/mod_fastcgi.so <FilesMatch "\.(fphp|html)$"> SetHandler application/x-httpd-php </FilesMatch> Action application/x-httpd-php /fcgi-bin/php-fpm virtual Alias /fcgi-bin/php-fpm /fcgi-bin-php-fpm <Location /fcgi-bin/php-fpm> Order Deny,Allow Deny from All Allow from env=REDIRECT_STATUS </Location> FastCgiExternalServer /fcgi-bin-php-fpm -appConnTimeout 10 -idle-timeout 250 -socket /var/run/php-fpm.sock -pass-header Authorization EOF ★重要★上記設定で「-appConnTimeout 10 -idle-timeout 250」は必ず設定するようにします。idele-timeoutはデフォルトで30秒になっていますが、場合によっては十分ではないため長く設定しておきます。「FastCGI: incomplete headers (0 bytes) received....」というエラーが吐出され、応答しなくなるケースがまれにあります。このエラーが発生した際は、「-idle-timeout」の時間をもっと長く設定することで解消できます。詳細の内容は以下のサイトを参照してください。 FastCGI設定マニュアル: http://www.fastcgi.com/mod_fastcgi/docs/mod_fastcgi.html PHP-FPMサービス確認と登録 サービス動作テスト service php-fpm start service php-fpm stop サービスに追加テスト chkconfig php-fpm on サービスから削除テスト chkconfig php-fpm off サービス確認 chkconfig --list php-fpm php-fpm 0:off 1:off 2:off 3:off 4:off 5:off 6:off サービス登録 chkconfig php-fpm on PHP-FPM設定 グローバルとプール設定に分けます。多くの設定オプションがありますが、下記のように短く設定しても問題はありません。FastCGIのプロセスについては、固定(static)での設定を推奨します。 Apache-1.3の初期バージョンから、FastCGIを使ってみましたが、ダイナミック(dynamic)での設定では、様々なトラブルに遭遇した経験があります。FastCGIプロセスは、待ち受けるプロセスであるため、メモリリークを注意しなければなりません。PHP-FPMでリクエストの最大数(pm.max_requests )を設定していれば、自動で子プロセスをリスタートしてくれる機能があり、メモリリークを防ぎます。メモリの状況を確認しながら、固定(static)で立ち上げる子プロセス数を決定します。 設定時に注意しなければならないのは、デフォルトで生成されたソケットファイルにはapacheまたはnginx権限ではアクセスできないため、listen.modeで権限を0666にする必要があります。2Gメモリのマシーンでプロセス数を100にしても問題なく動作確認できました。サイトによって異なりますのでHTOPをインストールしてメモリの使用率を見ながら調整します。ププロセス数固定(static)の設定では一度ロードされると固定でメモリを確保します。ダイナミック(dynamic)の設定では、メモリの使用率が設定範囲内でアクセス数によって変動します。 php-fpm.conf設定 mkdir /etc/fpm.d rm -f /etc/php-fpm.conf グローバル設定 cat > "/etc/php-fpm.conf" <<EOF [global] pid = run/php-fpm.pid error_log = log/php-fpm.log log_level = notice daemonize = yes include=/etc/fpm.d/*.conf EOF プールの設定(Apache検証用権限) Apacheの場合は下の設定に切り替えて検証します。 cat > "/etc/fpm.d/www.conf" <<'EOF' [apache] user = apache group = apache listen = /var/run/php-fpm.sock listen.mode = 0666 pm = static pm.max_children = 100 pm.max_requests = 1000 security.limit_extensions = .php .fphp .html .htm EOF プールの設定(Nginx検証用権限) Nginxの場合は下の設定に切り替えて検証します。 cat > "/etc/fpm.d/www.conf" <<'EOF' [nginx] user = nginx group = nginx listen = /var/run/php-fpm.sock listen.mode = 0666 pm = static pm.max_children = 100 pm.max_requests = 1000 security.limit_extensions = .php .fphp .html .htm EOF php動作テストファイル作成 cat > "/var/www/html/info_test.php" <<EOF <?php echo phpinfo(); ?> EOF Apache Bench(apache prefork + php-fpm) PHP-FPMは、ソケット、スタティックプロセス設定で、ApacheのMPMは、preforkでベンチマークを行いました。手順は、上記の設定を反映してから、PHPモジュールをApacheから外してから保存、Apacheサービスを再起動します。 Apache(prefork)+php-fpm(socket,static) PHPモジュール外し sed -i 's/LoadModule/\#LoadModule/g;' /etc/httpd/conf.d/php.conf sed -i 's/AddType/\#AddType/g;' /etc/httpd/conf.d/php.conf サービス再起動 servie httpd restart 測定 ab -n 10000 -c 200 http://www.mhoken.com/info_test.fphp This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.mhoken.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Apache Server Hostname: www.mhoken.com Server Port: 80 Document Path: /info_test.fphp Document Length: 93626 bytes Concurrency Level: 200 Time taken for tests: 17.830 seconds Complete requests: 10000 Failed requests: 9052 (Connect: 0, Receive: 0, Length: 9052, Exceptions: 0) Write errors: 0 Total transferred: 939760915 bytes HTML transferred: 938447640 bytes Requests per second: 560.84 [#/sec] (mean) Time per request: 356.605 [ms] (mean) Time per request: 1.783 [ms] (mean, across all concurrent requests) Transfer rate: 51470.65 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 2 59 33.6 54 281 Processing: 57 297 37.8 300 379 Waiting: 2 61 30.7 58 281 Total: 108 356 35.8 351 644 Percentage of the requests served within a certain time (ms) 50% 351 66% 360 75% 366 80% 372 90% 387 95% 398 98% 413 99% 506 100% 644 (longest request) Apache Bench(apache worker + php-fpm) MPMをWorkerに切り替えてから、Apacheサービスを再起動します。ApacheにはPHPモジュールがロードされないように注意します。デフォルト設定では四つのWorkerが起動します。 Apache(worker)+php-fpm(socket,static) ApacheのPHPモジュール外し sed -i 's/LoadModule/\#LoadModule/g;' /etc/httpd/conf.d/php.conf sed -i 's/AddType/\#AddType/g;' /etc/httpd/conf.d/php.conf Apacheのworkerへの切り替え設定 sed -i 's/\#HTTPD=/HTTPD=/g;' /etc/sysconfig/httpd サービス再起動 servie httpd restart 測定 ab -n 10000 -c 200 http://www.example.com/info_test.fphp This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.example.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: Apache Server Hostname: www.example.com Server Port: 80 Document Path: /info_test.fphp Document Length: 93622 bytes Concurrency Level: 200 Time taken for tests: 16.813 seconds Complete requests: 10000 Failed requests: 10012 (Connect: 0, Receive: 0, Length: 10012, Exceptions: 0) Write errors: 0 Total transferred: 941082361 bytes HTML transferred: 939767383 bytes Requests per second: 594.79 [#/sec] (mean) Time per request: 336.255 [ms] (mean) Time per request: 1.681 [ms] (mean, across all concurrent requests) Transfer rate: 54662.48 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 1 64 33.0 62 188 Processing: 77 271 37.7 272 448 Waiting: 1 80 51.7 69 329 Total: 146 335 31.3 329 566 Percentage of the requests served within a certain time (ms) 50% 329 66% 335 75% 339 80% 345 90% 373 95% 394 98% 417 99% 435 100% 566 (longest request) Apacheの検証結果 ベンチマーク結果の「Failed requests」は、無視します。理由は、HTTPからアクセスして「phpinfo();」を出力すると毎回サイズが異なります。このサイズが異なる時には「Failed requests」になるようです。PHPの運用は、上記の検証のようにApacheでの基本構成は、「Apache(worker) + PHP-FPM(FastCGI)」が一番良いパフォーマンスが出ています。 Nginxコンパイル構築 nginxの依存性にあるライブラリーのインストール yum -y install GeoIP-devel.x86_64 yum -y install bxslt-devel.x86_64 yum -y install perl-ExtUtils-Embed.x86_64 yum -y install pcre-devel.x86_64 RPM-GPG-KEYのインポート rpm --import http://mirror.centos.org/centos/6.5/os/x86_64/RPM-GPG-KEY-CentOS-6 Nginxの最新安定版のインストール rpm -i http://nginx.org/packages/centos/6/x86_64/RPMS/nginx-1.6.0-1.el6.ngx.x86_64.rpm RPMのインストールディレクトリ確認 rpm -ql nginx /etc/logrotate.d/nginx /etc/nginx /etc/nginx/conf.d /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/example_ssl.conf /etc/nginx/fastcgi_params /etc/nginx/koi-utf /etc/nginx/koi-win /etc/nginx/mime.types /etc/nginx/nginx.conf /etc/nginx/scgi_params /etc/nginx/uwsgi_params /etc/nginx/win-utf /etc/rc.d/init.d/nginx /etc/sysconfig/nginx /usr/sbin/nginx /usr/share/nginx /usr/share/nginx/html /usr/share/nginx/html/50x.html /usr/share/nginx/html/index.html /var/cache/nginx /var/log/nginx RPMでインストールした理由は、各種設定ファイルを自動で配置させるためです。後は、ソースからダウンロードしてGoogle開発のオープンソース「ngx_pagespeed」をサポートできるようにコンパイルしてから実行バイナリ「/usr/sbin/nginx」を差し替えます。 Nginx及びソースダウンロード cd /opt/src wget -q http://nginx.org/download/nginx-1.6.0.tar.gz tar zxvf nginx-1.6.0.tar.gz wget -q https://github.com/pagespeed/ngx_pagespeed/archive/v1.8.31.4-beta.zip -O ngx_pagespeed-1.8.31.4-beta.zip unzip ngx_pagespeed-1.8.31.4-beta.zip cd ngx_pagespeed-1.8.31.4-beta/ wget -q https://dl.google.com/dl/page-speed/psol/1.8.31.4.tar.gz tar -xzvf 1.8.31.4.tar.gz コンパイル設定 コンパイルオプションの確認は既存RPMでインストールされているものと同じ構成にするため「nginx -V」コマンドで確認してpgespeedモジュールを最後に追加すします。 cd /opt/src/nginx-1.6.0 ./configure --prefix=/etc/nginx \ --sbin-path=/usr/sbin/nginx \ --conf-path=/etc/nginx/nginx.conf \ --error-log-path=/var/log/nginx/error.log \ --http-log-path=/var/log/nginx/access.log \ --pid-path=/var/run/nginx.pid \ --lock-path=/var/run/nginx.lock \ --http-client-body-temp-path=/var/cache/nginx/client_temp \ --http-proxy-temp-path=/var/cache/nginx/proxy_temp \ --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \ --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \ --http-scgi-temp-path=/var/cache/nginx/scgi_temp \ --user=nginx --group=nginx \ --with-http_ssl_module \ --with-http_realip_module \ --with-http_addition_module \ --with-http_sub_module \ --with-http_dav_module \ --with-http_flv_module \ --with-http_mp4_module \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_random_index_module \ --with-http_secure_link_module \ --with-http_stub_status_module \ --with-http_auth_request_module \ --with-http_xslt_module \ --with-http_image_filter_module \ --with-http_degradation_module \ --with-mail \ --with-mail_ssl_module \ --with-file-aio \ --with-ipv6 \ --with-http_spdy_module \ --with-cc-opt='-O2 -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' \ --with-ld-opt=' -Wl,-E' \ --add-module=/opt/src/ngx_pagespeed-1.8.31.4-beta コンパイル make -j10 既存バイナリ上書き \cp objs/nginx /usr/sbin/nginx Nginx設定(検証のため臨時簡単設定) Nginx基本設定 worker_processesはCPUのコア数を設定します。 既存設定バックアップ \cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf_backup 設定ファイル上書き cat > "/etc/nginx/nginx.conf"<< 'EOF' user nginx; worker_processes 3; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; events { worker_connections 1024; } http { include /etc/nginx/mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; keepalive_requests 100; keepalive_timeout 10; gzip on; gzip_static on; gzip_comp_level 2; gzip_buffers 64 8k; gzip_min_length 1100; gzip_types text/plain text/xml text/css application/xml application/xhtml+xml application/rss+xml application/atom_xml application/javascript application/x-javascript application/x-httpd-php; gzip_disable "MSIE [1-6]\."; gzip_disable "Mozilla/4"; gzip_vary on; gzip_proxied any; gzip_http_version 1.1; server_tokens off; include /etc/nginx/conf.d/*.conf; } EOF Nginxサーバ設定 既存Apacheベンチマークディレクトリをそのまま設定してベンチマークを行います。 \cp /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf_backup cat > "/etc/nginx/conf.d/default.conf" <<'EOF' server { listen 80; server_name localhost; location / { root /var/www/html/; index index.php; try_files $uri $uri/ /index.php?$uri&$args; } location ~ \.php$ { root /var/www/html/; fastcgi_pass unix:/var/run/php-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param QUERY_STRING $query_string; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param HTTPS $https; fastcgi_buffer_size 128k; fastcgi_buffers 256 16k; #4096k total fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_max_temp_file_size 0; #disable buffering to disk client_max_body_size 0; #Allow large uploads } } EOF Apache Bench(nginx + php-fpm) Apacheとほぼ同じ設定になります。「gzip on」の方が「gzip off」より少し遅くなりますが、ほぼ変わらなかったため、「gzip on」の状態で測定しました。 ab -n 10000 -c 200 http://www.example.com/info_test.php This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking www.mhoken.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: nginx Server Hostname: www.example.com Server Port: 80 Document Path: /info_test.php Document Length: 93219 bytes Concurrency Level: 200 Time taken for tests: 14.597 seconds Complete requests: 10000 Failed requests: 1024 (Connect: 0, Receive: 0, Length: 1024, Exceptions: 0) Write errors: 0 Total transferred: 939682063 bytes HTML transferred: 938292127 bytes Requests per second: 685.07 [#/sec] (mean) Time per request: 291.940 [ms] (mean) Time per request: 1.460 [ms] (mean, across all concurrent requests) Transfer rate: 62866.29 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] median max Connect: 0 19 28.7 3 163 Processing: 4 272 110.6 276 905 Waiting: 1 199 98.3 196 862 Total: 4 290 109.6 293 908 Percentage of the requests served within a certain time (ms) 50% 293 66% 337 75% 362 80% 379 90% 426 95% 463 98% 489 99% 533 100% 908 (longest request) ApacheとNginxのパフォーマンス検証結果 1位:nginx(woker) + php-fpm ⇒ 685.07 [#/sec] 2位:apache(worker) + php-fpm ⇒ 594.79 [#/sec] 3位:apache(prefork) + php-fpm ⇒ 560.84 [#/sec] 4位:apache(prefork) + mod_php ⇒ 509.72 [#/sec] 上記結果は、環境や利用状況によって異なる場合がありますが、概ね「nginx(woker) + php-fpm」の構成が一番よいパフォーマンスが出ているように見えます。 CakePHP設定サンプル 以下はCakePHPをNginxで利用する際の設定サンプルです。WordPress/Drupalなどの設定も同じような構成になります。catコマンドで変数$が展開されないように「'EOF'」のように囲みます。 注意:fastcgi_paramの設定で、「include fastcgi_params;」を最後の行に挿入した場合、FastCGI設定内容がデフォルト値に上書きされます。 cat > "/etc/nginx/conf.d/default.conf" <<'EOF' server { listen 80; server_name localhost; location / { root /var/www/html/app/webroot/; index index.php; try_files $uri $uri/ /index.php$is_args$args; } location ~* ^.+.(jpg|jpeg|gif|css|png|js|ico|html|xml|txt)$ { access_log off; } location ~ \.php$ { root /var/www/html/app/webroot/; fastcgi_pass unix:/var/run/php-fpm.sock; fastcgi_index index.php; include fastcgi_params; fastcgi_param REMOTE_ADDR $remote_addr; fastcgi_param REMOTE_PORT $remote_port; fastcgi_param SERVER_ADDR $server_addr; fastcgi_param SERVER_PORT $server_port; fastcgi_param SERVER_NAME $server_name; fastcgi_param CONTENT_TYPE $content_type; fastcgi_param CONTENT_LENGTH $content_length; fastcgi_param QUERY_STRING $query_string; fastcgi_param PATH_INFO $fastcgi_path_info; fastcgi_param REQUEST_METHOD $request_method; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param REQUEST_URI $request_uri; fastcgi_param DOCUMENT_URI $document_uri; fastcgi_param DOCUMENT_ROOT $document_root; fastcgi_param SERVER_PROTOCOL $server_protocol; fastcgi_param GATEWAY_INTERFACE CGI/1.1; fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; fastcgi_param HTTPS $https; fastcgi_buffer_size 128k; fastcgi_buffers 256 16k; #4096k total fastcgi_busy_buffers_size 256k; fastcgi_temp_file_write_size 256k; fastcgi_max_temp_file_size 0; #disable buffering to disk client_max_body_size 0; #Allow large uploads } } EOF サーバの帯域幅検証(TCPスループット) この検証は、サーバ2台が必要になります。ローカルでも、広域ネットワークでも検証出来ます。サーバ側でのファイアウォールを解除しておく必要があります。デフォルトのポートは5201です。以下のツールを両方にインストールして確認します。仮にサーバーのIPを「192.168.1.3/192.168.1.4」と設定します。この検証を行うのはAWSまたはVPS環境上にDB接続を行う際、ネットワークにボトルネックがないかを確認するためです。またリバースプロキシサーバーを設定して運用する際に、サーバー単体ではパフォーマンスが出ていても、ネットワークにボトルネックになっていて、パフォーマンスが上がらないケースがあるので、必ず確認してみます。 ym install -y iperf3 192.168.1.3:server ポートを変更する時には、「-p 8080」のように追加します。 iperf3 -s 192.168.1.4:client サーバー側のポートがデフォルトポートと異なる場合は「-p 8080」のように追加します。 iperf3 -c 192.168.1.3 結論 近年ネットワークのトラフィックがスマートフォン普及によって急増し、ウェブサーバーを構築・運用する際、最も重要なポイントは、ウェブサーバーのパフォーマンスと安定性ではないかと考えています。ウェブでは、PHP言語が最も多く使われているため、安定的で高性能なウェブサーバが運用できるようなヒントになれば幸いです。 今まで検証してきた内容をまとめると以下のようになります。 サーバーはデフォルトのままのOSは使うな!! パフォーマンスチューニングは必ず行うようにします。 PHPは、FastCGI用にシェアドで、「Non Thread Safe」としてビルドする!! サーバーの運用が柔軟になり、トラブルが少なく安定的に運用できます。 PHPのSAPIは、php-fpmでFastCGIとして運用する!! 高負荷でもサーバーがダウンし難くなります。 ウェブサーバーは、Nginxを使う!! パフォーマンスの高いサーバーで、FastCGIとの相性が抜群です。 ウェブサーバーはのMPM(Multi-Processing Modules)は、Workerにする!! 効率のよいサーバーの運用ができます。 ベンチマークは必ず行う!! パフォーマンスのボトルネックを理解して運用するのはとても大事です。 ※注意:PHPを、apacheモジュールとして、Workerモデルでは運用できません。ApacheをWorkerモデルで運用する際は、必ずFastCGIとしてPHPを構築して運用します。 最後まで長文を読んで頂き ありがとうございました!!
ネクストの花多山です。 先週、金沢工業大学で開催されたハッカソンに参加してきました。 概要はこちら。 http://www.kanazawa-it.ac.jp/kitnews/2014/1197419_3722.html 9月20日(土)~22日(月)まで「地方都市イノベーション創出 ~消滅する地方都市を救え!~」をテーマに 産学連携による短期集中型のコンテストとして大学初の試みで開催されたものです。 ネクストは情報提供企業として、HOME'SのAPIを提供するという形で協力させて頂きました。 HOME'SのAPIを一般向けに公開するというのは、実はこちらも初の試みとなり、お話を頂いた時は、事前の準備などで色々と大変だろうなと及び腰になっていたというのが正直なところでした。 ただ、会社として地方都市活性化というテーマに少しでもお手伝いできればと考え、協力させて頂くことにしました。 金沢工業大学による初のハッカソンではありましたが、3日間のスケジュールは見事なプログラムとなっており、 また、学生と企業が連携して、課題に取り組む様は非常に濃密で有意義な時間だったと思います。 その様子を時系列に少しでもお伝えできればと思います。 事前準備 ハッカソンに協力するにあたって、以下の準備をして臨みました。 APIのクライアント認証プログラムの用意 APIの簡易リファレンスの作成 時間が取れず、かなり突貫での用意となりましたが。。 1日目(9/20 土) 10:00 まず、ハッカソンのルール説明 10:30 情報提供企業による会社説明と提供データ&デバイスの説明タイム ネクストも話をさせて頂きました。 ネクスト以外の情報提供企業は、IO DATA様、PFU様、富士ソフト様、チェンジビジョン様という顔ぶれ。 14:00 各チームに分かれ、アイデアソン 18:00 アイデアソン発表会 この発表会を受けて、審査員と我々企業からのフィードバックをさせてもらいました。 HOME'S APIは結構な人気で、多くのチームがHOME'Sに対する既存の問題点と地方都市活性化を結び付けたアイデアを考えてくれ、 地方都市を救えというよりもHOME'Sを救えというサブタイトルがあるのではと感じてしまうほどでした(笑)。 2日目(9/21 日) 10:00 アイデアソンの結果を受けて、チーム編成を若干変更 10:30 情報提供企業からの各データ&デバイスの講習会 私からは一時間ほど、実演しながらAPIの利用方法のレクチャーを実施しました。 13:00 開発スタート 私自身は学生さんたちのサポートと言うと聞こえはいいですが、準備不足による対応にかなり時間を割いたりと、色々と反省すべき点がありました。 ただ、暫定ながらAPI初の一般公開ということで、実際に利用する側の生の声や、本運用に向けての問題点を知ることができる有益な場だったと言えます。 3日目(9/22 月) 15:00 開発終了&成果報告会 アイデアソン同様、各チームの発表を受けて、審査員と我々企業からのフィードバックをさせてもらいました。 前日では、終わらないかもなと思っていたチームもありましたが、どのチームも何らかのアウトプットを出してくれて、上々の結果だったのではないでしょうか。学生たちの若いパワーを肌で感じることができました。 17:00 審査会&表彰式 ネクスト賞も贈呈させてもらいました。ネクスト賞を受賞したチームの成果物は、「HOME'S APIとキヨスク端末を使った集団移住を実現するためのシステム」。面白い発想と推進力が見事でした。 18:00 懇親会→終了 と、長くなりましたが、非常に濃密な3日目でした。私ですらそう感じたので、チームとして開発にどっぷり関わったメンバーにとっては尚更だったしょうね。 学生と企業が触れ合いお互いが刺激を受ける場として、そして地方都市をより活性化させる情報発信の場として、非常に意義深いイベントでした。 第二回も予定されているようなので、また会社として協力できればいいなと考えています。 ただ、ハッカソンは準備が一番大変、、と思い知らされたイベントでした。次回はもう少し余裕をもって臨みたいですね。 次回は機会があれば開発者として参加してみたいなと思います。
こんにちは。新規事業本部・金融グループの金(成奉)です。 前回( PHPコンパイルによる高性能のFastCGIウェブサーバー構築とチューニングに関するお話し(1) - 株式会社ネクスト エンジニアBlog )に引き続き、FastCGI基盤ウェブサーバーのPHPコンパイル構築、チューニング、設定などについてお話したいと思います。 PHP高速化について OPcache+APCu の構成でハイ・パフォーマンスPHP環境を構築します。OPcacheはネイティブのOPコードのキャッシュ機能をサポートし、APCuはユーザーデータのキャッシュ機能をサポートする。以前APCは両機能が一つになっていましたが、PHP5.5ではネイティブコードキャッシュのZend Opcacheがサポートされるようになりました。 PHP構築設定内容 apache2用のモジュール(prefork用)も一緒に生成します。 今回構築するサーバはFastCGIでの運用であるため、シェアド・オプションでコンパイルしたバイナリをインストールします。スレッドセーフ(Threads Safe)のPHPはまだ対応していないモジュール(PHPエクステンション)が多くあり、「Non Threads model」でコンパイルします。スレッドセーフにしたい場合は、「–enable-maintainer-zts」を追加します。スレッドセーフにコンパイルして構築すると、スレッドセーフに対応していないエクステンション(geos.cなど)を後で追加したくてもコンパイルできないため、とても不便です。残念なことに高機能のモジュールがコンパイルできないケースが多くて困る時がしばしばあります。 ミドルウェア・ビルド・ポリシについて CentOS系では、できるだけ、開発ライブラリー(xxx-devel.x86_64)系は、yumのデフォルト・レポジトリからインストールするようにします。特に「openssl」は、コンパイルして、ビルドした場合、最近のHeartBleedと呼ばれたセキュリティ脆弱性が発見された際には、ライブラリーを含めてすべてコンパイルしなおさなければなりません。バージョンが合わないため、やむを得ず、ライブラリーを構築しなければならないケースは例外とします。apacheの場合も、特別な理由がなければ、yumのデフォルト・レポジトリからインストールし、設定でセキュリティ対策を行うことをお薦めします。その他、yumレポジトリにインストールするバイナリがなく、パフォーマンス対策を行う必要がある場合、コンパイル・インストールします。yumレポジトリについても、デフォルト以外のものを無やみに追加しないようなポリシでサーバーを構築していきます。 PHPビルドの事前準備 phpダウンロード ビルドは /opt/src ディレクトリで行うと仮定します。 以下の作業はすべてroot権限で行います。 su - cd /opt/src wget -q http://jp1.php.net/get/php-5.5.16.tar.gz/from/this/mirror -O php-5.5.16.tar.gz tar zxvf php-5.5.16.tar.gz Shared Memory Allocationコンパイル・インストール セッションを共有メモリで扱うとパフォーマンスは向上します。このライブラリーは、Threads Safeに対応していないモジュールです。Non Threads modelでの構築の場合、もしくはセション処理が専門用途のサーバーとしてビルドする場合、検討する価値はあるかもしれません。このエクステンションの設定はここでは行いません。 wget ftp://ftp.ossp.org/pkg/lib/mm/mm-1.4.2.tar.gz tar zxvf mm-1.4.2.tar.gz cd mm-1.4.2 ./configure --prefix=/usr --libdir='${prefix}/lib64' make make install cd ../ セッションは、下のようにRAMディスクにマウントして設定する方法もあります。 mkdir /tmp/ramdisk chmod 777 /tmp/ramdisk mount -t tmpfs -o size=512M tmpfs /tmp/ramdisk/ vi php.ini session.save_path="/tmp/ramdisk" Igbinaryモジュールセットアップ cd /opt/src/php-5.5.16/ext wget -q https://github.com/phadej/igbinary/archive/master.zip -O igbinary.zip unzip igbinary.zip mv igbinary-master igbinary Redis(remote dictionary server)モジュールセットアップ Redis KVS(格納するバリューがデータ構造)クライアントモジュール cd /opt/src/php-5.5.16/ext wget -q https://github.com/nicolasff/phpredis/archive/master.zip -O phpredis.zip unzip phpredis.zip mv phpredis-master redis APCu(APC User Cache)モジュール cd /opt/src/php-5.5.16/ext wget -q https://github.com/krakjoe/apcu/archive/master.zip -O apcu.zip unzip apcu.zip mv apcu-master apcu PHPコンパイル・オプション追加設定 セットアップしたモジュール(Extension)をconfigureに認識させます。 cd /opt/src/php-5.5.16 ./buildconf --force オプションに追加されているかを確認します。 ./configure --help | grep "redis\|igbinary\|apcu" --enable-igbinary Enable igbinary support --enable-redis Enable redis support --disable-redis-session Disable session support --enable-redis-igbinary Enable igbinary serializer support igbinay/redis/apcu は、ソースファイルをダウンロードして、 phpize; phpize; ./configure;make; make install コマンドでもインストールが出来ます。 ビルド環境構築 既にインストールされていればスキップします。 yum -y install autoconf yum -y install automake yum -y install libtool.x86_64 yum -y install flex.x86_64 yum -y install bison.x86_64 yum -y install gcc.x86_64 yum -y install gcc-c++.x86_64 yum -y install make.x86_64 yum -y install kernel-headers.x86_64 yum -y install kernel-devel.x86_64 PHPビルド環境構築 既にインストールされていればスキップします。 httpd-develはHTTPD用のPHPバイナリも一緒に生成するためです。 ライブラリーごと一行にしているのは、みやすくするためです。 yum install -y httpd-devel.x86_64 yum install -y libxml2-devel.x86_64 yum install -y bzip2-devel.x86_64 yum install -y libcurl-devel.x86_64 yum install -y libpng-devel.x86_64 yum install -y openjpeg-devel.x86_64 yum install -y freetype-devel.x86_64 yum install -y t1lib-devel.x86_64 yum install -y libXpm-devel.x86_64 yum install -y gd-devel.x86_64 yum install -y gmp-devel.x86_64 yum install -y libc-client-devel.x86_64 yum install -y libicu-devel.x86_64 yum install -y openldap-devel.x86_64 yum install -y libmcrypt-devel.x86_64 yum install -y mysql-devel.x86_64 yum install -y readline-devel.x86_64 yum install -y net-snmp-devel.x86_64 yum install -y libtidy-devel.x86_64 yum install -y libxslt-devel.x86_64 yum install -y libmcrypt-devel.x86_64 yum install -y libevent.x86_64 yum install -y libevent-devel.x86_64 yum install -y aspell-devel.x86_64 yum install -y enchant-devel.x86_64 yum install -y oniguruma-devel.x86_64 yum install -y unixODBC-devel.x86_64 yum install -y sqlite-devel.x86_64 yum install -y krb5-devel.x86_64 MySQLサーバー・インストール 使わないシステムでも、インストールしておけば結構便利になることが多いため、インストールしておきます。使わない時には、サービスから外しサービスを停止します。 yum install -y mysql-server.x86_64 サービス登録 chkconfig mysqld on サービスから削除 使用しない場合は、サービスから削除しておきます chkconfig mysqld off 確認 chkconfig --list mysqld MySQL設定 cp /etc/my.cnf /etc/my.cnf.org symbolic-links=0 と [mysqld_safe] の間に以下を追加します。 vi /etc/my.cnf character_set_server=utf8 default-storage-engine=InnoDB innodb_file_per_table [mysql] default-character-set=utf8 [mysqldump] default-character-set=utf8 サービス起動(root) service mysqld start コマンド度実行と設定手順(初期設定) この設定はセキュリティのため、必ず行います。 mysql_secure_installation rootパスワード → そのままEnter rootパスワード設定 → Y Enter rootパスワード入力(2回) → ******* Enter anonymousユーザ削除 → Y Enter リモートのrootログイン禁止 → Y Enter testデータベース削除 → Y Enter 設定反映 → Y Enter ログイン確認 mysql -u root -p パスワード入力 Enter mysql>\s 上記設定したパスワードでログインができるか確認後終了 mysql> exit サービスを止めます。 service mysqld stop 普段使わない時にはサービスから外します。 chkconfig mysqld off Redisクライアントとサーバのインストール 世界的な流れとしては、以前よく使われたMemcachedよりは、Redisの方が主流になっています。そのため、Redisサーバーも一緒に構築します。 cd /opt/src ダウンロードとインストール wget -q http://redis.googlecode.com/files/redis-2.6.14.tar.gz tar xzf redis-2.6.14.tar.gz cd redis-2.6.14 make -j10 make install Redis設定 rm -rf /etc/redis /var/lib/redis mkdir /etc/redis /var/lib/redis \cp src/redis-server src/redis-cli /usr/bin \cp redis.conf /etc/redis sed -e "s/^daemonize no$/daemonize yes/" -e "s/^# bind 127.0.0.1$/bind 127.0.0.1/" -e "s/^dir \.\//dir \/var\/lib\/redis\//" -e "s/^loglevel verbose$/loglevel notice/" -e "s/^logfile stdout$/logfile \/var\/log\/redis.log/" redis.conf > /etc/redis/redis.conf Redisのサービススクリプト作成と設定 cat > "/etc/init.d/redis-server" <<'EOF' #!/bin/sh # # redis-server Startup script for the Redis Server # # chkconfig: - 85 15 # description: Redis is a persistent key-value database # processname: redis-server # config: /etc/redis/redis.conf # config: /etc/sysconfig/redis # pidfile: /var/run/redis.pid # Source function library. . /etc/rc.d/init.d/functions # Source networking configuration. . /etc/sysconfig/network # Check that networking is up. [ "$NETWORKING" = "no" ] && exit 0 redis="/usr/bin/redis-server" prog=$(basename $redis) REDIS_CONF_FILE="/etc/redis/redis.conf" [ -f /etc/sysconfig/redis ] && . /etc/sysconfig/redis lockfile=/var/lock/subsys/redis start() { [ -x $redis ] || exit 5 [ -f $REDIS_CONF_FILE ] || exit 6 echo -n $"Starting $prog: " daemon $redis $REDIS_CONF_FILE retval=$? echo [ $retval -eq 0 ] && touch $lockfile return $retval } stop() { echo -n $"Stopping $prog: " killproc $prog -QUIT retval=$? echo [ $retval -eq 0 ] && rm -f $lockfile return $retval } restart() { stop start } reload() { echo -n $"Reloading $prog: " killproc $redis -HUP RETVAL=$? echo } force_reload() { restart } rh_status() { status $prog } rh_status_q() { rh_status >/dev/null 2>&1 } case "$1" in start) rh_status_q && exit 0 $1 ;; stop) rh_status_q || exit 0 $1 ;; restart|configtest) $1 ;; reload) rh_status_q || exit 7 $1 ;; force-reload) force_reload ;; status) rh_status ;; condrestart|try-restart) rh_status_q || exit 0 ;; *) echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" exit 2 esac EOF 実行権限変更 chmod 755 /etc/init.d/redis-server サービス登録 chkconfig --add redis-server chkconfig --level 345 redis-server on または chkconfig redis-server on ランレベルについて 0:シャットダウン(システムの停止) 1:シングルユーザーモード(rootのみ) 2:ネットワークなしのマルチユーザーモード 3:通常のマルチユーザーモード(テキストログイン) 4:未使用 5:グラフィカルログイン・マルチユーザーモード 6:システムの再起動 redisサービス起動 service redis-server start cd /opt/src PostgreSQLのインストール PostgreSQL-9.3.4は、yumのデフォルト・レポジトリにはないため、コンパイル・インストールします。PostgreSQLはroot権限で実行できないため、以下のユーザーを追加しておきます。make時はオプション「-j10」オプションを追加し、時間節約のため、並列でコンパイルします。 重要:PostgreSQLのバックエンドやファンクションの多くがC++言語で書かれているため、安定運用のためにはstdc++ラブラリーをリンクして原因不明のトラブルを回避できます。今までPostgreSQLは一度もダウンした経験がありません。とても信頼できるデータベースです。 GISサーポートビルドなどの詳細は以下のURLを参照する。 http://nextdeveloper.hatenablog.com/entry/2014/05/20/164605 ユーザ確認と追加 yum install -y finger id postgres finger postgres 既に追加されている場合はスキップします。 useradd postgres ダウンロードと基本DBのインストール(PHP用のライブラリー構築) 普段使わない場合は、設定やサービスを起動しない。 本格的に使う場合は、以下を参照して設定する。 http://nextdeveloper.hatenablog.com/entry/2014/05/20/164605 cd /opt/src wget -q http://ftp.postgresql.org/pub/source/v9.3.4/postgresql-9.3.4.tar.gz tar zxvf postgresql-9.3.4.tar.gz cd postgresql-9.3.4 LDFLAGS=-lstdc++ ./configure --prefix=/usr --libdir='${prefix}/lib64' make -j10 world make install-world cd .. コンパイル前の確認 一度コンフィグレーションを行って、makeを実行した際には、必ず make clean; ./buildconf --force を実行してから、 ./configure -> make の手順でコンパイルを行います。それでも、コンフィグレーションでコンパイル・オプションなどが認識されない場合は、ソースを削除してから最初からやり直してください。 PHPコンパイル構築1(シェアド・ビルド/FastCGI用/Apacheモジュール) オプションの設定で、 -dir オプションは、/usr/local/mysql のようにインストールされたディレクトリ(prefixディレクトリ)を指定します。。 --with-xxx オプションがエラーになった場合は、ライブラリーのディレクトリも一緒に設定します。ここではは、PHPバイナリは、シェアド・コンパイル・バイナリを基本とします。インストールされるモジュールは、 /etc/php.d/xxxx.ini というファイル名でモジュールファイル(.so)を個別に設定するようにします。ここでは、PHPのApacheモジュールのバイナリも生成します。必要ない場合は、下のコンパイルオプションから --with-apxs2 \ を削除します。 PHP実行時、モジュールの中でもセッションが最初に実行されため、「session.so」がロードされていなければこのモジュールに依存しているExtenshonで「Undefined symbol」エラーが発生します。そのため、sessionモジュールは、PHP本体に組み込んでスタティックでコンパイルすることで、この問題を回避します。 コンフィグレーションを実行するまでに、 phpredis/igbinary/apcu が ./configure で下のように認識されているかを確認します。 ./buildconf --force ./configure --help | grep "redis\|igbinary\|apcu" --enable-apcu Enable APCu support --disable-apcu-rwlocks Disable rwlocks in APCu --enable-apcu-debug Enable APCu debugging --enable-apcu-clear-signal Enable SIGUSR1 clearing handler --disable-apcu-mmap Disable mmap, falls back on shm --enable-apcu-spinlocks Use spinlocks before flocks --enable-igbinary Enable igbinary support --enable-redis Enable redis support --disable-redis-session Disable session support --enable-redis-igbinary Enable igbinary serializer support --enable-cgi は、FastCGIオプションでコンパイルされます。指定しなくてもデフォルトで設定されます。CGI/FastCGIの両インターフェースをサポートしてます。 ./configure \ --prefix=/usr \ --exec-prefix=/usr \ --bindir=/usr/bin \ --sbindir=/usr/sbin \ --sysconfdir=/etc \ --datadir=/usr/share \ --includedir=/usr/include \ --libdir=/usr/lib64 \ --libexecdir=/usr/libexec \ --localstatedir=/var \ --sharedstatedir=/usr/com \ --mandir=/usr/share/man \ --infodir=/usr/share/info \ --with-apxs2 \ --with-config-file-path=/etc \ --with-config-file-scan-dir=/etc/php.d \ --with-libdir=lib64 \ --with-layout=GNU \ --with-fpm-user=www-data \ --with-fpm-group=www-data \ --enable-apcu=shared \ --enable-bcmath=shared \ --enable-calendar=shared \ --enable-cgi \ --enable-cli \ --enable-ctype=shared \ --enable-dba=shared \ --enable-dom=shared \ --enable-exif=shared \ --enable-fileinfo=shared \ --enable-filter=shared \ --enable-fpm \ --enable-ftp=shared \ --enable-gd-jis-conv \ --enable-gd-native-ttf \ --enable-igbinary=shared \ --enable-inline-optimization \ --enable-intl=shared \ --enable-json=shared \ --enable-mbstring=shared \ --enable-opcache=shared \ --enable-pdo=shared \ --enable-phar=shared \ --enable-pcntl=shared \ --enable-posix=shared \ --enable-re2c-cgoto \ --enable-redis=shared \ --enable-redis-session \ --enable-redis-igbinary \ --enable-session=static \ --enable-shmop=shared \ --enable-sigchild=shared \ --enable-simplexml=shared \ --enable-soap=shared \ --enable-sockets=shared \ --enable-sysvsem=shared \ --enable-sysvshm=shared \ --enable-sysvmsg=shared \ --enable-tokenizer=shared \ --enable-xml=shared \ --enable-xmlreader=shared \ --enable-xmlwriter=shared \ --enable-zend-signals \ --enable-zip=shared \ --enable-wddx=shared \ --disable-rpath \ --disable-ipv6 \ --disable-debug \ --with-freetype-dir=/usr \ --with-icu-dir=/usr \ --with-jpeg-dir=/usr \ --with-libxml-dir=/usr \ --with-png-dir=/usr \ --with-openssl-dir=shared,/usr \ --with-xpm-dir=/usr \ --with-zlib-dir=shared,/usr \ --with-bz2=shared \ --with-curl=shared,/usr \ --with-db4=shared \ --with-enchant=shared \ --with-gd=shared \ --without-gdbm \ --with-gettext=shared \ --with-gmp=shared \ --with-iconv=shared \ --with-imap=shared \ --with-imap-ssl \ --with-kerberos \ --with-ldap=shared \ --with-ldap-sasl \ --with-mcrypt=shared \ --with-mhash=shared \ --with-mm=/usr \ --with-mysql=shared,/usr \ --with-mysqli=shared,/usr/bin/mysql_config \ --with-pdo-mysql=shared,/usr/bin/mysql_config \ --with-openssl=shared \ --with-pear \ --with-pic=shared \ --with-pgsql=shared,/usr \ --with-pdo-pgsql=shared,/usr \ --with-pdo-sqlite=shared,/usr \ --with-pdo-odbc=shared,unixODBC,/usr \ --with-pcre-regex \ --with-pspell=shared \ --with-readline=shared \ --with-snmp=shared \ --with-t1lib=shared \ --with-tidy=shared,/usr \ --with-unixODBC=shared,/usr \ --with-xmlrpc=shared \ --with-xsl=shared,/usr \ --with-zlib=shared コンパイル make -j10 php-fpmユーザー追加 useradd www-data インストール make install && install -v -m644 php.ini-production /etc/php.ini && install -v -m644 sapi/fpm/php-fpm.conf /etc/php-fpm.conf && install -v -m755 sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm php.ini設定変更 sed -i 's/expose_php = On/expose_php = Off/g;' /etc/php.ini sed -i 's/\;date.timezone =/date\.timezone = Asia\/Tokyo/g;' /etc/php.ini シェアドPHPのインストールログ make install Installing PHP SAPI module: apache2handler /usr/lib64/httpd/build/instdso.sh SH_LIBTOOL='/usr/lib64/apr-1/build/libtool' libphp5.la /usr/lib64/httpd/modules /usr/lib64/apr-1/build/libtool --mode=install cp libphp5.la /usr/lib64/httpd/modules/ libtool: install: cp .libs/libphp5.so /usr/lib64/httpd/modules/libphp5.so libtool: install: cp .libs/libphp5.lai /usr/lib64/httpd/modules/libphp5.la libtool: install: warning: remember to run `libtool --finish /opt/src/php-5.5.16/libs' chmod 755 /usr/lib64/httpd/modules/libphp5.so [activating module `php5' in /etc/httpd/conf/httpd.conf] Installing shared extensions: /usr/lib64/20121212/ Installing PHP CLI binary: /usr/bin/ Installing PHP CLI man page: /usr/share/man/man1/ Installing PHP FPM binary: /usr/sbin/ Installing PHP FPM config: /etc/ Installing PHP FPM man page: /usr/share/man/man8/ Installing PHP FPM status page: /usr/share/fpm/ Installing PHP CGI binary: /usr/bin/ Installing PHP CGI man page: /usr/share/man/man1/ Installing build environment: /usr/lib64/build/ Installing header files: /usr/include/php/ Installing helper programs: /usr/bin/ program: phpize program: php-config Installing man pages: /usr/share/man/man1/ page: phpize.1 page: php-config.1 Installing PEAR environment: /usr/share/pear/ [PEAR] Archive_Tar - already installed: 1.3.11 [PEAR] Console_Getopt - already installed: 1.3.1 [PEAR] PEAR - already installed: 1.9.4 Wrote PEAR system config file at: /etc/pear.conf You may want to add: /usr/share/pear to your php.ini include_path [PEAR] Structures_Graph- already installed: 1.0.4 [PEAR] XML_Util - already installed: 1.2.1 /opt/src/php-5.5.16/build/shtool install -c ext/phar/phar.phar /usr/bin ln -s -f /usr/bin/phar.phar /usr/bin/phar Installing PDO headers: /usr/include/php/ext/pdo/ シェアドPHPのExtension設定 シェルスクリプトで書いてないのは個別に確認しやすくするためです。 内容を確認した上で、環境に合わせて修正してください。 mkdir /etc/php.d cat > "/etc/php.d/apcu.ini" <<EOF extension=apcu.so apc.enabled=1 apc.shm_size=128M apc.enable_cli=1 apc.write_lock=1 apc.slam_defense=0 apc.gc_ttl=3600 apc.ttl=7200 apc.entries_hint=4096 apc.slam_defense=1 apc.mmap_file_mask=/tmp/apc.XXXXXX apc.serializer=igbinary EOF echo -e extension=bcmath.so >/etc/php.d/bcmath.ini echo -e extension=bz2.so >/etc/php.d/bz2.ini echo -e extension=calendar.so >/etc/php.d/calendar.ini] echo -e extension=ctype.so >/etc/php.d/ctype.ini echo -e extension=curl.so >/etc/php.d/curl.ini echo -e extension=dba.so >/etc/php.d/dba.ini echo -e extension=dom.so >/etc/php.d/dom.ini echo -e extension=enchant.so >/etc/php.d/enchant.ini echo -e extension=exif.so >/etc/php.d/exif.ini echo -e extension=fileinfo.so >/etc/php.d/fileinfo.ini echo -e extension=ftp.so >/etc/php.d/ftp.ini echo -e extension=gd.so >/etc/php.d/gd.ini echo -e extension=gettext.so >/etc/php.d/gettext.ini echo -e extension=gmp.so >/etc/php.d/gmp.ini echo -e extension=iconv.so >/etc/php.d/iconv.ini echo -e extension=igbinary.so >/etc/php.d/igbinary.ini echo -e extension=imap.so >/etc/php.d/imap.ini echo -e extension=intl.so >/etc/php.d/intl.ini echo -e extension=json.so >/etc/php.d/json.ini echo -e extension=ldap.so >/etc/php.d/ldap.ini cat > "/etc/php.d/mbstring.ini" <<EOF extension=mbstring.so mbstring.language = Japanese mbstring.internal_encoding = UTF-8 mbstring.http_input = UTF-8 mbstring.http_output = pass mbstring.detect_order = UTF-8,SJIS,EUC-JP,JIS,ASCII EOF echo -e extension=mcrypt.so >/etc/php.d/mcrypt.ini echo -e extension=mysql.so >/etc/php.d/mysql.ini echo -e extension=mysqli.so >/etc/php.d/mysqli.ini echo -e extension=odbc.so >/etc/php.d/odbc.ini OPCacheプロダクション設定 メモリをある程度搭載しているマシーンでは、「opcache.memory_consumption」の数字を増やします。 mkdir /var/lib/php cat > "/etc/php.d/opcache.ini" <<EOF zend_extension=opcache.so [opcache] opcache.enable=1 opcache.enable_cli=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=4000 opcache.max_file_size=5M opcache.blacklist_filename=/var/lib/php/opcache*.blacklist opcache.revalidate_freq=0 opcache.revalidate_path=0 opcache.save_comments=0 opcache.load_comments=0 opcache.consistency_checks=1 opcache.fast_shutdown=1 EOF echo -e extension=openssl.so >/etc/php.d/openssl.ini echo -e extension=pcntl.so >/etc/php.d/pcntl.ini echo -e extension=pdo.so >/etc/php.d/pdo.ini echo -e extension=pdo_mysql.so >/etc/php.d/pdo_mysql.ini echo -e extension=pdo_odbc.so >/etc/php.d/pdo_odbc.ini echo -e extension=pdo_pgsql.so >/etc/php.d/pdo_pgsql.ini echo -e extension=pdo_sqlite.so >/etc/php.d/pdo_sqlite.ini echo -e extension=pgsql.so >/etc/php.d/pgsql.ini echo -e extension=phar.so >/etc/php.d/phar.ini echo -e extension=posix.so >/etc/php.d/posix.ini echo -e extension=pspell.so >/etc/php.d/pspell.ini echo -e extension=readline.so >/etc/php.d/readline.ini echo -e "extension=redis.so\nredis.serializer=igbinary" >/etc/php.d/redis.ini echo -e extension=shmop.so >/etc/php.d/shmop.ini echo -e extension=simplexml.so >/etc/php.d/simplexml.ini echo -e extension=snmp.so >/etc/php.d/snmp.ini echo -e extension=soap.so >/etc/php.d/soap.ini echo -e extension=sockets.so >/etc/php.d/sockets.ini echo -e extension=sysvmsg.so >/etc/php.d/sysvmsg.ini echo -e extension=sysvmsg.so >/etc/php.d/sysvmsg.ini echo -e extension=sysvshm.so >/etc/php.d/sysvshm.ini echo -e extension=tidy.so >/etc/php.d/tidy.ini echo -e extension=tokenizer.so >/etc/php.d/tokenizer.ini echo -e extension=wddx.so >/etc/php.d/wddx.ini echo -e extension=xml.so >/etc/php.d/xml.ini echo -e extension=xmlreader.so >/etc/php.d/xmlreader.ini echo -e extension=xmlrpc.so >/etc/php.d/xmlrpc.ini echo -e extension=xmlwriter.so >/etc/php.d/xmlwriter.ini echo -e extension=xsl.so >/etc/php.d/xsl.ini echo -e extension=zip.so >/etc/php.d/zip.ini echo -e extension=zlib.so >/etc/php.d/zlib.ini Peclコマンドでのモジュール追加インストール例 以下は必要ない場合はスキップします。 pecl install -f oauth-beta PHPモジュールのコンパイル・インストール 以下は必要ない場合はスキップします。 geosライブラリは、コンパイル時に注意が必要です。GIS系のライブラリーは、バージョンによって依存性がことなり、同じライブライーが既にインストールされている場合は、ライブラリーのディレクトリを変更して、ぶつからないようにしなければなりません。コンパイルする時は、一番安定している、3.3.9バージョンを選びます。 geosエクステンションをインストールするとgeoPHPという便利なクラスが利用できます。このライブラリーをインストールすることで、PHPからGISの様々なデータフォーマットが扱えるようになります。地図表示をより高機能にする際にはとても便利です。 geoPHPモジュール https://github.com/phayes/geoPHP/ Goesエクステンションのインストール wget http://download.osgeo.org/geos/geos-3.3.9.tar.bz2 tar -xvjf geos-3.3.9.tar.bz2 cd geos-3.3.9 ./autogen.sh ./configure --enable-php make clean make -j20 make install インストールされたエクステンションのリンク先がソースディレクトリになっているため、修正する必要があります。以下のように既存リンクを削除し、 ldconfig でインストールされた先がロードされるようにします。 mv src/.libs/libgeos-3.3.9.so src/.libs/libgeos-3.3.9.so_orig mv capi/.libs/libgeos_c.so.1 capi/.libs/libgeos_c.so.1_orig sudo echo -e /usr/local/lib >/etc/ld.so.conf.d/geos-x86_64.conf sudo echo -e extension=geos.so >/etc/php.d/geos.ini /sbin/ldconfig #正しくライブラリーがリンクされているか確認します。 [root@dev geos-3.3.9]# ldd /usr/lib64/20121212/geos.so linux-vdso.so.1 => (0x00007fff549ff000) libgeos_c.so.1 => /usr/local/lib/libgeos_c.so.1 (0x00007f2609235000) libc.so.6 => /lib64/libc.so.6 (0x00007f2608e8f000) libgeos-3.3.9.so => /usr/local/lib/libgeos-3.3.9.so (0x00007f2608afb000) libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f26087f5000) libm.so.6 => /lib64/libm.so.6 (0x00007f2608570000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f260835a000) /lib64/ld-linux-x86-64.so.2 (0x0000003424400000) ※注意※ 既存OSには、yumでインストールされている「geos-devel」バッケージが、3.3.2であるため、ぶつからないように注意します。コンパイル・インストールしたライブラリーのディレクトリが、 ldd コマンドで /usr/local/lib/ になっているかを確認します。 以上、ここまでが、PHPをシェアド・ビルド方法になります。上記でのコンパイルはほとんどのエクステンションが追加されたPHPパッケージになります。エクステンションで必要ない場合は、コメントにしてロードしないようにして構築します。 PHPコンパイル構築2(スタティック・ビルド/Apache2のPHPモジュール用) mod_phpようにビルドする際にはスタティックでコンパイルした方が、やや早いため、スタティック・ビルド方法も以下に追加します。スターティックのphp-fpmのバイナリも生成されます。オプションで設定で、 -dir オプションは、 /usr/local/mysql のようにインストールされたディレクトリ(prefixディレクトリ)を指定します。。 --with-xxx オプションがエラーになった場合は、ライブラリーのディレクトリも一緒に設定します。モジュール(extension)を追加する場合は、ダイナミックライブラリー(.so)で追加し、「.ini」ファイルで設定します。 --with-apxs2 のオプションも追加し、ApacheのPHPモジュール(libphp5.so)バイナリを生成しています。Opcacheは、スタティックでコンパイルしてもダイナミックライブラリーとしてインストールされますので、注意します。シェアドでビルドした場合若しくは必要ない場合は、スキップします。 cd /opt/src/php-5.5.16 phpredis/igbinary/apcu が configure で下のように認識されているかを確認します。 ./buildconf --force ./configure --help | grep "redis\|igbinary\|apcu" --enable-apcu Enable APCu support --disable-apcu-rwlocks Disable rwlocks in APCu --enable-apcu-debug Enable APCu debugging --enable-apcu-clear-signal Enable SIGUSR1 clearing handler --disable-apcu-mmap Disable mmap, falls back on shm --enable-apcu-spinlocks Use spinlocks before flocks --enable-igbinary Enable igbinary support --enable-redis Enable redis support --disable-redis-session Disable session support --enable-redis-igbinary Enable igbinary serializer support ./configure \ --prefix=/usr \ --exec-prefix=/usr \ --bindir=/usr/bin \ --sbindir=/usr/sbin \ --sysconfdir=/etc \ --datadir=/usr/share \ --includedir=/usr/include \ --libdir=/usr/lib64 \ --libexecdir=/usr/libexec \ --localstatedir=/var \ --sharedstatedir=/usr/com \ --mandir=/usr/share/man \ --infodir=/usr/share/info \ --with-apxs2 \ --with-config-file-path=/etc \ --with-config-file-scan-dir=/etc/php.d \ --with-libdir=lib64 \ --with-layout=GNU \ --with-fpm-user=www-data \ --with-fpm-group=www-data \ --enable-fpm \ --enable-inline-optimization \ --enable-apcu \ --enable-bcmath \ --enable-calendar \ --enable-cgi \ --enable-cli \ --enable-ctype \ --enable-dba \ --enable-dom \ --enable-exif \ --enable-fileinfo \ --enable-filter \ --enable-ftp \ --enable-gd-jis-conv \ --enable-gd-native-ttf \ --enable-intl \ --enable-igbinary \ --enable-json \ --enable-mbstring \ --enable-opcache \ --enable-pdo \ --enable-phar \ --enable-pcntl \ --enable-posix \ --enable-re2c-cgoto \ --enable-redis=static \ --enable-redis-session \ --enable-redis-igbinary \ --enable-session \ --enable-shmop \ --enable-sigchild \ --enable-simplexml \ --enable-soap \ --enable-sockets \ --enable-sysvsem \ --enable-sysvshm \ --enable-sysvmsg \ --enable-tokenizer \ --enable-xml \ --enable-xmlreader \ --enable-xmlwriter \ --enable-zip \ --enable-wddx \ --enable-zend-signals \ --disable-rpath \ --disable-debug \ --with-freetype-dir=/usr \ --with-icu-dir=/usr \ --with-jpeg-dir=/usr \ --with-libxml-dir=/usr \ --with-png-dir=/usr \ --with-openssl-dir=/usr \ --with-xpm-dir=/usr \ --with-zlib-dir=/usr \ --with-bz2 \ --with-curl=/usr \ --with-db4 \ --with-enchant \ --with-gd \ --without-gdbm \ --with-gettext \ --with-gmp \ --with-iconv \ --with-imap \ --with-imap-ssl \ --with-kerberos \ --with-ldap \ --with-ldap-sasl \ --with-mcrypt \ --with-mhash \ --with-mm=/usr \ --with-mysql=/usr \ --with-mysqli=/usr/bin/mysql_config \ --with-pdo-mysql=/usr/bin/mysql_config \ --with-onig \ --with-openssl \ --with-pear \ --with-pic \ --with-pgsql=/usr \ --with-pdo-pgsql=/usr \ --with-pdo-sqlite=/usr \ --with-pdo-odbc=unixODBC,/usr \ --with-pcre-regex \ --with-pspell \ --with-readline \ --with-snmp \ --with-t1lib \ --with-tidy \ --with-unixODBC=/usr \ --with-xmlrpc \ --with-xsl=/usr \ --with-zlib スタティックPHPのコンパイル・インストール コンパイル make -j10 php-fpmユーザー追加 useradd www-data インストール make install && install -v -m644 php.ini-production /etc/php.ini && install -v -m644 sapi/fpm/php-fpm.conf /etc/php-fpm.conf && install -v -m755 sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm php.ini設定変更 sed -i 's/expose_php = On/expose_php = Off/g;' /etc/php.ini sed -i 's/\;date.timezone =/date\.timezone = Asia\/Tokyo/g;' /etc/php.ini スタティックPHP・インストール・ログ make install all Installing PHP SAPI module: apache2handler /usr/lib64/httpd/build/instdso.sh SH_LIBTOOL='/usr/lib64/apr-1/build/libtool' libphp5.la /usr/lib64/httpd/modules /usr/lib64/apr-1/build/libtool --mode=install cp libphp5.la /usr/lib64/httpd/modules/ libtool: install: cp .libs/libphp5.so /usr/lib64/httpd/modules/libphp5.so libtool: install: cp .libs/libphp5.lai /usr/lib64/httpd/modules/libphp5.la libtool: install: warning: remember to run `libtool --finish /opt/src/php-5.5.16/libs' chmod 755 /usr/lib64/httpd/modules/libphp5.so [activating module `php5' in /etc/httpd/conf/httpd.conf] Installing shared extensions: /usr/lib64/20121212/ Installing PHP CLI binary: /usr/bin/ Installing PHP CLI man page: /usr/share/man/man1/ Installing PHP FPM binary: /usr/sbin/ Installing PHP FPM config: /etc/ Installing PHP FPM man page: /usr/share/man/man8/ Installing PHP FPM status page: /usr/share/fpm/ Installing PHP CGI binary: /usr/bin/ Installing PHP CGI man page: /usr/share/man/man1/ Installing build environment: /usr/lib64/build/ Installing header files: /usr/include/php/ Installing helper programs: /usr/bin/ program: phpize program: php-config Installing man pages: /usr/share/man/man1/ page: phpize.1 page: php-config.1 Installing PEAR environment: /usr/share/pear/ [PEAR] Archive_Tar - already installed: 1.3.11 [PEAR] Console_Getopt - already installed: 1.3.1 [PEAR] PEAR - already installed: 1.9.4 Wrote PEAR system config file at: /etc/pear.conf You may want to add: /usr/share/pear to your php.ini include_path [PEAR] Structures_Graph- already installed: 1.0.4 [PEAR] XML_Util - already installed: 1.2.1 /opt/src/php-5.5.16/build/shtool install -c ext/phar/phar.phar /usr/bin ln -s -f /usr/bin/phar.phar /usr/bin/phar Installing PDO headers: /usr/include/php/ext/pdo/ スタティックPHP設定(Extension設定) スタティックビルドでもopcacheはデフォルトでシェアドでコンパイルされるため、別途設定する必要があります。 extensions.iniファイルに追加されるモジュールをまとめて設定するようにします mkdir /var/lib/php cat > "/etc/php.d/extensions.ini" <<'EOF' ;Opcache zend_extension=opcache.so [opcache] [opcache] opcache.enable=1 opcache.enable_cli=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=8 opcache.max_accelerated_files=4000 opcache.max_file_size=5M opcache.blacklist_filename=/var/lib/php/opcache*.blacklist opcache.revalidate_freq=0 opcache.revalidate_path=0 opcache.save_comments=0 opcache.load_comments=0 opcache.consistency_checks=1 opcache.fast_shutdown=1 ;apcu apc.enabled=1 apc.shm_size=128M apc.enable_cli=1 apc.write_lock=1 apc.slam_defense=0 apc.gc_ttl=3600 apc.ttl=7200 apc.entries_hint=4096 apc.slam_defense=1 apc.mmap_file_mask=/tmp/apc.XXXXXX apc.serializer=igbinary ;mbstring mbstring.language = Japanese mbstring.internal_encoding = UTF-8 mbstring.http_input = UTF-8 mbstring.http_output = pass mbstring.detect_order = UTF-8,SJIS,EUC-JP,JIS,ASCII EOF 今回は以上になります。 次回は、動作確認、ApacheとNginxのパフォーマンス検証等、本記事のまとめについてお話します。 長文を読んで頂き、ありがとうございました。