Hokkaido.pm でuWSGIについて話してきました。uWSGIは Nginx や Cherokee でも標準対応がされ初めており、今後の発展が期待されるアプリケーションサーバです。スライドは以下です。
デモがメインだったので、デモの手順についても書いておきます。
まず、uWSGI はデフォルトではhttpではなくuwsgiプロトコルを喋るので、uwsgiプロトコルを喋れるフロントエンドを立ち上げます。Plack::App::uWSGI は、いちいちnginxとかをセットアップするのが面倒だったので自分で書いたPSGIサーバで動かせるuwsgiのフロントエンドで、githubにだけ上げてます。uWSGIにpsgiプラグインを実行させるためのmodifier1である"5"は、現状ではfastrouterには指定しなくていいようです。
# frontend.psgi use strict; use warnings; use Plack::Builder; use File::Basename; use Plack::App::uWSGI; use Plack::App::Directory; my $psgi = Plack::App::uWSGI->new( pass => "localhost:4000", param => {UWSGI_FASTROUTER_KEY => "psgi_cluster"}, # modifier1 => "5", )->to_app; my $wsgi = Plack::App::uWSGI->new( pass => "localhost:4000", param => {UWSGI_FASTROUTER_KEY => "wsgi_cluster"}, )->to_app; builder { mount '/static' => Plack::App::Directory->new( root => dirname(__FILE__) . '/static' )->to_app; mount '/psgi' => $psgi; mount '/wsgi' => $wsgi; };
$ plackup -Ilib ../frontend.psgi
次に、ロードバランサであるfastrouterを立ち上げます。以下の起動方法ではルータを4000番で立ち上げているので、WEBサービスのクライアントは4000番に接続してuwsgiでやりとりすることになります。また、4001番に立っているのがサブスクリプションサーバとなり、ワーカからこいつへ通知することでfastrouterが新しいノードを認識するという仕組みです。
$ ./uwsgi --plugins fastrouter --fastrouter :4000 --fastrouter-subscription-server :4001
後はワーカを立ち上げれば終了です。今回はPSGIとWSGIのワーカを3つずつ立ち上げました。PSGIのワーカは以下のような感じです。4001番のサブスクリプションサーバに対して、自分が「psgi_cluster」という名前のサービスについてmodifier1が"5"のuwsgiリクエストを処理できることを通知しています。-M を省略すると動作が安定しないみたいなのですが、不具合なのか仕様なのかちょっとまだ追えてません。
# app.psgi use strict; use warnings; use utf8; use Encode qw/encode_utf8/; use Text::Xslate; my $tpl = do { local $/; <DATA> }; sub { [ 200, ['Content-Type' => 'text/html; charset=UTF8'], [encode_utf8(Text::Xslate->new->render_string($tpl, {pid => $$}))] ] }; __END__ <img src="/static/hokkaidopm.gif"> <div style="font-size:100px;">PID: <: $pid :></div>
$ ./uwsgi --plugins psgi -s :4002 --psgi ../app.psgi -M --subscribe-to 127.0.0.1:4001:psgi_cluster:5 $ ./uwsgi --plugins psgi -s :4003 --psgi ../app.psgi -M --subscribe-to 127.0.0.1:4001:psgi_cluster:5 $ ./uwsgi --plugins psgi -s :4004 --psgi ../app.psgi -M --subscribe-to 127.0.0.1:4001:psgi_cluster:5
# app.wsgi # -*- coding: utf-8 -*- import os from jinja2 import Template tpl = ''' <img src="/static/python.png"> <div style="font-size:100px;">PID: {{pid}}</div> ''' def application(environ, start_response): response_headers = [('Content-type','text/html;charset=UTF-8')] start_response('200 OK', response_headers) return [Template(tpl).render(pid=os.getpid()).encode("UTF-8")]
$ ./uwsgi --plugins python -s :4005 --file ../app.wsgi -M --subscribe-to 127.0.0.1:4001:wsgi_cluster $ ./uwsgi --plugins python -s :4006 --file ../app.wsgi -M --subscribe-to 127.0.0.1:4001:wsgi_cluster $ ./uwsgi --plugins python -s :4007 --file ../app.wsgi -M --subscribe-to 127.0.0.1:4001:wsgi_cluster