Core concepts

Stick tables

Stick tables are in-memory storage spaces that run inside the load balancer process. They store data about traffic as it passes through the load balancer.

A stick table tracks data types (also known as counters) that count the occurrences of specific events. You can write ACL expressions that trigger actions based on these data types, such as denying a user’s request when that user’s behavior seems abnormal. There is a limited set of data types that you can use.

Stick table are useful for various purposes, including:

  • counting the number of requests a client makes
  • counting errors a client has triggered
  • counting the number of times a webpage has been accessed

Create a stick table Jump to heading

To create a stick table, you can either:

  • add a stick-table directive to a frontend or backend section
  • add a table directive to a peers section

For each stick-table directive that you add to your configuration, the load balancer provisions a new storage area, which is similar to a table in a relational database where each table holds its own set of records.

Use the stick-table directive Jump to heading

To provision a stick table:

  1. Add a stick-table line to a frontend or backend. In the following example, we define a stick table that tracks the HTTP request rate of each client that passes through the load balancer:

    haproxy
    frontend www
    bind :80
    stick-table type ip size 1m expire 10s store http_req_rate(10s)
    haproxy
    frontend www
    bind :80
    stick-table type ip size 1m expire 10s store http_req_rate(10s)

    In this example:

    • The table’s primary key is of type ip, which means that the keys will be IP addresses
    • The table holds a maximum of 1m records, which is 1048576 records
    • A record expires after 10 seconds unless it is accessed during that time
    • We store (associate) the http_req_rate(10s) counter with each IP address, which calculates the HTTP request rate over the last 10 seconds

    You can track more than one counter, as shown below:

    haproxy
    frontend www
    bind :80
    stick-table type ip size 1m expire 10s store http_req_rate(10s),conn_rate(10s),bytes_in_rate(10s)
    haproxy
    frontend www
    bind :80
    stick-table type ip size 1m expire 10s store http_req_rate(10s),conn_rate(10s),bytes_in_rate(10s)
  2. Invoke http-request track-sc0 to add a record to the table. It takes a fetch method whose value will be set as the key in the table. In the following example, we use the client’s source IP address, which we get with the src fetch method, as the key. We also include the http-request deny directive to deny any client whose request rate goes above 10:

    haproxy
    frontend www
    bind :80
    stick-table type ip size 1m expire 10s store http_req_rate(10s)
    http-request track-sc0 src
    http-request deny if { sc_http_req_rate(0) gt 10 }
    haproxy
    frontend www
    bind :80
    stick-table type ip size 1m expire 10s store http_req_rate(10s)
    http-request track-sc0 src
    http-request deny if { sc_http_req_rate(0) gt 10 }

    When the IP address goes into the table, the associated HTTP request rate counter begins counting that client’s rate of requests. Each time that the same client makes a request, this record and its associated counters update.

    The http-request deny directive rejects clients with an HTTP request rate greater than 10 within the time period tracked by the counter: 10 seconds.

Use the table directive Jump to heading

Available since

  • HAProxy 2.0
  • HAProxy Enterprise 2.0r1
  • HAProxy ALOHA 11.5

You can also define a stick table in a peers section via the table directive. When you operate multiple load balancers in an active-active or active-standby setup, then you’ll use a peers section to synchronize stick table data between them. Note that active-active clustering requires an enterprise module.

In the following example, we’ve added a stick table definition via the table line to the peers section and updated it to have the name sticktable1. We then reference it on the http-request track-sc0 and http-request deny lines in the frontend by prefixing it with the peers section name:

haproxy
peers mycluster
peer loadbalancer1 192.168.1.10:10000
peer loadbalancer2 192.168.1.11:10000
table sticktable1 type ip size 1m expire 10s store http_req_rate(10s)
frontend www
bind :80
http-request track-sc0 src table mycluster/sticktable1
http-request deny if { sc_http_req_rate(0,mycluster/sticktable1) gt 10 }
haproxy
peers mycluster
peer loadbalancer1 192.168.1.10:10000
peer loadbalancer2 192.168.1.11:10000
table sticktable1 type ip size 1m expire 10s store http_req_rate(10s)
frontend www
bind :80
http-request track-sc0 src table mycluster/sticktable1
http-request deny if { sc_http_req_rate(0,mycluster/sticktable1) gt 10 }

Stick table arguments Jump to heading

In this section, we will describe a stick table’s arguments.

type Jump to heading

Choose any of the following data types as the primary key in the stick table. Set this as the type argument on the stick table definition.

  • ip
  • ipv6
  • integer
  • string len length
  • binary len length

For example, you could track the HTTP request rate on a per-backend basis rather than on a per-client basis by setting the table’s type to string. Then, change the http-request track-sc0 directive to capture the name of the backend using the be_name fetch method:

haproxy
frontend www
bind :80
stick-table type string size 1m expire 10s store http_req_rate(10s)
use_backend apiservers if { path_beg /api/ }
default_backend webservers
backend webservers
server s1 192.168.50.20:80
http-request track-sc0 be_name table www
backend apiservers
server s1 192.168.50.21:80
http-request track-sc0 be_name table www
haproxy
frontend www
bind :80
stick-table type string size 1m expire 10s store http_req_rate(10s)
use_backend apiservers if { path_beg /api/ }
default_backend webservers
backend webservers
server s1 192.168.50.20:80
http-request track-sc0 be_name table www
backend apiservers
server s1 192.168.50.21:80
http-request track-sc0 be_name table www

size Jump to heading

Set the stick table’s size argument to one of the following values:

Size Number of records the table can store
1 1
1k 1 x 210 = 1024
1m 1 x 220 = 1048576
1g 1 x 230 = 1073741824

Sticky counters Jump to heading

A sticky counter is a variable that temporarily holds the input sample to look up as the primary key in the stick table.

For example, if you want to store a client’s HTTP request rate, you first get their source IP address using the src fetch method. You then store that value in sticky counter 0 by using http-request track-sc0:

haproxy
frontend www
bind :80
stick-table type ip size 1m expire 10s store http_req_rate(10s)
http-request track-sc0 src
haproxy
frontend www
bind :80
stick-table type ip size 1m expire 10s store http_req_rate(10s)
http-request track-sc0 src

An http-request track-sc0 line inserts or updates a record in a stick table. The sc0 part specifies the sticky counter to use. By default, there are three variants of this function, depending on which sticky counter you want to use:

  • http-request track-sc0
  • http-request track-sc1
  • http-request track-sc2

The sticky counter variable sc0 holds the IP address as you create or update the stick table entry. You can track multiple aspects of a request by invoking the other track-sc directives. Below, we track an entry in the table by the client’s source IP address, the name of the backend, and the Host header:

haproxy
peers mycluster
peer loadbalancer1 192.168.1.10:10000
peer loadbalancer2 192.168.1.11:10000
table sticktable1 type ip size 1m expire 10s store http_req_rate(10s)
table sticktable2 type string size 1m expire 10s store http_req_rate(10s)
table sticktable3 type string size 1m expire 10s store http_req_rate(10s)
frontend www
bind :80
# key is source IP address
http-request track-sc0 src table mycluster/sticktable1
# key is backend name
http-request track-sc1 be_name table mycluster/sticktable2
# key is Host header
http-request track-sc2 req.hdr(Host) mycluster/table sticktable3
haproxy
peers mycluster
peer loadbalancer1 192.168.1.10:10000
peer loadbalancer2 192.168.1.11:10000
table sticktable1 type ip size 1m expire 10s store http_req_rate(10s)
table sticktable2 type string size 1m expire 10s store http_req_rate(10s)
table sticktable3 type string size 1m expire 10s store http_req_rate(10s)
frontend www
bind :80
# key is source IP address
http-request track-sc0 src table mycluster/sticktable1
# key is backend name
http-request track-sc1 be_name table mycluster/sticktable2
# key is Host header
http-request track-sc2 req.hdr(Host) mycluster/table sticktable3

All fetch methods that retrieve a record from a stick table use the ID of the sticky counter that holds the key. For instance, the sc_http_req_rate fetch takes the sticky counter number as its first argument:

haproxy
http-request deny if { sc_http_req_rate(0,mysticktable) gt 10 }
haproxy
http-request deny if { sc_http_req_rate(0,mysticktable) gt 10 }

General-purpose counters Jump to heading

There are a number of built-in counters that track a predefined aspect of a request, such as http_req_rate([period]), which tracks HTTP request rate. There are also general-purpose counters, which you can increment manually.

The following stick table registers two general-purpose counters: gpc0 and gpc1. It uses http-request sc-inc-gpc0(0) to increment gpc0 and http-request sc-inc-gpc1(0) to increment gpc1:

haproxy
frontend www
bind :80
stick-table type ip size 1m expire 10s store gpc0,gpc1
http-request track-sc0 src
http-request sc-inc-gpc0(0) if { req.hdr(Host) example.com }
http-request sc-inc-gpc1(0) if { url_param(example) test }
haproxy
frontend www
bind :80
stick-table type ip size 1m expire 10s store gpc0,gpc1
http-request track-sc0 src
http-request sc-inc-gpc0(0) if { req.hdr(Host) example.com }
http-request sc-inc-gpc1(0) if { url_param(example) test }

Here, gpc0 increments whenever a request’s Host header equals example.com. The gpc1 counter increments whenever the URL parameter example has the value test.

Use the gpc0_rate([period]) and gpc1_rate([period]) counters to track the rate at which the gpc0 and gpc1 counters increment during the given time period:

haproxy
frontend www
bind :80
stick-table type ip size 1m expire 10s store gpc0,gpc1,gpc0_rate(10s),gpc1_rate(10s)
haproxy
frontend www
bind :80
stick-table type ip size 1m expire 10s store gpc0,gpc1,gpc0_rate(10s),gpc1_rate(10s)

Synchronize stick tables across peers Jump to heading

A peers section enables the replication of stick table data between two or more load balancers. This feature implements one-way replication of data. This makes it ideal for an active-standby cluster where the active node pushes data to the standby node. When the data replicates from the active node to the standby node, it overwrites existing data on the standby node. For active-active clustering, enterprise modules exist.

Enable synchronization Jump to heading

To enable synchronization:

  1. Add one or more peer lines to a peers section. Each one identifies a load balancer that takes part in the synchronization. One of the peer lines must be the local host:

    haproxy
    peers mycluster
    # local host, active node
    peer loadbalancer1 192.168.1.10:10000
    # standby node
    peer loadbalancer2 192.168.1.11:10000
    haproxy
    peers mycluster
    # local host, active node
    peer loadbalancer1 192.168.1.10:10000
    # standby node
    peer loadbalancer2 192.168.1.11:10000

    Ensure the host name specified in the peer directive for the local host matches the name of the host as determined by one of the following methods, in order of precedence:

    • The -L argument specified in the command line used to start the load balancer process.
    • The localpeer name specified in the global section of the load balancer configuration.
    • The host name returned by the hostname command. This is the default. The other methods are recommended.

    It is strongly recommended you use the exact same peers section on all peers and then rely on the -L or localpeer methods, above, to set the peer host name for each load balancer. This type of configuration makes it easier to maintain a consistent configuration across all peers.

  2. Add a peers attribute to your stick-table directive to include that stick table in the synchronization. The attribute references the name of the peers section you defined:

    haproxy
    backend
    stick-table type ip size 1m expire 10s store http_req_rate(10s) peers mycluster
    haproxy
    backend
    stick-table type ip size 1m expire 10s store http_req_rate(10s) peers mycluster

Persist data at reload Jump to heading

A useful side effect of using a peers section is that the load balancer will persist stick table data after a reload. This is because during a reload the old process connects to the new one and shares all of its stick table entries with it.

To use this feature, define a peers section with only the local host address:

haproxy
peers mycluster
peer local 127.0.0.1:10000
haproxy
peers mycluster
peer local 127.0.0.1:10000

Without this, stick table data will be lost during a reload.

Add tables to peers section Jump to heading

Available since

  • HAProxy 2.0
  • HAProxy Enterprise 2.0r1
  • HAProxy ALOHA 11.5

You can also add stick table definitions directly to the peers section, in which case you do not need to use the peers attribute on the stick table. Then, reference the table as peers-section-name/table-name.

In the following example, we’ve added a stick table definition via the table line to the peers section and updated it to have the name sticktable1. We then reference it on the http-request track-sc0 and http-request deny lines in the frontend:

haproxy
peers mycluster
peer loadbalancer1 192.168.1.10:10000
peer loadbalancer2 192.168.1.11:10000
table sticktable1 type ip size 1m expire 10s store http_req_rate(10s)
frontend www
bind :80
http-request track-sc0 src table mycluster/sticktable1
http-request deny if { sc_http_req_rate(0,mycluster/sticktable1) gt 10 }
haproxy
peers mycluster
peer loadbalancer1 192.168.1.10:10000
peer loadbalancer2 192.168.1.11:10000
table sticktable1 type ip size 1m expire 10s store http_req_rate(10s)
frontend www
bind :80
http-request track-sc0 src table mycluster/sticktable1
http-request deny if { sc_http_req_rate(0,mycluster/sticktable1) gt 10 }

Server syntax Jump to heading

Available since

  • HAProxy 2.0
  • HAProxy Enterprise 2.0r1
  • HAProxy ALOHA 11.5

Instead of writing peer lines, you can useserver lines. This allows the same functionality of a server as seen in a backend section, such as the ability to connect to the remote peer using TLS. You can also use a default-server line to set defaults for the server lines that follow.

haproxy
peers mycluster
# peers will receive sync traffic over the bound port
# optional: enable SSL
bind :10000 ssl crt /ssl.pem
# define defaults for 'server' lines
# e.g. 'ssl', peers will send sync traffic using SSL
default-server ssl
# do not set an IP address and port for the local peer
server loadbalancer1
server loadbalancer2 192.168.1.11:10000
haproxy
peers mycluster
# peers will receive sync traffic over the bound port
# optional: enable SSL
bind :10000 ssl crt /ssl.pem
# define defaults for 'server' lines
# e.g. 'ssl', peers will send sync traffic using SSL
default-server ssl
# do not set an IP address and port for the local peer
server loadbalancer1
server loadbalancer2 192.168.1.11:10000

See also Jump to heading

Do you have any suggestions on how we can improve the content of this page?