Windows Azure + Squid による勝手キャッシュ&リバースプロキシサーバーの構築

3月11日、東北地方太平洋沖地震が発生しました。私のほうではうまく表現できません。ただ心より祈るばかりです。

とはいっても、できることはないだろうか?と漠然と思っていたところ、日本赤十字社のサイトが過負荷で見えない、という話題が流れていました。
ぱっと思いついたのはとりあえずキャッシュサーバーとリバースプロキシを組み合わせて負荷を軽減できないか?ということでした。

幸い、リソースはWindows Azureですぐに展開できますし、SquidとDelegateは少し触ったことがあったので @halmnm を巻き込んでSquidを構築することに決めました。

並行してMicrosoftさんがAzure Passの90日無償開放、4インスタンス、転送量無制限という臨時仕様で解放してくれました。ありがとうございます。

さて構築にあたりポイントがいくつか。

  • 泥臭くても何でもいいから早く展開する
  • 細かな設定は二の次
  • 必ず他のサイトでも同様の事が発生するから、できるだけ多人数で分散できるようにする

といった点です。

本来キャッシュサーバーやリバースプロキシは自分の組織に対して行うものなので、たぶん厳密に言うと今回やっている内容はNGです。もし止めてくれという話が本家サイト側よりあれば管理してるサーバー群に対しては止めますのでご連絡ください。(といっても90日で勝手に止まりますけど)

さて本題。どうすれば手間なく展開できるか?とうことを考えると、何も考えずにAzureのデプロイパッケージを配布して、コンフィグでキャッシュ対象を指定できればいいよね。ということで、以下のようにしました。

  • Startup Tasks でFirewallのポリシーをOffに (外部プロセスのInBoundが許可されなかったので)
  • Startup Tasks でSquidなCABをCドライブに展開
  • Squid.confの出力
  • Squidのキャッシュディレクトリを作成
  • Squidのサービス化+サービス起動
  • WorkerRoleのメインスレッドで定期監視(サービスが落ちてたら起動)
  • Azureのサービス設定が変更されたらSquid.confを書き換えてサービス再起動

以上です。

当初は全部手動でしたが、JAZUGなみなさんのおかげでデプロイ以外自動で行えるようになりました。ありがとうございます。

というわけでメインなソースはこんな感じです。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.IO;
using System.ServiceProcess;

namespace SquidWorker
{
	public class WorkerRole : RoleEntryPoint
	{
		public override void Run()
		{
			while (true)
			{
				try {
					Thread.Sleep(60000);
					ServiceController sc = new ServiceController("squid");
					if (sc.Status == ServiceControllerStatus.Stopped)
					{
						sc.Start();
					}
				}
				catch (Exception ex) { 
				}
			}
		}

		public override bool OnStart()
		{
			// 同時接続の最大数を設定します
			ServicePointManager.DefaultConnectionLimit = 12;

			try
			{
				CreateSquidConfig();

				using (Process hProcess = Process.Start("C:\\squid\\sbin\\squid.exe", "-z"))
				{
					hProcess.WaitForExit();
					hProcess.Close();
				};

				using (Process hProcess = Process.Start("C:\\squid\\sbin\\squid.exe", "-i"))
				{
					hProcess.WaitForExit();
					hProcess.Close();
				};

				ServiceController sc = new ServiceController("squid");
				sc.Start();

				RoleEnvironment.Changed += (sender, args) =>
				{
					try
					{
						if (args.Changes.Any(chg => chg is RoleEnvironmentConfigurationSettingChange))
						{
							ServiceController serv = new ServiceController("squid");
							serv.Stop();
							serv.WaitForStatus(ServiceControllerStatus.Stopped,new TimeSpan(0,1,0));
							CreateSquidConfig();
							serv.Start();
						}
					}
					catch (Exception ex)
					{
					}
				};

			}
			catch (Exception ex) { 
			}

			return base.OnStart();
		}

		private void CreateSquidConfig()
		{
			string SourceUrl = RoleEnvironment.GetConfigurationSettingValue("SourceSiteUrl");
			using (StreamWriter writer = new StreamWriter("C:\\squid\\etc\\squid.conf", false, System.Text.Encoding.GetEncoding("shift_jis")))
			{
				writer.WriteLine("http_port 8000 accel defaultsite={0}",SourceUrl);
				writer.WriteLine("cache_peer {0} parent 80 0 no-query originserver",SourceUrl);
				writer.WriteLine("cache_dir ufs c:/squid/var/cache 10240 16 256");
				writer.WriteLine("cache_mem 1024MB");
				writer.WriteLine("cache_access_log none");
				writer.WriteLine("cache_log none");
				writer.WriteLine("cache_store_log none");
				writer.WriteLine("acl all src 0.0.0.0/0.0.0.0");
				writer.WriteLine("http_access allow all");
				writer.WriteLine("refresh_pattern . 1440 40% 40320 override-lastmod");
				writer.WriteLine("");
				writer.Close();
			};

		}
	}
}

SquidのWindowsバイナリはこちらのサイトから入手しました。 → http://squid.acmeconsulting.it/

最終的なソースと、Azureへデプロイする用のパッケージは SkyDriveのこちら にUpしていますのでご参考までに。

ソースをビルドする場合はWindows Azure SDK 1.4が必要です。(ビルド環境が1.4だったので)
使い方としてはServiceConfiguration.cscfgファイルのインスタンス数と、必要に応じてVMサイズ、それからSourceSiteUrlをキャッシュ対象のホスト名(FQDN)に修正してWindows Azure上へ展開するだけです。

<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="Azure0312Squid" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="1" osVersion="WA-GUEST-OS-1.10_201101-01">
  <Role name="SquidWorker">
    <Instances count="3" />
    <ConfigurationSettings>
      <Setting name="SourceSiteUrl" value="source.url.sample" />
    </ConfigurationSettings>
  </Role>
</ServiceConfiguration>

あとSquidはGPLです。配布物に入れちゃってますが大丈夫かな?詳しい人間違いがあったらご指摘お願いします。

キャッシュの取りまとめサイトや、完全ミラーサイト等、多数の方が精力的に取り組まれています。
もし何かありましたら、Twitterにて #cloudmix や #jazug 、 #azurejp のハッシュタグをつけてつぶやけば誰かが拾ってくれると思います。

ちょっといろいろグレーなやり方なのであまりおおっぴらには言えませんが、こんなやり方もあるよという参考までに。

ボランティアだし、もし何かされる場合はAt your own risk で。

最後に、復興までには長い時間が必要です。瞬発力も必要ですがこれからは持久力も必要なので、皆様体にはお気を付けください。

おいらも心から祈りつつ、できる範囲でできることを無理なく出来たらいいなと思います。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中