我创建了一个使用RabbitMq消息的Windows服务。 消费以异步方式完成,消息被推送到服务。
它可以大约水平伸缩。线性性能增益,即使只是在同一台服务器上创建更多服务实例。 由于我们对吞吐量有一个明确的目标,我发现通过简单地在Windows服务中创建n个任务来控制扩展,而不是部署n个服务实例,这样做更简单一些。
重写windows服务以简单地启动每个运行“MQ消耗”代码的n个任务,因此实质上是执行windows服务的多个实例所做的,不会产生相同的性能,实际上根本没有性能增益,实际上似乎代码执行的开销更大!。
我知道存在调度问题,但最重要的问题是。 是否可以使用任务并获得“近似”相同的性能,就像一个人启动应用程序的多个实例一样?如果是这样,实现会如何,因为我当前的设置规模很小。
一些代码段:
这是基本任务创建,其中每个任务都有一个taskwrapper实例,它基本上是消费和处理消息的整个业务逻辑的抽象:
public void Start()
{
for (var i = 0; i < _levelOfConcurrency; i++)
{
var task = Task.Factory.StartNew(() => new TaskWrapper().TaskRun(_cancelationTokenSource.Token,_sleeptime),
TaskCreationOptions.LongRunning);
_tasks[i] = task;
Console.WriteLine("Task created {0}", i);
}
}
public void Stop()
{
_cancelationTokenSource.Cancel();
Task.WaitAll(_tasks);
}
这是每个任务在taskwrapper类中的runloop基本上具有的内容:
public void TaskRun(CancellationToken cancellationToken,TimeSpan sleeptime)
{
_semaphoreDataController.Start(); // Process messages async, fully selfcontained/threaded
//Keep alive and occasionally check if cancelation is requested
while (!cancellationToken.IsCancellationRequested)
{
Thread.Sleep(sleeptime);
}
Dispose();
}
我希望有人可以启发我:-D
答案 0 :(得分:0)
问题的核心:
这很难取决于你的编程风格和它自己的程序。
使用多个线程进程可以获得与多个实例相同的性能。但正如我所说,这取决于你的服务。我建议你阅读这本书的在线版本:Parallel programming with .net。它开启了我对PLinq,任务和线程的关注。
但最终,它在CPU上运行并且进程间通信比线程间通信更复杂。
答案 1 :(得分:0)
因此,进一步调查确定了代码中的主要限制因素。
我使用RabbitMQ进行通信的方式是通过Burrow.NET,它将为应用程序创建一个专用通道,以便与队列进行通信。
这意味着即使您正在运行多个并行任务,它们也只能从一个通道的队列中消耗,从而限制了服务的速度。
拥有多个服务实例,为RabbitMQ提供n个通道,从而获得线性性能提升。
答案 2 :(得分:0)
DedicatedPublishingChannel作为其名称仅用于发布消息,因此我认为它不会消耗消息的速度问题。 此外,尽管从队列中只有一个通道可以订阅,但与处理这些消息的时间相比,传递给应用程序的消息速度总是非常快。我已经创建了一个应用程序,将数百万个msgs(Tweet json)从队列迁移到MongoDB,它始终是将数据写入数据库的瓶颈。
Burrow.NET处理任务管理以便为您并行处理消息:
ITunnel tunnel;
// Create tunnel
tunnel.Subscribe(new SubscriptionOption<Message>
{
BatchSize = 10, // Number of threads you want to process those messages
MessageHandler = message =>
{
// Process your message here
},
QueuePrefetchSize = 10, // Should be double the message processing speed
SubscriptionName = "Anything"
});
// Message will be acked automatically after finish
在我看来,我会尽可能使用限制IO资源。我遇到了一个问题,即我的应用程序创建了很多通道并且引用了很多服务器的内存,如果应用程序创建了许多不必要的连接,那就更糟了,这就是为什么Burrow.NET会帮助你尽可能少地建立连接/通道。
如果您认为可以足够快地处理邮件,则可以使用较大的数字设置预取大小,并使用BatchSize(也称为线程计数)进行调整。例如,如果我的应用程序可以以5毫秒/秒的速度处理队列中的消息,我会保持QueuePrefetchSize = 10.
如果你使用auto ack的上述方法,你不必担心不会消息,因为它会阻止新消息的到来。例如,您有QueuePrefetchSize = 10可以通过10个线程并行处理10条消息。您决定使用tunnel.SubscribeAsync同步异步消息,但由于某些原因(未处理的异常:D可能)4消息未被激活,这相当于QueuePrefetchSize为6.因此,只有6条消息可以是同时处理,速度会降低。所以请尝试上面的方法,看看它是怎么回事。