Skip to content

Commit bb5b42a

Browse files
authored
performances documentation (#360)
Signed-off-by: Gabriele Santomaggio <G.santomaggio@gmail.com>
1 parent 1932af5 commit bb5b42a

File tree

5 files changed

+98
-21
lines changed

5 files changed

+98
-21
lines changed

CiDockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM rabbitmq:3.13-management
1+
FROM rabbitmq:4-management
22

33
COPY .ci/conf/rabbitmq.conf /etc/rabbitmq/rabbitmq.conf
44
COPY .ci/conf/enabled_plugins /etc/rabbitmq/enabled_plugins

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,8 @@ The `BatchSend` is the primitive to send the messages, `Send` introduces a smart
300300

301301
The `Send` interface works in most of the cases, In some condition is about 15/20 slower than `BatchSend`. See also this [thread](https://groups.google.com/g/rabbitmq-users/c/IO_9-BbCzgQ).
302302

303+
See also "Client performances" example in the [examples](./examples/performances/) directory
304+
303305
### Publish Confirmation
304306

305307
For each publish the server sends back to the client the confirmation or an error.

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ Stream examples
1616
- [Single Active Consumer](./single_active_consumer) - Single Active Consumer example
1717
- [Reliable](./reliable) - Reliable Producer and Reliable Consumer example
1818
- [Super Stream](./super_stream) - Super Stream example with Single Active Consumer
19+
- [Client performances](./performances) - Client performances example
1920

examples/performances/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Client performances
2+
3+
This document describes how to tune the parameters of the client to:
4+
- Increase the throughput
5+
- And/or reduce the latency
6+
- And/or reduce the disk space used by the messages.
7+
8+
### Throughput and Latency
9+
10+
The parameters that can be tuned are:
11+
- `SetBatchSize(batchSize)` and `SetBatchPublishingDelay(100)` when use the `Send()` method
12+
- The number of the messages when use the `BatchSend()` method
13+
14+
In this example you can play with the parameters to see the impact on the performances.
15+
There is not a magic formula to find the best parameters, you need to test and find the best values for your use case.
16+
17+
### How to run the example
18+
```
19+
go run performances.go async 1000000 100;
20+
```
21+
22+
### Disk space used by the messages
23+
24+
The client supports also the batch entry size and the compression:
25+
`SetSubEntrySize(500).SetCompression(stream.Compression{}...`
26+
These parameters can be used to reduce the space used by the messages due of the compression and the batch entry size.
27+
28+
29+
### Default values
30+
31+
The default producer values are meant to be a good trade-off between throughput and latency.
32+
You can tune the parameters to increase the throughput, reduce the latency or reduce the disk space used by the messages.
33+
34+
35+
36+
### Load tests
37+
To execute load tests, you can use the official load test tool:
38+
https://github.com/rabbitmq/rabbitmq-stream-perf-test

examples/performances/performances.go

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/rabbitmq/rabbitmq-stream-go-client/pkg/message"
99
"github.com/rabbitmq/rabbitmq-stream-go-client/pkg/stream"
1010
"os"
11+
"strconv"
1112
"sync/atomic"
1213
"time"
1314
)
@@ -34,9 +35,17 @@ func handlePublishConfirm(confirms stream.ChannelPublishConfirm) {
3435
}
3536

3637
func main() {
37-
reader := bufio.NewReader(os.Stdin)
3838

39-
fmt.Println("RabbitMQ Sub Entry Batch example")
39+
useSyncBatch := os.Args[1] == "sync"
40+
useAsyncSend := os.Args[1] == "async"
41+
42+
messagesToSend, err := strconv.Atoi(os.Args[2])
43+
CheckErr(err)
44+
batchSize, err := strconv.Atoi(os.Args[3])
45+
messagesToSend = messagesToSend / batchSize
46+
47+
reader := bufio.NewReader(os.Stdin)
48+
fmt.Println("RabbitMQ performance example")
4049

4150
// Connect to the broker ( or brokers )
4251
env, err := stream.NewEnvironment(
@@ -46,7 +55,6 @@ func main() {
4655
SetUser("guest").
4756
SetPassword("guest"))
4857
CheckErr(err)
49-
fmt.Printf("------------------------------------------\n\n")
5058
fmt.Println("Connected to the RabbitMQ server")
5159

5260
streamName := uuid.New().String()
@@ -56,38 +64,66 @@ func main() {
5664
},
5765
)
5866
CheckErr(err)
59-
fmt.Printf("------------------------------------------\n\n")
6067
fmt.Printf("Created Stream: %s \n", streamName)
6168

62-
producer, err := env.NewProducer(streamName, stream.NewProducerOptions().
63-
SetSubEntrySize(500).
64-
SetCompression(stream.Compression{}.None()))
69+
producer, err := env.NewProducer(streamName,
70+
stream.NewProducerOptions().
71+
SetBatchSize(batchSize).
72+
SetBatchPublishingDelay(100))
6573
CheckErr(err)
6674

67-
//optional publish confirmation channel
6875
chPublishConfirm := producer.NotifyPublishConfirmation()
6976
handlePublishConfirm(chPublishConfirm)
70-
messagesToSend := 20_000
7177
fmt.Printf("------------------------------------------\n\n")
72-
fmt.Printf("Start sending %d messages, data size: %d bytes\n", messagesToSend, len("hello_world"))
73-
batchSize := 100
74-
var arr []message.StreamMessage
75-
for i := 0; i < batchSize; i++ {
76-
arr = append(arr, amqp.NewMessage([]byte("hello_world")))
78+
fmt.Printf("Start sending %d messages, data size: %d bytes\n", messagesToSend*batchSize, len("hello_world"))
79+
var averageLatency time.Duration
80+
var messagesConsumed int32
81+
handleMessages := func(consumerContext stream.ConsumerContext, message *amqp.Message) {
82+
atomic.AddInt32(&messagesConsumed, 1)
83+
var latency time.Time
84+
err := latency.UnmarshalBinary(message.Data[0])
85+
CheckErr(err)
86+
averageLatency += time.Since(latency)
7787
}
88+
_, err = env.NewConsumer(streamName, handleMessages, stream.NewConsumerOptions().SetOffset(stream.OffsetSpecification{}.First()))
89+
CheckErr(err)
7890

7991
start := time.Now()
80-
for i := 0; i < messagesToSend; i++ {
81-
err := producer.BatchSend(arr)
82-
CheckErr(err)
92+
93+
// here the client sends the messages in batch and it is up to the user to aggregate the messages
94+
if useSyncBatch {
95+
var arr []message.StreamMessage
96+
for i := 0; i < messagesToSend; i++ {
97+
for i := 0; i < batchSize; i++ {
98+
latency, err := time.Now().MarshalBinary()
99+
CheckErr(err)
100+
arr = append(arr, amqp.NewMessage(latency))
101+
}
102+
err := producer.BatchSend(arr)
103+
CheckErr(err)
104+
arr = arr[:0]
105+
}
106+
}
107+
108+
// here the client aggregates the messages based on the batch size and batch publishing delay
109+
if useAsyncSend {
110+
for i := 0; i < messagesToSend; i++ {
111+
for i := 0; i < batchSize; i++ {
112+
latency, err := time.Now().MarshalBinary()
113+
CheckErr(err)
114+
err = producer.Send(amqp.NewMessage(latency))
115+
CheckErr(err)
116+
}
117+
}
83118
}
119+
84120
duration := time.Since(start)
121+
fmt.Println("Press any key to report and stop ")
122+
_, _ = reader.ReadString('\n')
85123
fmt.Printf("------------------------------------------\n\n")
86-
fmt.Printf("Sent %d messages in %s \n", messagesToSend*100, duration)
124+
fmt.Printf("Sent %d messages in %s. Confirmed: %d avarage latency: %s \n", messagesToSend*batchSize, duration, messagesConfirmed, averageLatency/time.Duration(messagesConsumed))
87125
fmt.Printf("------------------------------------------\n\n")
88126

89-
fmt.Println("Press any key to stop ")
90-
_, _ = reader.ReadString('\n')
91127
time.Sleep(200 * time.Millisecond)
92128
CheckErr(err)
93129
err = env.DeleteStream(streamName)

0 commit comments

Comments
 (0)