Hi,<div><br></div><div>I am trying to improve the message throughput for a RabbitMQ queue in an Amazon cloud instance and am noticing a <b>significant</b>&nbsp;drop in performance when enabling acknowledgements for consumer of a durable queue (with persisted messages). &nbsp;The real problem is that the bottleneck appears to be on the rabbit node and not with the consumers, so adding more consumers does not improve the throughput (or help drain the queue any quicker). &nbsp;As a matter of fact, adding new consumers will just slow down existing consumers so everyone ends up consuming at a slower rate, preventing overall throughput from changing.</div><div><br></div><div>Trying to do batch acknowledgements using the Multiple flag helps a bit (8k msgs/s vs 5.5k msgs/s) but not much compared to the initial drop. &nbsp;It is only when I turn on <b><font face="courier new, monospace">auto_ack</font></b> for the consumers that I see the performance shoot <b>way&nbsp;</b>back up and when I start seeing a linear increase in throughput as I add more consumers.</div><div><br></div><div>Is this expected behavior? &nbsp;Is there a way to configure the rabbit node so it doesn't hit this bottleneck with acknowledgements?</div><div><br></div><div>Here is the sample code I'm using to test the throughput:</div><div><br></div><div>Publisher:</div><div><br></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><div><font face="courier new, monospace">#!/usr/bin/python</font></div></div><div><div><font face="courier new, monospace"><br></font></div></div><div><div><font face="courier new, monospace">import pika</font></div></div><div><div><font face="courier new, monospace"><br></font></div></div><div><div><font face="courier new, monospace">creds = pika.PlainCredentials('guest','guest')</font></div></div><div><div><font face="courier new, monospace">conn &nbsp;= pika.BlockingConnection(pika.ConnectionParameters(host='10.10.1.123', credentials=creds))</font></div></div><div><div><font face="courier new, monospace">chan &nbsp;= conn.channel()</font></div></div><div><div><br></div></div><div><div><font face="courier new, monospace">while True:</font></div></div><div><div><font face="courier new, monospace">&nbsp; &nbsp;&nbsp;</font><span style="font-family: 'courier new', monospace;">chan.basic_publish(exchange='simple_exchange', routing_key='simple_queue', body='', properties=pika.BasicProperties(delivery_mode=2))</span></div></div><div><div><br></div></div></blockquote><div><br></div><div>Consumer:</div><div><br></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;"><div><font face="courier new, monospace">&nbsp;#!/usr/bin/python</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">import pika</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">def callback(chan, method, properties, body):</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; chan.basic_ack(delivery_tag=method.delivery_tag, multiple=False)</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">creds = pika.PlainCredentials('guest','guest')</font></div><div><font face="courier new, monospace">conn &nbsp;= pika.BlockingConnection(pika.ConnectionParameters(host='10.10.1.123', credentials=creds))</font></div><div><font face="courier new, monospace">chan &nbsp;= conn.channel()</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">chan.basic_consume(callback, queue='simple_queue', no_ack=False)</font></div><div><font face="courier new, monospace">chan.basic_qos(prefetch_count=1000)</font></div><div><font face="courier new, monospace">chan.start_consuming()</font></div></blockquote><div><br></div><div>I spawn multiple processes for the producers and multiple for the consumer (so there is no python interpreter locking issues since each runs in its own interpreter instance). &nbsp;I'm using an an Amazon <b>c1.xlarge </b>(8 virtual cores and "high" IO)&nbsp;Ubuntu 12.04 LTS instance with RabbitMQ version 3.0.4-1 and an Amazon ephemeral disk (in production we would use an EBS volume instead). &nbsp;The queue is marked <b>Durable</b> and my messages all use <b><font face="courier new, monospace">delivery_mode</font></b> 2 (persist). &nbsp;</div><div><br></div><div>Below are the performance numbers. &nbsp;For each test I use 2 publishers processes and 6 consumer processes (where 3 different machines host 2 consumers each). &nbsp;The producers and consumers are all on <b>separate</b> machines from the rabbit node. &nbsp;Throughput measurements were done using the RabbitMQ management UI and linux utility <font face="courier new, monospace">top</font>. &nbsp;Python was compiled to pyc files before running.</div><div><br></div><div><font face="courier new, monospace"><b>no_ack = True:</b> &nbsp;</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; rate = 24,000/s&nbsp;</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; single consumer CPU &nbsp; = &nbsp;65%&nbsp;</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; single publisher CPU &nbsp;= &nbsp;80% (flow control enabled and being enforced)</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; (beam.smp) rabbit CPU = 400% (of 800%, 8 cores) -&gt; 0.0%wa 11.5%sy</font></div><div><font face="courier new, monospace"><br></font></div><div><b><font face="courier new, monospace">no_ack = False (manual acks per message):</font></b></div><div><font face="courier new, monospace">&nbsp; &nbsp; rate = &nbsp;5,500/s</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; single consumer CPU &nbsp; = &nbsp;20%</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; single publisher CPU &nbsp;= &nbsp;20% (flow control enabled and being enforced)</font></div><div><font face="courier new, monospace">&nbsp; &nbsp; (beam.smp) rabbit CPU = 300% (of 800%, 8 cores) -&gt; 4.5%wa 10.0%sy</font></div><div>&nbsp; &nbsp;&nbsp;</div><div>The most notable difference besides the throughput are the I/O waits when ACKs are enabled (4.5% vs 0.0%). &nbsp;This leads me to believe that the rabbit node is being bottlenecked by performing I/O operations for ACK bookkeeping. &nbsp;The I/O doesn't appear to be a problem for persisting the published messages since I'm <b>guessing</b>&nbsp;that rabbit is buffering those and syncing them to disk in batches. &nbsp;Does this mean the acknowledgements are not also being buffered before synced with disk? &nbsp;Can I configure the rabbit node to change this behavior to help speed up the acknowledgements? &nbsp; I'm not using transactions in the example code above, so I don't need any strict guarantees that ACKs were written to disk before returning.</div><div><br></div><div>Thanks,</div><div>Karl</div><div><br></div><div>P.S. I wrote the same sample consumer code in Ruby to see if there was a difference (in case there was a Python issue), but the numbers were about the same.</div>