我们是否正确排队和序列化?


13

我们通过各种服务处理消息(一条消息在完成之前可能会涉及9个服务,每个服务都具有与IO相关的特定功能)。现在,我们结合了最坏情况(XML数据协定序列化)和最佳情况(内存中的MSMQ)的性能。

消息的性质意味着我们的序列化数据最终约为12-15 KB,并且我们每周处理约400万条消息。MSMQ中的持久消息对我们来说太慢了,随着数据的增长,我们感受到了MSMQ的内存映射文件带来的压力。 该服务器的内存使用量为16GB,并且正在增长,仅用于排队。 当内存使用率很高时,由于机器开始交换,因此性能也会受到影响。我们已经在执行MSMQ自清除行为。

我觉得这里有些地方我们做错了。我尝试使用RavenDB保留消息并仅对标识符进行排队,但性能却非常慢(每分钟最多1000条消息)。我不确定这是使用开发版本还是使用什么版本,但我们确实需要更高的吞吐量[1]。该概念在理论上非常有效,但性能不能满足要求。

使用模式具有一项充当路由器的服务,该服务会进行所有读取。其他服务将基于它们的第3方挂钩附加信息,然后转发回路由器。大多数物体被触摸9至12次,尽管大约10%的物体在该系统中被迫循环一会儿,直到第三方做出适当响应为止。现在,由于这一原因,我们利用消息的优先级字段来解决此问题并具有适当的休眠行为。

因此,我的问题是,在C#/ Windows环境中用于在离散但LAN的计算机之间传递消息的理想堆栈是什么? 我通常从BinaryFormatter而不是XML序列化开始,但是如果更好的方法是将序列化卸载到文档存储中,那就太麻烦了。因此,我的问题。

[1]:我们的业务性质意味着我们越早处理消息,我们就越赚钱。我们已经通过经验证明,在本周晚些时候处理一条消息意味着我们赚钱的可能性较小。虽然“每分钟1000个”的性能听起来非常快,但我们确实需要将该数字提高到1万个/分钟。仅仅因为我每周在消息中提供数字并不意味着我们有整整一周的时间来处理这些消息。

===============编辑:

附加信息

根据评论,我将添加一些说明:

  • 我不确定序列化是我们的瓶颈。我已经对应用程序进行了基准测试,虽然序列化确实显示在热图上,但它仅占服务CPU利用率的2.5-3%。

  • 我最担心的是我们消息的持久性和对MSMQ的潜在滥用。我们使用的是非事务性,非持久性消息,因此我们可以保持排队性能,而且我真的很希望至少有持久性消息,以便它们在重新启动后仍能生存。

  • 添加更多的RAM是权宜之计。机器的内存已经从4GB减少到了16GB,并且越来越难以取舍以继续增加容量。

  • 由于应用程序的星形路由模式,对象弹出一半时间然后被推到队列中,它根本不会改变。这又使(IMO)能够将其存储在其他地方的某种键值存储中,并仅传递消息标识符。

  • 星型路由模式是应用程序不可或缺的,并且不会更改。我们无法以应用程序为中心,因为此过程中的每一部分都异步运行(以轮询方式),并且我们希望将重试行为集中在一个地方。

  • 应用程序逻辑是用C#编写的,对象是不可变的POCO,目标部署环境是Windows Server 2012,如果仅在Linux中支持特定软件,则允许我们站立其他计算机。

  • 我的目标是保持当前吞吐量,同时以最小的资本支出减少内存占用并提高容错能力。


由于将相关要点纳入问题,因此清除了评论。
克里斯·

在担心交换排队子系统之前解决最紧迫的问题是有意义的(尽管最终可能仍然值得这样做)。内存增长失控的事实表明某个地方仍然存在泄漏。什么(如果有的话)的内存分析完成了?
丹·里昂斯2013年

@DanLyons:唯一的内存增长是在MSMQ中。没有人真正谈论它,但这似乎是由于所有内存映射的非持久消息。由于我们要序列化大量数据,因此它确实保留了大量的内存。(最终)随着消息的消耗和MSMQ的内部清理运行而回收内存。
Bryan Boettcher

Answers:


1

这是您可能感兴趣的一些队列基准 。MSMQ应该能够每秒处理10K消息。可能是配置问题,还是客户端跟不上读取队列的步伐?另请注意,ZeroMQ在这些基准测试中的运行速度非常快(每秒约10万条消息),它没有提供持久性选项,但它可以使您到达性能明智的位置。


4

几年前,我们遇到了类似的情况,使用了排队的消息系统(本例中为音频指纹)。我们强烈评价排队的数据包的持久性,但是我们发现将所有内容排队到磁盘并从磁盘使用队列非常昂贵。

如果我们切换到基于内存的队列,性能会很出色,但是我们遇到了一个主要问题。队列的使用者偶尔会在相当长的时间内不可用(在我们的案例中,使用者和生产者元素通过WAN连接),因此,生产者的队列将增长到无法管理的程度,就像您的情况一样,一旦内存消耗非常高,在交换期间过多的内存抖动将系统带入完整的爬网。

我们设计了一个被VMQueue 命名的队列(对于Virtual Memory Queue,回顾起来是一个非常糟糕的名字)。此队列的想法是,如果使用者进程正在运行以达到标准速度,换句话说,处理速度足够快,能够将排队元素的数量保持在一定水平以下,那么它的性能基本上与内存相同-基于队列。但是,当使用者减慢速度或变得不可用并且生产者队列增长到一定大小时,该队列将开始自动在磁盘之间来回分页元素(使用BinaryFormatter序列化)。此过程可保持对内存使用的完全控制,并且分页过程非常快,至少比重内存负载期间发生的虚拟内存交换快得多。一旦使用者设法将队列中的资源耗尽到阈值以下,它将继续作为纯基于内存的队列工作

如果系统崩溃或重新启动,则队列能够恢复存储到磁盘的所有分页元素,它将仅丢失崩溃前仍保留在内存中的元素。如果您有能力在崩溃或重新启动期间丢失有限数量的数据包,则此队列可能会有所帮助。

如果您有兴趣,我可以共享VMQueue该类的源代码,以便您可以试用它。队列将接受任何标记为可序列化的类。创建队列后,您可以按元素数确定页面的大小。该类接口实际上与标准Queue类相同。但是,该代码很旧(.net 1.1),因此很遗憾没有通用接口。

我知道,从行之有效的MSMQ技术转移无疑是一个巨大的赌注,但是这个队列已经可靠地运行了近6年,这使我们能够在生产者机器离线数周的情况下生存和恢复!如果你有兴趣的话,请让我知道。:)


1

HP ProLiant ML350G5系统每分钟可处理82k事务-即它具有您提到的“ 10k /分钟”吞吐量的8倍以上。

性能:82774 tpmC

另外,说实话,我刚要使用64 GB甚至128 GB的RAM-RAM很便宜。Greenspun指出“将RAM扔给它”和“让一个受过MIT教育的聪明人对其进行优化”之间的区别,然后RAM获胜。

他最终获得​​了一台配备64 GB RAM的SQL Server计算机和一些运行ASP.NET页面的前端计算机...这个站点swaptree.com处理的当前会员人数超过40万(正在迅速增长)没有困难...

注意:“机器已经达到16 GB的RAM”远远不够,文章指出服务器正在处理64 GB RAM上的40万用户。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.