Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
uwsgi-docker-pycon2015
Search
bungoume
October 11, 2015
Technology
10
59k
uwsgi-docker-pycon2015
bungoume
October 11, 2015
Tweet
Share
More Decks by bungoume
See All by bungoume
djangocongressjp2023_password_hash
bungoume
2
1.1k
日経電子版でのDjango活用事例紹介 / djangocongressjp2022-nikkei
bungoume
4
4.7k
CircleCIの活用事例とCI高速化/circleci-community-meetup3-speedup
bungoume
3
1.4k
Password Hashing djangocongress 20180519
bungoume
5
3.9k
OSSで始めるセキュリティログ収集/oss-securitylog-builderscon2017
bungoume
29
11k
日経電子版のアプリ開発を支えるログ活用術/nikkei-log-201609
bungoume
1
1.3k
Kibanaで秒間1万件のアクセスを可視化した話/nikkei-kibana-loganalyst2015
bungoume
20
17k
Ansibleを結構使ってみた/ansible-nikkei-2015
bungoume
32
15k
Dynamic Inventoryと参照変数
bungoume
2
4.8k
Other Decks in Technology
See All in Technology
アジャイルチームがらしさを発揮するための目標づくり / Making the goal and enabling the team
kakehashi
3
150
B2B SaaSから見た最近のC#/.NETの進化
sansantech
PRO
0
910
プロダクト活用度で見えた真実 ホリゾンタルSaaSでの顧客解像度の高め方
tadaken3
0
200
ノーコードデータ分析ツールで体験する時系列データ分析超入門
negi111111
0
420
SREが投資するAIOps ~ペアーズにおけるLLM for Developerへの取り組み~
takumiogawa
1
460
強いチームと開発生産性
onk
PRO
35
11k
DynamoDB でスロットリングが発生したとき_大盛りver/when_throttling_occurs_in_dynamodb_long
emiki
1
440
SRE×AIOpsを始めよう!GuardDutyによるお手軽脅威検出
amixedcolor
0
190
Terraform Stacks入門 #HashiTalks
msato
0
360
AWS Lambdaと歩んだ“サーバーレス”と今後 #lambda_10years
yoshidashingo
1
180
rootlessコンテナのすゝめ - 研究室サーバーでもできる安全なコンテナ管理
kitsuya0828
3
390
Python(PYNQ)がテーマのAMD主催のFPGAコンテストに参加してきた
iotengineer22
0
530
Featured
See All Featured
RailsConf 2023
tenderlove
29
900
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
47
2.1k
Designing for humans not robots
tammielis
250
25k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
48k
Optimising Largest Contentful Paint
csswizardry
33
2.9k
4 Signs Your Business is Dying
shpigford
180
21k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
Why Our Code Smells
bkeepers
PRO
334
57k
KATA
mclloyd
29
14k
Typedesign – Prime Four
hannesfritz
40
2.4k
Docker and Python
trallard
40
3.1k
Transcript
uWSGI/Dockerを利用したWebサービス運用事例 PyConJP 2015, 10/11 Yuri Umezaki
#PyConJP_M 2
自己紹介 梅崎 裕利 • 会社 ◦ 日本経済新聞社デジタル編成局 • 主な業務 ◦
Ansibleでサーバ管理 ◦ Django+Elasticsearch(ES)で検索API作成 ◦ Fluentd+ES+Kibanaでログ分析 3
社内でのPython活用シーン • Google App Engine (2010〜) • New API (Search,
Authorization, Logging, etc…) ◦ Django, django-rest-frameworkなど ◦ 全部Python3系で動いています(すでにほぼv3.5) • ちょっとしたスクリプト ◦ Ansible module ◦ Slack通知 ◦ データ集計・分析 ◦ テストツール 4
目次 • uWSGI・Gunicornとは ◦ 特徴紹介 ◦ Gunicornとの比較 • サービスを停止させないGracefulな更新 ◦
更新の課題 ◦ uWSGIで用意されている機能 • Dockerとの併用事例 ◦ 複数PaaS対応(Docker, Heroku)方法 ◦ uWSGI設定例 • まとめ 5
対象 • 話すこと ◦ Djangoなど従来型のPython WebAppの話 • 話さないこと ◦ aiohttpなど非同期なWeb
6
uWSGI・Gunicorn 7
Python Webアプリケーションを動かす方法 WSGI対応サーバを利用する • gunicorn • uwsgi • Apache+mod_wsgi gunicornは利用事例が多くシンプル、
uwsgiは最近のトレンドで多機能 8
質問 • Gunicorn使っている人? ◦ 会場で20% ぐらい • uWSGI使っている人? ◦ 会場で40%
ぐらい 9
uWSGIは多機能 • http以外にもuwsgiプロトコルが話せる • 実はhttpsやspdy、WebSocketも話せる • 複数のアプリも動かせる(Emperorモード) • virtualenvなどが使える •
PythonだけでなくRuby, Perl, Lua, PHPなどにも使える • スプーラ機能 • プロファイラ • キャッシュや静的ファイル配信 • 設定パラメータを数えたら1200以上あった(!!) 10
Gunicornはシンプル • 簡単に起動できる ◦ gunicorn --workers=4 app.wsgi ◦ uwsgi --http
127.0.0.1:8000 --wsgi-file app/wsgi.py --master --processes 4 • 利用事例が多い • uWSGIほど設定項目は多くないが、必要十分 11
uWSGIとGunicornのベンチマーク 12
ベンチマーク環境 • Webサーバ ◦ AWS EC2 m4.large ◦ Amazon Linux
AMI 2015.9 • app ◦ Nginx: 1.8.0 (amazon-repo) ◦ debug-server (python3.5) • 負荷かけツール ◦ wrk ◦ 別サーバより実行 13
ベンチマークに利用したアプリケーション • debug-server ◦ https://www.github.com/bungoume/debug-server ◦ リクエスト内容をJSONで返すサーバ ◦ Django1.8.5 ◦
Python 3.5 (branch) 14
ベンチマーク内容 以下の秒間レスポンス数を比較 • nginx + uwsgi(uwsgi-protocol) • nginx + uwsgi(http)
• uwsgi直接(http) • nginx + gunicorn(http) • gunicorn直接(http) (ワーカー数・スレッド数)は(3, 3)と(4, 1)でテスト 15
nginxの設定 (共通) • ほぼamazon linuxデフォルトのまま 16
ベンチマーク: uWSGI + nginx (uwsgi) nginxの設定 uwsgiの設定(改行しています) 17
ベンチマーク: uWSGI + nginx (uwsgi) レスポンス内容(tcpdump) 18
ベンチマーク: uWSGI + nginx (uwsgi) ベンチマーク結果 19
ベンチマーク: uWSGI (http)+ nginx nginxの設定 uwsgiの設定 20
ベンチマーク: uWSGI (http)+ nginx レスポンス内容(tcpdump) 21
httpプロキシの注意 Python側(uwsgi)でRemote_IPやHost, protocolの値が変わってしまう X-Forwarded-ForやX-Forwarded-Host または、RFC7239のForwarded Headerに入れて利用する 22
ベンチマーク: uWSGI (http)+ nginx ベンチマーク結果 23
ベンチマーク: Gunicorn + nginx nginxの設定 gunicornの設定 24
ベンチマーク: Gunicorn + nginx レスポンス内容 25
ベンチマーク: Gunicorn + nginx ベンチマーク結果 26
ベンチマーク結果まとめ • 今回試した限りはuWSGIのほうが早かった • gunicornはthreadを2以上にしたりeventletを有効にしたりすると遅くなった • (もちろんアプリや設定、環境などによって異なる可能性はあるので注意) nginx+ uwsgi nginx+
uwsgi(http) uwsgi (http) nginx+ gunicorn gunicorn nginx (参考) worker:3 thread:3 1723.10 1747.53 1656.80 1139.12 1260.17 47868.37 worker:4 thread:1 1500.75 1525.72 1608.57 1357.21 1439.42 (req/s) 27
uwsgiやgunicornのhttpを直接使うときの注意点 • gunicorn直接だとheaderとコンテンツが分かれて送信される • uwsgi直接だとheaderにchunkedが入らない。keep-aliveにならない • uwsgi直接はkeep-aliveを使うのは少々無理やりな感じになる ◦ add-header=Connection: Keep-Alive
• uwsgiはhttp-soketでなくhttpを使ったほうがよい ◦ ただし、httpをつかってもkeep-aliveになるわけではない • nginxを挟むとheaderが追加され、パケットも一つになる 28
レスポンス内容: Gunicorn 直接 ヘッダ, body, 終端が別パケットで送られている 29
レスポンス内容: uWSGI 直接 コネクションが毎回切れている。chunkedになってない 30
uWSGI・Gunicorn まとめ • gunicornは事例多い・シンプル • uwsgiはトレンド・多機能 • 今回のベンチマークでは uwsgi >
gunicorn • uwsgiのhttpやgunicornを直接外部に公開するのは注意 ◦ nginxなどのリバースプロキシを通すのが良い 31
uWSGIでGracefulな更新 32
Gracefulな更新とは • サービスを止めずにアプリケーションを更新する方法 • ゼロダウンタイム・ゼロウェイトを実現したい • いろいろな方法がある ◦ DNSで切り替える ◦
LBでWebサーバを切り替える ▪ 複数のサーバを利用する ▪ サーバが切り替わるBrue-Greenデプロイ ◦ nginxで振り先を切り替える ◦ WSGIサーバでリロードする 33
イメージ図 切り替え箇所 新アプリ (サーバIP、 Port、 worker) 旧アプリ (サーバIP、 Port、 worker)
クライアント 34 • 切り替える場所の違い ◦ DNS, LBはサーバの切り替え ◦ nginxはサーバやSocket、Portの切り替え ◦ uWSGIは主にWorkerの切り替え
更新の注意点 • サービスを止めない ◦ 新しいアプリケーションが起動する間スローダウン ◦ 古いアプリケーションを止めるときにエラーが発生 • なるべく即座に反映できる ◦
DNSで切り替えるとクライアントが旧IPにアクセスし続ける恐れ • 簡単に更新できるようしておく ◦ 上段も設定変更が必要になることがある ◦ nginxで切り替える場合はデプロイのたびにnginxの設定変更が必要 ◦ 結合度が高まってしまう • ロールバックもできるように 35
uWSGI上で利用できる仕組み • Standard graceful reload • Worker reload • Chain
reload • Zerg mode • Reuse port • Master forking • Subscription system http://uwsgi-docs.readthedocs.org/en/latest/articles/TheArtOfGracefulReloading.html 36
Standard Graceful Reload (Prefork, Lazy-app) 動いているWorkerが止まるのを待って再起動する • 使い方 ◦ FIFOにrを書き込む(--maste-fifo
オプションでsocketを要しておきechoなどで書き込む) ◦ touch-reloadオプションを使う ◦ SIGHUPを送る ◦ uwsgi.reload() APIを呼ぶ • メリット ◦ 管理が簡単 ◦ 軽量なPreforkでも使える ◦ 不整合が起きない • デメリット ◦ 長い待ち時間が発生する 37
Worker Reload(秒間レスポンス数) • 約1分間の停止期間が発生(preforkでテスト) 38
Worker Reload(平均レスポンス時間) • 60秒でタイムアウト(504)が発生している • アプリケーション起動前の502も発生 39
Worker Reload(Lazy-app) Workerだけをリロードする • 使い方 ◦ FIFOにwを書き込む ◦ touch-worker-reloadオプションを使う •
メリット ◦ 全体の再起動が不要になる • デメリット ◦ コードの更新にしか有効でない 40
Worker Reload(レスポンス数) • 2秒ほど止まるが500エラーなどは出ていない 41
Worker Reload(レスポンス時間) • 一瞬詰まるが問題なさそう 42
Chain Reload (Lazy-app) Workerを一つひとつ順番にリロードしていく • 使い方 ◦ FIFOにcを書き込む ◦ touch-chain-reloadオプションを使う
• メリット ◦ ある程度ワーカー数があれば、クライアントの待ち時間を大幅に削減できる ◦ リロード時の負荷が少ない • デメリット ◦ コードの更新にしか有効でない 43
Chain Reload (レスポンス数) • 4workers, 2threadsにて。段階的に切り替わっており総数への影響は少ない 44
Chain Reload (平均レスポンス時間) • 待ちは発生していない 45
Worker reload, Chain reloadの問題点 uwsgiの設定更新には使えない • 依存ライブラリ更新ができない • Pythonのバージョンをあげられない 46
Unix socketをプールとして活用する(Zerg mode) マスターのuwsgiを用意してportをUnix socketに変換し、 socketに複数のインスタンスを紐付けて振り分ける • 使い方 ◦ masterデーモンを用意しておき、し、アプリはzergでsocketに割り当てる
◦ 更新時は同じsocketで起動し、古いものを落とす • メリット ◦ uWSGIの設定変更も可能になる ◦ 待ち時間が少ない ◦ ロールバックしやすい • デメリット ◦ 追加で常駐のmasterデーモンが必要で、リロード時は更にプロセスが必要になる ◦ 通常と異なる設定が必要。ちょっとわかりにくい 47
Zerg mode (レスポンス数) • 起動時に減るが、大きな影響はなさそう。終了は問題ない(graceful shutdown) 48
Zerg mode (平均レスポンス時間) • 起動時に若干増える。 49
同一ポートを利用 (Reuse-Port) Linux≧3.9かBSD系で使えるSO_REUSEPORTを活用する • 使い方 ◦ --reuse-portオプションを使って起動する ◦ 新しいアプリを同じポートで起動し、古いものを落とす •
メリット ◦ Zerg modeと同じように、uWSGI自体の設定変更も可能 ◦ masterデーモンが不要なので管理が楽 • デメリット ◦ カーネルサポートが必要 複数のプロセスで同じTCPポートをバインドできる夢の機能 LinuxだとKernelがバランシングしてくれる 50
Reuse Port (レスポンス数) • 古いものをSIGINT(強制終了)で止める 51
Reuse Port (レスポンス数) • しかし若干エラー(502)が出ている 52
Reuse Port (平均レスポンス時間) • 起動時と終了時に僅かな待ちが発生している。(緑は502) 53
Reuse Port (レスポンス数) • 古いバージョンをgraceful shutdownすると1分間止まってしまう 54
Reuse Portについて • 試したOSはLinux(4.1.7) • 複数バインド時にどちらに飛ばすかはKernel次第なので細かい制御は難しい • 夢の機能は万能ではなかった。 55
Master forking (黒魔術!) masterを再フォークする • 使い方 ◦ FIFOにfを書き込む • メリット
◦ カーネルサポートも追加プロセスも不要 ◦ かなり速い • デメリット ◦ ログやpidなどの一貫性が壊れる 56
結果 • 試した限りではうまく切り替わりませんでした... 57
Subscription System サブスクリプションサーバとよばれるロードバランサを用意して紐付ける • 使い方 ◦ uwsgi --fastrouter :1717 --fastrouter-subscription-server
192.168.0.100:2626 • メリット ◦ 簡単かつゼロダウンタイム ◦ 構成がシンプル • デメリット ◦ fastserverのようなサブスクリプションサーバが必要 58
Gracefulまとめ • 各機能に特徴があるので要件次第 • アプリケーションのみを安全に切り替えるならChain Reload • ライブラリ更新やロールバックを考慮するならZerg Dance •
ごく僅かなエラーより管理のしやすさを優先させるならReuse Port 利点・欠点を見ながら、良いものを選択 59
uWSGI+Docker利用事例 60
事例 61 • 新規モバイルアプリ向けAPI • 規模はまだ小さいサービス • Djangoを利用して作成
優先したこと 62 • 管理のしやすさ ◦ ライブラリを含め、アプリの更新がしやすい ◦ 別の環境に移行しやすい ≒ 昨今のコンテナ技術周りに追従しやすい
• 運用のしやすさ ◦ サーバにログインしなくても状況がわかるように ◦ 壊れたら消せる = ログは別の場所に送っておく
最初は優先しない • 性能 • 完全にGracefulな更新 63
というわけで、 reuse-port を使います 64
アプリとインフラの分割単位 • Herokuを参考 ◦ アプリ自体はHerokuでも動かせる形にしておく • http(またはuwsgiプロトコル)を話すところまでアプリ ◦ Pythonバージョンや異存ライブラリはアプリで指定 •
LBやリバースプロキシ、デプロイ自体はインフラ ◦ Ansibleやクラウドの機能を利用 65
アプリ側のディレクトリ構成 66 • debug-serverの例 • heroku,dockerどちらでも動く ◦ heroku deploy ◦
docker run
Dockerfileの中身 • Dockerfile • python:3-onbuild 67
uWSGIの設定例 68
構成図 69
現在のデプロイ方法 現在は1ホスト1コンテナの構成 • 新バージョンのコンテナをビルドする • 古いバージョンのコンテナIDを控えておく • reuse-portを使って新バージョンのコンテナを起動する • 数秒待つ
• 古いコンテナを止める 70
運用事例まとめ • Dockerを1ホスト1コンテナとして利用 ◦ 汎用的なVirtualenvとして • Dockerを利用することでHerokuでもdocker runでも動かせる • ECSなどのコンテナホスティングにそのまま載せられる
• ログなどの状態は内部に持たないようにしておく 71
今後の方針 72 • nginxやfluentd側もコンテナにする • デプロイしやすいサービスが出たら乗り換える ◦ AWSのECSに移行中
まとめ 73
74 • uWSGIは多機能、Gunicornはシンプル • 今回のベンチではuWSGIのほうがGunicornより速い • uWSGIはいろいろなGraceful Reload方法がある • 事例としてはReuse-Portを利用している
75 性能・運用のしやすさ・コストなどを 考慮してうまく使うようにしましょう
ご清聴ありがとうございました。 76
予備スライド 77
アクセスログの取り方 78