ロールとインスタンス間のメッセージング

今日、あなたの注目は、AtContent.comサービスのアーキテクチャソリューションに関する一連の記事の2番目の記事です。



AtContent.comサービスで作業する過程で、ロール内のインスタンス間およびロール間で同期するタスクがありました。 SDKの標準ツールは、2行のコードでこの問題を解決しません。 したがって、インスタンス間の通信のための独自のソリューションを開発しました。 これにより、ロールのすべてのインスタンスでタスクを一度に実行したり、特定の方法またはランダムに選択された1つのインスタンスでタスクを実行したりできます。





ソリューションの本質は、HTTPを介してロールインスタンス間で通信することです。 これを安全に行うには、ロール設定でエンドポイントを作成する必要があります。





図1.エンドポイントの作成



ポイントタイプは内部であり、使用されていないプライベートポートを指定します。 これは、データセンター内で交換が行われるために必要です。 追加後、HTTP経由でこのポイントにアクセスし、リクエストを送信できます。



インスタンスでリクエストを処理するには、ジェネリックハンドラーをWebロールに追加する必要があります。 これはCommunicator.ashxです





図2.汎用ハンドラーの作成



原則として、メッセージングを手配することはすでに可能ですが、さらにいくつかの問題が解決されていません。



最初の問題はセキュリティです。 以前に追加されたハンドラーは、外部アドレスとポートで利用可能です。 したがって、入り口で保護する必要があります。 最も簡単な方法は、キーとして機能するパラメーターをPOSTリクエストに追加することです。



2番目の問題は、インスタンスの内部エンドポイントへのアクセスです。 それを解決するために、SDKはServiceRuntimeという素晴らしいツールを提供しています。 それを使用するには、適切な名前空間を接続する必要があります。

using Microsoft.WindowsAzure; using Microsoft.WindowsAzure.ServiceRuntime;
      
      





その後、必要なロールインスタンスを選択し、それらにPOSTリクエストを送信できます。

 //   var Params = new Dictionary<string, string>(); Params["key"] = "key_value"; //   POST- string STDIN = ""; foreach (var Item in Params) { STDIN += Item.Key + "=" + HttpUtility.UrlEncode(Item.Value, Encoding.UTF8) + "&"; } byte[] sentData = Encoding.UTF8.GetBytes(STDIN); foreach (RoleInstance roleInst in RoleEnvironment.Roles["WebRole1"].Instances) { // WebRequest    WebRequest reqPOST = WebRequest.Create( "http://" + roleInst.InstanceEndpoints["InterEndpoint"].IPEndpoint + "/Communicator.ashx"); reqPOST.Method = "POST"; reqPOST.Timeout = 120000; reqPOST.ContentType = "application/x-www-form-urlencoded"; //  reqPOST.ContentLength = sentData.Length; System.IO.Stream sendStream = reqPOST.GetRequestStream(); sendStream.Write(sentData, 0, sentData.Length); sendStream.Close(); System.Net.WebResponse resp = reqPOST.GetResponse(); System.IO.Stream stream = resp.GetResponseStream(); System.IO.StreamReader sr = new StreamReader(stream); string s = sr.ReadToEnd(); }
      
      





この例は、WebRole1ロールのすべてのインスタンスにリクエストを一度に送信する方法を示しています。 タスクの処理に関係する追加のパラメーターを辞書パラメーターに追加できます。



特定のインスタンスまたはランダムなインスタンスにタスクを送信する場合は、RoleEnvironment.Roles ["WebRole1"]。必要なルールに従ってインスタンスを選択し、そのインスタンスのみにリクエストを送信します。



同時に、Communicator.ashxでは、このPOSTリクエストを処理し、必要なコマンドを実行することが残っています。

 //    if (context.Request.Form["key"] != "key_value") return; // 
      
      





このサービスで最も一般的なシナリオは、インスタンスキャッシュの変更です。



サービスインスタンス(ワーカーロール)にメッセージを送信する状況は、やや複雑です。 それと対話するための標準的なシナリオは、キューの使用です。 ただし、これは、HTTPを介してサービスインスタンスとやり取りできないことを意味しません。 これを行うには、内部タイプのエンドポイントをアプリケーションインスタンスに追加し、プライベートポートを指定する必要もあります。 また、サービスインスタンスの開始時に、着信POST要求を処理するHTTPListenerを追加する必要があります。

 private HttpListener listener = null; private AutoResetEvent connectionWaitHandle = new AutoResetEvent(false); public override void Run() { //      HttpListener Thread HttpListenerThread = null; while (true) { if (HttpListenerThread == null) { HttpListenerThread = new Thread(new ThreadStart(HttpListenerHandler)); HttpListenerThread.IsBackground = true; HttpListenerThread.Start(); } Thread.Sleep(1000); } } protected void HttpListenerHandler() { //   HttpListener     ServiceEndpoint if (listener == null) { listener = new HttpListener(); var HostEndpoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["ServiceEndpoint"].IPEndpoint.ToString(); listener.Prefixes.Add(string.Format("http://{0}/", HostEndpoint)); listener.Start(); } while (true) { IAsyncResult result = listener.BeginGetContext(HandleAsyncConnection, listener); connectionWaitHandle.WaitOne(); } } private void HandleAsyncConnection(IAsyncResult result) { // POST- HttpListener listener = (HttpListener)result.AsyncState; HttpListenerContext context = listener.EndGetContext(result); connectionWaitHandle.Set(); var Request = context.Request; var Response = context.Response; if (Request.HttpMethod == "POST") { Stream BodyStream = context.Request.InputStream; var encoding = context.Request.ContentEncoding; var reader = new StreamReader(BodyStream, encoding); var PostParams = HttpUtility.ParseQueryString(reader.ReadToEnd(), encoding); if (PostParams["key"] != "key_value") return; //  } Response.OutputStream.Close(); }
      
      





これがWorkerRole.csクラスのコードです。変更された部分です。 要求を処理するには、System.Web名前空間が必要であることに注意してください。 また、WorkerRoleに適切な参照を追加する必要があります。



このすべての後、同じロール内およびロールのインスタンス間で両方のインスタンスにアクセスするための動作メカニズムを取得しました。 この相互作用を使用するシナリオは多数あります。 これらのいくつかについては、「インスタンスでのデータのキャッシュとキャッシュの管理」および「クラウドキュー(キュー)の処理の効率的な管理」シリーズの記事で説明します。



この記事で説明されているいくつかの改善されたメカニズムは、Windows Azure用のOpenSource CPlaseライブラリの一部として利用できます。このライブラリはまもなくパブリックドメインになります。



シリーズを読む:




All Articles