web-dev-qa-db-ja.com

Digital Ocean DNSとNginxを使用してグローバルロードバランシングを設定するにはどうすればよいですか?

UPDATE:AWSで最終的にセットアップしたソリューションについては、以下に提供した回答を参照してください。

私は現在、Digital Oceanのアプリサーバーにグローバル負荷分散レイヤーを実装する方法を実験していますが、まだいくつか組み合わせていない部分があります。

目標

すべての接続をSFO、NYC、LON、そして最終的にはシンガポールの最も近いサーバーの「クラスター」にルーティングすることにより、ユーザーに高可用性サービスを提供します。

さらに、システム上の任意のサーバーを監視、スケーリング、および修復できるデーモンを作成することで、このメンテナンスを自動化したいと思います。または、さまざまなサービスを組み合わせて、同じ自動化の目標を達成します。最初に、それを手動で行う方法を理解する必要があります。

スタック

  1. Ubuntu 14.04
  2. Nginx 1.4.6
  3. node.js
  4. Compose.io からのMongoDB(以前のMongoHQ)

グローバルドメインの内訳

すべてを整えると、私のドメインは次のようになります。

**GLOBAL**
global-balancing-1.myapp.com
global-balancing-2.myapp.com
global-balancing-3.myapp.com

**NYC**
nyc-load-balancing-1.myapp.com
nyc-load-balancing-2.myapp.com
nyc-load-balancing-3.myapp.com

nyc-app-1.myapp.com
nyc-app-2.myapp.com
nyc-app-3.myapp.com

nyc-api-1.myapp.com
nyc-api-2.myapp.com
nyc-api-3.myapp.com

**SFO**
sfo-load-balancing-1.myapp.com
sfo-load-balancing-2.myapp.com
sfo-load-balancing-3.myapp.com

sfo-app-1.myapp.com
sfo-app-2.myapp.com
sfo-app-3.myapp.com

sfo-api-1.myapp.com
sfo-api-2.myapp.com
sfo-api-3.myapp.com

**LON**
lon-load-balancing-1.myapp.com
lon-load-balancing-2.myapp.com
lon-load-balancing-3.myapp.com

lon-app-1.myapp.com
lon-app-2.myapp.com
lon-app-3.myapp.com

lon-api-1.myapp.com
lon-api-2.myapp.com
lon-api-3.myapp.com

そして、特定のレイヤー、特定の領域にひずみがある場合、新しい液滴をスピンアップして支援することができます:nyc-app-4.myapp.comlon-load-balancing-5.myapp.comなど…

現在の作業方法

  • global-balancingサーバーの(最小)トリオがすべてのトラフィックを受信します。これらのサーバーは、この(乱雑に混乱する)記事 DNSラウンドロビン負荷分散の設定方法 に示されているように、「DNSラウンドロビン」のバランスがとられています。

  • Nginx GeoIP Module および MaxMind GeoIP Data を使用すると、指定されたリクエストのオリジンは$geoip_city_continent_codeまで決定されます。

  • 次に、global-balancingレイヤーは、適切なクラスターのload-balancingレイヤーで最も接続されていないサーバー(nyc-load-balancing-1sfo-load-balancing-3lon-load-balancing-2など)にリクエストをルーティングします。この層はまた、(最小)3つの液滴です。

  • 次に、リージョナルload-balancingレイヤーが、リクエストをアプリまたはAPIレイヤーで最も接続されていないサーバーにルーティングします:nyc-app-2sfo-api-1lon-api-3など…

Nginxカンフーの詳細は、このチュートリアルに記載されています: Villiage Idiot:Nginx with GSLB/Reverse Proxy on AWS 。 Nginxのロードバランシングに関するより一般的な情報は here および here を参照してください。

質問

global-balancingサーバーはどこに配置しますか?

それらをすべて1か所に配置したり、そのレイヤーを地球全体に広げたりするのは奇妙に思えます。たとえば、私はそれらすべてをニューヨークに置いたとします。その後、フランスの誰かが私のドメインを攻撃しました。リクエストはフランスからNYCに送信され、LONにルーティングされます。または、SFO、NYC、LONにそれぞれ1つずつ配置した場合、トロント(パークデール、代表)のユーザーが、結局、LONに行き、NYCにルーティングされるだけのリクエストを送信する可能性はありませんか?

後続のリクエストは同じIPにルーティングされますか?

のように、トロントのユーザーがglobal-balancingレイヤーがNYCに行く必要があると判断したリクエストを送信した場合、そのOriginからの次のリクエストは直接NYCに送信されますか、それとも、ドローがヒットしたか最も近いglobal-balancingサーバー(この場合はニューヨーク)。

セッションはどうですか?

ip_hash; ディレクティブを使用するようにNginxを構成したので、ユーザーは同じappまたはapiエンドポイント(私の場合はノードプロセス)にリダイレクトされますしかし、グローバルバランシングは、もしあったとしてもこれにどのように影響しますか

DNSの例

私は正確にはDNSのエキスパートではありません(現在、CNAMEレコードが解決されない理由を理解しようとしています)が、確かな例が提供されれば、すぐに調査できます。誰かがこのプロセスを以前に経験したことがあり、正常なセットアップのためにDNSレコードがどのように見えるかのサンプルを提供できますか?

SSL/TLSについてはどうですか?

すべてのサーバー用の証明書が必要ですか、それとも3つのglobal-balancingサーバー用の証明書が必要ですか?

このすべてを読んだら、カップケーキでご褒美をあげましょう。助けてくれてありがとう。

28
AJB

目標:すべての接続をSFO、NYC、LON、そして最終的にはシンガポールのサーバーの最も近い「クラスター」にルーティングすることにより、ユーザーに高可用性サービスを提供します。

次に、グローバルバランシングレイヤーは、要求を最も接続されていないサーバーにルーティングします...

私が構成を正しく読んでいる場合、実際にはグローバルバランサーから各リージョンのバランサーにプロキシしています。これは、ユーザーを最も近い地域にルーティングするという目標を満たしていません。

あなたが探しているものを手に入れるために私が知っている3つの方法があります:

  1. xリダイレクト
    グローバルバランサーはHTTPリクエストを受信し、IPアドレスに基づいて、リクエストの送信元と思われるリージョン内またはその近くのサーバーグループにリダイレクトします。これは、セットアップしようとしていたように聞こえます。この方法は一部のアプリケーションに副作用があり、大量のオーバーヘッドが追加されるため、ユーザーがデータを取得するのにかかる時間が長くなります。これは、リダイレクト先のリソースが非常に大きく、ローカルリージョナルクラスターがはるかに効率的にサービスを提供できる場合にのみ意味があります。

  2. エニーキャスト(BGPルーティングを利用)
    これは、Akamaiのような大手企業がCDNに使用するものです。基本的に、インターネット上には、まったく同じルーティング可能なIPアドレスを持つ複数のサーバーがあります。複数の地域にサーバーがあり、IPアドレスが192.0.2.1であるとします。私が米国にいて192.0.2.1に接続しようとしていて、ヨーロッパにいる誰かが192.0.2.1に接続しようとしている場合、最も近いサーバーにルーティングされる可能性があります。これは、インターネットの独自のルーティングを使用して、(ネットワークの状態に基づいて)トラフィックの最適なパスを見つけます。残念ながら、この方法を使用することはできません。独自のAS番号と物理ハードウェアが必要です。 Anycastブロックのチャンクを提供するVPSプロバイダーを見つけたら、知らせてください!

  3. ジオDNS
    「Geo-DNS」として販売されることが多いサービスを提供するDNSプロバイダーがいくつかあります。彼らはあなたの最も近いサーバーにトラフィックをルーティングすることができるエニーキャストアドレスでホストされたDNSサーバーの束を持っています。クライアントがヨーロッパのDNSサーバーにクエリを実行すると、ヨーロッパの地域サーバーのアドレスが返されます。他の地域のサーバーのアドレスは返されません。 Geo DNSサービスには多くのバリエーションがあります。また、リダイレクト方法と同様に、地理IPデータベースを維持し、近いと思われる地域のサーバーを返すだけですが、DNSの場合は、HTTPリクエストが行われる前のDNSを返します。これは通常、価格と使いやすさの点で優れたオプションです。

後続のリクエストは同じIPにルーティングされますか?

多くのロードバランサーには、同じネットワークアドレスからのリクエストを同じエンドサーバーにルーティングする必要があるという「スティッキネス」オプションがあります(エンドサーバーがまだ稼働している場合)。

セッションはどうですか?

これがまさにその粘り強さを望む理由です。セッションデータに関しては、すべてのサーバーを最新の状態に保つ方法を見つける必要があります。現実的には、これが常に保証されるわけではありません。処理方法はアプリケーションによって異なります。すべてのサーバーが世界中から確実にヒットできるように、Redisインスタンスなどを維持できますか?すべての地域でそのセッションデータが本当に必要ですか?または、メインのアプリケーションサーバーが1か所でセッションデータを処理できるようにすることはできますか?

DNSの例はありますか?

これらについては別の質問を投稿してください。みんなの「成功したセットアップ」は異なって見えます。

SSL/TLSについてはどうですか?

データをプロキシする場合、グローバルバランサーのみがHTTPSを処理する必要があります。リダイレクトする場合は、すべてのサーバーで処理する必要があります。

21
Brad

実用的なソリューション

私は過去数か月にわたって、Global-HAのセットアップ全体を理解するのに熱心に取り組んできました。楽しさのトンと私は最終的に非常にうまく機能するリグで解決しました、そして上記の質問で概説されたものとは異なります。

私はまだこれをチュートリアル形式で書くつもりですが、来年初めにアプリをリリースするための最終的なスプリントに向かう時間が足りないので、ここで私が最終的に機能したリグの概要を説明します。


概要

結局、展開全体をAWSに移動しました。私はDigital Oceanが大好きですが、率直に言って現実は、AWSが1つの屋根の下で提供されるサービスに関しては、AWSよりもはるかに数年前(そして誰もが)進んでいることです。私の月額費用はわずかに増加しましたが、調整と合理化が完了すると、最も基本的な展開(ELBの背後にある2つのインスタンス)の場合、リージョンあたり月額約75ドルのコストがかかるソリューションになりました。また、新しいリージョンは約30分以内にスピンアップしてデプロイできます。


グローバルバランシング

私はすぐに(@Bradの上記の回答のおかげで)自分のグローバルバランシングDNSレイヤーをスピンアップしようとするのはおかしいと気づきました。このようなレイヤーがどのように機能するかを理解するのはとても楽しいことでしたが、飛行機に乗ってナックルをこすり落として世界中に数百万ドル相当の機器を設置することはできなかったので、自分を転がすことは不可能でした自分の。

探していたものをようやく見つけたとき、新しい親友 AWS Route 53 を見つけました。グローバルに約 50奇数ノード の堅牢なDNSネットワークを提供し、ロケーションベースのルーティング、レイテンシベースのルーティング(これはちょっと素晴らしい)、および使用する他のAWSサービスにトラフィックを「自動的に」ルーティングするAWSエイリアスレコード(ELBと同様に負荷分散)。

最終的に、グローバルトラフィックを最も近い地域のElastic Load Balancerに転送するレイテンシベースのルーティングを使用しました。このElastic Load Balancerには、任意のリージョンで自動スケーリンググループが接続されています。

www.f5.comwww.dyn.comwww.akamai.comwww.dnsmadeeasy.com 。あなたのニーズに応じて、より良い解決策があるかもしれませんが、これは私にとって非常にうまく機能します。


コンテンツ配信ネットワーク

Route 53は AWS Cloudfront と非常にうまく統合します。ユーザーがアップロードするすべての静的メディアファイルを保存するために使用しているS3バケットをセットアップし、media.myapp.com S3バケットからソースを取得するようにCloudfrontディストリビューションを構成しました。他のCDNプロバイダーがあるので、買い物をしてください。しかし、Cloudfrontは非常に優れたレビューを取得しており、簡単にセットアップできます。


負荷分散とSSL終了

現在 AWS Elastic Load Balancer を使用して、 Auto-Scaling Group にあるアプリケーションインスタンス間で負荷を分散しています。リクエストは最初にELBによって受信されます。その時点でSSLは終了し、リクエストはAuto-Scalingグループのインスタンスにパススルーされます。

注:ELBの1つの大きな警告は、皮肉なことに、大規模なスパイクをあまりうまく処理できないことです。 ELBがそれ自体のスケールアップイベントをトリガーするまでに最大15分かかり、その間に500 /タイムアウトが作成されます。トラフィックの安定した一定の増加はかなりうまく処理されると思われますが、スパイクに見舞われた場合、失敗する可能性があります。打撃を受けることがわかっている場合は、「先に電話」してAWSがELBをウォームアップします。これは、とんでもないことであり、AWSの本質に反するパターンですが、私は彼らが取り組んでいることを想像していますそれ、またはそれが本当にそれほど大きな問題ではないので、それを無視します。 ELBが機能しない場合は、いつでも独自の HAProxy または Nginx 負荷分散レイヤーを起動できます。


自動スケーリンググループ

各リージョンには、負荷が特定のメトリックを通過するときにスケーリングするようにプログラムされたASGがあります。

IF CPU > 90% FOR 5 MINUTES: SCALEUP
IF CPU < 70% FOR 5 MINUTES: SCALEDN

ELB/ASGコンボのペースはまだ決まっていません。これは私のTo-Doリストから少し下がっていますが、この設定を使用している人は他にもたくさんいることは知っています。パフォーマンスに大きな問題はないようです。

Auto Scaling Groupの設定は、私の意見では少し複雑です。これは実際には3ステップのプロセスです。

  1. 好みに合わせて構成されたAMIを作成します。
  2. 作成したAMIを使用する起動構成を作成します。
  3. 作成した起動構成を使用するAuto-Scalingグループを作成し、任意のSCALEUPイベントで起動するAMIとインスタンスタイプを決定します。

インスタンスの起動時に構成とアプリのデプロイを処理するには、 "User Data" フィールドを使用して、特定のインスタンスが起動すると実行されるスクリプトを入力します。これはおそらく、時間の歴史の中で最悪の命名法です。 「ユーザーデータ」は、作成者だけが知っている起動スクリプトをどのように記述するか。とにかく、ここですべてのapt-gets、mkdirs、gitクローンなどを処理するスクリプトを貼り付けます。


インスタンスと内部バランシング

Nginxを使用して、すべてのNode.jsアプリ(app.myapp.com、api.myapp.com、mobile.myapp.com、www。 myapp.com、etc.myapp.comなど)。 ELBから渡されたリクエストをインスタンスが受け取ると、Nginxは、指定されたアプリケーションの正しいNode.jsポートへのリクエストのルーティングを処理します。一種の貧乏人のコンテナ化のようなものです。これには、私のアプリの1つが他のアプリと通信する必要がある場合(app.api.にリクエストを送信する必要がある場合など)に、localhost:XXXXを介して実行する必要がなく、追加の利点がありますAWSネットワークまたはインターネット自体を介して出かけます。

このセットアップでは、ホストしているアプリレイヤーがたまたまトラフィックを受信して​​いる場合にアイドルインフラストラクチャを排除することで、リソースの使用を最大化します。また、すべてのアプリにELB/ASGコンボを用意する必要がなくなり、より多くの現金を節約できます。

この種のセットアップを使用して遭遇した落とし穴や警告はありませんが、ヘルスチェックに関して実施する必要がある回避策が1つあります(以下を参照)。

すべてのインスタンスにIAMの役割があるという素晴らしい利点もあります。つまり、 AWSクレデンシャルは、誕生時に各インスタンスに「焼き込まれ」 、ENV変数を介してアクセスできます。そして、AWSは「自動的に」あなたの信用をあなたにローテーションします。非常に安全で、とてもクールです。


ヘルスチェック

上記の設定のルートをたどり、すべてのアプリを1つのボックスにフラットパッキングし、内部ロードバランサーを実行する場合、 ELBヘルスチェックを処理するための小さなユーティリティを作成する必要があります 。私がしたことは、ping.myapp.comという追加のアプリを作成することでした。次に、次のように、pingアプリが実行されているポートにヘルスチェックを送信するようにELBヘルスチェックを構成しました。

Ping Protocol: HTTP
Ping Port:     XXXX
Ping Path:     /ping

これにより、すべてのヘルスチェックが私の小さなpingヘルパーに送信され、インスタンスに存在するすべてのアプリでlocalhost:XXXX/pingにヒットします。すべてが200応答を返した場合、pingアプリはELBヘルスチェックに200応答を返し、インスタンスはさらに30秒間稼働します。

注:ELBを使用している場合は、自動スケーリングのヘルスチェックを使用しないでください。 ELBヘルスチェックを使用します。それはちょっと混乱します、彼らは同じものだと思いました、そうではありません。どちらか一方を有効にするオプションがあります。 ELBを使用します。


データレイヤー

私のセットアップで明らかに欠けているのは、データレイヤーです。 Compose.io をマネージドデータレイヤープロバイダーとして使用し、AWSにデプロイすることで、アプリレイヤーとデータレイヤーの間のレイテンシが非常に低くなります。データレイヤーをグローバルに展開する方法について予備調査を行ったところ、データレイヤーが非常に複雑で非常に高価であることがわかりました。そのため、まだ解決する必要のない問題としてリストから除外しました。最悪の場合は、データレイヤーをUS-Eastのみで実行し、ハードウェアを強化することです。私のAPIは厳密にはネットワーク上のJSONデータなので、平均応答が比較的小さいため、これは世界で最悪の事態ではありません。しかし、これが非常に大規模なグローバル規模でボトルネックになることがわかります。誰かがこのレイヤーに何か入力を持っているなら、私はあなたが何を言わなければならないかを聞きたいです。


Ta-Da!

ビールの予算に関するグローバルな高可用性。それを理解するのにたった6か月しかかかりませんでした。

これを読んだ人からの意見やアイデアを聞くのが大好きです。

12
AJB

Cloudflare無料プランを使用している場合は、WebサービスにAnycastを無料で使用できます。

2
miolini