TKC Works

ギジュツ的なメモ、読書感想文など

CouchbaseのPHP SDKでハマったこと

Nginxとphp-fpmの組み合わせで、Phalconで作ったWebアプリケーションからCouchbaseに接続してたんだけど、
"502 Bad gateway"とか "PHP Fatal error: Allowed memory size of ..."が頻発して困った。

とりあえずこの辺を参考にして、
http://webhoric.com/web-dev/nginxphp-fpm-502-bad-gateway

php-fpmのmax_requestsとかphp.iniのmemory_limitとかをガッツリ増やしてみたが変わらず。。

結果はむしろphp-fpmのmax_requestsを増やしすぎたのがよくなかった。

CouchbaseのPHP SDKは接続にコストがかかるからあまり多重に繋ぐなと書いてあった。
http://docs.couchbase.com/developer/php-2.0/performance-tuning.html

おそらくphp-fpmの子プロセスが死なずに残り続けてたのでSDKがCouchbaseに繋がる限界数に達してた。。
とりあえずmax_requestsを一桁にするとエラーが起こらなくなった。チューニングしながら最適値を見つける必要があるが。

Swiftで分割したStoryboardの呼び出し方

チームでアプリを開発する場合や一つのStoryboardが大きくなりすぎるのが嫌な場合など、Storyboardを分割したくなるけど、じゃあどうやって呼び出すの?となるので書いておく。

  • 基本的にはObjective-Cの時と同じ
  • UINavigationControllerを使っている場合はちょっと違うので注意
  • Storyboard上でIs Initial View Controllerのチェックを入れるのを忘れずに
//UIViewControllerの場合
@IBAction func hogeButtonTapped(sender: AnyObject) {
    let story = UIStoryboard(name: "Hoge", bundle: nil)
    let vc = story.instantiateInitialViewController() as HogeViewController
    self.presentViewController(vc, animated: true, completion: nil)
}

//UINavigationControllerの場合
@IBAction func hogeButtonTapped(sender: AnyObject) {
    let story = UIStoryboard(name: "Hoge", bundle: nil)
    let nc = story.instantiateInitialViewController() as UINavigationController
    self.presentViewController(nc, animated: true, completion: nil)
}

ファイル単位でARCを有効にする

ファイル単位でARCを有効にする

cocos2d-xでもSocket.IOでリアルタイム通信をやろうとした場合、
v3には標準のクラスに追加されたからそれを使えばなんとかなる。
ただし、Socket.IOのバージョンは0.9で1.0には対応してないしWebSocketオンリー。

C++でよいライブラリはないか探したけど見つからないので、
iOSからはこのobj-cのライブラリを使うことにした。
https://github.com/pkyeck/socket.IO-objc

ただし、一部ARCを有効にしないといけないファイルがあり、

//SocketRocket/SRWebSocket.m
#error SocketRocket must be compiled with ARC enabled

cocos2d-xで作成したプロジェクトは基本無効になっているためどうしようかと思っていたら、
ファイルごとに設定出来ることを発見。

Build Phases > Compile Sources で対象ファイルに-fobjc-arcを指定すればOK。

こちらを参考にさせて頂いた。
http://lab.dolice.net/blog/2013/05/10/objc-arc-switch/

UnityでiOSでもAndroidでもSocket.IOでリアルタイム通信

僕は別にアプリエンジニアじゃなかったんだけど、やらないといけなくなり、検証したのでメモ。
(Node.jsはv0.10.28、Socket.IOは0.9.17、Unityは4.3.4、iOSは7.1.2、Androidは4.4.2で検証)

スマホでSocket.IOを使いたい場合、ネイティブではこの辺のライブラリを使うと思う。
https://github.com/pkyeck/socket.IO-objc
https://github.com/Gottox/socket.io-java-client

ネイティブプラグインはよくわからなかったのでC#で書いてiOS,Android両方で使えるのはないかなと思っていたら
https://github.com/NetEase/UnitySocketIO
これが見つかった。他にはあまりなさそう。

で、一個問題があって、iOSだとEXC_BAD_ACCESSやら--aot-onlyと言われてうまく動かない。
SimpleJson.dllが古い、かつiOSでは使えないオプションが付いていたみたいなので、
SimpleJsonを自分でビルドし直した。
SimpleJson.csで#define SIMPLE_JSON_NO_LINQ_EXPRESSIONをアンコメントする必要がある。

ここが参考になった。
https://github.com/kaistseo/UnitySocketIO-WebSocketSharp
こっち使ってもよかったかも。
まあどちらにしてもSocket.IOといいつつWebSocketしか使えないし、1.0系に対応するかどうかはよくわからない。。

ちなみにDLLを更新した版はフォークしてここに置いた。
https://github.com/take4/UnitySocketIO

C#のサンプルコード※サーバー側はよくあるサンプルチャットなので割愛。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class NewBehaviourScript : MonoBehaviour {
    public GUIText text1;
    public string text = "";
    SocketIOClient.Client socket;

    // Use this for initialization
    void Start () {
        Debug.Log ("start");

        socket = new SocketIOClient.Client ("http://xxx.xxx.xxx.xxx:3000/"); 
        
        socket.On ("connect", (fn) => {
            Debug.Log("connect - socket");

        });
        
        socket.On ("message:receive", (data) => {
            Debug.Log(data.Json.ToJsonString());
            text = data.Json.ToJsonString() + "\n" + text;
        }); 
        
        socket.Connect();
    }
    
    // Update is called once per frame
    void Update () {
        text1.text = text;
    
    }

    void OnGUI() {
        if (GUI.Button( new Rect (30, 30, 120, 50), "PUSH")) {
            Dictionary<string, string> args = new Dictionary<string, string>();
            args.Add("message", "YO");
            socket.Emit("message:send", args);

        }
    }
}

f:id:take4kamada:20140711160943p:plain

追記

やっぱりこっちを使ったほうがよさげ
https://github.com/kaistseo/UnitySocketIO-WebSocketSharp https://github.com/KLab/websocket-unitymobile

NginxによるWebSocketの負荷分散

Node.js、Socket.IOを使ってリアルタイムなWebアプリなんかを作っていて、分散構成はどうすればいいのか試行錯誤しているメモ。

Nginxは1.3.13からWebSocketのプロキシに対応したので以下を参考にサクッとやってみる。 http://nginx.org/en/docs/http/websocket.html

upstream chatserver {
    server xxx.xxx.xxx.xxx:3000;
    server yyy.yyy.yyy.yyy:3000;
}

server {
    listen       3000;
    server_name  localhost;

    location / {
        proxy_pass http://chatserver;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

この設定でも確かにプロキシされたし、分散もされた。
しかし、接続先のサーバーが頻繁に変わってしまうようで、アプリの挙動がおかしくなった。

なのでセッションごとに同じサーバーに接続する仕組みが必要。
ip_hashだとなんとなくサーバーが偏りそうな気がしたのでstickyを試す。

http://nginx.org/en/docs/http/ngx_http_upstream_module.html
ここを見ているとstickyが標準で入っているっぽいが、実際には入っていないのでNginxをビルドし直してサードパーティモジュールとして組み込む。
(Nginx Plusなら入ってるのかな?)

stickyのダウンロード先、ビルド方法は以下を参照。
https://bitbucket.org/nginx-goodies/nginx-sticky-module-ng

設定はほとんど変わらず、stickyを追記するだけ。

upstream chatserver {
    sticky;
    server xxx.xxx.xxx.xxx:3000;
    server yyy.yyy.yyy.yyy:3000;
}

今のところこれでいけそう。
ちなみに各バージョンは

Nginx : 1.6.0
Node.js : v0.10.28
Socket.IO : 0.9.17

Nodeを分散するとNodeプロセス間でのデータの共有が必要で、それにはRedisのPub/Subがよいらしい。

http://www.cyberagent.co.jp/recruit/techreport/report/id=8858#id-2013-09%E6%8F%90%E5%87%BA%E5%88%86%EF%BC%8F%E5%85%AC%E9%96%8B%E7%94%A8%EF%BC%8F%E3%82%AA%E3%83%B3%E3%83%A9%E3%82%A4%E3%83%B3%E9%80%9A%E7%9F%A5%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0-homing-%EF%BC%88%E5%8F%A4%E8%B0%B7%E8%96%AB%EF%BC%89-2-4.Redis%E3%82%B5%E3%83%BC%E3%83%90%EF%BC%88Socket.IO%E7%94%A8%EF%BC%89

以上、アリーヴェデルチ