ほぼすべてのウェブサービスが前面に立っているもの
おかえし
ブラウザに example.com を入力すると、実際にアプリケーションを実行するマシンにたどり着くことはほとんどありません。アプリケーションが実行されるマシンに到達する前に、リクエストを送信するマシンに到達します。この転送マシンには名前があります。それは リバースプロキシ です。
このレッスンでは、リバースプロキシがどのような働きをするのか、ほぼすべての公開ウェブサービスがどのような理由でリバースプロキシの後ろに隠れているのか、そして同時にエッジレイヤーがどのような3つの役割を果たすのかを学びます。
このレッスンを終わったら、次の点を理解できるようになります:
- クライアント、プロキシ、およびオリジンの違い
- オリジンの後ろにプロキシがある理由は保護、スケーラビリティ、および誰もが気づかずに部分を交換できること
- リバースプロキシが一度に3つの役割を果たす: オリジンの隠蔽、TLSの終了、リプリカの間で負荷を分散する
- ブラウザからプロキシに、プロキシからアップストリームに、そして戻るリクエストの旅は、ホップバイホップでどのように進むか
このレッスンを終わったら、プロキシの配置について自信を持って推論できるようになり、エッジでの責任の分離と、状態のないプロキシ層が安価に増やすのに対し、単一のオリジンが増えない理由についても理解できるようになります。
フォワードプロキシ vs リバースプロキシ
二つのプロキシの方向
どちらの種類のプロキシも、二つのパーティの間で立ってトラフィックをリレーしますが、どのパーティを代表するかで異なります。
フォワードプロキシ: クライアントのグループの前面に立っています。クライアントはプロキシについて知っており、外部サーバーはプロキシのアドレスではなく、クライアントのアドレスを見ることはありません。コーポレートエグレスプロキシ、コンテンツフィルター、およびSOCKSプロキシはこのパターンに適しています。
リバースプロキシ: 外世界(クライアント)がプロキシのアドレスに話すことになります。クライアントは実際のサーバーがプロキシの後ろに隠れていることを知りません。ほとんどの公開ウェブサービスがこれを使用しています。
記号: フォワードプロキシはクライアントをサーバーから隠します。リバースプロキシはサーバーをクライアントから隠します。
なぜどちらの方向に気を付ける必要があるのか: ジョブ、失敗モード、およびセキュリティ境界は異なります。フォワードプロキシは、ユーザーが連絡する相手について心配し、リバースプロキシは、そのサーバーに連絡する相手について心配します。
クライアントが両方を通じてトラフィックを送信する場合、次の順序で移動します。client -> forward_proxy -> internet -> reverse_proxy -> origin.
なぜエッジレイヤには多くのものが住み着くのか
エッジレイヤはその役割を果たします
逆プロキシは同時に三つの仕事をこなします。どれか一つの仕事だけでレイヤが存在意義を持ちますが、すべてを同じアドレスでこなすことで、ほとんどすべてのプロダクション ウェブアーキテクチャが前方に同じ形状を呈する理由がわかります。
仕事1:オリジンを隠す。プロキシはパブリックIP上で応答します。バックエンドはインターネットに到達できないプライベートIP上に位置しています。プロキシを乗っ取らなければ、オリジンにアクセスする攻撃者はできません。
仕事2:TLSの終端。プロキシは example.com の証明書を持っており、Incoming HTTPSリクエストをデコードします。バックエンドはプロキシと信頼されているネットワークセグメント上でシンプルなHTTP(または内部のTLS)で通信します。証明書のローテーション、更新、およびシフルポリシーはすべて一つの場所で管理されます。
仕事3:負荷分散。プロキシはどのバックエンドがリクエストを処理するかを決定します。プロキシの背後にあるバックエンドはプールになります。プロキシはローテーション、最小接続数、ヘッダーに基づくハッシュなどの戦略を使用して、リクエストごとに一つを選択します。容量を追加するには、プールにバックエンドを追加するだけで、すべてのクライアントに新しいアドレスを告げる必要がありません。
それぞれの仕事は小さなプログラムです。一緒に働くと、Pythonアプリ自身よりも多くのデザイン重量を持つ単純な「Caddyの前でPythonアプリ」レイヤが持つ理由がわかります。
すべての三つの仕事にデザインする
あなたのチームは、単一のPythonプロセスがポート8000でリスニングする単一のVM上で小さなAPIを実行しています。トラフィックは増加しているため、単一のVMでは追いつかず、VMがパブリックIPを持っており、自らのTLS証明書を保持していることがセキュリティレビューで指摘されました。
逆プロキシを前面に配置することを決定します。レイアウトをスケッチして、DNSがどのように指示されるか、証明書がどこに存在するか、負荷がバックエンドにどのように到達するか、および元のVMがどのような変更を遂げるかを示してください。
在没有任何人注意的情况下更换一个组件
间接性买入自由
分布式系统中,最有用的间接性之一是反向代理。计算机科学的一个老谚语是:每个问题都可以通过增加一层间接性来解决(除了太多层间接性的问题)。
它为您买单:
- 可替换的后端。将应用程序从Python更换为Go?将从一个数据中心迁移到另一个数据中心?无缝部署一个新版本?所有这些操作都发生在稳定的公共地址后面。用户没有任何变化。
- 独立扩展。代理层次在TLS层上根据带宽和CPU进行扩展。后端层次根据应用程序工作量进行扩展。每个都在不同的机器上成长。
- 故障隔离。后端上的坏部署不会使公共地址失效。代理仍然保持正常运行;您可以推出修复或回滚;世界在后端恢复时重新连接。
- 跨切面关注点在一个地方。请求限制、地理屏蔽、请求日志、头部重写、缓存、响应压缩:所有这些都在代理中进行。后端代码专注于应用程序。
没有代理,所有这些问题都必须在应用程序进程内部解决。有了代理,它们都在一个层次上,一个团队负责。
成本:需要操作另一个层次。成熟的团队接受这个成本,因为代理层次本身运行无状态并水平扩展;将一个代理替换为两个不需要任何协调。
通过代理进行蓝绿部署
您的团队在反向代理后面运行API版本1的三个后端VM(蓝色池)。您想要部署版本2,并在出现问题时在30秒内快速回滚。
您启动三个运行版本2的后端VM(绿色池),与蓝色池并排运行,但尚未将任何流量路由到它们。
ブラウザからバックエンドへ、そして戻る
1つのリクエストを端から端まで追跡する
リバースプロキシの背後にあるバックエンドプールに対して、https://api.example.com/users/42 の HTTPS GET をトレースしてください。
ホップ 1: DNS解決。ブラウザは api.example.com にリゾルバーを尋ねます。リゾルバーはプロキシのパブリックIPを返します(例: 203.0.113.10)。ブラウザは 203.0.113.10:443 に TCP 接続を開きます。
ホップ 2: TLSハンドシェイク。プロキシは api.example.com の証明書を提示します。ブラウザは証明書を検証し、両者間でセッションキーに合意し、暗号化されたチャネルが開きます。
ホップ 3: TLS内でのHTTPリクエスト。ブラウザは GET /users/42 HTTP/1.1\nHost: api.example.com\n... を送信します。プロキシは暗号化されたリクエストバイトを解読します。
ホップ 4: バックエンドの選択。プロキシは api.example.com のアップストリームプールを確認し、ロードバランシング戦略に従って1つのバックエンド(例: 10.0.0.21:8000)を選択します。
ホップ 5: アップストリームリクエスト。プロキシは 10.0.0.21:8000 に対して(または再利用する)プランテキストHTTP接続を開き、リクエストを転送します。プロキシはヘッダーを書き換えることがあります: Connection などのホップ間ヘッダーを削除するなど。
ホップ 6: バックエンドの処理。バックエンドのアプリケーションはリクエストを読み取り、データベースをクエリし、JSON応答を構築します。
ホップ 7: アップストリーム応答。バックエンドはプロキシに単純なHTTPで応答を返します。
ホップ 8: エッジ応答。プロキシは応答を再度書き換えるか圧縮し、TLSセッションを通じて再度暗号化し、ブラウザに送信します。
ホップ 9: 接続ライフサイクル。TLSセッションは通常、次のリクエストまで開放され(HTTP/2では複数のリクエストが1つの接続にマルチプレックスされます)。プロキシからバックエンドへの接続は通常再利用のためのプールされます。
すべてのパブリックウェブサービスはこの形状のバリアントを実装しています。ホップの知識は、遅延がどの位置で蓄積されるか、ログがどこに属するか、そして失敗がどこで隠れるかを推理するのに役立ちます。
時間はどこに行ったの?
AユーザーがAPIが遅いと苦情を申し立てます。リクエストが850msかかり、エンドツーエンドで測定します。サーバーログに、リクエストを処理するためにアプリケーションが40msかかりました。プロキシログはプロキシがTLSハンドシェイク+ルーティング+レスポンス書き込みのために50msを費やしました。
新しいサービス用に最小限のエッジをデザインする
シンセシス
あなたは、逆プロキシとフォワードプロキシの違い、逆プロキシが一度に3つの仕事を処理する理由、オリジンを隠すことが、いつでも何かを変更する必要がある場合に利益をもたらす理由、リクエストがエッジをhop by hopでどのように流れるかを学びました。
それを適用してください。
新しいサービスnotes.example.comを計画する小さなチームがあります。ユーザーは個人用ノートを読み書きできます。リリース時に2つのバックエンドVMを実行し、1年以内に10つまで拡大することを予想しています。ユーザーにはHTTPS、徐々のロールアウトの新バージョン、バックエンドIPの公表なしを提供します。
このコースが次に進むところ
このコースが次に進むところ
このレッスンでは、エッジレイヤーの形状が確立されました。このコースの4つのレッスンはそれを拡張します:
- ステートレスホorizontalスケーリング: プロキシ階層(および、その背後にあるバックエンド)が安価に増える理由、およびスループットが増えた際のリプリカの数を決定するための数学
- イングレス/エグレス分離: 入力および出力トラフィックを処理する単一のプロキシボックスが意図せぬ方法で失敗する理由、およびレイヤーを分割する方法
- 障害モードおよび爆発半径: 単一の構成変更が大規模な障害に転じる経緯、および再発を防ぐための無faultのアクション項目を記述する方法
- 観察性および容量: エッジで問題がユーザーに伝わる前に検出できるように、測定すべき要素
各レッスンは独立しています。一緒にすると、Webスケールのフィートを理解するための機能的なメンタルモデルを提供します。
補助レッスン: geometry_of_proxies_and_origins では、このレッスンの内容を有向グラフとして再構成し、リクエストパスの観点からグラフ理論が何を教えるかを探求します。
お疲れ様でした。次へ進んでください。