我一直在构建一个用于多媒体消息传递的高吞吐量服务器应用程序,实现语言是C++。每个服务器都可以独立使用,也可以将许多服务器连接在一起以创建基于 DHT 的覆盖网络;服务器就像 Skype 中的 super 节点一样。
工作正在进行中。目前,服务器每秒可以处理大约 200,000 条消息(256 字节消息),并且在我的机器(Intel i3 Mobile 2 GHz、Fedora Core 18(64 位)、4 GB RAM)上的最大吞吐量约为 256 MB/s长度为 4096 字节的消息。服务器有两个线程,一个线程用于处理所有 IO(基于 epoll,边缘触发),另一个线程用于处理传入消息。覆盖管理还有另一个线程,但在当前讨论中无关紧要。
讨论中的两个线程使用两个循环缓冲区共享数据。线程号 1 使用一个循环缓冲区为线程号 2 排队新消息,而线程号 2 通过另一个循环缓冲区返回处理过的消息。服务器是完全无锁的。我没有使用任何同步原语,甚至没有使用原子操作。
循环缓冲区永远不会溢出,因为消息是池化的(在开始时预先分配)。事实上,所有重要/经常使用的数据结构都被合并以减少内存碎片并提高缓存效率,因此我们知道服务器启动时我们将要创建的最大消息数,因此我们可以预先计算最大缓冲区的大小,然后相应地初始化循环缓冲区。
现在我的问题是:线程 #1 一次将一条消息(实际上是指向消息对象的指针)的序列化消息排入队列,而线程 #2 从中取出消息队列中的 block (32/64/128 的 block ),并通过第二个循环缓冲区以 block 的形式返回处理后的消息。如果没有新消息,线程 #2 会一直忙着等待,因此让其中一个 CPU 核心一直处于忙碌状态。我怎样才能进一步改进设计?繁忙等待策略的替代方案是什么?我想优雅而高效地做到这一点。我考虑过使用信号量,但我担心这不是最佳解决方案,原因很简单,每次我在线程 #1 中排队消息时都必须调用“sem_post”,这可能会大大减少吞吐量,第二个线程必须调用“sem_post”的次数相等,以防止信号量溢出。此外,我担心信号量实现可能会在内部使用互斥量。
第二个不错的选择可能是使用signal,如果我能发现一种仅在第二个线程“清空队列并正在调用 sigwait”或“already waiting on sigwait”,简而言之,信号必须被提升最少次数,尽管如果信号被提升的次数比需要的多几次也没有坏处。是的,我确实使用了 Google 搜索,但我在 Internet 上找到的解决方案都不令人满意。以下是一些注意事项:
一个。服务器在进行系统调用时必须浪费最少的 CPU 周期,并且系统调用的使用次数必须最少。
B.开销必须非常低,算法必须高效。
C.没有任何锁定。
我希望所有选项都摆在桌面上。
这是我共享有关我的服务器的信息的站点的链接,以便更好地了解功能和用途: www.wanhive.com
最佳答案
如果您需要尽快唤醒线程#2,忙等待是个好办法。事实上,这是通知一个处理器有关另一个处理器所做更改的最快方式。您需要在两端生成内存栅栏(一侧写栅栏,另一侧读栅栏)。但是只有当你的两个线程都在专用处理器上执行时,这个说法才成立。在这种情况下,不需要上下文切换,只需缓存一致性流量。
可以做一些改进。
处理步骤的并行化。 有两种选择。
在第一种情况下,您需要 N 个循环缓冲区和 N 个处理线程以及 N 个输出缓冲区和一个消费者线程。线程 #1 在该循环缓冲区中按循环顺序对消息进行排队。
// Thread #1 pseudocode
auto message = recv()
auto buffer_index = atomic_increment(&message_counter);
buffer_index = buffer_index % N; // N is the number of threads
// buffers is an array of cyclic buffers - Buffer* buffers[N];
Buffer* current_buffer = buffers[buffer_index];
current_buffer->euqueue(message);
每个线程都使用来自其中一个缓冲区的消息并将结果排队到他的专用输出缓冲区。
// Thread #i pseudocode
auto message = my_buffer->dequeue();
auto result = process(message);
my_output_buffer->enqueue(result);
现在您需要按到达顺序处理所有这些消息。您可以通过以循环方式从输出循环缓冲区中出列已处理的消息,使用专用的消费者线程来执行此操作。
// Consumer thread pseudocode
// out_message_counter is equal to message_counter at start
auto out_buffer_index = atomic_increment(&out_message_counter);
out_buffer_index = out_buffer_index % N;
// out_buffers is array of output buffers that is used by processing
// threads
auto out_buffer = out_buffers[out_buffer_index];
auto result = out_buffer->dequeue();
send(result); // or whatever you need to do with result
在第二种情况下,当您不需要保留消息顺序时 - 您不需要消费者线程和输出循环缓冲区。您只需在处理线程中对结果做任何您需要做的事情。
N 必须等于 CPU 数量 - 第一种情况下为 3(“- 3”是一个 I/O 线程 + 一个消费者线程 + 一个 DHT 线程)和 CPU 数量 - 2 在第二种情况下(“- 2”是一个 I/O 线程 + 一个 DHT 线程)。这是因为如果处理器超额订阅,忙等待将无法生效。
关于c++ - 高吞吐量非阻塞服务器设计 : Alternatives to busy wait,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20322422/
我正在尝试使用ruby和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
最近,当我启动我的Rails服务器时,我收到了一长串警告。虽然它不影响我的应用程序,但我想知道如何解决这些警告。我的估计是imagemagick以某种方式被调用了两次?当我在警告前后检查我的git日志时。我想知道如何解决这个问题。-bcrypt-ruby(3.1.2)-better_errors(1.0.1)+bcrypt(3.1.7)+bcrypt-ruby(3.1.5)-bcrypt(>=3.1.3)+better_errors(1.1.0)bcrypt和imagemagick有关系吗?/Users/rbchris/.rbenv/versions/2.0.0-p247/lib/ru
在Rails4.0.2中,我使用s3_direct_upload和aws-sdkgems直接为s3存储桶上传文件。在开发环境中它工作正常,但在生产环境中它会抛出如下错误,ActionView::Template::Error(noimplicitconversionofnilintoString)在View中,create_cv_url,:id=>"s3_uploader",:key=>"cv_uploads/{unique_id}/${filename}",:key_starts_with=>"cv_uploads/",:callback_param=>"cv[direct_uplo
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
您如何在Rails中的实时服务器上进行有效调试,无论是在测试版/生产服务器上?我试过直接在服务器上修改文件,然后重启应用,但是修改好像没有生效,或者需要很长时间(缓存?)我也试过在本地做“脚本/服务器生产”,但是那很慢另一种选择是编码和部署,但效率很低。有人对他们如何有效地做到这一点有任何见解吗? 最佳答案 我会回答你的问题,即使我不同意这种热修补服务器代码的方式:)首先,你真的确定你已经重启了服务器吗?您可以通过跟踪日志文件来检查它。您更改的代码显示的View可能会被缓存。缓存页面位于tmp/cache文件夹下。您可以尝试手动删除
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是: