Nginx vs haproxy
Содержание:
II.3. Galera cluster check
Install a local service on the Galera nodes:
$ sudo apt-get install xinetd -y$ wget -O /usr/bin/clustercheck https://raw.githubusercontent.com/olafz/percona-clustercheck/master/clustercheck$ sudo chmod 755 /usr/bin/clustercheck$ sudo cat > /etc/xinetd.d/mysqlchk <<EOFservice mysqlchk{ disable = no flags = REUSE socket_type = stream port = 9200 wait = no user = nobody server = /usr/bin/clustercheck log_on_failure += USERID only_from = 0.0.0.0/0 bind = <galera_public_interface> per_source = UNLIMITED}EOF$ sudo echo "mysqlchk 9200/tcp" | tee -a /etc/services$ sudo service xinetd restart
|
Using ACLs to block requests
Now that you’ve familiarized yourself with ACLs, it’s time to do some request blocking!
The command returns a 403 to the client and immediately stops processing the request. This is frequently used for DDoS/Bot mitigation as HAProxy can deny a very large volume of requests without bothering the web server.
Other responses similar to this include (keep the request hanging until timeout tarpit expires, then return a 500 – good for slowing down bots by overloading their connection tables, if there aren’t too many of them), (have HAProxy stop processing the request but tell the kernel to not notify the client of this – leaves the connection from a client perspective open, but closed from the HAProxy perspective; be aware of stateful firewalls).
With both deny and tarpit you can add the flag to set a custom response code instead of the default 403/500 that they use out of the box. For example using will cause HAProxy to respond to the client with the error 429: Too Many Requests.
In the following subsections we will provide a number of static conditions for which blocking traffic can be useful.
HTTP protocol version
A number of attacks use HTTP 1.0 as the protocol version, so if that is the case it’s easy to block these attacks using the built-in ACL :
Contents of the user-agent string
We can also inspect the User-Agent header and deny if it matches a specified string.
This line will deny the request if the part of the user-agent request header contains the string evil anywhere in it. Remove the , leaving you with as the condition, and it will be an exact match instead of a substring.
Length of the user-agent string
Some attackers will attempt to bypass normal user agent strings by using a random md5sum, which can be identified by length and immediately blocked:
Attackers can vary more with their attacks, so you can rely on the fact that legitimate user agents are longer while also being set to a minimum length:
This will then block any requests which have a user-agent header shorter than 32 characters.
Path
If an attacker is abusing a specific URL that legitimate clients don’t, one can block based on path:
Or you can prevent an attacker from accessing hidden files or folders:
III.2 Init script GLB
First download it from here and install it 🙂
Init script for the Galera Load Balancer daemon.
Start/Stop the Galera Load Balancer daemon.Download me
#!/bin/shprog="glbd"proc=glbdexec=/usr/sbin/glbdLISTEN_PORT="8010"CONTROL_PORT="8011"THREADS="2"DEFAULT_TARGETS="djdb2:8000:0.75 djdb3:8000:0.75 divjobs3:8000:0.75 divjobs4:8000:1"stop() { echo -n " $prog: stopping... " killall $exec &> /dev/null if ; then echo "failed." return fi echo "done."}start() { if pidof $prog &> /dev/null ; then echo " $prog: already running..."; exit -1 fi echo " $prog: starting..." wait_for_connections_to_drop $exec --daemon --control 127.0.0.1:$CONTROL_PORT --threads $THREADS $LISTEN_PORT $DEFAULT_TARGETS PID=$! if ; then echo " $prog: failed to start." exit -1 fi echo " $prog: started, pid=$PID" exit 0}restart() { echo " $prog: restarting..." stop start}wait_for_connections_to_drop() { while (netstat -na | grep -m 1 ":$LISTEN_PORT" &> /dev/null); do echo " $prog: waiting for lingering sockets to clear up..." sleep 1s done;}getinfo() { echo getinfo | nc 127.0.0.1 $CONTROL_PORT && exit 0 echo " $prog: failed to query 'getinfo' from 127.0.0.1:$CONTROL_PORT" exit -1}getstats() { echo getstats | nc 127.0.0.1 $CONTROL_PORT && exit 0 echo " $prog: failed to query 'getstats' from 127.0.0.1:$CONTROL_PORT" exit -1}add() { if ; then echo $"Usage: $0 add <ip>:<port>" exit -1 fi if ; then echo " $prog: added '$1' successfully" exit 0 fi echo " $prog: failed to add target '$1'." exit -1}remove() { if ; then echo $"Usage: $0 remove <ip>:<port>" exit -1 fi if ; then echo " $prog: removed '$1' successfully" exit 0 fi echo " $prog: failed to remove target '$1'." exit -1}case $1 in start) start ;; stop) stop ;; restart) restart ;; getinfo) getinfo ;; getstats) getstats ;; status) getinfo ;; add) add $2 ;; remove) remove $2 ;; *) echo $"Usage: $0 {start|stop|restart|status|getstats|getinfo|add|remove}" exit 2esac
|
Load Balancing

With HAProxy, the load balancing algorithm can be adjusted to suit the type of service and protocol
In order to improve the performance and resilience of each API endpoint, it’s recommended to replicate the service over several nodes. Then, the API gateway will balance incoming client requests among them. You can adjust the load balancing algorithm to suit the type of service and protocol.
- For quick and short API calls, use the algorithm
- For longer-lived websockets, use the algorithm
- For services that have backend servers optimized to process particular functions, use the algorithm
In the following example, the mobile API backend is balanced across two nodes using the algorithm.
Load balancing your API endpoints improves performance and creates redundancy. Note that you can choose the most appropriate balancing algorithm on a per-backend basis.
You can also define active and passive health checks for your servers so that HAProxy automatically reroutes traffic if there’s a problem. In the following example, we monitor the health of our servers by sending GET requests to the /health URL and expecting a successful response.
The directive sets the method and URL to monitor. If you append you can add additional HTTP headers to this request. A parameter is added to each to enable the feature. Being able to watch a URL endpoint works well with tools like Prometheus that already expose a /metrics web page used for scraping metrics.
Step 1 — Installing ProxySQL
The developers of ProxySQL provide official Ubuntu packages for all ProxySQL releases on their GitHub releases page, so we’ll download the latest package version from there and install it.
You can find the latest package on the release list. The naming convention is , where is a string like for version 1.4.4, and is a string like for 64-bit Ubuntu 16.04.
Download the latest official package, which is 1.4.4 at the time of writing, into the directory.
Install the package with , which is used to manage software packages. The flag indicates that we’d like to install from the specified file.
At this point, you no longer need the file, so you can remove it.
Next, we’ll need a MySQL client application to connect to the ProxySQL instance. This is because ProxySQL internally uses a MySQL-compatible interface for administrative tasks. We’ll use is the command line tool, which is part of the package available in the Ubuntu repositories.
Update your package repository to make sure you’re getting the latest pre-bundled version, then install the package.
You now have all of the requirements to run ProxySQL, but the service doesn’t automatically start after installation, so start it manually now.
ProxySQL should now be running with its default configuration in place. You can check using .
The output will look similar to this:
The line means ProxySQL is installed and running.
Next, we’ll increase security by setting the password used to access ProxySQL’s administrative interface.
Other Considerations
inspect-delay
Let’s talk about a line that is sometimes needed and ends up causing confusion:
You only need to use this in a frontend or backend when you have an ACL on a statement that would be processed in an earlier phase than HAProxy would normally have the information. For example, needs a because HAProxy won’t wait in the TCP phase for the HTTP URL path data. In contrast doesn’t need an line because HAProxy won’t process http-request rules until it has an HTTP request.
When is present, it will hold the request until the rules in that block have the data they need to make a decision or until the specified delay is reached, whichever is first.
nbproc
If you are using the directive in the section of your configuration, then each HAProxy process has its own set of stick tables. The net effect is that you’re not sharing stick table information among those processes. Also note that the peers protocol, discussed next, can’t sync between processes on the same machine.
There are two ways to solve this. The first is to use the newer directive instead. This is a feature introduced in HAProxy Enterprise 1.8r1 and HAProxy 1.8 that enables multithreading instead of multiple processes and shares memory, thus sharing stick tables between threads running in a single process. See our blog post Multithreading in HAProxy to learn more about it.
Another solution is to use a configuration like the following:
The first proxy terminates TLS and passes traffic to a single server listed as server local unix:/var/run/hapee-1.8/ssl_handoff.sock send-proxy-v2. Then you add another frontend with bind unix:/var/run/hapee-1.8/ssl_handoff.sock accept-proxy process 1 in it. Inside this frontend you can have all of your stick table and statistics collection without issue. Since TLS termination usually takes most of the CPU time, it’s highly unusual to need more than one process for the backend work.
peers
Now that we’ve covered how to use stick tables, something to consider is setups that utilize HAProxy in active-active clusters, where a new connection from a client may end up at one of multiple HAProxy servers, such as by Route Health Injection or Amazon Elastic Load Balancer. One server has all of the stick table entries, but the other node has its own set of stick table definitions. To solve that problem you can add a section to the top of your configuration:
Then change your stick table definition to include a argument:
At least one of the peers needs to have a name that matches the server’s host name or you must include a line in the section of the configuration to inform HAProxy what it should see the host name as.
Now the two servers will exchange stick table entries; but there is a downside: they won’t sum their individual counters, so on one will overwrite the value on the other, rather than both seeing a sum of the two.
Enter the Stick Table Aggregator. This is a feature of HAProxy Enterprise that watches for values coming in over the peers protocol, adds the values together, then returns the combined result back to each of the HAProxy instances. The benefit of this is the ability to associate events that you wouldn’t be able to otherwise, since the data resides on two or more different nodes.
For example, in an active-active cluster of HAProxy load balancers, an attacker will be hitting both instances. If you aren’t combining the data, you’re only seeing half of the picture. Getting an accurate representation of the state of your nodes is important to detecting and stopping attacks. Here’s a representation of how the aggregator allows peers to exchange information:

Syncing multiple peers through Stick Table Aggregators
Check out our webinar DDoS Attack and Bot Protection with HAProxy Enterprise for a full example of using the Stick Table Aggregator.
Step 5 — Adding MySQL Nodes to the ProxySQL Server Pool
To make ProxySQL aware of our three MySQL nodes, we need to tell ProxySQL how to distribute them across its host groups, which are designated sets of nodes. Each host group is identified by a positive number, like or . Host groups can route different SQL queries to different sets of hosts when using ProxySQL query routing.
In static replication configurations, host groups can be set arbitrarily. However, ProxySQL’s group replication support automatically divides all nodes in a replication group into four logical states:
- writers, which are MySQL nodes that can accept queries that change data. ProxySQL makes sure to maintain all primary nodes up to the maximum defined amount in this group.
- backup writers, which are also MySQL nodes that can accept queries that change data. However, those nodes are not designated as writers; primary nodes exceeding the defined amount of maintained writers are kept in this group, and are promoted to writers if one of the writers fails.
- readers are MySQL nodes that cannot accept queries changing data and should be used as read-only nodes. ProxySQL puts only slave nodes here.
- offline, which is for nodes that are misbehaving due to issues like lack of connectivity or slow traffic.
Each of these four states have corresponding host groups, but the numerical group identifiers are not assigned automatically.
Putting it all together, we need to tell ProxySQL which identifiers it should use for each state. Here, we use for the offline host group, for the writer host group, for the reader host group, and for the backup writer host group.
To set these identifiers, create a new row with those variables and values in the configuration table.
These are the additional variables set in this row and what each one does:
- set to enables ProxySQL’s monitoring of these host groups.
- defines how many nodes can act as writers. We used here because In a multi-primary configuration, all nodes can be treated equal, so here we used (the total number of nodes).
- set to instructs ProxySQL to treat writers as readers as well.
- sets the maximum number of delayed transactions before a node is classified as offline.
Note: Because our example uses a multi-primary topology in which all nodes can write to the database, we will balance all SQL queries across the writer host group. On other topologies, the division between writer (primary) nodes and reader (secondary) nodes can route read-only queries to different nodes/host groups than write queries. ProxySQL does not automatically do this, but you can set up query routing using rules.
Now that ProxySQL knows how to distribute nodes across host groups, we can add our MySQL servers to the pool. To do so, we need to the IP address and initial host group of each server into the table, which contains the list of servers ProxySQL can interact with.
Add each of the three MySQL servers, making sure to replace the example IP addresses in the commands below.
Here, the value sets all of these nodes to be writers initially, and sets the default MySQL port.
Just like before, migrate these changes into runtime and save them to disk to put the changes into effect.
ProxySQL should now distribute our nodes across the host groups as specified. Let’s check that by executing a query against the table, which exposes the current state of the servers ProxySQL is using.
In the results table, each server is listed twice: once each for host group IDs and , indicating that all three nodes are both writers and readers. All nodes are marked , meaning they’re ready to be used.
However, before we can use them, we have to configure user credentials to access the MySQL databases on each node.
3: Настройка мониторинга MySQL
ProxySQL должен связываться с нодами MySQL, чтобы оценить их состояние. Для этого он должен иметь возможность подключаться к каждому серверу с помощью специального пользователя.
На данном этапе нужно настроить таких пользователей на нодах MySQL и установить дополнительные функции SQL, которые позволяют ProxySQL запрашивать состояние группы репликации.
Примечание: Поскольку группа репликации MySQL уже запущена, все последующие действия нужно выполнить только на одной ноде.
Откройте второй терминал и подключитесь по ssh у одной из нод.
Загрузите файл SQL, содержащий некоторые функции, необходимые для поддержки группы репликации ProxySQL.
Примечание: Этот файл предоставляется авторами ProxySQL, но специальным образом: это gist в личном хранилище GitHub, что означает, что файл может переместиться или устареть. В будущем его могут поместить в официальный репозиторий ProxySQL.
Просмотреть содержимое файла можно с помощью этой команды:
Выполните команды в файле. Вам будет предложено ввести пароль администратора MySQL.
Если команда выполнена успешно, она не вернет результат. В этом случае все ноды MySQL откроют ProxySQL необходимые функции для распознавания состояния группы репликации.
Затем нужно создать выделенного пользователя, который будет использоваться ProxySQL для мониторинга работоспособности экземпляров.
Откройте интерактивную строку MySQL, которая снова запросит пароль root.
mysql -u root -p
Затем создайте выделенного пользователя (здесь он называется monitor). Обязательно укажите надежный пароль.
Предоставьте пользователю права запрашивать состояние сервера MySQL у пользователя monitor.
Сбросьте привилегии, чтобы обновить настройки:
Благодаря репликации пользователь появится на всех трех нодах, как только вы как только вы добавите его на одну из нод MySQL.
Затем нужно предоставить ProxySQL информацию об этом пользователе, чтобы он мог получить доступ к нодам MySQL.
Formatting an ACL
There are two ways of specifying an ACL – a named ACL and an anonymous or in-line ACL.
The first form is a named ACL:
We begin with the acl keyword, followed by a name, followed by the condition. Here we have an ACL named . This ACL name can then be used with and statements such as . This form is recommended when you are going to use a given condition for multiple actions.
The condition, , checks to see if the URL starts with /static/. You’ll see how that works along with other types of conditions later in this article.
The second form is an anonymous or in-line ACL:
This does the same thing that the above two lines would do, just in one line. For in-line ACLs the condition is contained inside curly braces.
In both cases, you can chain multiple conditions together. ACLs listed one after another without anything in between will be considered to be joined with an and. The condition overall is only true if both ACLs are true.
This will prevent any client in the 10.0.0.0/16 subnet from accessing anything starting with /api/, while still being able to access other paths.
Adding an exclamation mark inverts a condition:
Now only clients in the 10.0.0.0/16 subnet are allowed to access paths starting with /api/ while all others will be forbidden.
The IP addresses could also be imported from a file:
Within blacklist.acl you would then list individual or a range of IP addresses using CIDR notation to block, as follows:
You can also define an ACL where either condition can be by using :
With this, each request whose path starts with /evil/ (e.g. /evil/foo) or ends with /evil (e.g. /foo/evil) will be denied.
You can also do the same to combine named ACLs:
With named ACLs, specifying the same ACL name multiple times will cause a logical OR of the conditions, so the last block can also be expressed as:
This allows you to combine ANDs and ORs (as well as named and in-line ACLs) to build more complicated conditions, for example:
This will block the request if the path starts or ends with /evil, but only for clients that are not in the 10.0.0.0/16 subnet.
Did you know? Innovations such as Elastic Binary Trees or EB trees have shaped ACLs into the high performing feature they are today. For example, string and IP address matches rely on EB trees that allow ACLs to process millions of entries while maintaining the best in class performance and efficiency that HAProxy is known for.
From what we’ve seen so far, each ACL condition is broken into two parts—the source of the information (or a fetch) such as path and src and the string it is matching against. In the middle of these two parts, one can specify flags (such as for a case-insensitive match) and a matching method ( to match on the beginning of a string, for example). All of these components of an ACL will be expanded on in the following sections.
Active Health Checks
The easiest way to check whether a server is up is with the directive’s parameter. This is known as an active health check. It means that HAProxy polls the server on a fixed interval by trying to make a TCP connection. If it can’t contact a server, the check fails and that server is removed from the load balancing rotation.
Consider the following example:
When you’ve enabled active checking, you can then add other, optional parameters, such as to change the polling interval and/or the number of allowed failed checks:
| Parameter | What it does |
| The interval between checks (defaults to milliseconds, but you can set seconds with the s suffix). | |
| The interval between checks when the server is already in the down state. | |
| The number of failed checks before marking the server as down. | |
| The number of successful checks before marking a server as up again. | |
| The interval between checks when up, but a check has failed; or the interval when down, but a check has passed. You are transitioning towards up or down. This allows you to speed up the interval. |
The next example demonstrates these parameters:
If you’re load balancing web applications, then instead of monitoring a server based on whether you can make a TCP connection, you can send an HTTP request. Add to a and HAProxy will continually send requests and expect to receive valid HTTP responses that have a status code in the 2xx to 3xx range.
The directive also lets you choose the HTTP method (e.g. GET, HEAD, OPTIONS), as well as the URL to monitor. Having this flexibility means that you can dedicate a specific webpage to be the health-check endpoint. For example, if you’re using a tool like Prometheus, which exposes its metrics on a dedicated page within the application, you could target its URL. Or, you could point HAProxy at the homepage of your website, which is arguably the most important.
You can also set a different IP address and/or port to check by adding the and parameters, respectively, to the line. In the following snippet, we target port 80 for our health checks, even though normal web traffic is sent to port 443:
Some web servers will reject requests that don’t include certain headers, such as a Host header. You can pass HTTP headers with the health check, like so:
You can accept only specific responses from the server, such as a specific status code or string within the HTTP body. Use with either the status or string keyword. In the following example, only health checks that return a 200 OK response are classified as successful:
Or, require that the response body contain a certain case-sensitive string of text:
You can also have one server delegate its own status to another server by adding a parameter to a line. It should be set to the name of a backend and server. If the tracked server is down, the server tracking it will also be down.
Step 4 — Configuring Monitoring in ProxySQL
To configure ProxySQL to use the new user account when monitoring nodes, we’ll the appropriate configuration variable. This is very similar to the way we set the admin password from Step 2.
Back in the ProxySQL admin interface, update the variable to the username of the new account.
Just like before, the configuration is not automatically applied, so migrate it into runtime and save to disk. This time, notice that we’re using instead of to update these variables because we’re modifying MySQL configuration variables.
The monitoring account is configured on all ends, and the next step is to tell ProxySQL about the nodes themselves.
Frontend
When you place HAProxy as a reverse proxy in front of your backend servers, a section defines the IP addresses and ports that clients can connect to. You may add as many sections as needed for exposing various websites to the Internet. Each keyword is followed by a label, such as www.mysite.com, to differentiate it from others.
Consider the following example:
Let’s see what these lines mean.
bind
A setting assigns a listener to a given IP address and port. The IP can be omitted to bind to all IP addresses on the server and a port can be a single port, a range, or a comma-delimited list. You’ll often use the and arguments to instruct HAProxy to manage SSL/TLS terminations, rather than having your web servers doing that.
Did You Know? If you have enabled HAProxy to use multiple processes via , then you can tell each bind directive which process to use with the parameter. For example, setting would bind the listener to the first process.
http-request redirect
A setting responds to the client that they should try a different URL. In our example, clients that request your website over non-encrypted HTTP are redirected to the HTTPS version of the site.
use_backend
The setting chooses a backend pool of servers to respond to incoming requests if a given condition is true. It is followed by an ACL statement, such as , that allows HAProxy to select a specific backend based on some criteria, such as checking if the path begins with /api/. To learn more about ACLs, read our blog post Introduction to HAProxy ACLs. These lines aren’t required and many frontend sections only have a line and no special selection rules.
default_backend
The setting is found in nearly every and gives the name of a to send traffic to if a rule doesn’t send it elsewhere first. If a request isn’t routed by a or directive, HAProxy will return a 503 Service Unavailable error.
2: Пароль администратора ProxySQL
При первом запуске новой установки ProxySQL использует стандартный конфигурационный файл для инициализации значений по умолчанию всех своих переменных. После этой инициализации ProxySQL сохраняет свою конфигурацию в базе данных, которой можно управлять и изменять с помощью командной строки.
Чтобы установить пароль администратора в ProxySQL, подключитесь к этой базе данных конфигурации и обновите соответствующие переменные.
Сначала откройте интерфейс администратора. При этом будет запрошен пароль, по умолчанию это admin.
-u определяет пользователя, через которого нужно подключиться. Здесь это admin, стандартный пользователь для выполнения административных задач, таких как изменение настроек конфигурации.
-h 127.0.0.1 помогает mysql подключиться к локальному экземпляру ProxySQL. Это нужно определить явно, потому что ProxySQL не прослушивает файл сокета, который mysql принимает по умолчанию.
-P определяет порт, к которому нужно подклюиться. Интерфейс администратора ProxySQL прослушивает порт 6032.
—prompt –опциональный флаг, который меняет стандартную командную строку (обычно это mysql>). Здесь она заменяется строкой ProxySQLAdmin> — это поможет вам понять, что вы находитесь в интерфейсе админа ProxySQL, и избежать путаницы, когда вы подключитесь к интерфейсам MySQL на реплицированных серверах баз данных.
Подключившись, вы увидите строку ProxySQLAdmin>:
Измените пароль учетной записи администратора, обновив переменную admin-admin_credentials в базе данных global_variables. Не забудьте заменить password в приведенной ниже команде надежным паролем:
Это изменение не будет выполнено немедленно, потому что так работает система конфигурации ProxySQL. Она состоит из трех отдельных слоев:
- memory, который изменяется при внесении изменений из интерфейса командной строки.
- runtime, который используется ProxySQL в качестве текущей конфигурации.
- disk, который используется для сохранения конфигурации при перезапуске.
На данный момент внесенное вами изменение находится в слое memory. Чтобы изменения вступили в силу, необходимо скопировать настройки памяти в область runtime, а затем сохранить их в disk.
Эти команды ADMIN обрабатывают только переменные, связанные с интерфейсом командной строки администрирования. ProxySQL предоставляет аналогичные команды, например MYSQL, для обработки других частей своей конфигурации. Но об этом немного позже.
Теперь, когда ProxySQL установлен и запущен с новым паролем администратора, нужно настроить 3 ноды MySQL, чтобы ProxySQL мог ими управлять. Пока не закрывайте интерфейс ProxySQL – мы будем использовать его позже.
Why does TCP port exhaustion occur with MySQL clients???
As I said, the MySQL request rate was a few thousands per second, so we never ever reach this limit of 64K simultaneous opened connections to the remote service…What’s up then???
Well, there is an issue with MySQL client library: when a client sends its “QUIT” sequence, it performs a few internal operations before immediately shutting down the TCP connection, without waiting for the server to do it. A basic tcpdump will show it to you easily.
Note that you won’t be able to reproduce this issue on a loopback interface, because the server answers fast enough… You must use a LAN connection and 2 different servers.
Basically, here is the sequence currently performed by a MySQL client:
Mysql Client ==> "QUIT" sequence ==> Mysql Server Mysql Client ==> FIN ==> MySQL Server Mysql Client <== FIN ACK <== MySQL Server Mysql Client ==> ACK ==> MySQL Server
Which leads the client connection to remain unavailable for twice the MSL (Maximum Segment Life) time, which means 2 minutes.
Note: this type of close has no negative impact when the connection is made over a UNIX socket.
Explication of the issue (much better that I could explain it myself):
“There is no way for the person who sent the first FIN to get an ACK back for that last ACK. You might want to reread that now. The person that initially closed the connection enters the TIME_WAIT state; in case the other person didn’t really get the ACK and thinks the connection is still open. Typically, this lasts one to two minutes.” (Source)
Since the source port is unavailable for the system for 2 minutes, this means that over 534 MySQL requests per seconds you’re in danger of TCP source port exhaustion: 64000 (available ports) / 120 (number of seconds in 2 minutes) = 533.333.
This TCP port exhaustion appears on the MySQL client server itself, but as well on the HAProxy box because it forwards the client traffic to the server… And since we have many web servers, it happens much faster on the HAProxy box !!!!
Remember: at spike traffic, my customer had a few thousands requests/s….
Multithreading Configuration
By default, HAProxy will start one process and one thread. To start more threads, you should set the option “” in the global configuration section.
Please note that the option “” is compatible with ““, which means that it is even possible to start multiple HAProxy processes with multiple threads in each.
Both the processes and threads should then also be mapped to CPU cores by using the configuration directive “”.
The complete configuration needed to run a single HAProxy process (1) with 4 threads (1-4) mapped to first four CPU cores (0-3) would look like the following:
global nbproc 1 nbthread 4 cpu-map auto:1/1-4 0-3
And that is basically all there is to it for a simple, fully functional use case!
Please refer to the HAProxy Configuration Guide, sections , and for the complete description of all the available options.
Prepare MySQL Servers
We need to prepare the MySQL servers by creating two additional users for HAProxy. The first user will be used by HAProxy to check the status of a server.
A MySQL user is needed with root privileges when accessing the MySQL cluster from HAProxy. The default root user on all the servers are allowed to login only locally. While this can be fixed by granting additional privileges to the root user, it is better to have a separate user with root privileges.
Replace haproxy_root and password with your own secure values. It is enough to execute these queries on one MySQL master as changes will replicate to others.