PollingDuplexHttpBinding
それを消費する Silverllight クライアントを持つサービスを作成しました。私のサービスには、基本的に、一定数のクライアントがサービスにデータを送信し (非常に頻繁に、毎秒、データは非常に大きく、各呼び出しは約 5KB です)、他のクライアントからサービスに送信された新しいデータをリッスンします。チャット ルーム アーキテクチャに非常によく似ています。
私が気付いている問題は、クライアントがインターネット経由でサービスに接続すると、数分後にサービスの応答が遅くなり、応答が遅れることです。私は、サービス ホストのアップロード容量 (インターネット アップロード速度、サーバー上では約 15KB/秒のみ) に達すると、他のクライアントから送信されたメッセージはバッファリングされ、利用可能な帯域幅がある場合に応じて処理されるという結論に達しました。サービスがクライアントから受信したメッセージを格納するために使用するこのバッファーの占有をどのように正確に制限できるのでしょうか? 私のクライアントがすべてのデータを取得することはそれほど重要ではありませんが、他の人から送信された最新のデータを取得することは重要です。
要するに、サービスがいっぱいになったとき、または特定の上限に達したときはいつでもキュー/バッファをきれいにして、遅延を取り除くために受信した呼び出しで再び埋め始めることができるようにしたい. どうすればいいですか?プロパティはMaxBufferSize
、クライアント側だけでなくサービス側でも減らす必要がありますか? または、サービスでこの機能をコーディングする必要がありますか? 何か案は?
ありがとう。
編集:
これが私のサービスアーキテクチャです:
//the service
[ServiceContract(Namespace = "", CallbackContract = typeof(INewsNotification))]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
public class NewsService
{
private static Dictionary<IChatNotification, string> clients = new Dictionary<IChatNotification, string>();
private ReaderWriterLockSlim subscribersLock = new ReaderWriterLockSlim();
[OperationContract(IsOneWay = true)]
public void PublishNotifications(byte[] data)
{
try
{
subscribersLock.EnterReadLock();
List<INewsNotification> removeList = new List<INewsNotification>();
lock (clients)
{
foreach (var subscriber in clients)
{
if (OperationContext.Current.GetCallbackChannel<IChatNotification>() == subscriber.Key)
{
continue;
}
try
{
subscriber.Key.BeginOnNotificationSend(data, GetCurrentUser(), onNotifyCompletedNotificationSend, subscriber.Key);
}
catch (CommunicationObjectAbortedException)
{
removeList.Add(subscriber.Key);
}
catch (CommunicationException)
{
removeList.Add(subscriber.Key);
}
catch (ObjectDisposedException)
{
removeList.Add(subscriber.Key);
}
}
}
foreach (var item in removeList)
{
clients.Remove(item);
}
}
finally
{
subscribersLock.ExitReadLock();
}
}
}
//the callback contract
[ServiceContract]
public interface INewsNotification
{
[OperationContract(IsOneWay = true, AsyncPattern = true)]
IAsyncResult BeginOnNotificationSend(byte[] data, string username, AsyncCallback callback, object asyncState);
void EndOnNotificationSend(IAsyncResult result);
}
サービス構成:
<system.serviceModel>
<extensions>
<bindingExtensions>
<add name="pollingDuplex" type="System.ServiceModel.Configuration.PollingDuplexHttpBindingCollectionElement, System.ServiceModel.PollingDuplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceThrottling maxConcurrentSessions="2147483647" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<pollingDuplex>
<binding name="myPollingDuplex" duplexMode="SingleMessagePerPoll"
maxOutputDelay="00:00:00" inactivityTimeout="02:00:00"
serverPollTimeout="00:55:00" sendTimeout="02:00:00" openTimeout="02:00:00"
maxBufferSize="10000" maxReceivedMessageSize="10000" maxBufferPoolSize="1000"/>
</pollingDuplex>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="NewsNotificationService.Web.NewsService">
<endpoint address="" binding="pollingDuplex" bindingConfiguration="myPollingDuplex" contract="NewsNotificationService.Web.NewsService" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<directoryBrowse enabled="true" />
</system.webServer>
</configuration>
クライアントは通常、次のように 500 ミリ秒から 1000 ミリ秒の間にサービスを呼び出します。
_client.PublishNotificationAsync(byte[] data);
コールバックは、他のクライアントから送信された通知をクライアントに通知します。
void client_NotifyNewsReceived(object sender, NewsServiceProxy.OnNewsSendReceivedEventArgs e)
{
e.Usernamer//WHich client published the data
e.data//contents of the notification
}
要約すると、クライアントの数が増加し、インターネットを介したサービス ホストのアップロード速度が制限されている場合、サービスによってサブスクライバーに送信されたメッセージはどこかにバッファリングされ、キューで処理されます。これが問題の原因です。これらのメッセージがどこにバッファリングされているかわかりません。LAN では、サーバーのアップロード速度がダウンロード速度と同じであるため、サービスは正常に動作します (100KB/秒の着信呼び出しに対して、100KB/秒の通知を送信します)。これらのメッセージはどこにバッファリングされますか? そして、どうすればこのバッファをクリアできますか?
メッセージがサービスでバッファリングされているかどうかを確認するために実験的なことを行いました。クライアントでこのメソッドを呼び出してみましたが、他の誰かが送信した通知を 1 つのクライアントがまだ受信中の場合でも、常に 0 を返します 4- 5分前:
[OperationContract(IsOneWay = false)]
public int GetQueuedMessages()
{
return OperationContext.Current.OutgoingMessageHeaders.Count();
}