はじめに – PythonでのNGINXの活用方法
Pythonは、簡単かつ楽しく使えること、ソフトウェア開発を容易にすること、そして他のスクリプト言語を上回るとされる実行時パフォーマンスで知られています。(ただし、PHPの最新バージョンであるPHP 7は、Pythonに匹敵する可能性があります。)
誰もが、Webサイトやアプリケーションの高速化を望んでいます。また、トラフィックが増加している、あるいは急増するWebサイトでは、パフォーマンスの問題やダウンタイムが発生しやすく、多くの場合、最も避けたい時間帯、つまりアクセスが最も集中する時間帯に発生します。さらに、トラフィック量が着実に増加している場合でも、利用が急増する場合でも、ほぼすべてのWebサイトでパフォーマンスの問題やダウンタイムが発生します。
そこで役立つのがNGINXとNGINX Plusです。これらは、次の3つの方法でWebサイトのパフォーマンスを向上させます。
- Webサーバーとして – NGINXはもともと、C10K問題、つまり10,000以上の同時接続を容易に処理するという課題を解決するために開発されました。PythonアプリのWebサーバーとしてNGINXを使用すると、トラフィックが少ない場合でもWebサイトを高速化できます。ユーザーが数千人規模になると、パフォーマンスが大幅に向上し、クラッシュやダウンタイムが減少することはほぼ確実です。NGINX Webサーバーでは、静的ファイルのキャッシュやマイクロキャッシュも利用できますが、いずれも別のNGINXリバースプロキシサーバーで実行する方が効果的です(次の段落を参照)。
- リバースプロキシサーバーとして – 現在のアプリケーションサーバー構成の前段に、リバースプロキシサーバーとしてNGINXを簡単に導入できます。NGINXがWebからのアクセスを受け、リクエストをアプリケーションサーバーに渡します。この「ちょっと変わった裏技」により、Webサイトの処理速度が向上し、ダウンタイムとサーバーリソースの消費が減少するほか、セキュリティも向上します。また、リバースプロキシサーバーで静的ファイルをキャッシュしたり(非常に効率的です)、アプリケーション自体の負荷を軽減するために動的コンテンツのマイクロキャッシュを追加したりすることもできます。
- 複数のアプリケーションサーバーに対応するロードバランサーとして – まず、リバースプロキシサーバーを導入します。次に、複数のアプリケーションサーバーを並列稼働させ、NGINXまたはNGINX Plusを使用してサーバー間のトラフィックを負荷分散することで、スケールアウトします。このような構成により、トラフィック要件に応じてWebサイトのパフォーマンスを容易に拡張し、信頼性と稼働時間を向上できます。特定のユーザーセッションを同じサーバーで維持する必要がある場合は、ロードバランサーがセッション維持をサポートするように設定します。
NGINXとNGINX Plusは、PythonアプリのWebサーバー、リバースプロキシサーバー、ロードバランサーのいずれかとして使用する場合でも、3つすべての用途で使用する場合でも、メリットをもたらします。
2部構成シリーズの第1回となる本記事では、Pythonアプリのパフォーマンスを向上させるための5つのヒントを紹介します。これには、NGINXおよびNGINX PlusをWebサーバーとして使用する方法、静的ファイルのキャッシュを実装する方法、アプリケーションが生成したファイルをマイクロキャッシュする方法が含まれます。第2回では、NGINXおよびNGINX Plusをリバースプロキシサーバーとして使用する方法と、複数のアプリケーションサーバーに対応するロードバランサーとして使用する方法を紹介します。
ヒント1 – Pythonのパフォーマンスボトルネックを特定する
Pythonアプリケーションのパフォーマンスが重要になる状況は、大きく2つに分かれます。1つは日常的な「妥当な」数のユーザーが利用する場合、もう1つは高負荷がかかる場合です。多くのサイト運営者は低負荷時のパフォーマンスをあまり気にしていませんが、私たちの考えでは、応答時間を0.1秒単位で気にかけるべきです。応答時間を数ミリ秒短縮するのは難しく、報われにくい作業ですが、ユーザーの満足度を高め、ビジネス成果の向上につながります。
しかし、このブログ記事と続編のPart 2では、多くの人が懸念する状況、つまりサイトへのアクセスが集中した際に発生する、大幅なパフォーマンス低下やクラッシュなどの問題に焦点を当てます。また、多くのハッカー攻撃はユーザー数が急増した場合と同様の影響をもたらすため、サイトのパフォーマンス向上は、攻撃への対処においても重要なステップとなることが少なくありません。
Apache HTTP Serverのようにユーザーごとに一定量のメモリを割り当てるシステムでは、ユーザー数が増えるにつれて物理メモリが過負荷になります。その結果、サーバーでディスクへのスワップが始まり、パフォーマンスが急激に低下し、動作不良やクラッシュが発生します。このブログ記事で説明するように、NGINXへ移行することで、この問題の解決に役立ちます。
Pythonは一般に、他のスクリプト言語よりもタスクの実行に多くのメモリを使用するため、特にメモリ関連のパフォーマンス問題が発生しやすい傾向があります(その分、処理は高速です)。したがって、その他の条件が同じであれば、Pythonベースのアプリは、別の言語で記述されたアプリよりも少ないユーザー負荷で「ダウン」する可能性があります。
アプリを最適化すればある程度の効果は期待できますが、通常、トラフィックに起因するサイトのパフォーマンス問題を解決するうえで、最善かつ最速の方法とはいえません。このブログ記事と併せて公開しているパート2で紹介する手順が、こうした問題に対処するための最善かつ最速の方法です。ここで紹介する手順を実施した後で、アプリをさらに改善するか、マイクロサービスアーキテクチャを採用するように書き直してください。
ヒント2 – シングルサーバーまたはマルチサーバー構成を選択
小規模なWebサイトは、単一サーバーへの導入で十分に機能します。大規模なWebサイトには複数のサーバーが必要です。ただし、その中間に位置する場合や、小規模サイトから大規模サイトへと成長している場合は、いくつかの重要な選択肢を検討する必要があります。
単一サーバー構成では、トラフィックの急増や全体的なトラフィックの急速な増加が発生した場合、大きなリスクにさらされます。スケーラビリティには限界があり、対策としては、アプリの改善、WebサーバーのNGINXへの切り替え、より大規模で高速なサーバーへの移行、コンテンツ配信ネットワーク(CDN)へのストレージのオフロードなどが考えられます。いずれの選択肢も、実装に時間とコストがかかるうえ、実装時にバグや問題が生じるリスクがあります。
また、単一サーバー構成では、サイトには必然的に単一障害点が存在します。サイトを停止させる可能性のある問題の多くは、迅速かつ簡単には解決できません。

単一サーバー構成でサーバーをNGINXに切り替える場合は、NGINX Open SourceとNGINX Plusのどちらでも自由に選択できます。NGINX Plusには、エンタープライズグレードのサポートと追加機能が含まれています。追加機能のうち、リアルタイムのアクティビティ監視などは単一サーバー構成で役立ちます。一方、負荷分散やセッション維持などは、複数サーバー構成でNGINX Plusをリバースプロキシサーバーとして使用する場合に利用できます。
総合的に考えると、サイトが今後も長期にわたって小規模なままであり、ダウンタイムも大きな懸念ではないと確信できる場合を除き、単一サーバー構成には一定のリスクがあります。マルチサーバー構成はほぼ制限なく拡張でき、単一障害点を設計によって排除し、必要に応じてパフォーマンスを調整できるほか、容量も迅速に追加できます。
ヒント3:WebサーバーをNGINXに変更
Webの黎明期には、「Apache」は「Webサーバー」の代名詞でした。しかし、2000年代初頭に開発されたNGINXは着実に普及しており、すでに世界の上位1,000、10,000、100,000、および[ngx_snippet name=’proportion-top-sites’]のサイトでシェア第1位のWebサーバーとなっています。
NGINXは、C10K問題、つまり所定のメモリ容量内で10,000を超える同時接続を処理するという課題を解決するために開発されました。他のWebサーバーでは、接続ごとに一定量のメモリが必要になるため、数千人のユーザーが同時にサイトへアクセスしようとすると、物理メモリが不足し、速度低下やクラッシュが発生します。NGINXは各リクエストを個別に処理し、より多くのユーザーに対応できるようスムーズにスケールします。(以下で説明するように、ほかの用途にも優れています。)
以下に、NGINXアーキテクチャの概要を示します。

図では、Pythonアプリケーションサーバーはバックエンドのアプリケーションサーバーブロックに配置され、FastCGI経由でアクセスされる構成になっています。NGINX自体はPythonを実行できないため、Pythonを実行できる環境へのゲートウェイが必要です。FastCGIは、PHP、Pythonなどの言語で広く使用されているインターフェースです。
ただし、PythonとNGINX間の通信には、Web Server Gateway Interface(WSGI)の方が広く利用されています。WSGIはマルチスレッド環境とマルチプロセス環境で動作するため、このブログ記事で紹介しているすべてのデプロイ方法に対応して適切にスケールできます。
WebサーバーをNGINXに移行する場合、必要な手順については豊富なサポート情報を利用できます。
- gunicornの設定 – 人気のWSGIサーバー「Green Unicorn」をNGINXで使用するための設定。
- uWSGIの設定 – NGINXで使用できる、もう1つの一般的なWSGIサーバーです。uWSGIはNGINXを直接サポートしています。
- uWSGI、NGINX、Djangoの使用 – 人気のあるPython Webフレームワークです。
このスニペットでは、uWSGIで使用するようにNGINXを構成する方法の一例として、PythonフレームワークのDjangoを使用するプロジェクトを取り上げます。
http { # ...
upstream django {
server 127.0.0.1:29000;
}
server {
listen 80;
server_name myapp.example.com;
root /var/www/myapp/html;
location / {
index index.html;
}
location /static/ {
alias /var/django/projects/myapp/static/;
}
location /main {
include /etc/nginx/uwsgi_params;
uwsgi_pass django;
uwsgi_param Host $host;
uwsgi_param X-Real-IP $remote_addr;
uwsgi_param X-Forwarded-For $proxy_add_x_forwarded_for;
uwsgi_param X-Forwarded-Proto $http_x_forwarded_proto;
}
}
}ヒント4 – 静的ファイルのキャッシュを実装する
静的コンテンツのキャッシュでは、数時間ごとにしか変更されない、あるいはまったく変更されないファイルのコピーを、アプリケーションサーバー以外の場所に保存します。静的コンテンツの代表例は、Webページの一部として表示されるJPEG画像です。
静的ファイルのキャッシュは、アプリケーションのパフォーマンスを向上させる一般的な方法であり、実際には複数のレベルで行われます。
- ユーザーのブラウザ
- 企業の内部ネットワークからインターネットサービスプロバイダー(ISP)まで、さまざまなレベルのインターネットプロバイダー
- ここで説明するように、Webサーバー上で
Webサーバーに静的ファイルのキャッシュを実装すると、次の2つのメリットがあります。
- ユーザーへの配信を高速化 – NGINXは静的ファイルのキャッシュに最適化されており、静的コンテンツのリクエストをアプリケーションサーバーよりもはるかに高速に処理します。
- アプリケーションサーバーの負荷を軽減 – キャッシュされた静的ファイルへのリクエストはWebサーバーが処理するため、アプリケーションサーバーには到達しません。
静的ファイルのキャッシュは単一サーバー構成でも問題なく機能しますが、基盤となるハードウェアは引き続きWebサーバーとアプリケーションサーバーで共有されます。Webサーバーがキャッシュ済みファイルの取得にハードウェアを使用している間は、たとえ非常に効率的に処理していても、そのハードウェアリソースをアプリケーションが利用できないため、アプリケーションの処理速度が多少低下する可能性があります。
ブラウザーキャッシュをサポートするには、静的ファイルのHTTPヘッダーを適切に設定します。HTTPの「Cache-Control」ヘッダー(特に「max-age」設定)、「Expires」ヘッダー、および「Entity」タグを検討してください。このトピックの概要については、NGINX Plus Admin Guideの「Using NGINX and NGINX Plus as an Application Gateway with uWSGI and Django」を参照してください。
次のコードでは、JPEG、GIF、PNG、MP4動画、PowerPointなどの静的ファイルをキャッシュするようにNGINXを設定します。www.example.comをWebサーバーのURLに置き換えてください。
server { # substitute your web server's URL for "www.example.com"
server_name www.example.com;
root /var/www/example.com/htdocs;
index index.php;
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ .php$ {
try_files $uri =404;
include fastcgi_params;
# substitute the socket, or address and port, of your Python server
fastcgi_pass unix:/var/run/php5-fpm.sock;
#fastcgi_pass 127.0.0.1:9000;
}
location ~* .(ogg|ogv|svg|svgz|eot|otf|woff|mp4|ttf|css|rss|atom|js|jpg
|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid
|midi|wav|bmp|rtf)$ {
expires max;
log_not_found off;
access_log off;
}
}ヒント5 – マイクロキャッシュを実装する
マイクロキャッシュを活用すると、Python、PHPなどの言語を実行するアプリケーションサーバーのパフォーマンスを大幅に向上できる可能性があります。キャッシュの観点から、Webページは次の3種類に分類されます。
- 静的ファイル – 「ヒント4」で説明したように、キャッシュできます。
- アプリケーションで生成される、パーソナライズされていないページ – このようなページは最新の状態に保つ必要があるため、通常はキャッシュに適していません。たとえば、ログインしていないeコマースユーザーに配信されるページが該当します(次の項目を参照)。購入可能な商品やおすすめの類似商品などは絶えず変化する可能性があるため、最新のページを提供することが重要です。ただし、たとえば0.1秒後に別のユーザーがアクセスした場合は、直前のユーザーと同じページを表示しても問題ないことがあります。
- アプリケーションが生成するパーソナライズされたページ – ユーザー固有のページであり、同じユーザーが同じパーソナライズされたページを再度閲覧する可能性も低いため、キャッシュしても有用ではありません。たとえば、ログイン済みユーザー向けのeコマースページが該当します。同じページを他のユーザーに表示することはできません。
静的ファイルと、アプリケーションが生成するパーソナライズされていないファイルはキャッシュできます
マイクロキャッシュは、上記の2つ目のページタイプ、つまりアプリケーションが生成するパーソナライズされていないページに有効です。「マイクロ」とは、短い時間枠を指します。サイトが同じページを1秒間に複数回生成する場合、そのページを1秒間キャッシュしても、鮮度への影響はそれほど大きくない可能性があります。一方、この短時間のキャッシュにより、特にトラフィックの急増時には、アプリケーションサーバーの負荷を大幅に軽減できます。キャッシュのタイムアウト期間中に同じコンテンツのページを10回、20回、あるいは100回生成する代わりに、対象のページを1回だけ生成し、その後はキャッシュしたページを多数のユーザーに配信します。
その効果は、まるで魔法のようです。1秒間に数十件のリクエストを処理すると遅くなるサーバーでも、処理するリクエストが1件だけなら非常に高速になります。(もちろん、これに加えてパーソナライズされたページも処理します。)F5のOwen Garrettによるブログ記事では、設定コードとともにマイクロキャッシュのメリットを詳しく解説しています。中核となる変更は、タイムアウトを1秒に設定したプロキシキャッシュの構成で、必要な設定コードはわずか数行です。
proxy_cache_path /tmp/cache keys_zone=cache:10m levels=1:2 inactive=600s max_size=100m;server {
proxy_cache cache;
proxy_cache_valid 200 1s;
# ...
}その他の設定例については、Tyler Hicks‑Wrightによるブログ記事「Python and uWSGI with NGINX」をご覧ください。
まとめ
パートIでは、単一サーバーのPython実装のパフォーマンスを向上させるソリューションと、単一サーバーの実装に導入するか、リバースプロキシサーバーまたは専用のキャッシュサーバーで実行できるキャッシュについて説明しました。(キャッシュは専用サーバーで実行する方が効果的です。)次の「パート2」では、2台以上のサーバーを必要とするパフォーマンス向上ソリューションについて説明します。
アプリケーション向けのNGINX Plusの高度な機能(サポート、リアルタイムのアクティビティ監視、稼働中の再構成など)をお試しになるには、今すぐ30日間の無料トライアルを開始するか、ユースケースについてお問い合わせください。
著者について

関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります