HAProxy Enterprise Documentation 2.2r1

gRPC

gRPC is a remote procedure call framework that allows a client application to invoke an API function on a server as if that function were defined in the client's own code. It uses Protocol Buffers to serialize messages, which allows clients and servers to exchange messages even when the two are written using different programming languages. gRPC offers bidirectional streaming of messages, meaning that an interaction between the client and server can be initiated from either side and once a connecton is established, calls can be streamed continuously similar to the WebSocket protocol.

HAProxy Enterprise can act as a Layer 7 proxy for gRPC traffic because gRPC uses HTTP/2 as its transport protocol. This gives you access to fetch methods for inspecting the messages as they pass through the load balancer.

Enable gRPC over HTTP/2

  1. To enable HTTP/2 between clients and HAProxy Enterprise, configure the bind line in a frontend section as an ssl endpoint. The proto parameter announces that the load balancer supports HTTP/2 (h2):

    frontend grpc_service
       mode http
       bind :3001 proto h2
       default_backend grpc_servers
  2. Configure SSL/TLS connections to the servers in the backend section and specify the HTTP/2 protocol:

    backend grpc_servers
       mode http
       balance roundrobin
       server s1 192.168.0.10:3000 check proto h2
       server s2 192.168.0.10:3000 check proto h2

Example

In this example, you use a gRPC service called RollDiceService that returns a random number between 1 and 6 and a gRPC client that calls the service.

  1. Download the client and server binaries.

  2. On your HAProxy Enterprise server, start the server binary so that it listens on port 3000:

    $ SERVER_ADDRESS=:3000 ./server
    
    2020/12/18 17:36:12 Listening on address :3000
  3. Update your HAProxy Enterprise configuration to have a frontend and backend that receives gRPC traffic and forwards it to the server you just started. Add proto h2 to the bind and server lines to use HTTP/2 as the protocol:

    frontend grpc_service
       mode http
       bind :3001 proto h2
       default_backend grpc_servers
    
    backend grpc_servers
       mode http
       server s1 127.0.0.1:3000 check proto h2
  4. Either on the HAProxy Enterprise server or another Linux machine on the network, start the client binary to connect to the gRPC service via the load balancer at port 3001. This will show the output of the client calling the RollDice function on the service:

    $ SERVER_ADDRESS=localhost:3001 NUMBER_OF_DICE=2 ./client
    
    2020/12/18 18:08:09 Rolling 2 dice...
    2020/12/18 18:08:09 roll: 4
    2020/12/18 18:08:09 roll: 1
    2020/12/18 18:08:11 Rolling 2 dice...
    2020/12/18 18:08:11 roll: 2
    2020/12/18 18:08:11 roll: 6
  5. Follow the HAProxy Enterprise access log to see the requests flow through the load balancer:

    $ sudo tail -f /var/log/2.2/lb-access-20201218.log
    
    Dec 18 18:08:21 lb1 hapee-lb[5699]: 127.0.0.1:51780 [18/Dec/2020:18:08:21.722] grpc_service grpc_servers/s1 0/0/0/1/+1 200 +99 - - ---- 1/1/1/0/0 0/0 "POST http://localhost:3001/RollDiceService/RollDice HTTP/2.0"
    Dec 18 18:08:23 lb1 hapee-lb[5699]: 127.0.0.1:51780 [18/Dec/2020:18:08:23.725] grpc_service grpc_servers/s1 0/0/0/1/+1 200 +99 - - ---- 1/1/1/0/0 0/0 "POST http://localhost:3001/RollDiceService/RollDice HTTP/2.0"

Converters

gRPC uses Protocol Buffers to serialize messages. Use the following converter function to extract information from a gRPC Protocol Buffers message:

Directive

Description

ungrpc(<field_number>,[<data_type>])

Extracts the value of a raw input field of a gRPC message.

Example

The ungrpc converter takes the ID of the Protocol Buffers field in a message. In the following example, the Protocol Buffers message has a field named numberOfDice that has an ID of 1:

message RollDiceRequest {
   int32 numberOfDice = 1;
}

In your configuration, specify this ID and the data type to extract the value. Here, we print the numberOfDice value to the end of the access log:

frontend grpc_service
   mode http
   bind :3001 proto h2
   default_backend grpc_servers

   # Store the numberOfDice value in the sess.numberofdice variable
   http-request set-var(sess.numberofdice) req.body,ungrpc(1,int32)

   # add the variable to the end of the standard HTTP log format
   log-format "%ci:%cp [%tr] %ft %b/%s %TR/%Tw/%Tc/%Tr/%Ta %ST %B %CC %CS %tsc %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r Number of dice: %[var(sess.numberofdice)]"

Your access log will now include the field's value:

$ sudo tail -f /var/log/2.2/lb-access-20201218.log

Dec 18 18:08:21 lb1 hapee-lb[5699]: 127.0.0.1:51780 [18/Dec/2020:18:08:21.722] grpc_service grpc_servers/s1 0/0/0/1/+1 200 +99 - - ---- 1/1/1/0/0 0/0 "POST http://localhost:3001/RollDiceService/RollDice HTTP/2.0" Number of dice: 2
Dec 18 18:08:23 lb1 hapee-lb[5699]: 127.0.0.1:51780 [18/Dec/2020:18:08:23.725] grpc_service grpc_servers/s1 0/0/0/1/+1 200 +99 - - ---- 1/1/1/0/0 0/0 "POST http://localhost:3001/RollDiceService/RollDice HTTP/2.0" Number of dice: 2

Next up

HTTP/2