JSON-RPC 2.0 を PHP で試してみる

追記@2014-05-27
このライブラリでいくつか気になる点が出てきました。

– 任意のエラーを吐く書き方が載っておらず分からない
– 引数の書き方がよく分からない。連想配列のようなJSONを引数にしたいなどのときに書き方が不明

後者に関しては、すべて$jsonで受け取るようにして、コード内でパースするのがいいのかもですが。。。jsonのパースのエラー処理はちと面倒です。



JSON-RPC 2.0という規格があります。データの送受信をJSONで行う、バッチリクエスト(いくつかのリクエストをまとめる)、返信を必要としない通信、など特徴があります。規格化されているので使いやすいかなと思い試してみました。

PHPのライブラリは

A simple Json-RPC PHP client/server that just works.
https://github.com/fguillot/JsonRPC


↑こちらを使ってみました。

Ubuntu/Debian (apache)で動作させてみます。事前にPHPを動かせる環境にしておいてください。

# ルートになります
$ su

# apacheのルートディレクトリに移動
$ cd /var/www/

# jsonrpcのためのディレクトリを作成
$ mkdir jsonrpc
$ cd jsonrpc

# クローンしてくる
$ git clone https://github.com/fguillot/JsonRPC

# 必要なファイルを移動
$ cp -R JsonRPC/src/JsonRPC/Server.php ./

# 試しにやってみる(中身は後述)
$ vi example.php

# apacheを起動
$ /etc/init.d/apache2 restart

# curlで問い合わせしてみる
$ curl --data-binary '{"jsonrpc": "2.0", "id":0, "method": "addition", "params": [100,200] }'  -H 'content-type: text/plain;' http://127.0.0.1/jsonrpc/example.php
{"jsonrpc":"2.0","id":0,"result":300}

# バッチリクエストしてみる
$ curl --data-binary '[{"jsonrpc": "2.0", "id":0, "method": "addition", "params": [100,200] }, {"jsonrpc": "2.0", "id":1, "method": "random", "params": [100,200] }]'  -H 'content-type: text/plain;' http://127.0.0.1/jsonrpc/example.php
[{"jsonrpc":"2.0","id":0,"result":300},{"jsonrpc":"2.0","id":1,"result":171}]

example.php
<?php

require 'Server.php';
use JsonRPC\Server;

$server = new Server;
$server->register('addition', function ($a, $b) {

    return $a + $b;
});
$server->register('random', function ($start, $end) {

    return mt_rand($start, $end);
});

echo $server->execute();


このように実際に試すことが出来ました。単純なPOSTですと、配列のようなデータをどう送信するか迷うところですが(「,」で区切ったりしますね)、JSONで送信出来ると簡単ですね。また、バッチリクエストは魅力的ですね。モバイルアプリケーションで、通信できなかった場合にキューにして貯めておいて、通信可能になったら一気に送信、的なことが出来ます。

ちなみにベンチマークを取ってみました。サーバーとベンチマークを同居させているので怪しいベンチマークですが。。。マシンはUbuntu 12.04, Opteron 3280です。ベンチマークソフトは、wrkです。

# json-rpcの単純なリクエスト
$ ./wrk --connections 100 --threads 4 --duration 5 --header 'content-type: text/plain;' --method 'POST' --body '{"jsonrpc": "2.0", "id":0, "method": "addition", "params": [3,5] }' http://localhost/jsonrpc/example.php
Running 5s test @ http://localhost/jsonrpc/example.php
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     8.69ms   50.43ms 573.45ms   98.29%
    Req/Sec     4.90k     1.78k   11.44k    68.92%
  92754 requests in 5.00s, 18.86MB read
Requests/sec:  18544.04
Transfer/sec:      3.77MB

# json-rpcのバッチリクエスト
$ ./wrk --connections 100 --threads 4 --duration 5 --header 'content-type: text/plain;' --method 'POST' --body '[{"jsonrpc": "2.0", "id":0, "method": "addition", "params": [100,200] }, {"jsonrpc": "2.0", "id":1, "method": "random", "params": [100,200] }]' http://localhost/jsonrpc/example.php
Running 5s test @ http://localhost/jsonrpc/example.php
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   316.80ms  433.95ms 989.28ms   65.53%
    Req/Sec     3.84k     2.47k   11.70k    64.09%
  71027 requests in 5.00s, 17.29MB read
Requests/sec:  14204.34
Transfer/sec:      3.46MB

# hello.php (比較対象としてHello, PHPとだけ返ってくるプログラムです($ echo '<?php echo "Hello, PHP\n"; ' > hello.php))
$ ./wrk --connections 100 --threads 4 --duration 5 http://localhost/jsonrpc/hello.php
Running 5s test @ http://localhost/jsonrpc/hello.php
  4 threads and 100 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    25.21ms   98.45ms 509.91ms   93.80%
    Req/Sec     7.63k     2.98k   23.00k    78.62%
  143708 requests in 5.00s, 28.12MB read
Requests/sec:  28736.42
Transfer/sec:      5.62MB)

そこそこ高速ですね。hhvmなどでやってみるとより高速かもです。

送受信の際に、いちいちjson-rpc:2.0となっていて冗長なのが気になるところですがバージョンアップに対応するにはこれしかないのでしょうし、このようにひと通りやってみるとなかなか使いやすい規格かなと思いました。