続・JavaでCGI

JavaでCGIの続き

前回やってみたら意外と早くて驚いた。でもバッチ経由起動でレスポンスが150msと結構おそかった。とはいえ、これくらいの性能なら社内LANでのアプリとしては問題ないだろうけど。

今回はバッチ経由をなくしてみた。Apacheのモジュールの作成流儀しらんのでパス。もう思い切ってServletから呼び出すことにした。

Java環境変数系が苦手だったが、J2SE 5.0からサブプロセスの起動に環境変数を自由にセットできるようになったのは皆さんご存知のとおり。

それをつかってrequestパラメータを渡してみる。

CGIのコードはほぼ同じ。ヘッダ部分を削除してあるけど。

以下Servletのコード。

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html; charset=Shift_JIS");

        String path = getServletContext().getRealPath("WEB-INF/classes");
        ProcessBuilder pb = new ProcessBuilder("java", "-cp" ,"\""+path+"\"", "cgi.NewMain");
        String QUERY_STRING = request.getQueryString();
        if(QUERY_STRING == null){
            QUERY_STRING = "";
        }
        pb.environment().put("QUERY_STRING", QUERY_STRING);
        pb.environment().put("SCRIPT_NAME", request.getRequestURI());
        pb.environment().put("SCRIPT_FILENAME", path+"/てきとうにつじつまあわせる");
        pb.environment().put("REQUEST_METHOD", request.getMethod());
        Process p = pb.start();
        InputStream is = new BufferedInputStream(p.getInputStream() , 512);
        byte[] buf = new byte[1024];
        int len;

        OutputStream os = new BufferedOutputStream(response.getOutputStream(),1024);
        while((len = is.read(buf)) >= 0){
            os.write(buf,0,len);
        }
        os.flush();
    }

なんか前回よりややはやくなったような・・・?気のせいかな?

というわけでJMeter起動。

おおよそ2/3になった。100msきるとは。どおりで体感できるはずだ。

んでプロセス起動しないでservletから直接main部分を呼び出すと…ほとんど1ms以下。さすがスレッドモデルははえー。

フロントエンドを別のmainにしてURLから対応するmainを起動するようにしてプロセスをプールしとけば平均10ms以下は余裕でいけそうな予感。jarファイルの更新監視をしといて、新しくなっていたらプールを破棄で。もうそれはCGIとは呼べないけど。

実際のところ100msでもまず運用時の速度は問題ないし、改善方法はいくらでもあるのだから、さくさく開発が出来るほういがいいよね。アプリケーションサーバー使ってるところはサブシステム単位でwarファイル作ってるだろうから、無理して1つのでかいwar作るよりさくさく開発できるんだよね、実は。一般ユーザーと管理者が同じwar使うのはおいらはお勧めしない。というかそのほうが珍しいか。



ネタとして遊ぶ分には面白かった。そしてServletの脅威の早さも再認識したり。デプロイ自体もServletだけ使ってる分には早いんだから、遅くなるんだとしたらどこが原因なんだろうか。柔軟すぎるマッピングをもつフロントコントローラパターンがダメとか?Servlet 3.0では動的にマッピング作れるんだからそこでかなりの部分を絞るようなつくりのほうがよいとか。よくないとか。

でも、よくよく考えるとそもそもデプロイ時間が問題なんるケースってあるのかな?よほどマシンパワーが低い環境でない限り3秒くらいあればデプロイ終わるよね。あれ?なにがネックなのかわからなくなってきた。結局作り方の問題とかじゃなくて仕様の決め方とか認識の共有とかそっちのほうが重要な気が。