TECH PLAY

株式会社LIFULL

株式会社LIFULL の技術ブログ

652

秋晴れがすがすがしい今日この頃ですが、いかがお過ごしでしょうか。鈴木です。 ネクストの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のパフォーマンス検証等、本記事のまとめについてお話します。 長文を読んで頂き、ありがとうございました。
アバター
こんにちは。新規事業本部・金融グループの金(成奉)です。  前回は高性能GIS専用のPostgreSQLデータベースサーバーの構築について話しましたが、今回はFastCGI基盤ウェブサーバーのPHPコンパイル構築、チューニング、設定などについてお話したいと思います。内容の範囲が広く、長文になっているため、3回に分けて投稿します。  PHPは、ほとんどのモジュールがコンパイルされるような構成となっています。おまけにGIS関連のデータを扱うことのできるGEOSエクステンションの追加などにも触れています。  ウェブサーバーは、ApacheとNginxになりますが、Nginxのコンパイル構築方法についても説明します。特にApacheでPHPを運用する際、最も効率よい構成はなんだろうと開発やインフラ担当の方はきっと悩んだことがあるかと思います。ApacheとPHPをどのような構成と設定で運用すれば、高いパフォーマンスで安定的にサーバーを運用できるかが、今回のメインテーマになります。またどのような構成が、PHPを使う上で一番パフォーマンスが出ているかのベンチマークについても触れます。  なぜ、このようなお話をするかというと、サーバーのパフォーマンスと安定性は、ハードウェアも大事ですが、ミドルウェアやアプリケーションのコンパイル方法、設定、構成によって大きく左右されるからです。なので、今回は、PHPにかぎらず、チューニング方法、コンパイル方法、構成方法を中心に広範囲にわたってお話をしていきたいと思います。 環境及び制限等について 以下の作業や検証は、最新のCentOS6.5とLinuxのカーネル「2.6.32」バージョンで行った記録です。以下の操作と検証で同じ結果が出るという保証はありません。尚、ハードウェアの構成やネットワークの状況によって異なりますので、参考にしていただければ幸いです。検証環境は以下のようになります。 ・さくらVPS ・Centos6.5 ・3CPU/4G メモリ 作業場所とユーザー権限について mkdir /opt/src cd /opt/src 下のようなライブラリだけでコンパイルはできると思いますが、足りない場合は、追加インストールする必要があります。root権限で行います。 PHPバージョンについて 5.5.16 PHPの初期設定は、下のコンパイル・インストールの説明を参照してください。詳細については、バージョンによって内容が少し異なるため、以下のURLを参照しながら用途に合わせて設定します。 http://www.php.net/manual/ja/ini.core.php PHPのコンパイル構築について PHP実行バイナリは、コンパイル設定(./configure)によってスタティックまたはシェアド(Static/Shared)のバイナリを生成することができます。一般的にパフォーマンスはスタティックでコンパイルした方が良いと言われています。しかし、PHP本体にバグやセキュリティ脆弱性が発見された場合、すべてソースから再コンパイルする必要があります。シェアドでコンパイルした場合は、該当するライブラリー(Extension)のみコンパイルすることで対応できます。 PHP-5.5をビルドするとphp-cgi実行ファイルが生成されますが、今はデフォルトでFastCGI対応となっています。実行ファイルとしてphp-cli、php-fpmなどが生成されます。これらはコンパイル・オプションでサポートするSAPI(Server API)を追加してビルドすることで実行ファイルやモジュールのバイナリ(mod_phpなど)が異なります。PHPの歴史になりますが、初期バージョン(PHP/FI)も、FastCGI対応でビルドできるようになっていました。PHP3、PHP4になってからは、Apacheモジュール(mod_php)としての運用が主流となり、暫くの間、FastCGIがサポートされていなかった期間がありました。近年は、FastCGIでの運用が、世界の人々に支持され、新しくphp-fpmのSAPIが追加され、今後は、PHPはFastCGIでの運用が推奨されるようになっていくのではないかと考えています。 FastCGIでは、最初実行時に別のPHPプロセスを立ち上げてリクエストを待ち受ける状態になり、すべてのライブラリー(Extension)をメモリにロードし、リクエストを待ち受ける仕組みなので、コンパイル・オプションによるパフォーマンス差はそれほどありません。しかし、ApacheのMPM、PreforkモデルでApacheモジュール(mod_php)として運用する際、コンパイル・オプションのスタティックとシェアドとではパフォーマンスに差が大きく出ます。スタティック・オプションの方が10-30%程度早くなります。PHPをApacheのPreforkモデルで運用(mod_phpでの運用)する際は、アプリケーションで使用するPHPのExtensionを事前に決め、スタティック・オプションでコンパイル構築した環境での運用を強くお薦めします。FastCGIとして運用する場合は、コンパイル方法によるパフォーマンスの差はほとんどないため、柔軟にPHPのExtensionを、インストール・追加・変更できるシェアド・コンパイルの方がシステム運用上便利です。 ApacheのMPM(Multi-Proccessing Module)には、PreforkとWorkerがあります。ApacheのWorkerモデルではPHPモジュール(mod_php)は動作しません。ApacheサーバーをWorkerモデルで運用する際は、FastCGIで運用する必要があります。Nginxというウェブサーバーは、基本Workerモデルで動作します。このようにPHPをどのようなオプションでコンパイルするかの決定は、とても重要で、どのミドルウェアと構成するかによっても、システムの安定運用やパフォーマンスに大きく異なってきます。 PHPの運用構成について Windowsサーバでの運用 IIS/FastCGI+PHPの構成が基本です。CGIとしても運用できますが、パフォーマンスに問題があるため、推奨できません。WindowsバージョンのApacheとPHPのバイナリも配布されていていて最近はとても安定してきましたので、小規模であればWindowsでも十分運用できるようになりました。ただし、Windowsでは、Unix/Linuxのカーネルオプションのように設定の変更ができないため、ある程度のアクセス制限を超えてしまうとApacheエラーのトラブルはまだあります。Java系のTomcatサーバも似たような現象があります。 Windows環境のApacheまたはTomcatをイントラネットで運用する際、500人規模の社内環境であれば、それほど問題ないですが、それ以上の場合には、OSレベルで弾かれるケースがあるため、WindowsサーバーのIISに変更するか、Unix/Linux基盤にシステム構成を変更した方が安定的に運用できます。理由は、パフォーマンスが落ちたからといってメモリやハードウェアを増設しても、Windowsのカーネル設定を変更することができないため、それ以上のパフォーマンスが見込めないからです。 Unix/Linuxでの運用 様々な運用方法と構成があります。一般的には「apache+mod_php」で運用するケースが一番多いでしょう。Internet上に多くのPHP構築マニュアルがありますが、ApacheでPHPを「Apache+mod_fcgid+php」構成で運用するのは、、個人的な意見としては推奨できません。呼び出されたCGIをメモリに常駐させる仕組みでメモリを多く消費してしまいます。mod_fcigdをFastCGIのように扱っている内容もよく見かけますが、mod_fcigdとmod_fastcgiは全く別物です。PHPを運用する際の構成については、下のような基本構成があり、それぞれ設定が異なります。 ApacheでPHPをFastCGIで運用する時には、fastcgiライブラリとmod_fastcgi(fastcgiライブラリも含まれて配布されています)をコンパイルしてApacheに組み込む必要があります。yumのレポジトリからダウンロードできるところもあります。私は、デフォルトのyumレポジトリ以外は、コンパイルして構築する方法を好みます。その方が、依存性などによる原因不明のトラブルがなくなり、よりシステムを安定的に運用できます。 実は、FastCGI本家で提供されている仕様は、20年程前に公開されてから全く変っていません。仕組みは、Javaのサブレッドと同じ仕組みだと思えば、理解し易くなると思います。まずこのFastCGIからダウンロードできるライブラリーのソースと仕様を少し理解していれば、PHPをFastCGIで運用するために設定する際、迷いや様々なインターネットの構築関連情報に振り回されなくなります。FastCGIの本家サイトが殆ど活動していなくなってから、FastCGIの設定について多すぎる情報が返って難しくしている感じがします。 Apache以外にもPHPを様々なサーバで利用できます。近年注目を浴びているNginxをお薦めします。JavaをFastCGIとして動作させることもでき、ほとんどの言語がサポートされています。Nginxで運用する構成は、最近PHPのSAPIに追加されたphp-fpmを利用するのが一般的で安定的に運用できます。php-fpmは設定でSocketまたはTCP/IPで運用できますが、Socketの方が少し早いです。しかし、注意しなければならないのは、sysctl.conf(カーネルパラメータ)を正しく設定しないとソケットがクラッシュしてしまいます。キュー制限(net.core.somaxconn)やファイル制限等を正しく設定すればハイ・パフォーマンスのPHP運用環境が構築できます。スケーラビリティを考えているのであれば、TCP/IPで簡単に設定して運用することも可能です。他にリバースプロキシーとキャッシュサーバ構成でPHPを複数台Webサーバに負荷分散させることもできます。今回の説明では、分散構成の構築の説明までは詳しくは触れませんが、以下のような構成が考えられますので参考にして頂ければと思います。 参考サイト ・FastCGI本家   http://www.fastcgi.com/ ・Nginxのアーキテクチャー   http://www.aosabook.org/en/nginx.html オープン系のPHP運用の基本構成 01. Apache-Prefork + mod_php 02. Apache-Prefork + mod_fastcgi + php-cgi 03. Apache-Prefork + mod_fastcgi + php-fpm 04. Apache-Worker + suphp(cgi) + php-cgi 05. Apache-Worker + mod_fastcgi + php-cgi 06. Apache-Worker + mod_fastcgi + php-fpm 07. Apache-Worker + mod_fcgid + php-cgi 08. Apache-Worker + spawn-fcgi + mod_fastcgi + php-cgi 09. Nginx(Worker) + spawn-fcgi + php-cgi 10. Nginx(Worker) + php-fpm 注意1:5番のmod_fcigidは、一般的に言われているFastCGIとは異なります。 注意2:2番と3番の構成は推奨できません。ApacheのPHPモジュール(mod_php)とFastCGIを比較したベンチマークで、FastCGIが遅いと言っているサイトもありますが、この構成でベンチマークを行ったためです。 *注意3:php-fpmとspawn-fcgiには、FastCGIのプロセス管理機能があります。spawn-fcgiというのは、単体で各種言語のFastCGIを管理できるようにしたツールです。Unix/Linuxのプロセスというのは、それぞれの権限で実行されたりするため、セキュリティの意味でとても大事な機能になります。FastCGIライブラリーのソースで「fcgi_pm.c/fcgi_util.c」の内容を管理しやすくしたツールだと考えれば理解しやすくなります。他に「fcgi_buf.c/fcgi_protocol.c」というソースファイルもありますが、これらの内容を少し理解していれば、FastCGIのパフォーマンス・チューニングにとても役立ちます。ですので、php-fpmというのは、PHPのFastCGI(php-cgi)と、spawn-fcgi(管理機能なのユーティリティ)が一つにまとめられているバイナリであると考えれれば分かりやすくなります。同じ管理機能をPerl、RubyやPythonなど他のプログラミング言語で実装する際にも、spawn-fcgiを利用することでFastCGI環境での管理や運用がしやすいシステム構築ができます。つまりPHPをFastCGIで安全に運用する際に、FastCGIのプロセスを管理してくれるspawn-fcgiのようなツールとの組み合わせが必要であり、外部ツールを利用する時には「php-cgi + spawn-fcgi + mod_fastcgi」という構成になります。プロセスの管理機能等が、既に組み込まれている「php-fpm」だと「spawn-fcgi」は、不要になります。Apache環境では、「Apache-Worker + mod_fastcgi + php-fpm」という構成が、一番パフォーマンスのよい安定的に運用できるPHP環境になります。 推奨のPHP構成 ①PHP言語のみの環境 Nginx(Worker) + php-fpm Apache-Worker + mod_fastcgi + php-fpm ②PHP/Ruby/Perl/Pythonなど多言語運用環境 Nginx(Worker) + spawn-fcgi + php-cgi Apache-Worker + spawn-fcgi + mod_fastcgi + php-cgi 複数台の運用構成例 varnish:SSLに対応していないため、フロントエンドにpound(sslラッパー)を配置させます。 フロントエンドにnginxの代わりにhaproxyなどもよく使われます。 varnishとバックエンドの間にhaproxyを配置させる構成もあります。 HTTPのPOST、セッション、クッキーなどを正しく設定して構築する必要があります。 N: 数 1. pound <--> varnish <--> N * (apache + mod_php) 2. nginx <--> N * (apache + mod_php) 3. pound <--> varnish <--> N * (apache + mod_fastcgi + php-cgi) 4. nginx <--> N * (apache + mod_fastcgi + php-cgi) 5. pound <--> varnish <--> N * (apache + mod_fastcgi+php-fpm) 6. nginx <--> N * (apache + mod_fastcgi+php-fpm) 7. pound <--> varnish <--> N * (nginx + php-fpm) 9. nginx <--> N * (nginx + php-fpm) 負荷分散システム構成の整理 ①pound->varnish->haproxy->backend ②nginx->backend ③haproxy->backend ★まとめ★ ハイ・パフォーマンスのPHP運用環境構築のキーポイントは、コンパイルによるチューニング、カーネル・パラメータによるチューニング、キャッシング、負荷分散、PHP運用の基本構成、内部processingの高速化、内部networkの高速化などを総合的に適切に行うことにあります。より高速なデータアクセスと計算能力が必要とされる場合は、グリッドコンピューティング(Globusツールキット:標準ミドルウェア)構築という手段もありますが、リソースを無駄使いしないように開発現場でのデータベースやプログラミングの最適化も重要な要素となります。 長い説明になりましたが、結論は、PHPを利用する上で一番お薦めできる基本構成は以下の二つになります。 Nginx構成  Nginx-Worker + php-fpm Apache構成  Apache-Worker + mod_fastcgi + php-fpm FastCGI運用関連の設定について  FastCGIはリクエストを待ち受けるプロセス数を、ダイナミック(dynamic)または固定(static)で設定できます。自分は、固定での設定を好みます。php-fpmは、このプロセスを管理するデーモンの役割をしています。「mod_fastcgi + php-cgi」という構成の場合も、FastCGIプロセス数の設定は、ダイナミックか固定で設定しますが、定期的にメンテナンスを行う必要がありました。このような管理機能をphp-fpmというSAPIが追加されサポートされるようになったことによって、無停止で安全にFastCGIのプロセスの自動管理ができるようになりました。 PHP関連のカーネル・パラメーター・チューニングについて 上でも触れたようにPHPをソケット設定のFastCGIで運用する場合は、カーネルパラメーターを変更する必要があります。関連するパラメータの確認方法は以下のコマンドで行います。近年の金融取引システムにでは、100万分の1秒単位でのパフォーマンスを競う「LowLatency」システムが要求されます。下のカーネルパラメータ設定は、ハイ・パフォーマンスのPHP環境構築のため、「Low Latency System」の設定を一部参考にしました。 Tunedでのチューニング 以下のツールをインストールしてコマンドを実行すると自動でチューニングしてくれるそうです。内容が分からない場合は、次のコマンドは実行しないでそのままスキップしてください。 インストール yum install -y tuned オプション確認 tuned-adm list Available profiles: - default - enterprise-storage - desktop-powersave - laptop-ac-powersave - laptop-battery-powersave - sap - spindown-disk - virtual-guest - server-powersave - throughput-performance - virtual-host - latency-performance チューニング実行(latency-performance) tuned-adm profile latency-performance GRUB構文追加設定によるチューニング 以下の内容については、カーネルとOSの知識がある方に限ります。OSが起動しなくなる危険もありますので、参考程度にしていただければ幸いです。100万分の1秒単位を競う金融機関の高速取引システム(Low latency Trading System)で効果を発揮する設定を参考にしたものです。今はリアルタイムカーネル等の応用もありますので、Unix/Linuxで新しい技術について興味のある方は、Ubuntuのlowlatencyカーネルを参考にしていただければと思います。GRUB構文の最後に以下の行を追加して設定します。以下の作業は、ご自身の責任と判断で行ってください。不安があるようでしたら、この設定はスキップしてください。 nosoftlockup nohz=off highres=off intel_idle.max_cstate=0 processor.max_cstate=0 cgroup_disable=memory nmi_watchdog=0 divider=4 nosoftlockup mce=ignore_ce GRUB構文の例 注意:以下の「kernel」の部分をそのままコピーして入れ替えるとOSが起動しなくなります。必ず、上の行を最後に追加するようにしてください。 view /etc/ title CentOS (2.6.32-431.17.1.el6.x86_64) root (hd0,0) kernel /vmlinuz-2.6.32-431.17.1.el6.x86_64 ro root=UUID=035d9a21-778d-40cf-9ecb-d244d7b95781 rd_NO_LUKS rd_NO_MD SYSFONT=latarcyrheb-sun16 KEYBOARDTYPE=pc KEYTABLE=jp106 LANG=ja_JP.UTF-8 rd_NO_LVM rd_NO_DM quiet nomodeset clocksource=kvm-clock console=tty0 console=ttyS0,115200n8r crashkernel=auto nosoftlockup nohz=off highres=off intel_idle.max_cstate=0 processor.max_cstate=0 cgroup_disable=memory nmi_watchdog=0 divider=4 nosoftlockup mce=ignore_ce initrd /initramfs-2.6.32-431.17.1.el6.x86_64.img 各GRUB設定項目の説明については紙面上省略します。項目別に検索してご確認いただければと思います。 ulimit設定変更 サーバーの負荷テストを行う際にulimit設定関連のエラーで検証できないことが多いため、ulimitのデフォルト値を変更します。変更しておいた方が問題が少ないです。「/etc/security/limits.conf」やコマンドで設定出来ますが、再起動するとデフォルト値に戻ります。再起動時に自動で反映されるようにするには、以下のように追加します。 制限確認 ulimit -n -u -s 推奨設定反映 ulimit -n 65536 -u 16384 -s 32768 起動時の推奨設定反映 echo "ulimit -n 65536 -u 16384 -s 32768" >> /etc/sysconfig/init カーネルパラメータチューニング 以下の内容については、ご自身の責任と判断で行ってください。設定は、「Low latency Trading System」の設定を参考にしています。必ず設定内容を確認し、ご自分のシステムに合わせ、各項目の内容を理解した上で変更を行ってください。以下の設定反映によるシステムの停止及びトラブル等に対しての責任は負いかねます。以下の設定は、IPV6をを無効にし、IPV4のみを利用している環境の設定になります。 セフォマ計算とメモリのLatency問題関連設定適用 以下のcatコマンドで作成されたシェルを実行し、出力される内容をカーネルパラメータのセフォマとして設定します。 ファイアウォール設定でリバーシプロキシーサーバーでの利用または大規模サイトの場合、メモリに合わせて「netfilter」のCONNTRACK_MAXのチューニングを行う必要があります。 CONNTRACK_MAXチューニング 参照 http://wiki.khnet.info/index.php/Conntrack_tuning OS_BIT=64 RAMSIZE=`grep MemTotal /proc/meminfo | sed -e 's/^[^0-9]*//' | cut -d' ' -f1` HASHSIZE=`echo "scale=0; ($RAMSIZE * 1024) / 131072 / ($OS_BIT / 32)" | bc -l` CONNTRACK_MAX = `echo "scale=0; $HASHSIZE * 8" | bc -l` チューニング値計算と一部設定反映 計算された値をカーネルパラメータ設定の内容を確認して修正します。 cd /opt cat > "kernel_optimize.sh" <<'EOF' #!/bin/sh SHARED_BUFFER_RATIO=0.25 OPTIMAL_SHMMNI=8192 OS_BIT=64 echo "kernel.shmmni=$OPTIMAL_SHMMNI" MAX_MEM=`grep MemTotal /proc/meminfo | sed -e 's/^[^0-9]*//' | cut -d' ' -f1` OS_PAGE_SIZE=`getconf PAGE_SIZE` OPTIMAL_SHMMAX=`echo "scale=0; (8192 + 208) * (($MAX_MEM * 1024) / $OS_PAGE_SIZE) * $SHARED_BUFFER_RATIO" | bc -l | cut -d'.' -f1`0 echo kernel.shmmax=$OPTIMAL_SHMMAX OPTIMAL_SHMALL=`echo "scale=0; ($OPTIMAL_SHMMAX / $OS_PAGE_SIZE) * ($OPTIMAL_SHMMNI / 16)" | bc -l | cut -d'.' -f1` echo kernel.shmall=$OPTIMAL_SHMALL if [ $MAX_MEM -gt 8192 ]; then #latency issues configuration echo 2 > /proc/sys/vm/dirty_ratio echo 1 > /proc/sys/vm/dirty_background_ratio else echo 10 > /proc/sys/vm/dirty_ratio echo 5 > /proc/sys/vm/dirty_background_ratio fi #netfilter設定 HASHSIZE=`echo "scale=0; ($MAX_MEM * 1024) / 131072 / ($OS_BIT / 32)" | bc -l` CONNTRACK_MAX=`echo "scale=0; $HASHSIZE * 8" | bc -l` echo "net.netfilter.nf_conntrack_max=$CONNTRACK_MAX" echo "options nf_conntrack hashsize=$HASHSIZE" >/etc/modprobe.d/nf_conntrack.conf EOF #既存カーネルパラメータファイルのバックアップ cp /etc/sysctl.conf /etc/sysctl.conf_backup #上記設定を反映 sh kernel_optimize.sh #カーネルパラメータの設定 #下の内容は、各項目の内容を確認し、上で実行して計算された数値に変更してからcatコマンドを実行してください。修正は★マークが付いている箇所になるます。 cat > "/etc/sysctl.conf" <<'EOF' ### カーネルパラメータ設定 # SysRq設定 kernel.sysrq=0 # スケジューラの設定 kernel.sched_nr_migrate=12 # コアダンプファイル名の設定 kernel.core_uses_pid=1 ###### チューニング設定 ###### # カーネル・メッセージキュー最大サイズ kernel.msgmnb=65536 # カーネル・メッセージ最大サイズ kernel.msgmax=65536 # セマフォチューニング計算 #SHARED_BUFFER_RATIO=0.25 #OPTIMAL_SHMMNI=8192 #echo "kernel.shmmni = $OPTIMAL_SHMMNI" #MAX_MEM=`grep MemTotal /proc/meminfo | sed -e 's/^[^0-9]*//' | cut -d' ' -f1` #OS_PAGE_SIZE=`getconf PAGE_SIZE` #OPTIMAL_SHMMAX=`echo "scale=0; (8192 + 208) * (($MAX_MEM * 1024) / $OS_PAGE_SIZE) * $SHARED_BUFFER_RATIO" | bc -l | cut -d'.' -f1`0 #echo kernel.shmmax=$OPTIMAL_SHMMAX #OPTIMAL_SHMALL=`echo "scale=0; ($OPTIMAL_SHMMAX / $OS_PAGE_SIZE)*(OPTIMAL_SHMMNI / 16)" | bc -l | cut -d'.' -f1` #echo kernel.shmall=$OPTIMAL_SHMALL # デフォルトの設定内容について #kernel.shmmni = 4092 #kernel.shmmax = 68719476736 #kernel.shmall = 4294967296 # カーネルヘッダーソースの内容 #define SHMMAX 0x2000000 /* max shared seg size (bytes) */ #define SHMMIN 1 /* min shared seg size (bytes) */ #define SHMMNI 4096 /* max num of segs system wide */ #define SHMALL (SHMMAX/getpagesize()*(SHMMNI/16)) #define SHMSEG SHMMNI /* max shared segs per process */ ## SHMMAX SHMMNI 68719476736 4096 ## SHMALL = ----------- * ---------- = ------------- * ------ = 4294967296 ## PAGE_SIZE 16 4096 16 #以下4Gメモリ設定の例 #セマフォチューニング計算の内容を下で設定します。 #1プロセスごとの共有メモリの最小サイズ (byte) kernel.shmmni=8192 #システム全体の共有メモリ・ページ最大数 #★下はセマフォチューニング計算の内容に合わせて修正します。 kernel.shmmax=20593713000 #共有メモリ・セグメントのバイト数上限 #★下はセマフォチューニング計算の内容に合わせて修正します。 kernel.shmall=2574213632 #パラメータ順の内容 #semmsl semmns semopm semmni #セマフォIDごとのセマフォの数、システム全体のセマフォの数、一度に実施できるセマフォ操作の数、セマフォIDの最大値 #OracleDB(semopm)は100以上設定必須 #以下の設定はメモリデータベースのALTIBASEチューニング参考。 kernel.sem=2000 32000 512 5029 # ファイルオープン・IO関連 #Oracle/MySQLチューニング参照 fs.aio-max-nr=1048576 fs.file-max=6815744 # メモリチューニング vm.swappiness=20 vm.overcommit_ratio=99 vm.overcommit_memory=2 #IPV6無効化 net.ipv6.conf.all.disable_ipv6=1 net.ipv6.conf.default.disable_ipv6=1 # パケット転送無効 net.ipv4.conf.all.forwarding=0 net.ipv4.conf.default.forwarding=0 # listenキュー制限設定 net.core.somaxconn=262144 # ICMPエラーメッセージを無視 net.ipv4.icmp_ignore_bogus_error_responses=1 # 偽装・不正パケット:リダイレクトログ記録 net.ipv4.conf.all.log_martians=1 net.ipv4.conf.default.log_martians=1 # スプーフィング対策 送信元IP偽装防止 net.ipv4.conf.all.rp_filter=1 # L3 環境のジャンボフレームで通信する場合 #net.ipv4.tcp_mtu_probing=1 # ネットワークリソース関連設定 net.ipv4.tcp_fin_timeout=15 net.ipv4.tcp_sack=1 net.ipv4.tcp_fack=1 net.ipv4.tcp_keepalive_time=60 net.ipv4.tcp_keepalive_intvl=3 net.ipv4.tcp_keepalive_probes=3 # RFC1337に準拠(Protect Against TCP Time-Wait) net.ipv4.tcp_rfc1337=1 # ソケットの高速リサイクル(DOS攻撃防止) net.ipv4.tcp_max_tw_buckets=1440000 net.ipv4.tcp_tw_recycle=1 net.ipv4.tcp_tw_reuse=1 # TCP SYN Flood攻撃対策 net.ipv4.tcp_syncookies=1 # RFC1323 # TCPウィンドウスケーリング有効(64KByte以上のバッファー) net.ipv4.tcp_timestamps=0 net.ipv4.tcp_window_scaling=1 # ブロードキャストアドレス宛pingには無応答 # ※Smurf攻撃対策 net.ipv4.icmp_echo_ignore_broadcasts=1 # ICMP Redirectパケットを拒否 net.ipv4.conf.all.accept_redirects=0 net.ipv4.conf.default.accept_redirects=0 # Source Routedパケットは拒否 net.ipv4.conf.all.accept_source_route=0 net.ipv4.conf.default.accept_source_route=0 # Kdump使用設定 net.ipv4.conf.all.force_igmp_version=2 net.ipv4.conf.default.force_igmp_version=2 kernel.unknown_nmi_panic=1 kernel.panic_on_unrecovered_nmi=1 kernel.panic_on_io_nmi=1 # ARP応答なし設定 net.ipv4.conf.all.arp_ignore=1 net.ipv4.conf.default.arp_ignore=1 # スプーフィング対策(送信元IP偽装防止) net.ipv4.conf.all.rp_filter=1 net.ipv4.conf.default.rp_filter=1 #クライアントが増えた時のトラブル回避策 net.ipv4.neigh.default.gc_thresh1=1024 net.ipv4.neigh.default.gc_thresh2=2048 net.ipv4.neigh.default.gc_thresh3=4096 # NICチューニング設定 # ネットワークバッファーは16Mで十分 # 4MBまではカーネルで自動調整 net.core.rmem_max=16777216 net.core.wmem_max=16777216 net.core.rmem_default=16777216 net.core.wmem_default=16777216 net.core.optmem_max=16777216 net.core.netdev_max_backlog=250000 net.ipv4.tcp_mem=4096 87380 16777216 net.ipv4.tcp_rmem=4096 87380 16777216 net.ipv4.tcp_wmem=4096 87380 16777216 net.ipv4.tcp_max_orphans=16777216 net.ipv4.tcp_max_syn_backlog=65535 net.ipv4.tcp_low_latency=1 net.ipv4.tcp_no_metrics_save=1 net.ipv4.tcp_congestion_control=htcp net.ipv4.neigh.default.unres_qlen=100 net.ipv4.neigh.lo.unres_qlen=100 net.ipv4.neigh.eth0.unres_qlen=100 net.ipv4.neigh.eth1.unres_qlen=100 net.ipv4.route.flush=1 # 高負荷のサーバ/NAT/プロキシーサーバー向けのエラー対策設定 # iptablesの再起動必要、iptablesが動作していない環境では設定する必要はありません。 #net.netfilter.nf_conntrack_max 計算 #OS_BIT=64 #RAMSIZE=`grep MemTotal /proc/meminfo | sed -e 's/^[^0-9]*//' | cut -d' ' -f1` #HASHSIZE=`echo "scale=0; ($RAMSIZE * 1024) / 131072 / ($OS_BIT / 32)" | bc -l` #CONNTRACK_MAX = `echo "scale=0; $HASHSIZE * 8" | bc -l` #echo net.netfilter.nf_conntrack_max=$CONNTRACK_MAX #4Gメモリ設定例 #★下はメモリに合わせて修正します。 #iptablesが起動していない場合は、反映時にエラーになります。 net.netfilter.nf_conntrack_max=122576 net.netfilter.nf_conntrack_generic_timeout=10 net.netfilter.nf_conntrack_tcp_timeout_established=2160 net.netfilter.nf_conntrack_tcp_timeout_close=8 net.netfilter.nf_conntrack_tcp_timeout_close_wait=10 net.netfilter.nf_conntrack_tcp_timeout_time_wait=10 net.netfilter.nf_conntrack_tcp_timeout_fin_wait=10 net.netfilter.nf_conntrack_tcp_timeout_syn_sent=10 net.netfilter.nf_conntrack_tcp_timeout_syn_recv=10 net.netfilter.nf_conntrack_tcp_timeout_max_retrans=30 net.netfilter.nf_conntrack_tcp_timeout_unacknowledged=30 net.netfilter.nf_conntrack_tcp_loose=1 net.netfilter.nf_conntrack_tcp_be_liberal=0 net.netfilter.nf_conntrack_tcp_max_retrans=3 net.netfilter.nf_conntrack_acct=1 net.netfilter.nf_conntrack_checksum=1 net.netfilter.nf_conntrack_log_invalid=0 net.netfilter.nf_conntrack_expect_max=256 EOF 今回は以上になります。 次回は、PHP構築設定、MySQL設定、Redis設定などについてお話します。 長文を読んで頂き、ありがとうございました。
アバター
Apple原理主義者の大坪です。 題名を読んで「なんのことだ」と思った方。あなた方は正しい。しかし自分に嘘はつけない。私にはこの題名以外思いつかない。つまるところは先日発表されたこれですよ。 こういう時は(どういう時だ)やはり冷静にならなくてはならない。自分の状況をできる限り客観的に見つめ、その上で落ち着いてとるべき行動を考えましょう。私が何を持っているか。 ・ストレージの残りが常に10GBを切っている2011年購入のMac Book Air ・ガラスにヒビがはいったiPad 2 ・バッテリが8時間持たなくなってきたiPhone 4S ・常に火の車の家計 Mac Book Air, iPhone,iPadそのどれもが早急に更新を必要としていながら資金は限られている。というか客観的に考えれば無い。この状況において、Apple Watchに心を動かすのは全く持って正しくない。そもそもiPhone4SではApple Watchは使えない。ええいこうなったらiPhone6 Plusを買ってしまえ!と叫ぶなど正気の沙汰とは思えません。まったくどういうつもりなのか。 Apple Watchは厚すぎるし、丸くないし、未だバッテリ持続時間が発表されないことからも長く持つとは思えない。初代iPadが辿った運命を顧みれば、新しいカテゴリの初物に手をだすのは賢明ではないし、そもそも私は過去数十年腕時計を腕につけたことがない。まったく馬鹿げている。証明終わり。さあ、仕事に戻ろう。 と理解はできていても、ふと気がつけばAppleのサイトでApple Watchの動画など見返している。ああ、これつけたらかっこいいかもしれないなあ、自分の腕できれいな蝶蝶がひらひらするんだよ...しかし次の瞬間現実が肩を叩く。動画のお兄さん、お姉さんがかっこいいのは、Apple Watchのためではないのだよ。自分の姿形を鏡で見てご覧、と。 かくのごとく現実と感情の間で揺れ動き続きため息をつくのはあまり楽しいことではない。 しかーし 人生は捨てたものではない。救いの手はすぐそこまできています。Origamiが昨日 1.4にバージョンアップ されました。そしてApple Watchがサポートされたのです。一介のソフトウェア開発者たるもの、まずその上でソフトウェアを開発し、その上で個人的に購入するか否か悩むべきなのです。 などという破綻した理屈をこねまわしつつまず触ってみましょう。 あれこれ参照 して、Origami1.4をインストールしましょう。すでにOrigamiをインストールした人であれば、この ページ に行って、「3」のリンクをクリック、ダウンロードされたファイルをダブルクリックし、インストーラーの指示に従えばOKです。 と簡単に書きましたが、Avocadoをインストールしていると、エラーページに飛びます(親切だなあ)指示に従って自分のアカウント下にあるLibraryフォルダから、Graphicsフォルダをデスクトップに移動させる。そのあとインストーラーを再度走らせるとOrigami1.4がインストールされます。 さて その後Quartz Composerを立ち上げます。"File"メニューを選ぶと一番上に"New Origami File"なる項目があることに気がつきます。これを選ぶといきなりここまでできます。 いままでお約束のように「ここまで作りましょう」と書いていた作業がメニュー選ぶだけで完成。「ああ、なんて簡単なの!」と喜びの涙を流しながらViewer中のiPhoneをいじってもいいのですが、やはりここはあれでしょう。一番左の"Phone Dimensions"パッチを選び、Patch InspectorもしくはParametersを選択し、今"iPhone"になっている"Phone" の項目を"Apple Watch"にしましょう。どきどきしながらViewerを見ると... なんと!Apple Watchが手に入ったではありませんか。などとわざとらしく言ったところで心に感じる薄ら寒さは隠せない。しかし現実を認めたら負けです。 ちなみにOrigami1.3からこうしたパラメータ変更はもっと簡単にできるようになっています。"Phone Dimensions"パッチの、Phoneの横をダブルクリックしましょう。 するとこんなメニューが開きます。ここからApple Watchを選べば終了。簡単ですね。 今回追加された機能を利用した サンプル も既に公開されています。しかしこのサンプル結構力作なので、読み解くのは簡単ではない。ここは「とにかくやってみるか」と思えるくらい簡単なサンプルを作ってみましょう。 Layer Groupをダブルクリックして中に入り、以下のパッチを追加します。(Patch Libraryから検索しましょう) System Time Date Formatter Text Layer やりたいことは、時間のデータをどこからか取ってきて、適当にフォーマットし画面上にText Layerで表示する、というものです。追加したパッチを以下のようにつなぎましょう。そしてどきどきしながらViewerをみるのです。 やったー。これがApple Watchだー(棒読み) 来年のいつになるかわからない発売までに、Appleがどんな「時計盤」を出してくるだろうか。今から胸がわくわくします。そしてこんなデザインは決してでてこないことに関しても自信がある。 とはいえ、時間を知るのはWatchの基本中の基本。少しだけこのプログラムをいじってみましょう。 Date Formatterを選び、Patch Inspectorを開きます。でもってSettingをこんなふうにセットしましょう。さらにはText LayerのFont Sizeを適当に選べば... まああれですね。少しはマシですが「だから何?」という声は頭の中から消えない。いや、ここで負けてはいけない。私が何かの講師だったら 「これを使ってあなたの考えるWatchを作ってください」 とやるところです。そうやって他人が作った様々な時計盤のデザインを眺めながらぼんやりと考えるのです。いつの日かOrigamiじゃない本物が手に入るといいなあ,,,と。 今回のプログラムは Github に置きました。
アバター
はじめまして。プロダクト開発部の冨田と申します。 『Junkup』というニュースリーダーサービスのアルファ版をローンチしました。 http://www.junkup.net/ 『Junkup』とは WEB型のニュースリーダーで下記のような特徴があります。 タイトルが似ているサイトを「関連記事」として名寄せする Twitter、はてなブックマーク、Pocketなどへ同時にシェア出来る レスポンシブなのでPC、タブレット、スマホから利用できる 『Junkup』の生い立ち 私はGoogle Readerのヘビーユーザーで1日に1000~2000件のニュースに目を通していました。 しかし、2013年3月頃に閉鎖されるという衝撃の発表が行われ、 FeedlyやGunosyやSmartNewsなど、どこに乗り換えようか悩んでいました。 ただ、どれを使ってもいまいちしっくり来ませんでした。 キュレーション系のニュースサービスへの不満 紙幅が限られているので欲しいニュースが手に入るとは限らない チャンネルを追加すると似たようなニュースで溢れる 単純なRSSリーダーへの不満 色々なニュースソースを登録すると似たようなニュースで溢れる これらの不満な点を解消すべく『クリエイターの日』という業務時間の10%を使い、 合宿形式で研究開発する制度を利用して自分好みのニュースリーダーを開発し始めました。 『Junkup』ローンチへ 開発を始めて数カ月後、新規事業を提案できる社内制度「Switch」の 新規サービス部門へ応募してみないかと声がかかりました。 採択されると期限つきですが予算がつきます。 期限内にKPIを達成できないと終了となります。 KPIを達成すると事業化できるかも!? サービス内容をブラッシュアップし経営陣に対しプレゼンしたところ採択され、 2014年4月から9月まで予算がつきました。 予算はAWSの費用やサイト開発費用に当てており、 2014年7月にローンチし現在に至っております。 期限内にローンチしKPIを達成しなければならないため、 最小限の機能しかまだありません。 まずは、KPI達成に向けて9月末まで全力でブラッシュアップしていきます! ご意見、ご要望はjunkup@next-group.jpまでご連絡ください。 クリエイターの日 http://creators.next-group.jp/ 新規事業提案制度「Switch」 http://recruit.next-group.jp/keyword/#sec02-02
アバター
Apple原理主義者の大坪です。 最近 「UXとUIは何が違うのか」 といった議論を時々みかけます。それぞれの言葉について、合意のとれた定義がないから正解はないのですが、この問題に対してのあれこれの議論は時として興味深いものになります。 というわけで昨日見つけた記事について。 記事の題名は "Recruiting a Designer? Here's What You Should Know" 「デザイナーを探している人が知っておくべきこと」 デザイナーという言葉はとても幅広いわけです。車などのプロダクトデザインもあれば雑誌のデザインもあり、web、アプリなどのデザインもある。この記事ではweb、アプリなどを対象にしたTech Industory(日本語ではIT業界なのですかね)での様々なデザイナーの役割について書かかれています。 記事中それぞれの「デザイナー」が使っているツールとかもでているのですが、如何せん疲れたエンジニアにはよくわからない。というわけで、大胆に省略して自分で理解できた、と思ったところだけを訳します。 UX デザイナー: 主に考えること:ユーザは製品を使ってどう感じるか? お気に入りのツール:Photoshop, Sketch, Illustrator, Fireworks, InVision 例えばこんなことを言う:ユーザが登録を終了したら、「ありがとう」のページを出そう UIデザイナー 主に考えること:個々のページはどのようにユーザと視覚的にコミュニケーションするか? お気に入りのツール:Photoshop, Sketch, Illustrator, Fireworks 例えばこんなことを言う:ログイン/新規登録のリンクはページの右上におくべきだ ビジュアルデザイナー(グラフィックデザイナー) 主に考えること:ピクセルと格闘して、美しいアイコン、コントロール、それにフォントを作る お気に入りのツール:Photoshop, Sketch(訳注:あれ、Illustratorは?) 例えばこんなことを言う:カーニングをオフにして、ボタンは1ピクセル左にすべき インタラクションデザイナー(モーションデザイナー) 主に考えること:ユーザが触った後に、画面はどう動くべきか? お気に入りのツール:AfterEffects, Core Composer, Flash, Origami 例えばこんなことを言う:メニューは左端からease-inで800msecで現れるようにしよう UXリサーチャー(ユーザリサーチャー) 主に考えること:製品のユーザは誰なのか?そして何を望んでいるのか? お気に入りのツール:Mic, Paper, Docs 例えばこんなことを言う:リサーチの結果、典型的なユーザは.. フロント開発者(UI開発者) 主に考えること:製品のインタフェースを実装する お気に入りのツール:CSS, HTML, JavaScript 例えばこんなことを言う:960px 12カラムの グリッドシステム を使ってるよ プロダクトデザイナー 会社によって定義が異なり、これまでに記述した内容のどれでもあり、どれも含みうる。 ーーー この記事を転載した こちらのページ ではコメント欄でいろいろな議論がなされています。 多くの指摘は 「役割は分けられるにしても結局全部できなきゃだめだよね」 というものです。一番極端な意見では In the end, an experienced senior designer should be able to do all the roles above. They should also understand how HTML/CSS (front-end) and various programming environments (back-end) effect their designs; capabilities/requirements/limitations. via: UI, UX: Who Does What? A Designer's Guide To The Tech Industry | Co.Design | business + design 経験をつんだシニアデザイナーは上記の役割全部をこなす必要がある。HTML/CSS(フロントエンド)からバックエンドの環境がどのようにデザイン上での機能/要求/制約に関係するか理解しなくてはならない。 なるほど、、とは思いますがそれができれば苦労はしない、と言いたくもなる。 加えてあれですよ。Apple原理主義者としては 「HTML/CSSだけでは足らん。iOSで何ができるか、できないか理解してもらわなくては」 と言いたくもなるわけですが、そうするとここに書かれた「シニアデザイナー」はますます非現実的なものになっていく。 というわけで結局 「専門性を持った上で、専門が異なる人ときちんと会話できることが必要だよね」 ということになるのかな、と思うわけです。別の記事から引用します。 At Etsy, like many companies these days, product designers are responsible for staying active and involved throughout the entire development process. From product definition to user flows to wireframes to visual design to, yes, writing and deploying their own HTML and CSS, designers are tasked with staying involved from start to finish. via: Why Designers Really Should Learn to Code Etsyでは昨今多くの企業でなされているように、プロダクトデザイナーは開発の全てのプロセスに関わり、そして責任を持つ。製品の定義からユーザフロー、ワイヤフレーム、ビジュアルデザイン、そしてHTML,CSSの作成まで行う。デザイナーは開発の最初から最後まで関わることになる。 なぜ Etsy ではこういう方法をとっているのか。例えばデザイナーが自分でコーディングまで行うとするとエンジニアの 「そんなの無理」 という「言い訳」に悩まされる必要がなくなる。つまりデザイナーが独立して思うがままに開発を進められる、、、からではない、とこの文章は続きます。 However, we expect the same of our engineers and product managers - we push everyone on a team to be involved in every step of creating great products. 中略 What’s been most interesting to me about requiring designers to work in code is that, instead of making our designers more independent, working in code has actually created a deeper collaboration with their engineering partners. via: Why Designers Really Should Learn to Code しかしながら、エンジニア、プロダクトマネージャーも同じようにすることが期待される。つまりチームの全員が製品開発の全てのステップに関わるようにしているのだ。 (中略) デザイナーがコードを書くことの一番興味深い点は、それによってデザイナーがより独立する、ということではなく、コードを書くことによって、エンジニア達とよりよく共同作業できるという点にある。 お互い共同しましょう、と言っているだけではなく、実際に協力する相手の作業を担当してこそお互いの立場が理解できる。 That’s what collaboration really is - crossing boundaries and finding common ground so that we can work together and share a mutual understanding. via: Why Designers Really Should Learn to Code お互いの境界線を越え、一緒に働ける共通の場所を見いだし、互いに理解し合う。それこそが真の協力というものだ。 あれですよ。私のような疲れたエンジニアが自分で製品のUIをデザインしたとする。それに対してデザイナーさんが出してきた案をみて 「をを、こんなに違う。当たり前とはいえこの差異はなんなのか」 と驚愕する。この驚愕はきっと無駄ではない、と信じたい。 と無理矢理前向きにまとめたところで今回はおしまい。
アバター
こんにちは。7月からAndroidチームに配属されました衛藤です。 先月の6月25, 26日に、Google最大のイベント"Google I/O 2014"が開催されました。 私自身は参加していないのですが、YouTubeでの配信を見ていたところ、 Notificationについての話がちらほらと出ていましたので、その辺りを書いてみたいと思います。 Notificationについて スマホユーザにはおなじみのNotificationですが、Googleによると下記のように説明されています。(そのままですが・・・) A notification is a message you can display to the user outside of your application's normal UI. iOSなんかでは、ロック画面に通知が表示され、そこからダイレクトにアプリに飛べたりするのですが、 Androidではそれ専用のWidgetアプリくらいしかありませんでした。 現状だと、画面の上からスワイプして通知画面を引き出して来ないと通知が分かりません。 この通知ですが、ユーザにアプリを開いてもらうための強力なツールになります。 プロモーション、そして継続利用 アプリをリリースした後に重要になってくることが二つあります。 1. プロモーション 2. アプリの継続利用 プロモーションでは、広告やプレスリリース等でアプリをより多くの人に知ってもらいます。TwitterのRT拡散も結構効果あり。 より多くのユーザにアプリをストアから落としてもらうのは一番重要ですが、アプリの継続利用も意識する必要があります。そこで継続利用に欠かせないNotificationを活用しより多くのユーザに長く使って頂く。開発者にとっても非常にうれしいことですね。 今回のGoogle I/Oでは、Notificationが強化された、という説明がいろんなセッションで出ていました。 仕組みというよりはビジュアル面がメインのテーマでしたが、ようやくロックスクリーンにも表示できるようになりました。 以下、セッションから一部抜粋しながらまとめていきます。 Google I/O 2014 - Keynote から Android Lセクション(25:00前後) 人々がポケットから端末を取り出しチェックする一番のトリガーは・・・Notiifcationである。それも1日何十回も。 Android LではNotificationが強化され、ロックスクリーンから直接アプリへ飛ぶことができる。 アプリを使っている途中でも、上からNotificationが表示されるようになる。邪魔な場合は横にスワイプすればよい。 Android Wearセクション(49:00前後) Androidユーザは1日平均125回、Android端末を取り出している。そのため、Android Wearは素早く、必要な情報が一目でわかるように設計されている。 Notificationをバイブレーションとともに知らせることで、重要なメッセージを逃すことなく確認できる。 AndroidスマートフォンとAndroid Wearは通知も連携できる。 Google I/O 2014 - What's New In Android から Notifications(21:50前後) Material Designに沿った見た目になった。 新しいテンプレート"Media Style"が追加された。 Android Lより前のバージョンだと4つの通知を確認するまで4つのステップが必要であった。 端末が鳴る/バイブレーションを確認する 端末の電源ボタンを入れる ロック画面を解除する 上から通知画面をスワイプしてくる Android Lからは・・・ 端末が鳴る、電源ボタンを押す、それだけ。 プライバシー設定により、アプリがどんな内容で通知すべきか制御できる。 プライバシー設定のバリエーション(.setVisibility(Notification.VISIBLITY_***)) VISIBILITY_PUBLIC : 内容は誰でも見ることができる。 VISIBILITY_PRIVATE : 内容は本人だけがロック解除後に見ることができる。 VISIBILITY_SECRET : アイコン含み何も表示されない。 背景の色も独自に設定できる(.setColor(***)) 一応サンプルコード Android 4.4まではステータスバーへの通知になります。 Notification.BuilderはAPIレベル11からのものなので、それ未満の場合はSupportPackageに入っているNotificatoinCompat.Builderを使う必要があります。 Intent intent = new Intent(this, MyActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext()); builder.setContentIntent(pendingIntent); builder.setTicker("Ticker"); builder.setContentTitle("Content Title"); builder.setContentText("Content Text"); builder.setSmallIcon(R.drawable.ic_launcher); NotificationManager mgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); mgr.notify(0, builder.build()); 今後、Android Lが正式に出るとロック画面への表示が出来るようになります。 なお、下記のようにaddAction()によって通知領域内にボタンを6個くらいまで設置することができるようです。 音楽アプリ系でよく使われそうです。 .addAction(R.drawable.skip_previous, "Previous track", prevIntent) .addAction(R.drawable.fast_reverse, "Rewind", rewIntent) .addAction(R.drawable.puase, "Pause", pauseIntent) .addAction(R.drawable.fast_forward, "Fast forward", ffIntent) .addAction(R.drawable.skip_next, "Next track", nextIntent) .setColor(R.color.app_color) .setStyle(new Notification.MediaStyle() .setShowActionsInCompactView(2) .setMediaToken(mediaToken) まとめ Android Lからロックスクリーンに通知機能が追加になるとともに、Android Wearとの連携も可能になります。 また、現行と同じくNotificationのスタイルもBigPicture/BigText/Inboxなどが選べるため、表現の仕方によっては、アプリの継続利用率も上がってくるのではと思います。 特に何かを探す系のアプリなんかでは、PUSH通知と組み合わせておすすめ情報の通知(画像と共に)、在庫などに合わせて「残り○○ですよ!」みたいな通知、スケジューラとの連動など、アプリを有効活用してもらう仕組みの幅が広がりそうですね。 色やアイコンも自由なので、コーポレートカラーやアプリのテーマカラー、アイコン等を積極的に取り入れ、自社のイメージを前面に押し出していくこともブランディングの一つになりそうです。 ちなみに、通知は時間帯も非常に重要です。 自分で使っていれば分かると思いますが、一番使う時間帯は・・・ 寝る前など家にいるとき 通勤電車 昼休憩など http://research.rakuten.co.jp/report/20120524/ 楽天のスマートフォンの使用実態に関する調査より 一番スマホが見られている時間帯に、「アプリを見たい!」と思わせる通知を見せる、これだけでも効果は違うのでは、と思います。 以前からNotificationは重要だといわれてきましたが、今回Android Wearとも連動し 今後Notificationはアプリにとってさらに強力なツールになっていく、そう思ったテーマでした。 最後まで読んでいただき、ありがとうございました!
アバター
こんにちは。クリエイターの日運営委員の松尾です。 前回 に引き続き、1Q後半に活動する5チームと クリエイターの日の報告会について紹介します! 社内で使うツールのデザインに取り組んでいる様子です。 使いやすいデザインにはとことんこだわります。 こちらのチームのメンバーは全員が新卒入社。 サービスのリリースに向けて開発のスピードは上がってます。 今年新卒として入社したばかりのエンジニアも頑張ってます。 手の動きで何かを操作しようとしている様子…? 不動産会社様に使って頂くサービスを作成中。 エンドユーザ、クライアント、社内など、 クリエイターの日に作るプロダクトのターゲットは様々です。 クリエイターの日のサイト に新しいコンテンツを制作中。 多くの方に制度の良さを伝えるべく、コンテンツを追加していきます。 今回も多くのクリエイターが活動に参加してくれました。 また、活動期間の終了後には、社内で報告の場を設けました。 「この部分はどういう構成で動いているのか」 「業務に応用できそうな部分はあるか」 「サービスとしていつリリースするのか」 などなど、様々な質問が飛び交う報告会です。 ネクストのものづくりをより活発にするべく 今後もクリエイターの日を盛り上げていきます。
アバター
Apple原理主義者の大坪です。 さて、Google I/O 2014シリーズの第3弾は、デザインに関して私が理解でき(たような気がして)かつ印象的だった点について。 今回Googleは新しいデザイン言語としてMaterial Designを発表しました。キーノートで 「われわれは、ピクセルが色だけでなく奥行きも持っていたらどうなるか想像してみた。また状況に応じてテクスチャーを変えられるような素材があったらどうだろうと考えてみた。これがMaterial Designを開発するきっかけになった」とAndroid OSのユーザー体験の責任者、Matias Durateは語った。 via: Google I/O:デザインでもAppleに対抗へ―ユニバーサル・デザイン言語、Material Design発表 – Techcrunch この発表があったとき、そしてその背景にながれたアニメーションを見たNerdの90%は 「をを、Googleはとうとう画面のピクセルが物理的に変化するディスプレイを開発したのか!」 と熱狂したに違いない。しかし実際に発表されたのは、Material Designでした。がっかり(<これだから頭のおかしいエンジニアは。。) ━━━ 私が興味深いと思ったのはGoogleのMaterial DesignとiOS7で"Depth":「深さ」という共通の言葉が強調されていていたこと。そしてその実現方法が異なっていたこと。2次元でしかない画面上でどうやったらユーザに奥行きがあることをわかってもらえるか? Google Designのサイト にいってマウスを動かせばすぐ気が付きますが、マウスの下にあるタイル(少なくともその形状をしたもの)が少し浮き上がったように見える。これは周囲との間の陰影関係を制御しているように見えます。 対してiOSではぼかしを含んだ半透明の画面、またはデバイスの動きに応じて背景が少しずれるパララックス効果を使うことで、画面間に奥行きの差があることを示しました。 実現方法の差異はさておき、デモされる画面を見ていると、色の連続的な変化、モーフィングなど「動き」がますます重要になっていることが見て取れます。このGoogle I/Oでも" Material Design:Motion "なるセッションがあり、「動き」がUIの中でどれだけ重要であるかが語られていました。特にこのセッションでは「振付(コリオグラフ)」なる言葉が使われているのには驚きました。そのうち画面設計でもコリオグラファー:振付師という言葉が使われるかもしれません。 画面が非連続的に変化するのではなく、連続的に変化することで、何が起こっているかをユーザに理解させる。こうした点においてiOS7とMaterial Designは共通している。 (ここに「であるからして、Origamiのようなデザインツールの重要性がますます..」という いつもの言説 が数十行あると思ってください) しかしながら違いもあります。私の意見ではAppleよりもGoogleの方が「異なるデバイス間での共通デザイン」という要素を強調しているように思える。Mac OS XもYosemiteでiOSのデザインに近づいたわけですが、それは明示的に強調されていません。WWDCのキーノートを見返したのですが、Yosemiteの新デザインのプレゼンにおいてiOSとの共通性は全く言及されていない。 対するにMaterial Designではたとえば新しく導入された画面上のボタン(Floating Action:下の図の緑の丸です)がすべてのデバイスで画面上に存在している。 Material Design unifies all Google products under one aesthetic. via: Google I/O 2014 Roundup - HardwareZone.com.ph Windowsはこうした「共通化」について一番極端だったといえるかもしれません。あのタイル画面をPCでもモバイル機器でも「どん」と正面に据えたわけです。このようにApple/Google/Microsoftがそれぞれ異なる画面上で何を共通にし、何を個別にしたかの判断はなかなか興味深いものがあります。 ━━━ 次に今回発表されたAndroid Wearのデザインについて。 このセッションについては、実際に行われたセッションの動画が公開されていませんが面白い要素がいくつかありました。 Smart Watchの画面デザインはどうあるべきか?それを考える上で 「まずやってみる」 ことはとても重要。かくしてGoogleのデザインチームは針金(のようなもの)を使ってAndroid スマートフォンを手首に固定したらしい。この「プロトタイプ」は傑作でした。(ああ、写真をとっておけば) これをやると何がわかるか?手首に固定された画面というのは、非常に激しく動く。これは手のひらの中にあるスマホの画面や、机に座って眺めるPCの画面と大きく異るところです。 従って静止した画面上ではどんなに美しく見えるデザインでも、揺れ動く手首の上では役に立たない。動く画面上では読み取れる情報量は少なくならざるを得ない。 調べてみると他社では、スマートフォンのUIをそのまま縮小してスマートウォッチに載せたような画面デザインもあるようです。 「スマートフォンのUIと共通性が高いので、すぐに移行できる」 という説明もロジックとしては成り立つでしょう。 しかしながらGoogleは実際に「使用」してみて異なるアプローチを採用したわけです。前掲のビデオで強調されているように腕につけたディスプレイ上では 「ユーザが行うタスクはなんなのか。それを実現するために必要な最低限の情報はなにか」 と考え、情報とインタラクションを絞らなくてはならない。そう考えると、Smart Watchの画面デザインというのは、スマホやPCサイトとは異なるチャレンジであることに改めて気がつくわけです。いや、楽しい。 しかし 仮にその問題を解いても 「Smart Watchを購入し、日常的に利用したいか?」 というさらなる難問が控えているわけです。 前回書いた内容 に沿って考えれば、Smart Phoneでは解けず、Smart Watchが解こうとしている問題は本当に存在しているのか?そしてAndroid Wearはその問題を効果的に解いているのか?これは実際に使ってみないとわからない。 ではさっそく当日プレゼントされたAndroid Wearを着用して自分で確かめてみよう、、としたわけですが、Androidスマホを持っていないと設定画面の最初で躓くことを知ったのでした。 ここらへんがApple原理主義者の限界、ということでGoogle I/O 2014の参加報告はめでたく(どこがだ)お開きです。
アバター
こんにちは。5月よりiOSチームにジョインした成田と申します。 先日のWWDC2014の発表には驚かされましたね! OSのアップデートなどは予想通りでしたが、新言語の発表があることを想像できた人はほとんどいないのではないでしょうか。 当然HOME'SのiOSアプリチームもWWDC2014には注目しており、 当日の朝はSwiftの発表やiOS8の新しい機能に盛り上がっていました!(現地行きたい) 毎年毎年、新しい技術が発表されキャッチアップしていくのが大変ですが、それが楽しみでもあります。 iOS8から盛り込まれる新しい機能を利用して、どんなことが提供できるのか毎日毎日メンバーみんなで頭をひねって考えています。 さて、今回はそんなiOSチームが定期的に取り組んでいることを紹介したいと思います。 iOSアプリレビューランチ 隔週月曜日、ランチタイムに開催しています。 iOSアプリチームメンバーが、各々見つけてきた"気になる"アプリを紹介し合います。 エンジニアだけでなく企画も、デザイナーも全員参加です。 それぞれ視点の違う色々な人が集まるので、自分では見ることのないようなジャンルのアプリを知ることもでき、とても面白いです。 たまに海外のアプリも紹介されるのですが「こんなビジネスモデルがあるのか!」と驚かされることもあります。 やっぱりiOSアプリだと、UI関係が一番話題に上がりますね。 「最近、こんなUIが流行ってるよね」 「これ最近見るパターンだよね~」 なんて会話が繰り広げられます。 新卒の石田さんがアプリを紹介する様子。 毎回みんなネタ切れにならないように必死にアプリを探してきます 笑 iOS開発もくもくランチ 週1.5回開催、こちらもランチタイムに行っています。 エンジニアで集まり、iOS、Objective-C、Xcode、そしてSwiftなどを勉強しています。 残念ながら仕事が忙しかったり場所が確保できなかったりと、なかなか開催できないのですが「どんな新しいことができるだろう」、「どんなことに対応しないといけないか」などを考える良い時間となっています。 WWDC2014のKeynoteがあったお昼もエンジニアで集まって発表内容をざっくりと整理しました。 やはり今はiOS8が一番アツい内容です。 Swift勉強会 社外の方も参加可能なSwift勉強会です。 定期的(2~4週間おき)に開催したいと考えています。 先日の第1回の内容はiOS開発グループの石田さんが書いたブログ 「第1回Swift勉強会@ネクストを開催しました!」 に詳しく書いてありますので是非ご覧ください。 現在、第2回を企画中です。 ご興味のある方は是非ご参加ください! 週末開発ハッカソン こちらは不定期開催です。 週末、どこかのワーキングスペースに有志で集まって自分の好きなこと、やりたいことなど課題を設定してもくもくと開発します。 業務ではなかなかできないことにも取り組めるので良い"息抜き"になっています。 ここで学んだことを業務にも生かせて自分の腕も上がるので良い機会となっています。 輪読会 毎週水曜日、朝一時間早めに出社して行っています。 今はあの「リーダブルコード」を開発チームで輪読しています。 発表者が章ごとにまとめた資料を作り、ざっくりとした内容を話します。 章が終わると一度区切って、内容についてディベートをします。 ここでメンバー同士の考え方の違いが分かります。 色々と話していく中で考えをすり合わせることでコーディングスタイルなどを統一させていくことができます(と思っています)。 朝一のフレッシュな頭で行っているので良い頭の運動にもなります! もうすぐ「リーダブルコード」を読み終わるので、次回は「iOSヒューマンインターフェイスガイドライン: UI設計の基本事項」を読み解いていく予定です。 まとめ HOME'S iOSアプリチームの取り組み、いかがでしたでしょうか? より良いアプリを作るため、目に見える部分だけでなく目に見えない部分も改善しようと日々取り組んでいます! そんなiOSチームが開発した HOME’Sアプリ が先日デザインを一新してアップデートいたしました! ダウンロードしていただけると、とても嬉しいです! これからもiOSアプリチーム一丸となり、工夫を凝らしながら頑張っていきます! よろしくお願いします!
アバター