Manual Load Balancing with HAProxy

WebViewer Server comes with a load balancer known as HAProxy located at our pdftron/wv-loadbalancer repository on DockerHub. This can be used in conjunction with WebViewer Server to load balance.

This guide details how to manage load balancing using the HAProxy image, in a way that is extensible to any environment.

How it works

HAProxy contains network entries called webAwebBwebC ... and so on. These entries indicate the location of a server that HAProxy can send requests to. The methods here will modify these entries to point at the correct server.

By default WebViewer Server does all load balancing using the leastconn method. This sends incoming requests to servers with the smallest number of active connections.

Setting initial servers

You can set the initial locations of these webX entries by setting the environment variables INITIAL_NODE_AINITIAL_NODE_B ... up to INITIAL_NODE_F on the wv-loadbalancer image. HAProxy will initially send requests to any healthy and responding servers set in these variables.

Setting servers dynamically

To set servers dynamically with HAProxy you can take advantage of something known as TCP Management - this can be used to change these webX entries to the current location of a server.

There are several ways to send requests to the server with this method, but all commands to HAProxy will be sent with the same structure.

set server nodes/[webX] addr [WVS ip address] [WVS port]

  • Locally in the server hosting HAProxy using sockets - this can be done through a socket communication application such as socat

Bash

1socat /var/run/hapee.sock set server nodes/webA addr 192.168.1.1 8090
  • Remotely by setting ENABLE_TCP_MANAGEMENT to true on the Docker image and sending requests to the TCP Management port 4893 wherever the balancer is located. The following code does this using Node.js.

JavaScript

1const connectSocket = (balancer) => {
2 return new Promise((resolve, reject) => {
3 var socket = new net.createConnection(4893, balancer);
4 socket.on('connect', () => {
5 resolve(socket);
6 });
7
8 socket.on('error', () => {
9 reject(balancer + ": Balancer not online.");
10 });
11 });
12};
13const writeSocket = (command, socket, forceClose) => {
14 return new Promise((resolve, reject) => {
15 console.log(command);
16 socket.write(command, (error, data) => {
17 if (error) {
18 console.log(error);
19 reject();
20 }
21 });
22
23 socket.on('data', (data) => {
24 //console.log("balancer response:" + data);
25 socket.end();
26 resolve(data);
27 });
28 });
29};
30command = "set server nodes/webA addr 192.168.1.1 8090\n"
31var socket = await connectSocket("insert balancer ip here");
32await writeSocket(command, socket, false)

The above code sets webA to be the Webviewer Server at 192.168.1.1:8090. HAProxy will now send webA requests to this server.

Whenever a change occurs, you can dynamically rewrite remotely using the above code. The changes will instantly occur. More commands can be found at the HAProxy Management documentation

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales