3

サーバーから株式市場の最新情報を取得するためにajaxポーリングを使用するWebページがあります。代わりにSignalRを使用したいのですが、どのように/どのように機能するかを理解するのに苦労しています。

わかりました、それは実際には株式市場の更新ではありませんが、アナロジーは機能します。

私が見たSignalRの例は、現在の接続、すべての接続、またはグループのいずれかにメッセージを送信します。私の例では、在庫の更新は現在の接続の外部で行われるため、「現在の接続」などはありません。また、ユーザーのアカウントはいくつかの株に関連付けられているため、すべての接続またはグループに株通知を送信することもできません。特定のuserIdに関連付けられている接続を見つけることができる必要があります。

偽のコード例を次に示します。

foreach(var stock in StockService.GetStocksWithBigNews())
{
    var userIds = UserService.GetUserIdsThatCareAboutStock(stock);

    var connections = /* find connections associated with user ids */;

    foreach(var connection in connections)
    {
        connection.Send(...);
    }
}

接続のフィルタリングに関するこの質問では、現在の接続をメモリに保持できると述べていますが、(1)スケーリングには適しておらず、(2)マルチノードWebサイトには適していません。これらの点は両方とも、現在のアプリケーションにとって非常に重要です。そのため、各ノードに接続しているユーザーを見つけるために、すべてのノードにメッセージを送信する必要があると思います>>私の脳は混乱して爆発します。

質問

スケーラブルな特定のユーザーの接続を見つけるにはどうすればよいですか?私はこれを間違った方法で考えていますか?

4

2 に答える 2

6

私は昨夜、これも学ぶために小さなプロジェクトを作成しました。私は1.0アルファを使用しましたが、それは簡単でした。私はハブを作成し、そこからうまくいきました:)

私のプロジェクトでは、N個のコンピューティングユニット(一部のサーバーは作業を処理しています)があり、それらが起動すると、ComputeUnitRegisterを呼び出します。

await HubProxy.Invoke("ComputeUnitReqisted", _ComputeGuid);

そして彼らが何かをするたびに彼らは呼ぶ

HubProxy.Invoke("Running", _ComputeGuid);

ここで、HubProxyは:

HubConnection Hub = new HubConnection(RoleEnvironment.IsAvailable ?
                    RoleEnvironment.GetConfigurationSettingValue("SignalREndPoint"):
                    "http://taskqueue.cloudapp.net/");
IHubProxy HubProxy = Hub.CreateHubProxy("ComputeUnits"); 

RoleEnviroment.IsAvailableを使用したのは、これをAzureロール、コンソールアプリ、または.NET4.5で実行できるようになったためです。ハブはMVC4Webサイトプロジェクトに配置され、次のように開始されます。

        GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(50);
        RouteTable.Routes.MapHubs();

public class ComputeUnits : Hub
{
     public Task Running(Guid MyGuid)
     {
         return Clients.Group(MyGuid.ToString()).ComputeUnitHeartBeat(MyGuid,
                DateTime.UtcNow.ToEpochMilliseconds());            
     }
     public Task ComputeUnitReqister(Guid MyGuid)
     {
         Groups.Add(Context.ConnectionId, "ComputeUnits").Wait(); 
         return Clients.Others.ComputeUnitCameOnline(new { Guid = MyGuid,
                HeartBeat = DateTime.UtcNow.ToEpochMilliseconds() });           
     }
     public void SubscribeToHeartBeats(Guid MyGuid)
     {
         Groups.Add(Context.ConnectionId, MyGuid.ToString());
     }
}

私のクライアントはJavascriptクライアントであり、メソッドがあります(このためのコードも表示する必要がある場合はお知らせください)。しかし、基本的に、彼らはを聞き、ComputeUnitCameOnlineその実行時にサーバーを呼び出しますSubscribeToHeartBeats。これは、サーバーコンピューティングユニットが何らかの作業を実行しているときはいつでも、Runningを呼び出し、ComputeUnitHeartBeatjavascriptクライアントでをトリガーすることを意味します。

これを使用して、グループと接続の使用方法を確認できることを願っています。そして最後に、数行のコードを追加することで、複数の紺碧の役割にスケールアウトしました。

    GlobalHost.HubPipeline.EnableAutoRejoiningGroups();
    GlobalHost.DependencyResolver.UseServiceBus(
        serviceBusConnectionString,
        2,
        3,
        GetRoleInstanceNumber(),
          topicPathPrefix /* the prefix applied to the name of each topic used */
        );

Azureのサービスバスで接続文字列を取得できます。Provider=SharedSecretを覚えておいてください。ただし、パッケージ化されたnugetを追加すると、connectionstring構文もweb.configに貼り付けられます。2は、分割するトピックの数です。トピックには1Gbのデータを含めることができるため、パフォーマンスに応じてデータを増やすことができます。3はそれを分割するノードの数です。2つのAzureインスタンスとローカルホストがあるため、3つを使用しました。このようにRoleNumberを取得できます(ローカルホストを2にハードコーディングしたことに注意してください)。

private static int GetRoleInstanceNumber()
{
    if (!RoleEnvironment.IsAvailable)
        return 2;

    var roleInstanceId = RoleEnvironment.CurrentRoleInstance.Id;
    var li1 = roleInstanceId.LastIndexOf(".");
    var li2 = roleInstanceId.LastIndexOf("_");
    var roleInstanceNo = roleInstanceId.Substring(Math.Max(li1, li2) + 1);
    return Int32.Parse(roleInstanceNo);
}

あなたはそれをすべてライブで見ることができます:http://taskqueue.cloudapp.net/#/compute-units

于 2012-11-11T05:25:32.507 に答える
2

SignalRを使用する場合、クライアントがサーバーに接続した後、接続IDが提供されます(これは、リアルタイム通信を提供するために不可欠です)。はい、これはメモリに保存されますが、SignalRはマルチノード環境でも使用できます。たとえば、RedisやSQL Serverバックプレーン(今後さらに追加予定)を使用できます。簡単に言うと、バックプレーン/サービスバスを介してスケールアウトシナリオを心配することなく処理します。

于 2012-11-10T18:40:55.907 に答える