Πώς ρυθμίσαμε το HAProxy για να πετύχουμε 2.000.000 ταυτόχρονες συνδέσεις SSL

Αν κοιτάξετε προσεκτικά το παραπάνω στιγμιότυπο οθόνης, θα βρείτε δύο σημαντικές πληροφορίες:

  1. Αυτή η μηχανή έχει 2,38 εκατομμύρια συνδέσεις TCP και
  2. Η ποσότητα RAM που χρησιμοποιείται είναι περίπου 48 Gigabytes .

Πολύ φοβερό, σωστά; Αυτό που θα ήταν ακόμη πιο φοβερό είναι εάν κάποιος παρείχε τα στοιχεία εγκατάστασης και οι ρυθμίσεις που απαιτούνται για την επίτευξη αυτού του είδους κλίμακας σε ένα μόνο μηχάνημα HAProxy. Λοιπόν, θα το κάνω ακριβώς σε αυτήν την ανάρτηση;)

Αυτό είναι το τελευταίο μέρος της σειράς πολλαπλών μερών σε δοκιμές φόρτωσης HAProxy. Εάν έχετε χρόνο, σας προτείνω να διαβάσετε πρώτα τα δύο πρώτα μέρη της σειράς. Αυτά θα σας βοηθήσουν να απαλλαγείτε από τους συντονισμούς επιπέδου πυρήνα που απαιτούνται σε όλα τα μηχανήματα σε αυτήν τη ρύθμιση.

Φόρτωση δοκιμής HAProxy (Μέρος-1)

Φόρτωση δοκιμής; HAProxy; Αν όλα αυτά σας φαίνονται ελληνικά, μην ανησυχείτε. Θα παράσχω ενσωματωμένους συνδέσμους για να διαβάσετε τι… medium.com Load Testing HAProxy (Part 2)

Αυτό είναι το δεύτερο μέρος της σειράς 3 μερών για τον έλεγχο απόδοσης του διάσημου TCP load balancer και του αντίστροφου διακομιστή μεσολάβησης… medium.com

Υπάρχουν πολλά μικρά στοιχεία που μας βοήθησαν να συγκεντρώσουμε ολόκληρη τη ρύθμιση και να επιτύχουμε αυτούς τους αριθμούς.

Πριν σας πω την τελική διαμόρφωση HAProxy που χρησιμοποιήσαμε (αν είστε ανυπόμονοι μπορείτε να μετακινηθείτε προς τα κάτω) Θέλω να το αναπτύξω περπατώντας σας στη σκέψη μας.

Αυτό που θέλαμε να δοκιμάσουμε

Το στοιχείο που θέλουμε να δοκιμάσουμε ήταν η έκδοση HAProxy 1.6. Αυτό το χρησιμοποιούμε στην παραγωγή αυτή τη στιγμή σε μηχανήματα 4 πυρήνων, 30 Gig. Ωστόσο, όλη η συνδεσιμότητα δεν βασίζεται σε SSL.

Θέλαμε να δοκιμάσουμε δύο πράγματα από αυτήν την άσκηση:

  1. Το ποσοστό CPU αυξάνεται όταν αλλάζουμε ολόκληρο το φορτίο από συνδέσεις εκτός SSL σε συνδέσεις SSL. Η χρήση της CPU θα πρέπει σίγουρα να αυξηθεί, λόγω της μεγαλύτερης χειραψίας 5 κατευθύνσεων και στη συνέχεια της κρυπτογράφησης πακέτων.
  2. Δεύτερον, θέλαμε να δοκιμάσουμε τα όρια της τρέχουσας εγκατάστασης παραγωγής μας όσον αφορά τον αριθμό των αιτημάτων και τον μέγιστο αριθμό ταυτόχρονων συνδέσεων που μπορούν να υποστηριχθούν πριν αρχίσει η υποβάθμιση της απόδοσης.

Απαιτήσαμε το πρώτο μέρος λόγω μιας σημαντικής διάθεσης δυνατοτήτων που βρίσκεται σε πλήρη εξέλιξη, η οποία απαιτεί επικοινωνία μέσω SSL. Χρειαζόμασταν το δεύτερο μέρος, ώστε να μειώσουμε την ποσότητα του υλικού που αφιερώνεται στην παραγωγή σε μηχανήματα HAProxy.

Τα συστατικά που εμπλέκονται

  • Πολλαπλές μηχανές πελατών για να τονίσουν το HAProxy.
  • Μονή μηχανή HAProxy έκδοση 1.6 σε διάφορες ρυθμίσεις

    * 4 πυρήνες, 30 Gig

    * 16 πυρήνες, 30 Gig

    * 16 πυρήνες, 64 Gig

  • Διακομιστές Backend που θα βοηθήσουν στην υποστήριξη όλων αυτών των ταυτόχρονων συνδέσεων.

HTTP και MQTT

Αν έχετε διαβάσει το πρώτο άρθρο αυτής της σειράς, θα πρέπει να γνωρίζετε ότι ολόκληρη η υποδομή μας υποστηρίζεται σε δύο πρωτόκολλα:

  • HTTP και
  • MQTT.

Στη στοίβα μας, δεν χρησιμοποιούμε HTTP 2.0 και ως εκ τούτου δεν έχουμε τη λειτουργικότητα των μόνιμων συνδέσεων στο HTTP. Έτσι, κατά την παραγωγή, ο μέγιστος αριθμός συνδέσεων TCP που βλέπουμε είναι κάπου γύρω (2 * 150k) σε ένα μηχάνημα HAProxy (Inbound + Outbound). Αν και ο αριθμός των ταυτόχρονων συνδέσεων είναι αρκετά χαμηλός, ο αριθμός των αιτήσεων ανά δευτερόλεπτο είναι αρκετά υψηλός.

Από την άλλη πλευρά, το MQTT είναι ένας διαφορετικός τρόπος για επικοινωνία. Προσφέρει εξαιρετικές παραμέτρους ποιότητας υπηρεσίας και επίμονη συνδεσιμότητα. Έτσι, η αμφίδρομη συνεχής επικοινωνία μπορεί να συμβεί μέσω ενός καναλιού MQTT. Όσο για το HAProxy που υποστηρίζει συνδέσεις MQTT (υποκείμενες TCP), βλέπουμε κάπου περίπου 600-700k συνδέσεις TCP κατά την ώρα αιχμής σε ένα μόνο μηχάνημα.

Θέλαμε να κάνουμε μια δοκιμή φόρτωσης που θα μας δώσει ακριβή αποτελέσματα για συνδέσεις με βάση HTTP και MQTT.

Υπάρχουν πολλά εργαλεία εκεί έξω που μας βοηθούν να φορτώσουμε εύκολα έναν διακομιστή HTTP και πολλά από αυτά τα εργαλεία παρέχουν προηγμένες λειτουργίες, όπως συνοπτικά αποτελέσματα, μετατροπή αποτελεσμάτων βάσει κειμένου σε γραφήματα κ.λπ. για MQTT. Έχουμε ένα εργαλείο που αναπτύξαμε οι ίδιοι, αλλά δεν ήταν αρκετά σταθερό για να υποστηρίξει αυτό το είδος φορτίου στο χρονικό πλαίσιο που είχαμε.

Αποφασίσαμε λοιπόν να πάμε για δοκιμές φορτίων για πελάτες HTTP και να προσομοιώσουμε τη ρύθμιση MQTT χρησιμοποιώντας το ίδιο;) Ενδιαφέρον, σωστά;

Διαβάστε καλά.

Η αρχική ρύθμιση

Αυτό θα είναι μια μεγάλη ανάρτηση καθώς θα παράσχω πολλές λεπτομέρειες που νομίζω ότι θα ήταν πραγματικά χρήσιμες σε κάποιον που έκανε παρόμοιες δοκιμές φορτίου ή βελτιώσεις.

  • Πήραμε ένα μηχάνημα 30 Gig 16 πυρήνων για τη ρύθμιση του HAProxy αρχικά. Δεν πήγαμε με την τρέχουσα εγκατάσταση παραγωγής μας, επειδή πιστεύαμε ότι η CPU χάθηκε λόγω τερματισμού SSL στο τέλος του HAProxy θα ήταν τεράστια.
  • Για το τέλος του διακομιστή, πήγαμε με έναν απλό διακομιστή NodeJs που απαντά pongκατά τη λήψη ενός pingαιτήματος.
  • Όσο για τον πελάτη, καταλήξαμε αρχικά να χρησιμοποιούμε το Apache Bench. Ο λόγος που πήγαμε abήταν επειδή ήταν ένα πολύ γνωστό και σταθερό εργαλείο για τη δοκιμή φορτίου των τελικών σημείων HTTP και επίσης επειδή παρέχει όμορφα συνοπτικά αποτελέσματα που θα μας βοηθήσουν πολύ.

Το abεργαλείο παρέχει πολλές ενδιαφέρουσες παραμέτρους που χρησιμοποιήσαμε για τη δοκιμή φόρτωσης όπως:

  • - c, concurrency Καθορίζει τον αριθμό των ταυτόχρονων αιτημάτων που θα έπλητταν τον διακομιστή.
  • -n, no. of requests Όπως υποδηλώνει το όνομα, καθορίζει τον συνολικό αριθμό αιτημάτων της τρέχουσας εκτέλεσης φόρτωσης.
  • -p POST file Περιέχει το κύριο μέρος του αιτήματος POST (αν αυτό θέλετε να δοκιμάσετε.)

Αν κοιτάξετε προσεκτικά αυτές τις παραμέτρους, θα διαπιστώσετε ότι είναι δυνατές πολλές παραλλαγές τροποποιώντας και τις τρεις. Ένα δείγμα αιτήματος ab θα μοιάζει κάπως έτσι

ab -S -p post_smaller.txt -T application/json -q -n 100000 -c 3000 //test.haproxy.in:80/ping

Ένα δείγμα αποτελέσματος ενός τέτοιου αιτήματος μοιάζει κάπως έτσι

Οι αριθμοί που μας ενδιαφέρουν ήταν

  • Καθυστέρηση 99%.
  • Ώρα ανά αίτημα.
  • Αριθμός αποτυχημένων αιτημάτων.
  • Αιτήματα ανά δευτερόλεπτο.

Το μεγαλύτερο πρόβλημα abείναι ότι δεν παρέχει παράμετρο για τον έλεγχο του αριθμού των αιτήσεων ανά δευτερόλεπτο. Έπρεπε να αλλάξουμε το επίπεδο ταυτότητας για να λάβουμε τα επιθυμητά αιτήματα ανά δευτερόλεπτο και αυτό οδηγεί σε πολλά ίχνη και σφάλματα.

Το πανίσχυρο γράφημα

Δεν μπορούσαμε τυχαία να κάνουμε πολλαπλές φορτίσεις και να συνεχίσουμε να παίρνουμε αποτελέσματα γιατί αυτό δεν θα μας έδινε σημαντικές πληροφορίες. Έπρεπε να πραγματοποιήσουμε αυτές τις δοκιμές με κάποιο συγκεκριμένο τρόπο, ώστε να βγάλουμε ουσιαστικά αποτελέσματα. Ακολουθήσαμε λοιπόν αυτό το γράφημα

Αυτό το γράφημα αναφέρει ότι μέχρι ένα συγκεκριμένο σημείο, εάν συνεχίσουμε να αυξάνουμε τον αριθμό των αιτημάτων, ο λανθάνων χρόνος θα παραμείνει σχεδόν ο ίδιος. Ωστόσο, πέρα από ένα συγκεκριμένο σημείο ανατροπής , ο λανθάνων χρόνος θα αρχίσει να αυξάνεται εκθετικά. Είναι αυτό το σημείο ανατροπής για ένα μηχάνημα ή για μια ρύθμιση που σκοπεύαμε να μετρήσουμε.

Γάγγλια

Πριν δώσω κάποια αποτελέσματα δοκιμών, θα ήθελα να αναφέρω τα Ganglia.

Το Ganglia είναι ένα επεκτάσιμο σύστημα κατανεμημένης παρακολούθησης για υπολογιστικά συστήματα υψηλής απόδοσης, όπως συστάδες και πλέγματα.

Look at the following screenshot of one of our machines to get an idea about what ganglia is and what sort of information it provides about the underlying machine.

Pretty interesting, eh?

Moving on, we constantly monitored ganglia for our HAProxy machine to monitor some important things.

  1. TCP established This tells us the total number of tcp connections established on the system. NOTE: this is the sum of inbound as well as outbound connections.
  2. packets sent and received We wanted to see the total number of tcp packets being sent and received by our HAProxy machine.
  3. bytes sent and received This shows us the total data that we sent and received by the machine.
  4. memory The amount of RAM being used over time.
  5. network The network bandwidth consumption because of the packets being sent over the wire.

Following are the known limits found via previous tests/numbers that we wanted to achieve via our load test.

700k TCP καθιερωμένες συνδέσεις,

50k πακέτα στάλθηκαν, 60k πακέτα ελήφθησαν

10–15MB byte που εστάλησαν καθώς και ελήφθησαν,

14–15 Μεγάλη μνήμη στην κορυφή,

Δίκτυο 7MB.

ALL these values are on a per second basis

HAProxy Nbproc

Αρχικά όταν ξεκινήσαμε τη δοκιμή φόρτωσης HAProxy, ανακαλύψαμε ότι με SSL η CPU χτυπήθηκε αρκετά νωρίς στη διαδικασία, αλλά τα αιτήματα ανά δευτερόλεπτο ήταν πολύ χαμηλά. Κατά τη διερεύνηση της κορυφαίας εντολής, διαπιστώσαμε ότι το HAProxy χρησιμοποιούσε μόνο 1 πυρήνα. Ενώ είχαμε 15 επιπλέον πυρήνες.

Το Googling για περίπου 10 λεπτά μας οδήγησε να βρούμε αυτήν την ενδιαφέρουσα ρύθμιση στο HAProxy που επιτρέπει στο HAProxy να χρησιμοποιεί πολλούς πυρήνες.

Καλείται nbprocκαι για να μάθετε καλύτερα τι είναι και πώς να το ρυθμίσετε, ρίξτε μια ματιά σε αυτό το άρθρο:

//blog.onefellow.com/post/82478335338/haproxy-mapping-process-to-cpu-core-for-maximum

Tuning this setting was the base of our load testing strategy moving forward. Because the ability to use multiple cores by HAProxy gave us the power to form multiple combinations for our load testing suite.

Load Testing with AB

When we had started out with our load testing journey, we were not clear on the things we should be measuring and what we need to achieve.

Initially we had only one goal in mind and that was to find the tipping point only by variation of all the below mentioned parameters.

I maintained a table of all the results for the various load tests that we gave. All in all I gave over 500 test runs to get to the ultimate result. As you can clearly see, there are a lot of moving parts to each and every test.

Single Client issues

We started seeing that the client was becoming bottleneck as we kept on increasing our requests per second. Apache bench uses a single core and from the documentation it is evident that it does not provide any feature for using multiple cores.

To run multiple clients efficiently we found an interesting linux utility called Parallel. As the name suggests, it helps you run multiple commands in parallel and utilises multiple cores. Exactly what we wanted.

Have a look at a sample command that runs multiple clients using parallel.

cat hosts.txt | parallel 'ab -S -p post_smaller.txt -T application/json -n 100000 -c 3000 {}'
[email protected]:~$ cat hosts.txt//test.haproxy.in:80/ping//test.haproxy.in:80/ping//test.haproxy.in:80/ping

The above command would run 3 ab clients hitting the same URL. This helped us remove the client side bottleneck.

The Sleep and Times parameter

We talked about some parameters in ganglia that we wanted to track. Lets discuss them once by one.

  1. packets sent and received This can be simulated by sending some data as a part of the post request. This would also help us generate some network as well as bytes sent and received portions in ganglia
  2. tcp_established This is something which took us a long, long time to actually simulate in our scenario. Imagine if a single ping request takes about a second, that would take us about 700k requests per second to reach our tcp_established milestone.

    Now this number might seem easier to achieve on production, but it was impossible to generate it in our scenario.

What did we do you might ask? We introduced a sleep parameter in our POST call that specifies the number of milliseconds the server needs to sleep before sending out a response. This would simulate a long running request on production. So now say we have a sleep of about 20 minutes (Yep), that would take us around 583 requests per second to reach the 700k mark.

Additionally, we also introduced another parameter in our POST calls to the HAProxy and that was the times parameter. That specified number of times the server should write a response on the tcp connection before terminating it. This helped us simulated even more data transferred over the wire.

Issues with apache bench

Although we found out a lot of results with apache bench, we also faced a lot of issues along the way. I won’t be mentioning all of them here as they are not important for this post as I’ll be introducing another client shortly.

We were pretty content with the numbers we were getting out of apache bench, but at one point of time, generating the required tcp connections just became impossible. Somehow the apache bench was not handling the sleep parameter we had introduced, properly and was not scaling for us.

Although running multiple ab clients on a single machine was sorted out by using the parallel utility. Running this setup across multiple client machines was still a pain for us. I had not heard of the pdsh utility by then and was practically stuck.

Also, we were not focussing on any timeouts as well. There are some default set of timeouts on the HAProxy, the ab client and the server and we had completely ignored these. We figured out a lot of things along the way and organized ourselves a lot on how to go about testing.

We used to talk about the tipping point graph but we deviated a lot from it as time went on. Meaningful results, however, could only be found by focusing on that.

With apache bench a point came where the number of TCP connections were not increasing. We had around 40–45 clients running on 5–6 different client boxes but were not able to achieve the scale we wanted. Theoretically, the number of TCP connections should have jumped as we went on increasing the sleep time, but it wasn’t working for us.

Enter Vegeta

I was searching for some other load testing tools that might be more scalable and better functionality wise as compared to apache bench when I came across Vegeta.

From my personal experience, I have seen Vegeta to be extremely scalable and provides much better functionality as compared to apache bench. A single Vegeta client was able to produce the level of throughput equivalent to 15 apache bench clients in our load test.

Moving forward, I will be providing load test results that have been tested using Vegeta itself.

Load Testing with Vegeta

First, have a look at the command that we used to run a single Vegeta client. Interestingly, the command to put load on the backend servers is called attack :p

echo "POST //test.haproxy.in:443/ping" | vegeta -cpus=32 attack -duration=10m -header="sleep:30000" -body=post_smaller.txt -rate=2000 -workers=500 | tee reports.bin | vegeta report

Just love the parameters provided by Vegeta. Let’s have a look at some of these below.

  1. -cpus=32 Specifies the number of cores to be used by this client. We had to expand our client machines to 32core, 64Gig because of the amount of load to be generated. If you look closely above, the rate isn’t much. But it becomes difficult to sustain such a load when a lot of connections are in sleep state from the server end.
  2. -duration=10m I guess this is self explanatory. If you don’t specify any duration, the test will run forever.
  3. -rate=2000 The number of requests per second.

So as you can see above, we reached a hefty 32k requests per second on a mere 4 core machine. If you remember the tipping point graph, you will be able to notice it clearly enough above. So the tipping point in this case is 31.5k Non SSL requests.

Have a look at some more results from the load test.

16k SSL connections is also not bad at all. Please note that at this point in our load testing journey, we had to start from scratch because we had adopted a new client and it was giving us way better results than ab. So we had to do a lot of stuff again.

An increase in the number of cores led to an increase in the number of requests per second that the machine can take before the CPU limit is hit.

We found that there wasn’t a substantial increase in the number of requests per second if we increased the number of cores from 8 to 16. Also, if we finally decided to go with a 8 core machine in production, we would never allocate all of the cores to HAProxy or be it a any other process for that matter. So we decided to perform some tests with 6 cores as well to see if we had acceptable numbers.

Not bad.

Introducing the sleep

We were pretty satisfied with our load test results till now. However, this did not simulate the real production scenario. That happened when we introduced a sleep time as well which was absent till now in our tests.

echo "POST //test.haproxy.in:443/ping" | vegeta -cpus=32 attack -duration=10m -header="sleep:1000" -body=post_smaller.txt-rate=2000 -workers=500 | tee reports.bin | vegeta report

So a sleep time of 1000 milliseconds would lead to server sleeping for x amount of time where 0< x <; 1000 and is selected randomly. So on an average the above load test will give a latency of ≥ 500ms

The numbers in the last cell represent

TCP established, Packets Rec, Packets Sent

respectively. As you can clearly see the max requests per second that the 6 core machine can support has decreased to 8k from 20k. Clearly, the sleep has its impact and that impact is the increase in the number of TCP connections established. This is however nowhere near to the 700k mark that we set out to achieve.

Milestone #1

How do we increase the number of TCP connections? Simple, we keep on increasing the sleep time and they should rise. We kept playing around with the sleep time and we stopped at the 60 seconds sleep time. That would mean an average latency of around 30 sec.

There is an interesting result parameter that Vegeta provides and that is % of requests successful. We saw that with the above sleep time, only 50% of the calls were succeeding. See the results below.

We achieved a whooping 400k TCP established connections with 8k requests per second and 60000 ms sleep time. The R in 60000R means Random.

The first real discovery we made was that there is a default call timeout in Vegeta which is of 30 seconds and that explained why 50% of our calls were failing. So we increased that to about 70s for our further tests and kept on varying it as and when the need arose.

We hit the 700k mark easily after tweaking the timeout value from the client end. The only problem with this was that these were not consistent. These were just peaks. So the system hit a peak of 600k or 700k but did not stay there for very long.

Θέλαμε ωστόσο κάτι παρόμοιο με αυτό

Αυτό δείχνει μια σταθερή κατάσταση όπου διατηρούνται 780k συνδέσεις. Εάν κοιτάξετε προσεκτικά τα παραπάνω στατιστικά στοιχεία, ο αριθμός των αιτημάτων ανά δευτερόλεπτο είναι πολύ υψηλός. Στην παραγωγή, ωστόσο, έχουμε πολύ μικρότερο αριθμό αιτημάτων (κάπου περίπου 300) σε ένα μηχάνημα HAProxy.

Ήμασταν σίγουροι ότι εάν μειώσαμε δραστικά τον αριθμό των HAProxies που έχουμε στην παραγωγή (κάπου περίπου 30, που σημαίνει 30 * 300 ~ 9k συνδέσεις ανά δευτερόλεπτο), θα χτυπήσουμε τα όρια του μηχανήματος πρώτα με τον αριθμό των συνδέσεων TCP και όχι του CPU.

Αποφασίσαμε λοιπόν να επιτύχουμε 900 αιτήματα ανά δευτερόλεπτο και 30MB / s δίκτυο και 2,1 εκατομμύρια TCP δημιουργήθηκαν συνδέσεις. Συμφωνήσαμε σε αυτούς τους αριθμούς, καθώς αυτοί θα ήταν 3 φορές το φορτίο παραγωγής μας σε ένα μόνο HAProxy.

Plus, till now we had settled on 6 cores being used by HAProxy. We wanted to test out 3 cores only because this is what would be easiest for us to roll out on our production machines (Our production machines, as mentioned before are 4 core 30 Gig. So for rolling out changes with nbproc = 3 would be easiest for us.

REMEMBER the machine we had at this point in time was 16 core 30 Gig machine with 3 cores being allocated to HAProxy.

Milestone #2

Now that we had max limits on requests per second that different variations in machine configuration could support, we only had one task left as mentioned above.

Achieve 3X the production load which is

  • 900 requests per second
  • 2.1 million TCP established and
  • 30 MB/s network.

We got stuck yet again as the TCP established were taking a hard hit at 220k. No matter what the number of client machines or what the sleep time was, number of TCP connections seemed to have stuck there.

Let’s look at some calculations. 220k TCP established connections and 900 requests per second = 110,000 / 900 ~= 120 seconds .I took 110k because 220k connections include both incoming and outgoing. So it’s two way.

Our doubt about 2 minutes being a limit somewhere in the system was verified when we introduced logs on the HAProxy side. We could see 120000 ms as total time for a lot of connections in the logs.

Mar 23 13:24:24 localhost haproxy[53750]: 172.168.0.232:48380 [23/Mar/2017:13:22:22.686] api~ api-backend/http31 39/0/2062/-1/122101 -1 0 - - SD-- 1714/1714/1678/35/0 0/0 {0,"",""} "POST /ping HTTP/1.1"
122101 is the timeout value. See HAProxy documentation on meanings of all these values. 

On investigating further we found out that NodeJs has a default request timeout of 2 minutes. Voila !

how to modify the nodejs request default timeout time?

I was using nodejs request, the default timeout of nodejs http is 120000 ms, but it is not enough for me, while my…stackoverflow.comHTTP | Node.js v7.8.0 Documentation

The HTTP interfaces in Node.js are designed to support many features of the protocol which have been traditionally…nodejs.org

But our happiness was apparently short lived. At 1.3 million, the HAProxy connections suddenly dropped to 0 and started increasing again. We soon checked the dmesg command that provided us some useful kernel level information for our HAProxy process.

Basically, the HAProxy process had gone out of memory. So we decided to increase the machine RAM and we shifted to 16 core 64 Gig machine with nbproc = 3 and because of this change we were able to reach 2.4 million connections.

Backend Code

Following is the backend server code that was being used. We had also used statsd in the server code to get consolidated data on requests per second that were being received by the client.

var http = require('http');var createStatsd = require('uber-statsd-client');qs = require('querystring');
var sdc = createStatsd({host: '172.168.0.134',port: 8125});
var argv = process.argv;var port = argv[2];
function randomIntInc (low, high){ return Math.floor(Math.random() * (high - low + 1) + low);}
function sendResponse(res,times, old_sleep){ res.write('pong'); if(times==0) { res.end(); } else { sleep = randomIntInc(0, old_sleep+1); setTimeout(sendResponse, sleep, res,times-1, old_sleep); }}
var server = http.createServer(function(req, res) headers = req.headers; old_sleep = parseInt(headers["sleep"]); times = headers["times"] );
server.timeout = 3600000;server.listen(port);

We also had a small script to run multiple backend servers. We had 8 machines with 10 backend servers EACH (yeah !). We literally took the idea of clients and backend servers being infinite for the load test, seriously.

counter=0while [ $counter -le 9 ]do port=$((8282+$counter)) nodejs /opt/local/share/test-tools/HikeCLI/nodeclient/httpserver.js $port & echo "Server created on port " $port
 ((counter++))done
echo "Created all servers"

Client Code

As for the client, there was a limitation of 63k TCP connections per IP. If you are not sure about this concept, please refer my previous article in this series.

So in order to achieve 2.4 million connections (two sided which is 1.2 million from the client machines), we needed somewhere around 20 machines. Its a pain really to run the Vegeta command on all 20 machines one by one and even of you found a way to do that using something like csshx, you still would need something to combine all the results from all the Vegeta clients.

Check out the script below.

result_file=$1
declare -a machines=("172.168.0.138" "172.168.0.141" "172.168.0.142" "172.168.0.18" "172.168.0.5" "172.168.0.122" "172.168.0.123" "172.168.0.124" "172.168.0.232" " 172.168.0.244" "172.168.0.170" "172.168.0.179" "172.168.0.59" "172.168.0.68" "172.168.0.137" "172.168.0.155" "172.168.0.154" "172.168.0.45" "172.168.0.136" "172.168.0.143")
bins=""commas=""
for i in "${machines[@]}"; do bins=$bins","$i".bin"; commas=$commas","$i; done;
bins=${bins:1}commas=${commas:1}
pdsh -b -w "$commas" 'echo "POST //test.haproxy.in:80/ping" | /home/sachinm/.linuxbrew/bin/vegeta -cpus=32 attack -connections=1000000 -header="sleep:20" -header="times:2" -body=post_smaller.txt -timeout=2h -rate=3000 -workers=500 > ' $result_file
for i in "${machines[@]}"; do scp [email protected]$i:/home/sachinm/$result_file $i.bin ; done;
vegeta report -inputs="$bins"

Apparently, Vegeta provides information on this utility called pdsh that lets you run a command concurrently on multiple machines remotely . Additionally, the Vegeta allows us to combine multiple results into one and that’s really all we wanted.

HAProxy Configuration

This is probably what you came here looking for, below is the HAProxy config that we used in our load test runs. The most important part being that of the nbproc setting and the maxconn setting. The maxconn setting allows us to provide the maximum number of TCP connections that the HAProxy can support overall (one way).

Changes to maxconn setting leads to increase in HAProxy process’ ulimit. Take a look below

The max open files has increased to 4 million because of the max connections for HAProxy being set at 2 million. Neat !

Ανατρέξτε στο παρακάτω άρθρο για πολλές βελτιστοποιήσεις HAProxy που μπορείτε και πρέπει να κάνετε για να επιτύχετε το είδος των στατιστικών που επιτύχαμε.

Χρησιμοποιήστε το HAProxy για να φορτώσετε ισορροπία 300k ταυτόχρονες συνδέσεις υποδοχής tcp: Θύρα εξάντλησης, Keep-ζωντανή και…

Προσπαθώ να δημιουργήσω ένα σύστημα ώθησης πρόσφατα. Για να αυξήσετε την επεκτασιμότητα του συστήματος, η βέλτιστη πρακτική είναι να κάνετε… www.linangran.com

Το http30 πηγαίνει στο http83: p

Αυτό είναι όλο για τους λαούς. Αν το έχετε κάνει μέχρι τώρα, είμαι πραγματικά έκπληκτος :)

Μια ειδική κραυγή στον Dheeraj Kumar Sidana που μας βοήθησε μέχρι τώρα και χωρίς τη βοήθεια του οποίου δεν θα μπορούσαμε να καταλήξουμε σε ουσιαστικά αποτελέσματα. :)

Επιτρέψτε μου να μάθω πώς σας βοήθησε αυτή η ανάρτηση ιστολογίου. Επίσης, προτείνουμε (❤) και διαδώστε την αγάπη όσο το δυνατόν περισσότερο για αυτήν την ανάρτηση αν νομίζετε ότι αυτό μπορεί να είναι χρήσιμο για κάποιον.