ThriftPy+gunicorn_thriftでRPCサーバーを動かす

ThriftPyを使って作ったサーバーを動かすのに、thriftpy本体が持ってるサーバークラスを使ってもいいのだけど、タイムアウト処理やマルチプロセス動作だとかやるのが少し面倒だなーと考えてました。

githubでサーバークラスを差し替えるpull requestを出してたら、コメントでgunicorn_thriftというパッケージがあるから試すといいよと教わりました。ThriftPyと同じOrganization。

github.com

ThriftPyで作ったサービスの場合は、TProcessorのインスタンスをgunicorn_thriftコマンドに指定して起動する。

Python3.5、Ubuntu 16.04で試した。

main.py:

import thriftpy
from thriftpy.thrift import TProcessor


class AppServiceHandler:
    def echo(self, message):
        return message


main_thrift = thriftpy.load("main.thrift")
app = TProcessor(main_thrift.TIAppService, AppServiceHandler())

起動コマンド:

$ gunicorn_thrift -w 4 main:app

裏では、gunicornをカスタムのワーカークラスが動作している。gunicornのコマンドオプションも使えてうれしいです。

thrift_syncクラスを使った場合、単純なロードのパフォーマンスはmake_serverのほうがほんの少し良いみたいですが、気にするほどではなさそう。

以下、パフォーマンス試験に使ったコードと結果

thriftpy performance test

ありがたい。

Procfileを扱う

Procfileというのを使ったのでメモを残す。

Procfileという名前のファイルを作って、アプリケーションの起動コマンドをまとめておくと、Procfileを扱うツールから簡単に実行できる。

Procfile:

web: gunicorn -w 4 main:app 0.0.0.0:$PORT
test: py.test .

起動(honchoの場合):

$ honcho start web
22:55:01 system | web.1 started (pid=53633)
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53635] [INFO] Starting gunicorn 19.6.0
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53635] [INFO] Listening at: http://0.0.0.0:5000 (53635)
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53635] [INFO] Using worker: sync
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53638] [INFO] Booting worker with pid: 53638
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53639] [INFO] Booting worker with pid: 53639
22:55:02 web.1  | [2016-11-21 22:55:02 +0900] [53640] [INFO] Booting worker with pid: 53640

環境変数を.envファイルに記述し、Procfile内で使うことができる。こうすると、起動コマンドはProcfileで共有し、利用する各環境では.envに設定を記載するといったこともやりやすい。

Procfileを扱うモジュールはRubyだとForeman、PythonだとHoncho、GoだとGoremanといった感じで色々あるようだ。

HerokuではProcfileを記述してプロセスを起動できるようだ。

Google App EngineのPython SDKをDockerで動かしてみた

GoogleAppEngineを久々に使おうとしたらいろいろ変わっていて戸惑いまくり。 静的ページをホストしてるだけのプロジェクトで更新をしたかったので、SDKのインストールが必要なんですが、毎回面倒なのでDockerで少し楽できないかと、ゴニョゴニョしてました。 github.com とりあえずdev_appserverとappcfgを動く状態にして使ってみてます。

ThriftPyを使ってPythonでThriftのRPCを扱う

Python3でApache Thriftを扱うライブラリは無いか探してたところ、ThriftPyというのがあるらしいとわかったので試してました。

ThriftPy — ThriftPy 0.3.9 documentation

ThriftPyは、ApacheThriftのPython版と比べると、PurePython実装(Cythonによるスピードアップ可能)で使いやすそうです。

Apache ThriftのPythonチュートリアルをThriftPyで実装してみたところ、問題なく動きました。 試した環境は、Ubuntu16.04、Python3.5。

ソースコード

4ファイルです。PythonServer.pyがRPCのサーバー側、PythonClient.pyがクライアント側です。shared.thriftに書かれた定義をtutorial.thrift側でincludeして継承するところも問題なさそうでした。

クライアント側のmain関数、サーバー側のCalculatorHandlerは元のチュートリアルと内容はほぼ同じです。

Thrift Tutorial (using thriftpy)

参考

退職と入社

8年ほど勤務した株式会社ビープラウドを退職しました。

11月から株式会社オープンコレクターに入社します。 www.open-c.jp オープンコレクターという会社は、もりよしが代表で1人の組織でしたが、私とあおだぐが新しく加わって3人になります。

開発や技術支援の案件あればご相談ください。

Pythonでファイルディスクリプタをサブプロセスに渡す

Pythonのsubprocessモジュールでサブプロセスを実行するときに、親プロセス側で開いたファイルのファイルディスクリプタを渡す方法。

subprocess.Popenのpass_fds引数を指定すると、指定したファイルディスクリプタは閉じられないようだ。

試したPythonのバージョンは3.5。

コード

send_fd.py:

import sys
import subprocess

# ファイルを開く(readで全部読まれるのを避けるのでバッファをOFFにしとく)
input_file = open('spam.txt', 'rb', buffering=0)
# ファイルディスクリプタを取得
fd = input_file.fileno()
# 5バイト読む
print('send_fd: ', input_file.read(5))
# receive_fd.pyに引数でFDを渡して子プロセスとして実行
process = subprocess.Popen(
    [sys.executable, 'receive_fd.py', str(fd)],
    pass_fds=[fd])
# プロセスが終了するまで待つ
process.wait()
# ファイルを閉じる
input_file.close()
print('end')

receive_fd.py:

import os
import sys

# 引数で渡されたFDを取得
fd = int(sys.argv[1])
# FDからファイルオブジェクトを作る
input_file = os.fdopen(fd, 'rb')
# 最後まで読み込んで表示
print('receive_fd: ', input_file.read())
# ファイルを閉じる
input_file.close()

spam.txt:

Hello World!

実行結果

tokibito@ubuntu:~/sandbox$ python3.5 send_fd.py
send_fd:  b'Hello'
receive_fd:  b' World!\n'
end

親プロセス側で5バイト読んで、子プロセス側で残りを読んでいる。

参考

PyConJP 2016に参加しました

PyConJP 2016に参加してきました。 スピーカーとして、トーク1つ、ビギナーセッション1つ、オープンスペース2枠で話してきました。

ビギナーセッション(コードリーディング)

ビギナーセッションは、講師の応募がなかったそうで、お願いされたのを引き受けて話しました。

www.slideshare.net os.path、this、antigravityモジュールのコードを読んでみましょう、というものです。

Pythonコードの追いかけ方、pdbの使い方について話しました。 資料は6ページしかないですが、画面上で実際に操作しながら説明しました。

Pythonでpyftpdlibを使ってFTPサーバーを作る際に使ったテクニックの紹介 (トーク)

CfPを出して採用されたので話しました。

www.slideshare.net GitHub - tokibito/soloftpd: FTP server application. www.youtube.com

PythonでGitリポジトリをゴニョゴニョ (オープンスペース1日目)

オープンスペースは、1日目の午後の時点では、2日目の枠が半分ほど埋まっていたのですが、1日目はスカスカでした。

なにかやろうと思い、過去にブログに書いたネタを引っ張り出してきてやってました。

dulwichモジュールでgitリポジトリを読んでみたり、それをgitのサブコマンド化したりしてました。 tokibito.hatenablog.com

socketモジュールでHello, world! (オープンスペース2日目)

2日目でもオープンスペースの枠が埋まりきっておらず、空いてたので話しました。

今回はネットワーク周りの初心者向けのセッションはなかった?みたいだったので、socketでHello, world!でもやってみようと思い、話してました。

PythonのsocketモジュールでHello, world! · GitHub

こちらは5,6人ほど来てくれて盛り上がってました。

サーバーを起動してngrokを使ってインターネットからアクセスできるようにし、参加者からメッセージを投稿してもらったりしていました。 コードを変更して、HTTPのレスポンスを返すようにしてみたりもしました。

感想

  • 今回も他の人のトークはあまり聞いておらず、休憩スペースで駄弁ったりしていました。じっと座って聞くのは疲れてしまうので、自分にはこれが合ってる感じです。
  • 気になっていたトークはYouTubeにアップされてる動画を見ようと思います。動画がアップされてるのありがたい。
  • 何年かぶりに会えた方もいたので、とてもよかった。
  • 今回、朝ごはんがあったのは、結構嬉しかった。毎度のことながら、あのチケット価格で飲み食い全部込みということなので、かなり安いと思います。
  • オープンスペースは少人数で気軽に話せたりするので、次回のPyConJPでもあれば、何かしようと思います。
  • 楽しかった。来年もできれば参加したいと思います。