2011年4月4日

Windows AzureでZeroMQを使ってみた

Windows Azureのインスタンス間通信にzeromq(http://www.zeromq.org/)をWindows Azure上で使う機会があったので、使うまでの手順とか注意点を記す。またWindows Azureプロジェクトからzeromqを利用するために、clrzmq2(http://www.zeromq.org/bindings:clr)というzeromqのC#バインディングを用いる。

全体的な流れは以下の通り。

  1. zeromqを64bit Windows向けにビルドする
  2. clrzmq2を64bit Windows向けにビルドする
  3. Azureプロジェクトを用意する

zeromqのビルド

まず最初にzeromqを64bit Windows向けにビルドするため、以下のURLから最新のソースコードを持ってくる(この時点ではバージョン2.1.4が最新)。

http://www.zeromq.org/intro:get-the-software

そしてDLしたファイルを解凍し、できたディレクトリ内の zeromq-2.1.4\builds\msvc\msvc.sln をVisual Studioで開く(Visual Studio 2010の場合、プロジェクトの自動変換が必要)。プロジェクトを開いたら、ビルド構成を以下のように設定する。

  • アクティブソリューション構成:Release
  • アクティブソリューションプラットフォーム:x64

そして、以下のスクリーンショットのようになったことを確認する。

image_thumb4

確認ができたら、libzmqプロジェクトをビルド。

image_thumb6

すると、64bit Windows向けzeromqのDLLが zeromq-2.1.4\lib\libzmq.dll にできる。

clrzmq2のビルド

次にclrzmq2のビルドを行うため、以下のURLから最新(この時点ではzeromq-clrzmq2-f420936.zipが最新)のソースコードをダウンロード・解凍し、Visual Studioで開く。

https://github.com/zeromq/clrzmq2

そして、zeromqの時と同様にビルド構成の設定を行う。

  • アクティブソリューション構成:WIN_RELEASE
  • アクティブソリューションプラットフォーム:x64

以下のようになったことを確認する。

image_thumb22

確認できたら、clrzmqプロジェクトをビルド。すると zeromq-clrzmq2-f420936\clrzmq\bin\Release 内にclrzmq.dllができる。

Azureプロジェクトを作成

次にいままでの手順でビルドしたlibzmq.dllおよびclrzmq.dllを用いて、Azure上でZeroMQを立ち上げるためのプロジェクトを作成する。まず普通にVisual StudioからWindows Azureプロジェクトを作成。とりあえずWorkerRoleをひとつ(WorkerRole1)作っておく。

image_thumb3

次に、ZeroMQがリスニングするエンドポイントの設定を行う

  • Name:ZeroMQ(適当でOK)
  • Type:Input(Azure内部の通信のみで使うのならInternalにする)
  • Protocol:tcp(zeromqはhttp/httpsには対応していない)
  • Public Port:51349(適当に空いてそうな番号を選ぶ、49152~65535で選ぶのが望ましい)

image_thumb5

次にビルドしたclrzmq.dllへの参照を追加し、プロパティから、[ローカルコピー] および [特定バージョン] を [True] にする。

image_thumb12 image_thumb17

そしてビルドしたlibzmq.dllをWorkerRole1プロジェクト内にコピーする。同時にlibzmq.dllが依存するDLL(msvcp100.dllおよびmsvcr100.dll)もコピーしておく(64bit版Windows 7の場合、C:\Windows\system32にある)。

msvcp100.dllおよびmsvcr100.dllをコピーする際はVisual Studio上に直接ペーストすると32bit DLLがペーストされる問題に注意。詳細はこちらの記事を参照。

image_thumb15

そして追加した3つのDLLのプロパティにおいて、以下のように設定する。

image_thumb20

構成マネージャーからWorkerRole1プロジェクトのプラットフォームをx64に変更する(clrzmq.dllを直接使っているプロジェクトは全てx64にする必要がある)。

image_thumb1

最後に、WorkerRole.csを以下のように書き換える。

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using ZMQ;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.Diagnostics.Management;

namespace WorkerRole1 {
	public class WorkerRole : RoleEntryPoint {

		public override void Run() {

			try {
				var endpoints = new List<string> {
					"ZeroMQ"
				};

				var sockets = endpoints.Select((endpoint) => {
					var ep = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints[endpoint].IPEndpoint;
					var address = String.Format("tcp://*:{0}", ep.Port);

					Trace.TraceInformation("{0} listening on '{1}'", endpoint, address);

					var socket = new Socket(SocketType.PULL);
					socket.Bind(address);
					socket.PollInHandler += (a, b) => {
						Trace.TraceInformation(a.Recv(Encoding.UTF8));
					};

					return socket;

				}).ToList();

				while (true) {
					Context.Poller(sockets);
				}

			} catch (System.Exception e) {
				Trace.TraceError("{0}", e);
			}
		}

		public override bool OnStart() {
			ServicePointManager.DefaultConnectionLimit = 12;

			var wadConnectionString = "Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString";
			var account = CloudStorageAccount.Parse(
				RoleEnvironment.GetConfigurationSettingValue(wadConnectionString));

			var roleInstanceDiagnosticManager = account.CreateRoleInstanceDiagnosticManager(
				RoleEnvironment.DeploymentId, RoleEnvironment.CurrentRoleInstance.Role.Name,
				RoleEnvironment.CurrentRoleInstance.Id);

			var config = roleInstanceDiagnosticManager.GetCurrentConfiguration();
			if ( null == config ) {
				config = DiagnosticMonitor.GetDefaultInitialConfiguration();
			}

			config.Logs.ScheduledTransferPeriod = TimeSpan.FromSeconds(10);
			config.Logs.ScheduledTransferLogLevelFilter = LogLevel.Undefined;

			roleInstanceDiagnosticManager.SetCurrentConfiguration(config);

			return base.OnStart();
		}
	}
}

そして、出来上がったプロジェクトをAzure向けに発行しデプロイすれば終了。あとは、以下のようなプログラムを作って動作確認する。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ZMQ;

namespace zeromq {
	class Program {
		static void Main(string[] args) {
			byte[] buf = new byte[1024];
			System.Security.Cryptography.RNGCryptoServiceProvider rng = 
				new System.Security.Cryptography.RNGCryptoServiceProvider();

			rng.GetBytes(buf);

			var context = new Context(1);
			var socket = context.Socket(SocketType.PUSH);

			socket.Connect("tcp://<<url>>:51349");

			while (true) {
				var msg = Convert.ToBase64String(buf);
				socket.Send(msg, Encoding.UTF8);

				Console.ReadLine();
			}
		}
	}
}

まとめ

ZeroMQ on Windows Azureを実現するためのポイントは以下の通り。

  • libzmq.dll および clrzmq.dll(clrzmq2) をx64向けにビルドする
  • clrzmq.dll の[特定バージョン]をTrueにする
  • x64向けの msvcp100.dll および msvcr100.dll を追加しておく(64bit版Windows 7などからコピる)

で、あとは通常のWindows上で使うのと一緒。

0 件のコメント:

コメントを投稿