Websocket SignalR客户端以固定的间隔错过一些事件

Websocket SignalR客户端以固定的间隔错过一些事件,websocket,signalr,Websocket,Signalr,我有一个简单的信号器设置:OWIN托管的.NET服务器和JavaScript客户端(都是@v2.1.1)。客户端使用SignalR同步其在服务器上的RxReplaySubject中维护的有序事件流副本。当客户端连接时,它提供一个startAfter查询参数,用于针对ReplaySubject初始化IObserver,然后该观察者将观察到的序列中的每个事件发送给客户端。每个事件都有一个序列号,客户机可以根据事件序列号判断序列中是否缺少任何事件。(这将是此应用程序中的一个严重问题。) 问题在于,客户

我有一个简单的信号器设置:OWIN托管的.NET服务器和JavaScript客户端(都是@v2.1.1)。客户端使用SignalR同步其在服务器上的Rx
ReplaySubject
中维护的有序事件流副本。当客户端连接时,它提供一个
startAfter
查询参数,用于针对
ReplaySubject
初始化
IObserver
,然后该观察者将观察到的序列中的每个事件发送给客户端。每个事件都有一个序列号,客户机可以根据事件序列号判断序列中是否缺少任何事件。(这将是此应用程序中的一个严重问题。)

问题在于,客户端通常只接收部分事件序列。事实上,这是有规律的每250个事件就有一个很大的差距。因此,每个测试都显示第一个差距在70到80到250之间。为什么总是250?从那以后,“跳到”点的间隔总是250;e、 例如,从263到500的差距,然后从511到750的差距,等等。。我必须假设这是某种默认的缓冲区大小

此外,客户机第一次连接到服务器时,总是能够很好地接收整个序列。随后的连接显示出常规的跳过问题。所以这似乎是服务器端的问题,而不是客户端的问题

然后,我向服务器添加了一些检查,以确保每个客户端的
IObserver
都能以正确的顺序看到所有事件。它是。因此,几乎可以肯定的是,问题出在信号服务器端,与Rx无关

最后,我检查了被丢弃的消息是否只是无序传递(我可以接受,尽管我假设SignalR提供了有序传递保证)。它们不是——信息只是消失在一片空白中

如果有帮助的话,我目前正在本地运行,在Win 8.1 x64上运行IIS Express,在IE开发者频道和Chrome 36上进行测试。连接正在使用WebSocket。我在信号源(客户端或服务器)或Rx.Net源中都找不到250作为特殊数量的任何引用

对故障排除有什么建议吗?在开始构建复杂的解决方案之前,我希望找到一个稳定的解决方案

以下是相关的服务器端代码:

公共类AllEventsReplaySource
{
专用只读IHubConnectionContext客户端;
私有只读ReplaySubject allEvents;
专用AllEventsReplaySource(IHubConnectionContext客户端)
{
这个。客户=客户;
this.allEvents=新的ReplaySubject();
//(未显示:生成ReplaySubject输入的代码。)
}
public void SubscribeClient(字符串connectionId,int startAfter)
{
this.allEvents.Skip(startAfter.Subscribe)(e=>
{
//(未显示:验证客户端此时未发生跳过的代码。)
clients.Client(connectionId).notifyEvent(e);
});
}
私有只读静态惰性实例=
new Lazy(()=>new AllEventsReplaySource(
GlobalHost.ConnectionManager.GetHubContext().Clients));
公共静态AllEventsReplaySource实例
{
获取{return instance.Value;}
}
}
[HubName(“allEventsReplayHub”)]
公共类AllEventsReplayHub:Hub
{
私有只读AllEventsReplaySource源;
公共图书馆
:此(AllEventsReplaySource.Instance)
{ }
公共AllEventsReplayHub(AllEventsReplaySource来源)
{
this.source=源;
}
已连接的公用覆盖任务()
{
var-previousSequenceNumber=Int32.Parse(Context.QueryString[“startAfter”]);
var connectionId=this.Context.connectionId;
AllEventsReplaySource.Instance.SubscribeClient(connectionId,previousSequenceNumber);
返回base.OnConnected();
}
}

您遇到的问题似乎与消息缓冲区溢出一致。当SignalR从其缓冲区释放消息时,默认情况下,它在250个消息片段中释放消息

信号器将至少缓冲发送到给定
连接ID
的最后1000条消息。这意味着,当您发送1251条消息时,前250条消息将被缓冲区取消引用。这解释了为什么当客户机第一次连接到服务器时,它会接收整个消息序列。在缓冲区删除片段之前,必须向给定的客户端发送至少1251条消息。同样,这都是假设默认设置

虽然您可以增加成本,但这可能无法解决您的根本问题。似乎您正在尝试以服务器无法将消息发送到客户端的速度发送消息。如果连续这样做,无论大小,都会耗尽缓冲区空间

更常见的做法是增加缓冲区,而不是增加缓冲区,因为缓冲区会消耗大量内存,特别是当您向许多不同的客户端发送大量大型唯一消息时

避免缓冲区溢出的最佳方法是让客户端至少每1000条消息发送一次ACK。有鉴于此,可以避免发送超过1000条未确认的消息,从而完全避免此问题


顺便说一句,如果你愿意的话,你可以看看你自己。请注意,capacity构造函数参数是DefaultMessageBufferSize。

谢谢,这听起来很有希望!明天早上我会调查的设计一个等待ACK的正确实现花了一段时间,但它是有效的!:)再次感谢。我目前使用的增量大小为每个ACK 50条消息;500美元似乎太多了。