HTTP Topic

HTTP/2 and Performance Optimization

What You'll Learn:

  • HTTP/2 features and benefits over HTTP/1.1

  • Performance optimization techniques

  • Implementing HTTP/2 in Spring Boot

Detailed Explanation:

HTTP/2 Key Features

1. Binary Protocol

  • HTTP/1.1: Text-based protocol

  • HTTP/2: Binary protocol (more efficient parsing)

2. Multiplexing

  • Multiple requests/responses over single connection

  • Eliminates head-of-line blocking

3. Header Compression (HPACK)

  • Compresses headers to reduce overhead

  • Uses static and dynamic tables

4. Server Push

  • Server can push resources before client requests them

5. Stream Prioritization

  • Client can specify priority for requests

HTTP/2 vs HTTP/1.1 Comparison

HTTP/1.1 Limitations:

1. Multiple TCP connections for parallelism
2. Head-of-line blocking
3. Uncompressed headers
4. No server push capability

HTTP/2 Advantages:

1. Single connection for all requests
2. True multiplexing
3. Header compression
4. Built-in server push
5. Better resource prioritization

Enabling HTTP/2 in Spring Boot

Application Properties:

# Enable HTTP/2
server.http2.enabled=true

# SSL configuration (HTTP/2 requires HTTPS)
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=password
server.ssl.key-store-type=PKCS12
server.ssl.key-alias=tomcat

# Server configuration
server.port=8443
server.servlet.context-path=/api

Programmatic Configuration:

@Bean
public ServletWebServerFactory servletContainer() {
    TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
    tomcat.addConnectorCustomizers(connector -> {
        if (connector.getProtocolHandler() instanceof AbstractHttp11Protocol) {
            ((AbstractHttp11Protocol<?>) connector.getProtocolHandler())
                .setMaxSwallowSize(-1);
        }
    });
    return tomcat;
}

Performance Optimization Techniques

1. Resource Compression:

@Configuration
public class CompressionConfig {
    
    @Bean
    public FilterRegistrationBean<GzipFilter> gzipFilter() {
        FilterRegistrationBean<GzipFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new GzipFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }
}

2. Connection Keep-Alive:

# Tomcat connection settings
server.tomcat.max-connections=10000
server.tomcat.max-threads=200
server.tomcat.connection-timeout=5s

3. Static Resource Caching:

@Configuration
public class StaticResourceConfig implements WebMvcConfigurer {
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
            .addResourceLocations("classpath:/static/")
            .setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS));
    }
}

HTTP/2 Server Push

Servlet 4.0 Implementation:

@WebServlet("/index.html")
public class PushServlet extends HttpServlet {
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        
        // Get push builder from request
        PushBuilder pushBuilder = request.newPushBuilder();
        
        if (pushBuilder != null) {
            // Push CSS file
            pushBuilder.path("/static/css/styles.css")
                      .addHeader("content-type", "text/css")
                      .push();
            
            // Push JavaScript file
            pushBuilder.path("/static/js/app.js")
                      .addHeader("content-type", "application/javascript")
                      .push();
        }
        
        // Serve main content
        response.getWriter().write("<html>...</html>");
    }
}

Monitoring HTTP/2 Performance

Metrics Configuration:

@Configuration
public class MetricsConfig {
    
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> registry.config().commonTags(
            "application", "my-app",
            "protocol", "HTTP/2"
        );
    }
    
    @Bean
    public TimedAspect timedAspect(MeterRegistry registry) {
        return new TimedAspect(registry);
    }
}

Performance Monitoring:

@RestController
public class UserController {
    
    @GetMapping("/api/users/{id}")
    @Timed(value = "user.get", description = "Time taken to get user")
    @Counted(value = "user.get.counter", description = "Number of user get requests")
    public User getUser(@PathVariable Long id) {
        return userService.findById(id);
    }
}

HTTP/2 Client with WebClient

WebClient Configuration:

@Configuration
public class WebClientConfig {
    
    @Bean
    public WebClient webClient() {
        HttpClient httpClient = HttpClient.create()
            .protocol(HttpProtocol.HTTP2)
            .compress(true)
            .followRedirect(true);
        
        return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(httpClient))
            .baseUrl("https://api.example.com")
            .defaultHeader(HttpHeaders.USER_AGENT, "MyApp/1.0")
            .build();
    }
}

Using WebClient with HTTP/2:

@Service
public class ApiClient {
    
    private final WebClient webClient;
    
    public Mono<User> getUser(Long id) {
        return webClient.get()
            .uri("/users/{id}", id)
            .header("Accept", "application/json")
            .retrieve()
            .bodyToMono(User.class)
            .timeout(Duration.ofSeconds(5));
    }
    
    public Flux<User> getUsers() {
        return webClient.get()
            .uri("/users")
            .retrieve()
            .bodyToFlux(User.class);
    }
}

Performance Testing

Load Testing with HTTP/2:

@SpringBootTest
@TestPropertySource(properties = {
    "server.http2.enabled=true",
    "server.ssl.enabled=true"
})
public class Http2PerformanceTest {
    
    @Autowired
    private TestRestTemplate restTemplate;
    
    @Test
    public void testHttp2Performance() {
        // Warm up
        IntStream.range(0, 100).forEach(i -> 
            restTemplate.getForObject("/api/users/1", User.class));
        
        // Measure performance
        long startTime = System.currentTimeMillis();
        IntStream.range(0, 1000).parallel().forEach(i -> 
            restTemplate.getForObject("/api/users/1", User.class));
        long endTime = System.currentTimeMillis();
        
        double averageTime = (endTime - startTime) / 1000.0;
        assertThat(averageTime).isLessThan(50.0); // Less than 50ms per request
    }
}

 

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?