运维开发网

wcf – 如何清除服务器上的传出消息缓冲区?

运维开发网 https://www.qedev.com 2020-06-21 19:45 出处:网络 作者:运维开发网整理
我使用PollingDuplexHttpBinding编写了一个服务,它有一个消耗它的Silverllight客户端.我的服务基本上有一定数量的客户端向服务发送数据(通常,每秒一次,数据非常大,每次调用大约5KB),并且还监听其他客户端发送给服务的新数据.被路由到他们,非常类似于聊天室架构. 我注意到的问题是,当客户端通过互联网连接到服务时,几分钟后服务的响应变慢,回复变得滞后.我得出的结论是,当
我使用PollingDuplexHttpBinding编写了一个服务,它有一个消耗它的Silverllight客户端.我的服务基本上有一定数量的客户端向服务发送数据(通常,每秒一次,数据非常大,每次调用大约5KB),并且还监听其他客户端发送给服务的新数据.被路由到他们,非常类似于聊天室架构.

我注意到的问题是,当客户端通过互联网连接到服务时,几分钟后服务的响应变慢,回复变得滞后.我得出的结论是,当服务主机上传容量达到(互联网上传速度,在服务器上仅约15KB / s)时,其他客户端发送的消息会在有可用带宽时进行缓冲和处理.我想知道如何限制服务用来存储来自客户端的接收消息的缓冲区的占用量?我的客户获得所有数据并不是那么重要,而是他们获得了其他人发送的最新数据,因此实时连接正是我所寻求的,但代价是保证交付.

简而言之,我希望能够在服务填满时清理我的队列/缓冲区,或者达到一定的上限并开始用接收到的呼叫填充它以消除延迟.我该怎么做呢? 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
        }

因此,回顾一下,当客户数量增加,服务主机上传速度超过互联网时,服务发送给订户的消息会在某处缓冲并在队列中处理,这是导致问题的原因,

我不知道这些消息在哪里被缓冲.在局域网中,服务工作正常,因为服务器的上传速度等于其下载速度(对于100KB / s的传入呼叫,它发出100KB / s的通知).这些消息在哪里被缓冲?我该如何清除这个缓冲区呢?

我做了一些实验性尝试,看看消息是否在服务上缓冲,我尝试在客户端调用此方法,但它总是返回0,即使一个客户端仍在接收其他人发送的通知4 5分钟前:

[OperationContract(IsOneWay = false)]
public int GetQueuedMessages()
{

            return OperationContext.Current.OutgoingMessageHeaders.Count();
}
我根据你的情况做了一些数学计算.

>邮件大小= 100KB

>上传频道= 15KB / s

>下载频道= 100KB / s

>客户端每秒拨打1-2次服务

client will call the service typically between 500ms-1000ms periods

它是否正确?

对于一个客户端,仅针对消息的下载流量将为100-200KB / s,这仅是消息正文.在启用安全性的情况下,将有更多标题和更多内容.

消息将被组合用于异步调用.因此,如果我们有3个客户端并且每个发送一条消息,则回调包含每个客户端的2条消息. 4个客户端 – 每个回调中有3条消息.

3个客户端的下载频道为200-400KB / s.

对我来说,看起来消息对于您声明的带宽来说太大了.

检查你是否可以:

>减少邮件大小.我不知道你的业务性质,所以不能在这里给出建议.

>对邮件或流量使用压缩.

>增加网络带宽.如果没有这个理想的解决方案

有很高的延迟.你可以花几天时间来优化你的

代码,即使你正确使用你的网络解决方案仍在继续

我知道这听起来像是Captain Obvious但是有些问题没有正确答案,除非你改变问题.

执行上述步骤后,将ServiceThrottlingBehavior与将管理回调队列的自定义代码结合使用.

如果达到边界,ServiceThrottlingBehavior将拒绝请求.

http://msdn.microsoft.com/en-us/library/ms735114(v=vs.100).aspx

这是一个微不足道的样本.应根据您的环境专门定义实数.

<serviceThrottling 
 maxConcurrentCalls="1" 
 maxConcurrentSessions="1" 
 maxConcurrentInstances="1"
/>

更新:

Big mistake on my part in the question, each call is 5KB/s,

即使有5KB的消息,15KB / s还不够.我们只计算3个用户的流量. 3每秒传入消息.系统现在应该使用双工通知用户其他人发送了什么.每个用户都应该从他的合作伙伴处获得消我们共有3条消息.可以跳过一个(属于发件人),因此每个用户都应该收到2条消息. 3个用户将获得10KB(5KB 5KB = 1个消息10KB)= 30KB.

每秒一封邮件将为3个用户上传频道提供30KB /秒的速度.

Where are these messages getting buffered? And how can I clear this

buffer?

这取决于您如何托管您的服务.如果是自托管服务,则根本不进行缓冲.您的代码尝试向接收方发送消息,但由于通道泛滥,因此速度非常慢.使用IIS可能会有一些缓冲,但从外部触摸它并不是一个好习惯.

正确的解决方案是限制.由于带宽限制,您不应尝试将所有消息发送到所有客户端.相反,您应该限制发送消息的线程数量.因此,从上面的3个用户而不是并行发送3个消息,您可以按顺序发送它们,或者决定只有一个用户将在该轮次中获得更新,下一轮中的下一个用户将获得更新.

因此,一般的想法是,只要您拥有数据,就不会尝试将所有内容发送给所有人,但只发送您可以承受的数据量,并使用线程数或响应速度来控制数据.

0

精彩评论

暂无评论...
验证码 换一张
取 消