HTTP/2 server push allows a server to send multiple resources in response to a client request without the client explicitly requesting for each of these resources, that is, to send dependent resources preemptively when the client requests a resource. It reduces latency that could be introduced by waiting for each request to serve the resource.

For example, take a website with three resources such as index.html, style.css, and favicon.ico. Consider one user, through his browser, connects to the home page of this website and retrieves index.html. Once the browser receives index.html, it discovers that it needs style.css and favicon.ico. Then the browser will issue requests to get the other two files. Therefore, to assemble this webpage, the browser will stack network round trips as it gradually discovers the site’s composition.

With HTTP/2 PUSH, the server can take the initiative by having some rules that trigger push at certain moments. For example, when the server receives a request to index.html, it can push style.css and favicon.ico without waiting for the respective request from the browser. If done correctly, by the time the browser finishes parsing index.html, the transfer of styles.css and script.js would have already started in push mode.

LINK Header

The external resources required for a given webpage can be specified to the client using the preload link elements. The server could also send Link headers with the type set to preload. The client uses it to request the resource before processing the initially requested page.

Link: </style.css>; rel=preload; as=style

If server push is enabled, Avi Load Balancer can intercept these Link headers to create PUSH_PROMISE frames and fetch the resources without the client making a request for them. The server can also choose to specify certain preload link elements to not be pushed using the nopush target attribute:

Link: </styles.css>; rel=preload; as=style; nopush

PUSH_PROMISE Frames

The server sends this frame to the browser to start pushing a resource. All server push streams are initiated through PUSH_PROMISE frames. When an entity sends the PUSH_PROMISE frame, it conveys its intent to push the described resources to the client which need to be delivered with the response data that requests the pushed resources.

Note:

PUSH_PROMISE frames sent from the server is not supported. However, if Server push is enabled, Avi Load Balancer will send the PUSH_PROMISE frame to the client on receiving the link headers from the server.

Working of HTTP/2 server Push with Avi Load Balancer

The following diagram below that explains the working of server push with Avi Load Balancer.



  1. Client sends request to Avi Load Balancer to access /index.html. NSX Advanced Load Balancer sends the request to back end server.

  2. When back end server responds to Avi Load Balancer,it intercepts that response and checks if there are any link headers present. If link headers are present and preload is set, Avi Load Balancer sends the PUSH_PROMISE frame to the client with the response it received from the server. Please note the PUSH_PROMISE frames in the diagram above.

  3. After sending the PUSH_PROMISE frames to the client, Avi Load Balancer sends GET request to fetch the resources pre-emptively.

  4. Once Avi Load Balancer receives a response from the server, it sends the response back to the client.

Note:

Server Push works even if the back end connection is HTTP/1.1.

Configuring the HTTP/2 Server Push

  1. Use the following commands to enable the server push:

     [admin:ctrl]: > configure applicationprofile System-HTTP 
            
     [admin:ctrl]: applicationprofile> http_profile         
            
     [admin:ctrl]: applicationprofile:http_profile> http2_profile         
               
     [admin:ctrl]: applicationprofile:http_profile:http2_profile> enable_http2_server_push         
            
     Overwriting the previously entered value for enable_http2_server_push 
            
     [admin:ctrl]: applicationprofile:http_profile:http2_profile> save 
            
     [admin:ctrl]: applicationprofile:http_profile> save 
            
     [admin:ctrl]: applicationprofile> save 
  2. When HTTP/2 server push is enabled, you can define the number of resources that must be fetched pre-emptively. This ability can limit the number of requests so that the client does not get overwhelmed. To define the max number of concurrent push requests over a client-side HTTP/2 connection, follow the steps given below:

    [admin:ctrl]: > configure applicationprofile System-HTTP 
        
     [admin:ctrl]: applicationprofile> http_profile         
        
     [admin:ctrl]: applicationprofile:http_profile> http2_profile          
        
     [admin:ctrl]: applicationprofile:http_profile:http2_profile> max_http2_concurrent_pushes_per_connection 16 
        
     Overwriting the previously entered value for max_http2_concurrent_pushes_per_connection 
        
     [admin:ctrl]: applicationprofile:http_profile:http2_profile> save 
        
     [admin:ctrl]: applicationprofile:http_profile> save 
        
     [admin:ctrl]: applicationprofile> save 
Note:

There are also other fields in app profile setting, that is, max_http2_control_frames_per_connection and max_http2_concurrent_streams_per_connection. If the values are lesser than max_http2_concurrent_pushes_per_connection, these values will be used to limit the number of push streams (resources).

Selective Server Push

You can use HTTP Policies or DataScripts to add Link headers in the response because server push works by intercepting Link headers. This way, you can achieve a way to selectively push certain resources based on conditions met in the match criteria provided.

The sample HTTP Response policy is as shown below:



HTTP/2 Server Push and Avi Load Balancer Caching

If the requirement is to fetch some resources from cache instead of Avi Load Balancer sending new requests to the back end server, Avi Load Balancer caching can be leveraged.

You can leverage the HTTP cache to store the server response and any pushed resources. Since the fetched resources are also server responses that are triggered after the PUSH_PROMISE frames are sent, they will be stored as separate cache objects in the HTTP cache. The request flow in case Avi Load Balancer Caching is enabled is as follows:





Visibility and Troubleshooting

Application Logs:

Headers:



HTTP Statistics

admin:ctrl]: > show virtualservice vs_v2_to_v1 httpstats
+---------------------------------+---------------------------------+
| Field                           | Value                           |
+---------------------------------+---------------------------------+
| connections_handled             | 16                              |
| requests_handled                | 48                              |
| response_2xx                    | 44                              |
| response_3xx                    | 0                               |
| response_4xx                    | 2                               |
| response_5xx                    | 2                               |
| cache_hits                      | 12                              |
| cache_bytes                     | 184451                          |
| http2_requests_handled          | 48                              |
| http2_response_2xx              | 42                              |
| http2_response_3xx              | 0                               |
| http2_response_4xx              | 2                               |
| http2_response_5xx              | 2                               |
| http2_protocol_errors           | 0                               |
| http2_flow_control_errors       | 0                               |
| http2_frame_size_errors         | 0                               |
| http2_compression_errors        | 0                               |
| http2_refused_stream_errors     | 0                               |
| http2_enhance_your_calm         | 0                               |
| http2_miscellaneous_errors      | 0                               |
| http2_trailers_received         | 0                               |
| http2_control_frame_flood_errors| 2                               |
| http2_queued_frames_flood_errors| 0                               |
| http2_empty_frame_flood_errors  | 0                               |
| open_requests                   | 0                               |
| req_body_buffered_reqs          | 0                               |
| resp_body_buffered_reqs         | 0                               |
| invalid_httpv1_requests         | 0                               |
| invalid_httpv2_requests         | 0                               |
| dropped_requests                | 0                               |
| server_push_requests_handled    | 32                              |
| server_push_response_2xx        | 28                              |
| server_push_response_3xx        | 0                               |
| server_push_response_4xx        | 2                               |
| server_push_response_5xx        | 2                               |
+---------------------------------+---------------------------------+