0
# Load Balancing
1
2
Client-side load balancing enables applications to distribute requests across multiple service instances with support for multiple algorithms, health checking, retry mechanisms, and both blocking and reactive programming models.
3
4
## Capabilities
5
6
### Load Balanced Annotation
7
8
Marks RestTemplate or WebClient beans for automatic load balancing.
9
10
```java { .api }
11
/**
12
* Marks RestTemplate or WebClient beans for load balancing
13
*/
14
@LoadBalanced
15
public @interface LoadBalanced {}
16
```
17
18
**Usage Examples:**
19
20
```java
21
@Configuration
22
public class LoadBalancerConfig {
23
24
@Bean
25
@LoadBalanced
26
public RestTemplate restTemplate() {
27
return new RestTemplate();
28
}
29
30
@Bean
31
@LoadBalanced
32
public WebClient.Builder webClientBuilder() {
33
return WebClient.builder();
34
}
35
}
36
37
@Service
38
public class UserService {
39
40
@Autowired
41
@LoadBalanced
42
private RestTemplate restTemplate;
43
44
public String getUser(String userId) {
45
// This will be load balanced across user-service instances
46
return restTemplate.getForObject("http://user-service/users/" + userId, String.class);
47
}
48
}
49
```
50
51
### Load Balancer Client
52
53
Main interface for client-side load balancing operations.
54
55
```java { .api }
56
/**
57
* Main interface for client-side load balancing
58
*/
59
public interface LoadBalancerClient extends ServiceInstanceChooser {
60
/**
61
* Execute a request using load balancing
62
* @param serviceId The service ID to load balance across
63
* @param request The request to execute
64
* @return The result from the request execution
65
* @throws IOException If request execution fails
66
*/
67
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
68
69
/**
70
* Execute a request using load balancing with a specific service instance
71
* @param serviceId The service ID
72
* @param serviceInstance The service instance to use
73
* @param request The request to execute
74
* @return The result from the request execution
75
* @throws IOException If request execution fails
76
*/
77
<T> T execute(String serviceId, ServiceInstance serviceInstance,
78
LoadBalancerRequest<T> request) throws IOException;
79
80
/**
81
* Create a proper URI with a real host and port for systems to utilize
82
* @param instance The service instance
83
* @param original The original URI
84
* @return A reconstructed URI
85
*/
86
URI reconstructURI(ServiceInstance instance, URI original);
87
}
88
```
89
90
### Service Instance Chooser
91
92
Interface for selecting service instances.
93
94
```java { .api }
95
/**
96
* Interface for selecting service instances
97
*/
98
public interface ServiceInstanceChooser {
99
/**
100
* Choose a ServiceInstance from the LoadBalancer for the specified service
101
* @param serviceId The service ID to choose an instance for
102
* @return A ServiceInstance that matches the serviceId
103
*/
104
ServiceInstance choose(String serviceId);
105
106
/**
107
* Choose a ServiceInstance from the LoadBalancer for the specified service and request
108
* @param serviceId The service ID to choose an instance for
109
* @param request The request context
110
* @return A ServiceInstance that matches the serviceId
111
*/
112
<T> ServiceInstance choose(String serviceId, Request<T> request);
113
}
114
```
115
116
### Load Balancer Request
117
118
Interface for wrapping requests in load balancing context.
119
120
```java { .api }
121
/**
122
* Interface for wrapping requests in load balancing context
123
*/
124
public interface LoadBalancerRequest<T> {
125
/**
126
* Apply the request to the given ServiceInstance
127
* @param instance The service instance to apply the request to
128
* @return The result of applying the request
129
* @throws Exception If the request fails
130
*/
131
T apply(ServiceInstance instance) throws Exception;
132
}
133
```
134
135
**Usage Example:**
136
137
```java
138
@Autowired
139
private LoadBalancerClient loadBalancerClient;
140
141
public String callService() {
142
return loadBalancerClient.execute("user-service",
143
instance -> {
144
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/users";
145
// Make HTTP call using the selected instance
146
return restTemplate.getForObject(url, String.class);
147
});
148
}
149
```
150
151
### Request and Response Framework
152
153
Framework for handling load balancer requests and responses.
154
155
```java { .api }
156
/**
157
* Interface for load balancer requests
158
*/
159
public interface Request<C> {
160
/**
161
* @return The request context
162
*/
163
C getContext();
164
}
165
166
/**
167
* Interface for load balancer responses
168
*/
169
public interface Response<T> {
170
/**
171
* @return Whether the response has a server
172
*/
173
boolean hasServer();
174
175
/**
176
* @return The selected server
177
*/
178
T getServer();
179
}
180
181
/**
182
* Default implementation of Request
183
*/
184
public class DefaultRequest<T> implements Request<T> {
185
public DefaultRequest(T context);
186
}
187
188
/**
189
* Default implementation of Response with selected ServiceInstance
190
*/
191
public class DefaultResponse implements Response<ServiceInstance> {
192
public DefaultResponse(ServiceInstance serviceInstance);
193
}
194
195
/**
196
* Response implementation for no available instances
197
*/
198
public class EmptyResponse implements Response<ServiceInstance> {
199
public EmptyResponse();
200
}
201
```
202
203
### Context Classes
204
205
Context objects for carrying request information through the load balancing process.
206
207
```java { .api }
208
/**
209
* Default request context implementation
210
*/
211
public class DefaultRequestContext implements RequestDataContext {
212
public DefaultRequestContext(RequestData requestData, String hint);
213
}
214
215
/**
216
* Request context containing request data
217
*/
218
public interface RequestDataContext {
219
/**
220
* @return The request data
221
*/
222
RequestData getClientRequest();
223
}
224
225
/**
226
* Request context with load balancer hints
227
*/
228
public class HintRequestContext implements RequestDataContext {
229
public HintRequestContext(RequestData requestData, String hint);
230
public String getHint();
231
}
232
233
/**
234
* Context for retryable requests
235
*/
236
public class RetryableRequestContext implements RequestDataContext {
237
public RetryableRequestContext(RequestData requestData, int retryCount);
238
public int getRetryCount();
239
}
240
241
/**
242
* HTTP request data holder
243
*/
244
public class RequestData {
245
public RequestData(HttpRequest httpRequest);
246
public HttpRequest getHttpRequest();
247
public HttpHeaders getHeaders();
248
public String getUrl();
249
}
250
251
/**
252
* HTTP response data holder
253
*/
254
public class ResponseData {
255
public ResponseData(HttpHeaders headers, Object requestData);
256
public HttpHeaders getHeaders();
257
public Object getRequestData();
258
}
259
```
260
261
### Load Balancer Properties
262
263
Configuration properties for load balancer behavior.
264
265
```java { .api }
266
/**
267
* Base load balancer configuration properties
268
*/
269
@ConfigurationProperties("spring.cloud.loadbalancer")
270
public class LoadBalancerProperties {
271
private HealthCheck healthCheck = new HealthCheck();
272
private Retry retry = new Retry();
273
private StickySession stickySession = new StickySession();
274
private XForwarded xForwarded = new XForwarded();
275
276
/**
277
* Health check configuration
278
*/
279
public static class HealthCheck {
280
private boolean enabled = true;
281
private Duration interval = Duration.ofSeconds(25);
282
private String path = "/actuator/health";
283
// getters and setters
284
}
285
286
/**
287
* Retry configuration
288
*/
289
public static class Retry {
290
private boolean enabled = true;
291
private int maxRetriesOnSameServiceInstance = 0;
292
private int maxRetriesOnNextServiceInstance = 1;
293
private Set<Class<? extends Throwable>> retryableExceptions = new HashSet<>();
294
// getters and setters
295
}
296
297
/**
298
* Sticky session configuration
299
*/
300
public static class StickySession {
301
private boolean enabled = false;
302
private String instanceIdCookieName = "sc-lb-instance-id";
303
// getters and setters
304
}
305
}
306
307
/**
308
* Client-specific load balancer properties
309
*/
310
@ConfigurationProperties("spring.cloud.loadbalancer")
311
public class LoadBalancerClientsProperties {
312
private Map<String, LoadBalancerProperties> clients = new HashMap<>();
313
// getters and setters
314
}
315
```
316
317
### HTTP Client Interceptors
318
319
Interceptors for adding load balancing to HTTP clients.
320
321
```java { .api }
322
/**
323
* HTTP client interceptor for load balancing
324
*/
325
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
326
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer);
327
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
328
LoadBalancerRequestFactory requestFactory);
329
}
330
331
/**
332
* Load balancer interceptor with retry support
333
*/
334
public class RetryLoadBalancerInterceptor implements ClientHttpRequestInterceptor {
335
public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
336
LoadBalancerProperties properties);
337
}
338
339
/**
340
* Async HTTP client interceptor
341
*/
342
public class AsyncLoadBalancerInterceptor implements AsyncClientHttpRequestInterceptor {
343
public AsyncLoadBalancerInterceptor(LoadBalancerClient loadBalancer);
344
}
345
```
346
347
### Customization Interfaces
348
349
Interfaces for customizing HTTP clients.
350
351
```java { .api }
352
/**
353
* Interface for customizing RestTemplate
354
*/
355
public interface RestTemplateCustomizer {
356
/**
357
* Customize the RestTemplate
358
* @param restTemplate The RestTemplate to customize
359
*/
360
void customize(RestTemplate restTemplate);
361
}
362
363
/**
364
* Interface for customizing AsyncRestTemplate
365
*/
366
public interface AsyncRestTemplateCustomizer {
367
/**
368
* Customize the AsyncRestTemplate
369
* @param restTemplate The AsyncRestTemplate to customize
370
*/
371
void customize(AsyncRestTemplate restTemplate);
372
}
373
```
374
375
### Retry Support
376
377
Support for retrying failed load balanced requests.
378
379
```java { .api }
380
/**
381
* Factory for creating retry policies
382
*/
383
public interface LoadBalancedRetryFactory {
384
/**
385
* Create a retry policy for the given service
386
* @param service The service ID
387
* @param loadBalancerProperties The load balancer properties
388
* @return A retry policy
389
*/
390
LoadBalancedRetryPolicy createRetryPolicy(String service,
391
LoadBalancerProperties loadBalancerProperties);
392
}
393
394
/**
395
* Retry policy interface for load balanced requests
396
*/
397
public interface LoadBalancedRetryPolicy extends RetryPolicy {
398
/**
399
* Check if retry is possible
400
* @param retryContext The retry context
401
* @return true if retry is possible
402
*/
403
boolean canRetry(LoadBalancedRetryContext retryContext);
404
405
/**
406
* Register a throwable with the retry policy
407
* @param retryContext The retry context
408
* @param throwable The throwable that occurred
409
*/
410
void registerThrowable(LoadBalancedRetryContext retryContext, Throwable throwable);
411
}
412
413
/**
414
* Recovery callback for retry scenarios
415
*/
416
public abstract class LoadBalancedRecoveryCallback<T, R> implements RecoveryCallback<R> {
417
/**
418
* Create a recovery callback
419
* @param request The original request
420
* @param originalUri The original URI
421
* @param loadBalancerClient The load balancer client
422
*/
423
protected LoadBalancedRecoveryCallback(LoadBalancerRequest<T> request,
424
URI originalUri,
425
LoadBalancerClient loadBalancerClient);
426
}
427
428
/**
429
* Exception for HTTP status codes that should trigger retries
430
*/
431
public class RetryableStatusCodeException extends Exception {
432
public RetryableStatusCodeException(String serviceId, int statusCode, HttpResponse response);
433
public int getStatusCode();
434
public HttpResponse getResponse();
435
}
436
```
437
438
### Reactive Load Balancing
439
440
Reactive load balancing support for WebClient.
441
442
```java { .api }
443
/**
444
* Reactive load balancer interface
445
*/
446
public interface ReactiveLoadBalancer<T> {
447
/**
448
* Choose a server instance
449
* @param request The request context
450
* @return A Mono containing the response
451
*/
452
Mono<Response<T>> choose(Request request);
453
454
/**
455
* Choose a server instance with default request
456
* @return A Mono containing the response
457
*/
458
default Mono<Response<T>> choose() {
459
return choose(REQUEST);
460
}
461
462
Request REQUEST = new DefaultRequest<>();
463
464
/**
465
* Factory interface for creating reactive load balancers
466
*/
467
interface Factory<T> {
468
ReactiveLoadBalancer<T> getInstance(String serviceId);
469
}
470
}
471
472
/**
473
* WebClient exchange filter function for load balancing
474
*/
475
public class ReactorLoadBalancerExchangeFilterFunction implements ExchangeFilterFunction {
476
public ReactorLoadBalancerExchangeFilterFunction(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory);
477
}
478
479
/**
480
* WebClient filter with retry support
481
*/
482
public class RetryableLoadBalancerExchangeFilterFunction implements ExchangeFilterFunction {
483
public RetryableLoadBalancerExchangeFilterFunction(RetrySpec retrySpec,
484
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory);
485
}
486
```
487
488
## Configuration Properties
489
490
```properties
491
# Enable/disable load balancer
492
spring.cloud.loadbalancer.enabled=true
493
494
# Health check configuration
495
spring.cloud.loadbalancer.health-check.enabled=true
496
spring.cloud.loadbalancer.health-check.interval=25s
497
spring.cloud.loadbalancer.health-check.path=/actuator/health
498
499
# Retry configuration
500
spring.cloud.loadbalancer.retry.enabled=true
501
spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance=0
502
spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance=1
503
504
# Sticky session configuration
505
spring.cloud.loadbalancer.sticky-session.enabled=false
506
spring.cloud.loadbalancer.sticky-session.instance-id-cookie-name=sc-lb-instance-id
507
508
# Client-specific configuration
509
spring.cloud.loadbalancer.clients.user-service.health-check.enabled=false
510
spring.cloud.loadbalancer.clients.user-service.retry.max-retries-on-next-service-instance=2
511
```
512
513
**Usage Examples:**
514
515
```java
516
// Basic load balancing with RestTemplate
517
@RestController
518
public class UserController {
519
520
@Autowired
521
@LoadBalanced
522
private RestTemplate restTemplate;
523
524
@GetMapping("/users/{id}")
525
public String getUser(@PathVariable String id) {
526
return restTemplate.getForObject("http://user-service/users/" + id, String.class);
527
}
528
}
529
530
// Reactive load balancing with WebClient
531
@Service
532
public class ReactiveUserService {
533
534
private final WebClient webClient;
535
536
public ReactiveUserService(@LoadBalanced WebClient.Builder webClientBuilder) {
537
this.webClient = webClientBuilder.build();
538
}
539
540
public Mono<String> getUser(String id) {
541
return webClient.get()
542
.uri("http://user-service/users/{id}", id)
543
.retrieve()
544
.bodyToMono(String.class);
545
}
546
}
547
548
// Manual load balancing
549
@Service
550
public class ManualLoadBalancingService {
551
552
@Autowired
553
private LoadBalancerClient loadBalancerClient;
554
555
public String callService() {
556
return loadBalancerClient.execute("user-service", instance -> {
557
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/users";
558
RestTemplate restTemplate = new RestTemplate();
559
return restTemplate.getForObject(url, String.class);
560
});
561
}
562
}
563
```