Debian + Nginx 0.7.x + mod_wsgi + pythonでthriftを動かす

Google App Engine(Python)でThriftを動作させる
これが上手くいったので、wsgiな環境なら、どんなサーバーでも動作可能なはず。

ということで、Nginx 0.7.x + mod_wsgiでthriftのサーバーを動かしてみました。



Nginx 0.7.xとmod_wsgiのモジュール取得



Nginx + WSGI + Pylons環境の構築方法
こちらを参考にしました。

Nginxのダウンロードは、以下のURLから行えます。
http://nginx.org/en/download.html

今回は、最新の安定版nginx-0.7.64を使用しました。

またmod_wsgiは、以下のURLからダウンロードできます。
http://hg.mperillo.ath.cx/nginx/mod_wsgi/archive/tip.tar.gz



必須ライブラリのインストール



ビルドには以下のライブラリが必要となるので、事前にインストールしておきます。


apt-get install gcc make libc6-dev python python-dev libpcre3-dev libssl-dev





ソースの展開と修正



/usr/local/srcにモジュールをダウンロードし、展開します。


# wget http://nginx.org/download/nginx-0.7.64.tar.gz
# wget http://hg.mperillo.ath.cx/nginx/mod_wsgi/archive/tip.tar.gz
# tar zxf nginx-0.7.64.tar.gz
# tar zxf mod_wsgi-8994b058d2db.tar.gz
# mv mod_wsgi-8994b058d2db mod_wsgi



mod_wsgiはしばらくメンテナンスされておらず、Nginx 0.5.xでのみビルドが通るようです。
Nginxの関数名がいくつか変更されているので、修正しておきます。


1.ngx_garbage_collector_temp_handlerという関数はNginx0.7で廃止されたようです。
※何に変更されたかまでは調べ切れていません・・・
wsgiのテンポラリ指定時に使用しているようで、wsgi_temp_pathというパラメータを
使用しなければ、削っても問題ないはず。(たぶん)

mod_wsgi/src/ngx_http_wsgi_module.cをエディタで開き、ngx_garbage_collector_temp_handlerを
使用している箇所をコメントしてしまいます。

■154行目

/*
{ ngx_string("wsgi_temp_path"),
    NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
    ngx_conf_set_path_slot,
    NGX_HTTP_LOC_CONF_OFFSET,
    offsetof(ngx_http_wsgi_loc_conf_t, temp_path),
    (void *) ngx_garbage_collector_temp_handler },
*/




■345行目

/*
ngx_conf_merge_path_value(conf->temp_path,
                            prev->temp_path,
                            NGX_HTTP_WSGI_TEMP_PATH, 1, 2, 0,
                            ngx_garbage_collector_temp_handler, cf);
*/




2.ngx_http_discard_bodyという関数名は、0.6からngx_http_discard_request_bodyに
変更されています。

mod_wsgi/src/ngx_http_wsgi_handler.cを開き、関数名を修正します。

■74行目付近

if (r->method == NGX_HTTP_GET || r->method == NGX_HTTP_HEAD) {
/* XXX not sure */
/* rc = ngx_http_discard_body(r); */
rc = ngx_http_discard_request_body(r);





インストール



インストールはお決まりのcongifure,make,make installで実行します。
今回実行したのはこんな感じ。
※--add-module=/usr/local/src/mod_wsgi/で、mod_wsgiを有効にするのを忘れずに。


###実際は一行
# ./configure --add-module=/usr/local/src/mod_wsgi/ --sbin-path=/sbin/nginx
--conf-path=/usr/local/nginx/nginx.conf --pid-path=/usr/local/nginx/nginx.pid
--with-http_ssl_module --with-md5=auto/lib/md5 --with-sha1=auto/lib/sha1

Configuration summary
+ using system PCRE library
+ using system OpenSSL library
+ md5: using OpenSSL library
+ using sha1 library: auto/lib/sha1
+ using system zlib library

nginx path prefix: "/usr/local/nginx"
nginx binary file: "/sbin/nginx"
nginx configuration prefix: "/usr/local/nginx"
nginx configuration file: "/usr/local/nginx/nginx.conf"
nginx pid file: "/usr/local/nginx/nginx.pid"
nginx error log file: "/usr/local/nginx/logs/error.log"
nginx http access log file: "/usr/local/nginx/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"

# make
# make install





nginx.confの修正



まず、nginxに渡すパラメーターファイルをmod_wsgiのソースの中からコピーしておきます。


#mkdir /usr/local/nginx/conf
#cp /usr/local/src/mod_wsgi/conf/wsgi_vars /usr/local/nginx/conf/




次に、/usr/local/nginx/nginx.confを修正します。

■nginx.conf

worker_processes 1;

events {
    worker_connections 1024;
}


http {
    include     mime.types;
    default_type application/octet-stream;

    sendfile        on;
    keepalive_timeout 65;

    server {
        listen     80;
        server_name sv01;
        include conf/wsgi_vars;

        location / {
            root html;
            index index.html index.htm;
        }

        location /thrift {
            wsgi_pass /opt/thrift/nginx.py;
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
            root html;
        }
    }
}



設定ファイルのポイントは、
include conf/wsgi_vars;
の行を追加して、wsgiの設定を読み込む。

location /thriftの設定でサーバにhttp://server.com/thrift/とアクセスしたときに
/opt/thrift/nginx.pyのプログラムを実行する

という点でしょうか。

/opt/thrift/nginx.pyにサンプルプログラムを作成してみます。



サンプルプログラム



/opt/thrift/nginx.pyの内容はこんな感じになりました。


# -*- coding:utf-8 -*-
import cStringIO

#Thriftを使用するため、importを追加
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.transport import TIOStreamTransport

from sample import Calculator
from sample.ttypes import *

#Calculatorの実装
class CalculatorHandler:
    def add(self, n1, n2):
        return n1+n2

def application(environ, start_response):
    
    handler = CalculatorHandler()
    processor = Calculator.Processor(handler)
    
    #自作したTIOStreamTransportをtransportとして指定する
    input_stream = environ['wsgi.input']
    output_stream = cStringIO.StringIO()
    
    transport = TIOStreamTransport.TIOStreamTransport(input_stream, output_stream)
    
    protocol = TBinaryProtocol.TBinaryProtocol(transport, True, True)
    transport.open()
    processor.process(protocol, protocol)
    transport.close()
    
    #シーク位置を先頭に戻す
    output_stream.seek(0)
    
    headers = [('Content-Type', 'application/x-thrift')]
    start_response('200 OK', headers)
    
    return output_stream





また、/opt/thriftにthriftコマンドで作成したgen-pyフォルダをコピーします。
そして、thrift\lib\py\src以下のファイルを/opt/thrift/thrift以下に配置しました。

TIOStreamTransportを使用するため、
Google App Engine(Python)でThriftを動作させる
ここで作成したTIOStreamTransportを
/opt/thrift/thrift/transport/TIOStreamTransport.pyに配置します。

最終的な、/opt/thriftの構成はこんな感じ。


nginx.py
/gen-py
    __init__.py
    /sample
        __init__.py
        Calculator.py
        Calculator-remote
        constants.py
        ttypes.py
/thrift
    __init__.py
    Thrift.py
    TSCons.py
    /protocol
        __init__.py
        TBinaryProtocol.py
        TProtocol.py
    /server
        __init__.py
        THttpServer.py
        TNonblockingServer.py
        TServer.py
    /transport
        __init__.py
        THttpClient.py
        TIOStreamTransport.py
        TSocket.py
        TTransport.py
        TTwisted.py



※今思えば、thriftのライブラリをpython setup.py installで
インストールしたほうが早かったかも。



クライアントプログラム



テストに使用したクライアントのプログラムは、以前と同様の内容です。


#!/usr/bin/env python
# -*- coding:utf-8 -*-

import sys
sys.path.append('./gen-py')

#sampleは雛形に指定したthriftファイルの名前になる模様
from sample import Calculator
from sample.ttypes import *

#お決まりのimport
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol
from thrift.transport import THttpClient

try:

    transport = THttpClient.THttpClient("http://sample.com/thrift/")
    protocol = TBinaryProtocol.TBinaryProtocol(transport)
    
    client = Calculator.Client(protocol)
    transport.open()
    
    #指定したaddメソッドを呼び出す
    num1 = 1
    num2 = 10
    sum = client.add(num1, num2)
    #計算結果を表示
    print '[client print] %d+%d=%d' % (num1, num2, sum)
    
    #後始末
    transport.close()

except Thrift.TException, tx:
    print '%s' % (tx.message)






これで無事動いてくれました。


【参考URL】
第2回 WSGIを使ったもう少し複雑なアプリケーションの作成





関連記事

コメント

プロフィール

Author:symfo
blog形式だと探しにくいので、まとめサイト作成中です。
https://symfo.web.fc2.com/

PR

検索フォーム

月別アーカイブ