Blog

NGINXを使ってロードバランサーを構築してみた

初めに

こんにちは!ニフティ新卒2年目の仲上です。
先日応用情報処理技術者試験を受けてきたのですが、結果が出るのがまだ先なので、1か月くらいずっとそわそわしてます。合否報告が来た時には、受験したことを忘れてそうです。
さて、今回はNGINXで作成したロードバランサーについて紹介したいと思います。
私が担当しているシステムはクラウドサービス上に構築されているのですが、そのサービスではローカルネットワーク内にクラウドサービスのロードバランサーを作成することができませんでした。そのため、サーバーにNGINXを導入し、ロードバランサーを作成したので、その時のことについてまとめていきたいと思います。

NGINXとは

NGINX(エンジンエックス)とは、フリーソフトかつオープンソースなミドルウェアであり、WEBサーバーを作成する際に使われるソフトウェアです。同じWEBサーバーソフトウェアとしてApache(アパッチ)がありますが、Apacheがマルチプロセスモデルなのに対し、NGINXはイベント駆動モデルで設計されており、NGINXのほうが大量アクセスに強いとされています。
Apacheもロードバランサー機能を持っていますが、大量アクセスに強いこととパラメータチューニングが容易なことから、今回はNGINXを選択しました。

有料版と無料版の違い

NGINXには有料版と無料版があり、いくつか違いがあります。ロードバランサーの機能でも有料版でしか使えない機能は多くありますが、その中でも最も注目する点はヘルスチェックにあります。

有料版

アクティブヘルスチェック機能を有しています。定期的に振り分けへリクエストを送り、正しい応答が返ってくるか確認します。

無料版

パッシブチェック機能を有しています。正確には、アクティブヘルスチェックを使用できないため、パッシブヘルスチェックしか使うことができません。パッシブヘルスチェックでは、実際に飛んできたリクエストを振り分け先のサーバーに送り、その応答を見てヘルスチェックを行っています。
詳しくは後述しますが、今回はパッシブヘルスチェックでも要件を十分に満たせると判断したため、無料版のNGINXを採用しました。

構成・開発

こちらが今までの構成図となります。
そしてこちらが、新しい構成内容となっています。
WEBサーバーとAPサーバー間で接続・負荷分散するためにロードバランサを作成します。 今までAPサーバーは予備機をホットスタンバイさせておき、問題があれば切り替える運用をとっていました。これからは常時複数のAPサーバーに振り分けられるようになるため、負荷分散や冗長化構成による保守性の向上などが期待できます。 FWやACLは WEB→LB→AP で通信を行えるようにあらかじめ開放しておきます。

作成

WEBサーバーやAPサーバーと同じネットワーク内にサーバーを1台設置します。以後こちらのサーバーはLBサーバーと呼称します。 ロードバランサーではサーバースペックはそこまで求められないので、準備できる中で最も安いグレードを用意しました。OSにはCentOS 7 を使用しています。 まず、LBサーバーにNGINXをインストールします。 NGINXのインストールチェックと自動起動設定をonにします。 NGINXの設定ファイルを開き、ロードバランサとしての設定を書き込んでいきます。 以下の内容を追記します。 これは振り分けグしたときのログを残すための設定です。 続いて、ロードバランサー関係の設定を追加します。 default.conf は今回使わないので、設定ファイル対象から外しておきます。 proxy.conf には以下の内容で追記します。

ロードバランスの方法

NGINXのロードバランサーにはロードバランスの方法が3つあります。
  • ラウンドロビン…振り分け先のサーバーへ均等にリクエストがとぶように振り分ける方式です。デフォルトではこの設定になっています。振り分け先のサーバを重みづけして、リクエスト数の比重を変えることもできます。
  • リース接続…アクティブな接続数が最も少ないサーバーに振り分けられるような設定です。
  • IPハッシュ…同じIPアドレスからのリクエストは、同じ振り分け先サーバーへ振り分けられるような設定です。1つの処理が複数のリクエストにまたがっており、かつ同一のサーバーで行われる必要があるときに有効な設定です。
今回は1つのリクエストで1つの処理が完結していることと、全サーバーへ均等にリクエストを割り振りたかったことから、ラウンドロビンを採用しました。

パラメータ解説

  • upstream pool1…振り分け先のサーバー情報を書く部分です。
パラメータ名概要
fail_timeoutサーバーが正常に動作していないと判定された場合、ここで定義された時間はリクエストが送られなくなります。また、max_failsの判定時間も兼ねています。
max_failsサーバーが正常に動作していないと判定するためのリクエスト回数です。ここで指定したリクエスト回数が fail_timeout で定義した時間内に発生した場合、サーバーが正常に動作していないと判断されます。
現在の設定だと、10秒間に100回失敗した場合に振り分け先が正常に動作していないと判定されます。
  • listen…NGINXが受け付けるport番号を指定します。
  • server_name…NGINXを入れているホストマシンの名前です。
  • location…振り分け元のパスです。今回はrootを指定しているので、LBサーバーに送信されたリクエストはすべて振り分けられます。
パラメータ名概要
proxy_pass中継先のパスです。upstreamで定義した名前を入れることができます。
proxy_next_upstream_triesNGINXがエラーと判定し、再度リクエストを送るための条件です。404や500はデフォルトで再送信しないようになっているので、再送したい場合は明示的に宣言してあげる必要があります。
proxy_next_upstream_triesリクエストが失敗したとき、再送する回数の上限です。最初の送信も含まれます。0を宣言すると、proxy_next_upstream_timeoutの間、無限にトライするようになります。
proxy_next_upstream_timeout1回のリクエストに対する制限時間です。この時間を超えたリクエストはタイムアウトになります。
proxy_connect_timeout接続先へコネクションを張るまでのタイムアウト時間です。
proxy_send_timeout接続先へデータを送信するまでのタイムアウト時間です。
proxy_read_timeout接続先がレスポンスを返すまでのタイムアウト時間です。

ヘルスチェックとサーバの復旧基準について

ヘルスチェック

先ほど、無料版ではパッシブヘルスチェックしか使えないと書きました。このヘルスチェックは、振り分け先のサーバーからエラーが返ってきても、proxy_next_upstream_timeoutの時間内ならほかのサーバーへ再振り分けされる仕様になっています。そのため、先ほどの設定で正常に動作していないと判定するためには10秒間に100件の失敗リクエストが必要だと書きましたが、100件すべてがエラーとして返されるわけではないです。

復旧基準

NGINXはサーバーが正常に動作していないと判定すると、振り分け先からそのサーバーを除外します。NGINXはサーバーが振り分け先から除外されてからfail_timeout時間経過するごとに、パッシブヘルスチェックで除外されたサーバーへリクエストを1件送信します。そのリクエストに対して正常なレスポンスが返ってきた場合、サーバーが復旧したと判断し、振り分けを再開するようになっています。

動作確認

一通り設定が終わったので、動作確認を行います。 WEBの向き先をAPサーバーからLBサーバーに変更して、upstream.logを確認します。
(セキュリティ上の理由から、一部情報をマスクしています。ご了承ください。)
振り分け先のIPアドレスを見ると、複数のホストに振り分けられていることが確認できます。

困ったこと・苦労したこと

サーバーを使ってロードバランサーを作成するのが初めてだったこともあり、サーバーの必要スペックを模索するのが大変でした。NGINXはCPUやメモリのリソースをどの程度必要とするのか、I/Oはボトルネックとならないか、ネットワークの帯域は問題がないかなど考えるべきことが山のようにありました。最終的に、NGINXのロードバランサー機能はサーバーのリソースをそこまで必要としなかったため、最初に準備したサーバーで問題なく動作しました。
また、他にロードバランサーを作成した人がチーム内にいなかったため、機能試験の項目列挙や実際の試験に苦労しました。機能試験に関してはAPIの動作確認だけでなく、WEB側から見てエラー画面が表示されないか、すべての処理を問題なく終了できるかを網羅的にチェックしました。とにかく量が多かったので、一部自動化して試験を行いましたが、それでもかなり時間のかかる作業でした。一緒に試験をしていただいた先輩社員にはこの場を借りて感謝です。また、ロードバランサーの負荷試験も課題の1つでした。どの程度のアクセスを許容するか、試験ツールには何を使うか、その負荷は実際運用していた際に発生する負荷と同義なのかなど、こちらも考えることがたくさんありました。試験に関することは、それだけで記事が1本かけてしまいそうなので、また機会がありましたらどこかで書こうと思います。

おわり

今回は、APサーバーの負荷分散を目的として、LBサーバーの作成を行いました。かなり限定的ではありますが、様々な事情でローカルネットワーク内にクラウドのロードバランサーが立てられないといったときなどの参考になれば幸いです。 今後はNGINXのパラメータチューニングなどを行って、より適切に振り分けられるように設定を詰めていきたいと思います。

We are hiring!

ニフティでは、さまざまなプロダクトへ挑戦するエンジニアを絶賛募集中です!
ご興味のある方は以下の採用サイトよりお気軽にご連絡ください! Tech TalkやMeetUpも開催しております!
こちらもお気軽にご応募ください!