Deep Insider の Tutor コーナー
>>  Deep Insider は本サイトからスピンオフした姉妹サイトです。よろしく! 
連載:コードから触るIIS 8

連載:コードから触るIIS 8

Webファームによる負荷分散(2): IISマネージャー/コードによる操作

2014年7月11日

Webファームに備えられている機能とは? IISマネージャーによるWebファームの操作や、コードによる操作について説明する。

株式会社グラニ 田中 孝佳
  • このエントリーをはてなブックマークに追加

 前回の記事では、Webファームの基本的な概念の説明と、3台のサーバーによる単純なWebファームの構築を行った。今回の記事では、IISマネージャーの画面に沿って、Webファームの機能について紹介する。

IISマネージャーによるWebファームの操作

 今回は、前回の記事で構築したWebファームを使って説明を進めていく。まず、Webファームのリバースプロキシ元であり、管理する側であるwebfarm-ctrlサーバーにログインして、IISマネージャーを起動する。IISマネージャーの左側の[接続]ペインから、[Server Farms]の下にある[webfarm-ctrl.cloudapp.net]をダブルクリックして機能ビューを開く(図1)。

図1 IISマネージャーでServerファームの[機能ビュー]を開いたところ

 今回は、この画面に表示されている7つの機能のうち、Webファームに特徴的な「Health Test」「Load Balance」「Monitoring and Management」「Proxy」「Server Affinity」の主な項目について説明したい。

Health Test

 負荷分散対象となるリバースプロキシ先のWebサーバーの健全性を確かめるテストを行う機能である。ただし、注意点として、Webサーバーが健全でないことを検出しても、そのWebサーバーを再起動したり、自身のサービス状態を変更したりすることは、Webファームの機能としては備えていないことが挙げられる。

図2 図1から[Health Test]をダブルクリックで開いたところ

 図2の[URL]欄に「http」もしくは「https」で始まるテスト対象のURLを入力する。

 [Interval (seconds)]欄にテスト間隔(秒単位)を、[Time-out (seconds)]欄には許容できるリクエストのタイムアウト時間を入力する。

 [Acceptable status codes]欄には許容できるHTTPステータスコードを入力し、[Response match]欄にはレスポンスに含まれるべき文字列を入力できる。

 ここでいったん、[Verify URL Test]ボタンをクリックすると、次のような画面が表示され、テストがその場で実行される。

図3 図2の状態で、[Verify URL Test]ボタンをクリックして実行した画面

プロキシ先の2つのWebサーバーが正常に稼働していることが確認できる。

 その下の[Live Traffic Test]グループの3つの項目は、実際に流れているリクエストに対しエラーが一定件数以上発生していないかチェックする機能である。[Failure codes]がエラーと判定するHTTPステータスコードであり、[Maximum Failures]がその数を超えたらサーバーを障害と見なす最大値である。[Failure Period]が測定する時間間隔であり、これを「0」にするとこの機能を無効化できる。

 一番下の[Minimum Servers]というのが、これらのテストを行った結果、負荷分散対象として正常な状態であるサーバーの最小値である。この数値を下回ると、最初に書いた通りイベントが発生する(図4はイベントビューアーで発生したイベントを確認しているところ)。

図4 イベントビューアーで、[Windowsログ]-[Application]を開いた画面

[Minimum Servers]を「2」に設定して、プロキシ先のWebサーバーのIISを停止させると、「不健全」な状態を検知したイベントが確認できる。

 イベントビューアーを使うと、Windowsログ>Applicationの項目に表示されているのが確認できる。が、これだけだと通知やサーバー復帰の対応もできないため、その部分については自作する必要がある。

Load Balance

 Webファームは、複数台のWebサーバーを水平負荷分散させる技術であり、それら複数台のサーバーにどのようにリクエストを分散させるかのアルゴリズムを指定できる。それがLoad Balanceのページで設定できる内容である。設定できるアルゴリズムは以下の通りである。

  • Weighted round robin: 重み付けされたラウンドロビン
  • Weighted total traffic: 重み付けした上で、トラフィック合計が最小のサーバーへ転送
  • Least current request: 現在のリクエストが最小のサーバーへ転送
  • Least response time: 応答時間が最小のサーバーへ転送
  • Server variable hash: サーバー変数によるハッシュ分散
  • Query string hash: クエリ文字列によるハッシュ分散
  • Request hash: リクエストによるハッシュ分散

 選択したアルゴリズムに応じて設定できる項目が変わる。例えば、重み付けであれば、全サーバーに対して均等な値にするか、サーバーごとの重みを定義するかが設定できるようになる。

[Load balance algorithm]欄で「Weighted round robin」を選択

図5 図1から[Load Balancer]をダブルクリックで開いたところ

[Load balance algorithm]欄で「Server variable hash」を選択

図5 図1から[Load Balancer]をダブルクリックで開いたところ
図5 図1から[Load Balancer]をダブルクリックで開いたところ

[Load balance algorithm]を「Weighted round robin」にするとサーバーごとの重みを設定でき、「Server variable hash」にするとサーバー変数のキーを入力できる。

 なお、重み付けの値については、「weighted」と名の付くパターンが2つあるが、この2つで設定値が共通になっている。

Monitoring and Management

 [Monitoring and Management]のページは、登録しているサーバーの一覧とそのステータス、さらには負荷状況までを表示するページである。先ほどの[Load Balance]の設定で、サーバーの負荷に応じてプロキシ先を決定するアルゴリズムタイプを選択した場合、ここに表示されている値が使用される。そのため、[Load Balance]のアルゴリズムタイプを該当するものに変えた場合、自動的にこの統計値はリセットされる。

図6 図1から[Monitoring and Management]をダブルクリックで開いたところ

Proxy

 [Proxy]のページでは、Webサーバーにリバースプロキシする際の設定が行える。HTTPバージョンの操作、プロキシしたリクエストのタイムアウト、バッファーの値などを指定できる。

図7 図1から[Proxy]をダブルクリックで開いたところ

Server Affinity

 [Server Affinity]は、クライアントが複数回サーバーにアクセスする際に同じサーバーにアクセスするようにするための設定である。

図8 図1から[Server Affinity]をダブルクリックで開いたところ

 図8にある[Client Affinity]を使う場合、ユーザーはCookieを有効にする必要がある。[Cookie Name]欄に指定した名前でCookieが保存される。図8の通りに設定した状態で、IEのF12開発者ツールを使いながら、Webサイトにアクセスすると、実際にCookieが保存されているのを確認できる(図9)。

図9 [Client Affinity]を設定した状態で、F12開発者ツールを使って、「http://webfarm-ctrl.cloudapp.net」にアクセスした画面

「MyArrAffinity」というキーでCookieが設定されているのが確認できる。このキー名は先ほどの[Server Affinity]の画面で設定したものである

コードによる操作

 今回設定した内容のうち、Proxy、Health Test、Client Affinityに関してC#コードから設定を行うサンプルを作成した。

 前回同様、このコードを実行するためのVisual Studioプロジェクトの作成および設定は、第2回を参考にしてほしい。またこのサンプルについてもGitHubに「WebFarmTool」というフォルダー以下にアップロードしている。

C#
using System;
using System.Linq;
using Microsoft.Web.Administration;

namespace WebFarmTool
{
  class Program
  {
    static void Main(string[] args)
    {
      var program = new Program();
      program.UpdateHelathCheck("webfarm-ctrl.cloudapp.net", TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(30), 2);
      program.UpdateProxySetting("webfarm-ctrl.cloudapp.net", TimeSpan.FromSeconds(10), 512, 8192);
      program.UpdateClientAffinity("webfarm-ctrl.cloudapp.net", true, "MyARRAffinity");
    }

    void UpdateHelathCheck(string webFarmName, TimeSpan interval, TimeSpan timeout, int minServers)
    {
      using (var manager = new ServerManager())
      {
        // ApplicationHostの設定を取得
        var appHostConfig = manager.GetApplicationHostConfiguration();

        // WebFarmの設定リストから指定したWebFarm名の要素を取得
        var webFarmsSection = appHostConfig.GetSection("webFarms");
        var webFarmSection = webFarmsSection.GetCollection().First(e => e["name"] as string == webFarmName);

        // applicationRequestRouting->healthCheck要素を取得して設定
        var applicationRequestRouting = webFarmSection.GetChildElement("applicationRequestRouting");
        var healthCheck = applicationRequestRouting.GetChildElement("healthCheck");
        healthCheck["interval"] = interval; 
        healthCheck["timeout"] = timeout;
        healthCheck["minServers"] = minServers;
        manager.CommitChanges();
      }
    }

    void UpdateProxySetting(string webFarmName, TimeSpan timeout, int minResponseBuffer, int responseBufferLimit)
    {
      using (var manager = new ServerManager())
      {
        // ApplicationHostの設定を取得
        var appHostConfig = manager.GetApplicationHostConfiguration();

        // WebFarmの設定リストから指定したWebFarm名の要素を取得
        var webFarmsSection = appHostConfig.GetSection("webFarms");
        var webFarmSection = webFarmsSection.GetCollection().First(e => e["name"] as string == webFarmName);

        // applicationRequestRouting->protocol要素を取得して設定
        var applicationRequestRouting = webFarmSection.GetChildElement("applicationRequestRouting");
        var protocol = applicationRequestRouting.GetChildElement("protocol");
        protocol["timeout"] = timeout;
        protocol["minResponseBuffer"] = minResponseBuffer;
        protocol["responseBufferLimit"] = responseBufferLimit;
        manager.CommitChanges();
      }
    }

    void UpdateClientAffinity(string webFarmName, bool use, string cookieName)
    {
      using (var manager = new ServerManager())
      {
        // ApplicationHostの設定を取得
        var appHostConfig = manager.GetApplicationHostConfiguration();

        // WebFarmの設定リストから指定したWebFarm名の要素を取得
        var webFarmsSection = appHostConfig.GetSection("webFarms");
        var webFarmSection = webFarmsSection.GetCollection().First(e => e["name"] as string == webFarmName);

        // applicationRequestRouting->affinity要素を取得して設定
        var applicationRequestRouting = webFarmSection.GetChildElement("applicationRequestRouting");
        var affinity = applicationRequestRouting.GetChildElement("affinity");
        affinity["useCookie"] = use;
        affinity["cookieName"] = cookieName;
        manager.CommitChanges();
      }
    }
  }
}
WebファームのHealth Testを設定するメソッド(UpdateHealthCheck)、Proxyを設定するメソッド(UpdateProxySetting)、およびClient Affinityを設定するメソッド(UpdateClientAffinity)

 今回はIISマネージャーの画面を参考に、Webファームに備えられているいくつかの機能に関して説明した。次回は最後としてSSL証明書の設定に関して取り上げる。

※以下では、本稿の前後を合わせて5回分(第7回~第11回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

連載:コードから触るIIS 8
7. RedisをBackplaneとしたSignalRのスケールアウト

SignalRアプリをスケールアウトする際の注意点と、それを回避するためのBackplane機構について説明。さらにRedisをBackplaneとして活用する方法を解説する。

連載:コードから触るIIS 8
8. Webガーデンによるアプリケーションプールのマルチプロセス化

ASP.NET アプリのスケーリング方法を解説。今回は、Webサイトを1つのアプリケーションプール上の複数のワーカープロセスで動かす「Webガーデン」について説明する。

連載:コードから触るIIS 8
9. Webファームによる負荷分散(1): Webファームの基本構造と構成

ASP.NETアプリをスケーリングする方法の1つとして、複数のサーバーによる水平負荷分散を実現する「Webガーデン」というIIS機能について説明する。

連載:コードから触るIIS 8
10. 【現在、表示中】≫ Webファームによる負荷分散(2): IISマネージャー/コードによる操作

Webファームに備えられている機能とは? IISマネージャーによるWebファームの操作や、コードによる操作について説明する。

連載:コードから触るIIS 8
11. Webファームによる負荷分散(3):HTTPSとWebファームの関連

IISで構築したWebファーム内における複数台のサーバーでHTTPSを有効にする場合、どんな方法があるのか? 各方法によるサーバー構成を、PowerShellを用いて行う方法を解説する。連載最終回。

サイトからのお知らせ

Twitterでつぶやこう!