わーくあうと!

日々の作業でためになったことをアウトプットすることで自分の成長につながればなと。

apacheでメモリリークしないようにするチューニング

今日のことなんですが、運用しているWebサービスに集中したアクセスがあって繋がりづらい自体に陥ってしまいました(SSHすらも) psコマンドで確認したところhttpdプロセスがメモリをもりもり使っててメモリリークメモリリークとは違うけど、まあ今回はそう呼ぶ)していたようで、これはよくないとApacheのチューニングを行ったのでその内容を記事にしておきます。

 

なにをしたか

httpdプロセスが立ち上がりすぎてメモリが溢れないよう、立ち上がるプロセス量を調整しました。

↓この記事を参考にチューニングしました。

Apacheをデフォルト設定のままで使っていませんか?

 

Apacheに割り当て可能なメモリ量を調べる

参考記事では「OS起動直後にfreeコマンドを打てばわかるよ」というような事を言っていましたが、現在サービス運用中で再起動はしたくないので以下の方法で割り当て量を出しました。

a,VPSに積まれたメモリは2GB

b,システムが現在使っているメモリ量は約1.5GB。(freeコマンドのusedの値)

c,現在Apacheが使用しているメモリ総量は約1GB。

Apacheが使用しているメモリ総量はこれ↓で計算。

# ps aux | grep [h]ttpd | grep [a]pache | awk 'BEGIN{x=0}{x+=$6}END{ print x }'
1026700

つまり Apache以外が使っているメモリは 1.5GB(b)-1GB(c)=0.5GB なので 使えるメモリ量は 2GB(a)-0.5GB=1.5GB=1536MB としました。

 

Apacheの最大子プロセス数を調べる

まずはApacheの子プロセスあたりの平均メモリ使用量を計算。

# ps aux | grep [h]ttpd | grep [a]pache | awk 'BEGIN{x=0}{x+=$6}END{ print x/NR }'
51255

子プロセス一つあたり51255(約52MB)使っているみたい。 なので、Apacheの最大子プロセス数は

Apacheの最大子プロセス数 : P =
1536MB(Apacheに割り当て可能なメモリ量) / 52MB(Apacheの子プロセスあたりの平均メモリ使用量)

で P = 29.538461・・・・ となります。

 

Apacheの設定変更

ここまでで調べた値を元にhttpd.confを編集します。 参考記事では下記の内容で設定するのをオススメしていましたが

<IfModule prefork.c>
StartServers P×5/256
MinSpareServers P×5/256
MaxSpareServers P×10/256
ServerLimit P
MaxClients P
MaxRequestsPerChild 1000
</IfModule>

それで計算するとこうなります。

<IfModule prefork.c>
StartServers 1
MinSpareServers 1
MaxSpareServers 2
ServerLimit 30
MaxClients 30
MaxRequestsPerChild 1000
</IfModule>

うーん、なんか少なすぎるような。。 適当にもう少し増やしてみます。

<IfModule prefork.c>
StartServers 3
MinSpareServers 3
MaxSpareServers 7
ServerLimit 30
MaxClients 30
MaxRequestsPerChild 1000
</IfModule>

ほんと適当です。根拠無いです。

おそらく ServerLimit と MaxClients さえ変えなければそこまでひどい事にはならないと思うので。

と、今回はこんな感じで設定してみました。これでメモリリーク起きなくなるはず。  

jetpackのパブリサイズ共有で、メッセージにプレフィックスを付ける方法

jetpackパブリサイズ共有を使って記事の更新をTwitterFacebookに共有してるのですが、デフォルトの文言がタイトルとURLだけで分かりづらいので先頭に【ブログ更新】みたいなプレフィックスつけたいなーと思って対応したのでメモ。

デフォルトの文言を変更したくてjetpackプラグインの中身を漁ってたら『jetpack/modules/publicize/publicize.php』の33行目付近に

var $default_prefix = '';
var $default_message = '%title%';
var $default_suffix = ' %url%';

という記述があり、この値を使っているようでした。

ここを変えれば変わるのですが、直接プラグインをいじるのはいけてないので何かないかなーともう少し読み進めたら『wpas_default_prefix』という名前でapply_filtersしてました。

なので function.php に add_filter を定義して値を上書きした・・・けど何故か呼ばれなかった。

色々試してみたけど、どうも function.php に書いた add_filter が定義される前に publicize.php の apply_filters 部分が呼ばれているようだった。

仕方がないのでプラグインを直接いじって対応することにした。

修正後がこれ↓

var $default_prefix = '【ブログ更新】';
var $default_message = '%title%';
var $default_suffix = ' %url%';

プラグインはいじりたくなかったけど仕方ない...  

WordPressにTwitter Cardsを設定してみた。

公式のTwitterクライアントなんかでURLが含まれたツイートをクリックした時に概要がシュッと出るあれ、自分のブログでも出たらかっこいいなーと思って設定してみました(このブログでは無いですが)

作業としては『ブログ側の対応』『Twitterへ申請』の2つがあるのでそれぞれ説明します。

ブログ側の対応

htmlのhead部分にコードを挿入するのですが、テーマを直接いじるのも嫌だったので『Twitter Cards』というプラグインを使いました。

プラグインー>新規追加 から『Twitter Cards』で検索すれば見つかるのでインストールします。

インストールしたプラグインを有効化したらこれだけでもうブログ側の対応は終わりです。

Twitterへ申請

Card Validator | Twitter Developers https://dev.twitter.com/docs/cards/validation/validator

↑のリンクから表示の確認をした後に申請をします。

Validate & Apply タブにあるテキストフィールドに自分のブログ記事のURLを入れてEnter押すと表示を確認できます。 ここで何もエラーが出なければそのまま『Request Approval』ボタンから申請画面へと進みます。(自分の場合はここで『invalid card type』というエラーが出て、色々試しても解決できずに一晩寝てまた試したらなぜか通りました。Twitterのバグ?)

で、申請画面にある項目(Webサイトの簡単な説明文など入れる必要あります)を適当に埋めて『Register Domain』ボタンを押せば申請完了です。

あとはTwitterから対応完了の連絡が来るのを待つだけ。

ちなみにこの連絡は数週間かかるらしいです。  

ニコ動のURLからブログ記事のアイキャッチを自動的に作成する方法

wordpressで、youtubeニコニコ動画からアイキャッチを自動生成する方法を探してたら↓の記事を見つけた。

YouTubeの動画からブログ記事のアイキャッチ画像を自動的に作成する方法

この記事を参考に『auto-post-thumbnail.php』の

// Get all images from post's body
 preg_match_all('/<\s*img [^\>]*src\s*=\s*[\""\']?([^\""\'>]*)/i', $post[0]->post_content, $matches);

の下に

if (empty($matches[0])) {
 preg_match('%(?:youtube\.com/(?:user/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $post[0]->post_content, $match);
 if (!empty($match[1])) {
 $matches=array(); $matches[0]=$matches[1]=array('http://i3.ytimg.com/vi/'.$match[1].'/hqdefault.jpg');
 }
}

を追記する事でYouTubeの動画が貼られた記事で自動でアイキャッチを作成することができた。

その勢いで正規表現部分とサムネ画像URL部分をいじればニコ動にも対応できるかなーと思い、

if (empty($matches[0])) {
 preg_match('/http:\/\/(?:www\.nicovideo\.jp\/watch|nico\.ms)\/[a-z][a-z](\d+)/', $post[0]->post_content, $match);
 if (!empty($match[1])) {
 $matches=array(); $matches[0]=$matches[1]=array('http://tn-skr.smilevideo.jp/smile?i='.$match[1]);
 }
}

といったコードを先程のYouTubeのコードの下に追記したが、うまく行かなかった。

色々とデバッグした結果、どうやら『function apt_generate_post_thumb』内でmimeタイプのチェックをしているが、これがファイルの拡張子でチェックしているため拡張子が偽装されているものについてはここで弾かれているようだった(ニコ動のサムネはファイル名に拡張子が無い)

ということで、ファイルデータから直接mimeタイプを取れるよう修正した(プラグインを直接編集するのは気が引けるが...)

編集内容は

// No file type! No point to proceed further
 if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) ) {
 return null;
}

という記述の

if (!$type || !$ext) {
 $finfo = finfo_open(FILEINFO_MIME_TYPE);
 $type = finfo_buffer($finfo, $file_data);
 $ext = "aaa";//なんでもいいから値入れる.
 finfo_close($finfo);
}

を書く。

これでニコ動のアイキャッチ生成にも対応できた。

LESSのbox-shadow、transitionなどで複数パラメータを使用する

すいませんすいません。最近アプリ開発をサボってちょっとしたWebサイト作ってます・・・。

で、久しぶりにcssいじってたらLESSなんて便利なものがあったので使ってたのですが、『box-shadow』や『transition』で複数の値カンマ区切りでいい感じに指定する方法が見つからなくて悩んだので解決策をメモっておきます。

解決までの経緯を書くのが面倒なので、最終的なコードを晒すと

/* box-shadow. */
.box-shadow(...) {
 @props: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
 -webkit-box-shadow: @props;
 -moz-box-shadow: @props;
 -ms-box-shadow: @props;
 -o-box-shadow: @props;
 box-shadow: @props;
}
.box-shadow(@style) {
 -webkit-box-shadow: @style;
 -moz-box-shadow: @style;
 -ms-box-shadow: @style;
 -o-box-shadow: @style;
 box-shadow: @style;
}

こんな感じでmixin定義。で、

.box-shadow(0 0 10px 0 rgba(0,0,0,0.2), inset 0 0 10px 0 rgba(255,0,0,0.2);

こんな感じで呼び出す。 複数指定しない場合は

.box-shadow(0 0 10px 0 rgba(0,0,0,0.2);

こんな感じ。

で、「RGBAの値を入力するのが面倒だ!16進数指定したい!hex!」って場合は

.box-shadow(0 0 10px 0 fade(#000, 20%);

という書き方もできる。

このmixinについてざっくり説明すると、引数が複数の場合は上の .box-shadow を呼んで、引数が一つの場合は下の .box-shadow を呼ぶようになっている。

また、『transition』でも同じように

/* transition. */
.transition(...) {
 @props: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
 -webkit-transition: @props;
 -moz-transition: @props;
 -ms-transition: @props;
 -o-transition: @props;
 transition: @props;
}
.transition(@style) {
 -webkit-transition: @style;
 -moz-transition: @style;
 -ms-transition: @style;
 -o-transition: @style;
 transition: @style;
}

と定義しておけば複数パラメータに対応できる。

MindNodeからfreeMindへのデータ移行方法

かなり限定的な話だけど、さっきマインドマップツールを移行する時に移行方法を発見したのでメモっておく。

  1. freeMindのノードを全選択してコピー
  2. 適当なテキストエディタに貼り付け
  3. 「    」←スペース4つを「」←タブ文字に置換(タブ文字を書けないのでそこはいい感じにやって下さい...)
  4. 置換後の文字列をコピってMindNodeに貼りつけ

以上。

最近のハイライト(4月19日版)

最近のAir for iOSでのアプリ制作で困ったこと、考えたこと、どうやって解決したか、などをつらつらとメモっておく。(主にプログラム周り)

 

イベントを活用しようと思った

今までサーバーサイドのプログラムばかり書いていたせいかイベント駆動の概念が無かったが、これからは使ってみようと思った。

例えば『メニュー』クリックで『シーン』を切り替える処理を書く場合、

イベント使わない → メニュークラス から シーンクラス の シーンを切り替える() メソッドを呼ぶ。

イベント使う → メニュークラス から シーン切り替えのイベントを送出。シーンクラスでイベントを受け取り、シーンを切り替える。

こんな感じに書ける。

何が嬉しいかというと、メニュークラスとシーンクラスの依存を断ち切る事ができる。うん。嬉しい。使っていこう。

 

データの永続化どうしよう

これは書いているうちに長くなったので別エントリにまとめた。

Air for iOSでのデータ保存について - わーくあうと!

 

リファレンス見やすくて嬉しい

あと ActionScript 3.0 のリファレンスガイドがとても見やすい。それぞれのクラスの継承関係から使用例、メソッドの詳細まで細かく書いてるので、リンクを辿って読んでいくと新しい発見もあって楽しい。

例えば上のほうで書いた、「イベントを使おう」と思ったきっかけも、

俺:「SharedObjectが継承しているEventDispatcherってなんだろう」

(リファレンス読む)

俺:「へーこんな事できるのかー面白そう。使ってみよう」

って経緯だった。リファレンス読もう。

 

その他AS3についてもろもろ

AS3ってこんな書き方できないのーとTwitterでつぶやいてみた

 

もちろん誰からもリプライは無かった。

以上、最近のハイライトでした。

Air for iOSでのデータ保存について

ゲームを作ってるとゲーム内の値(所持金、経験値など)をローカルに保存する必要が出てくる。

方法は色々あるが、『SharedObject』や『File』、『SQLite』なんかを使う方法があるらしい。

これは特に迷う事無くSharedObjectを使おうと決めた。理由はオブジェクトをそのまま保存できて自前でシリアライズする手間もなく、一番ラクそうだったから。

カスタムクラスの保存ができない・・・

そんなこんなで使ってみたがカスタムクラスの保存ができない。というかObject型で保存される。少し調べてみたら、『registerClassAlias』関数でカスタムクラスをあらかじめ登録することでカスタムクラスのインスタンスを保存できるようになるようだった。

registerClassAlias("HogeModel", HogeModel);
SharedObject.getLocal(Defines.APP_SO_NAME_SPACE);

↑こんな感じでSharedObject.getLocalの前にカスタムクラスを登録する。

(これはこれで保存するカスタムクラスをいちいち書かないといけなくて面倒だけど)

勝手に保存される・・・

SharedObjectの動きを確認していると、SharedObject.flush()を読んでいなくても保存されていることに気がついた。どこかに.flush()するコード残ってたかなーと探してみたが見当たらない。

あれー、、と思いながらリファレンスのflushの説明を読んでみると

ローカルに永続化された共有オブジェクトを直ちにローカルファイルに書き込みます。このメソッドを使用しない場合、共有オブジェクトがファイルに書き込まれるのは、共有オブジェクトセッションの終了時となります。つまり、SWF ファイルが閉じられるとき、共有オブジェクトが参照されなくなってガベージコレクションされるとき、SharedObject.clear() または SharedObject.close() が呼び出されたとき、のいずれかの時点です。

と書かれている。仕様でした。

これはこれで便利だが、自分が想定していない所で保存されると追い辛いバグを孕みそうな予感がしたので、自前の保存関数をかまして使うことで、自動で保存されないようにした。

コードで書くと下記のような感じ

public class AppData {

    public function AppData() {
    }

    /*
    * SharedObjectを取得.
    */
    public static function getSharedObject():SharedObject {
        registerClassAlias("HogeModel", HogeModel);
        return SharedObject.getLocal(Defines.APP_SO_NAME_SPACE);
    }

    /*
    * (1)SharedObjectの保存領域部分を返す.
    */
    private static var __tmp:Object;
    public static function getDataObject():Object {
        var so:SharedObject = AppData.getSharedObject();

        if(__tmp == null){
            __tmp = ObjectUtil.clone(so.data);
        }
        return __tmp;
    }

    /*
    * (2)保存.
    */
    public static function saveAll():void {
        var so:SharedObject = AppData.getSharedObject();
        //↓__tmpを入れなおしている.
        so.data = AppData.getDataObject();
        so.flush();
    }
}

(1)で保存領域を複製した物(__tmp)を返し、(2)でso.dataに代入しなおして保存している。

これはまぁぶっちゃけ保存し忘れするかもしれないってのとトレードオフの関係なので、やるべきかどうかは個人の自由かなと思う。

以上。そんな感じ。

情報が多すぎる

最近は、朝起きて朝ご飯を食べつつ

のチェックをしていると、(日によるが)全て見終わる頃にはもう昼過ぎになっている。

その後は昼ご飯を食べてちょっと昼寝して、起きたらまたtwitterなどを巡回して、やっとアプリ開発作業を始める。

見なきゃいいのに目の前に情報があったら気になってそわそわしてしまうので見てしまう。

情報が多すぎる。