11 Ekim 2021 Pazartesi

SpringCloud LoadBalancer - Client Side Load Balancing İçindir

Giriş
Açıklaması şöyle
Spring Cloud provides several ways to implement load balancing, including Ribbon, Spring Cloud Load Balancer, Spring Cloud Gateway, and Kubernetes Load Balancer.
Bu proje, WebClient ile client side load balancing yapmak içindir.

Maven
Şu satırı dahil ederiz
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
LoadBalancerClientFactory Sınıfı
Örnek
Şöyle yaparız
@Bean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
  Environment environment,
  LoadBalancerClientFactory loadBalancerClientFactory) {

  String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
  return new RoundRobinLoadBalancer(
    loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), 
    name);
}
@LoadBalancedAnotasyonu
@LoadBalancedAnotasyonu yazısına taşıdım

@LoadBalancerClient Anotasyonu
configuration Alanı
Load Balancing için iki gerçekleştirim var

1. RoundRobinLoadBalancer 
2. RandomLoadBalancer 

Örnek - RoundRobinLoadBalancer 
Şöyle yaparız
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
@LoadBalancerClient(name = WebClientConfig.CLIENT_NAME, 
                    configuration = IgniteLoadBalancerConfiguration.class)
public class WebClientConfig {
    public static final String CLIENT_NAME = "client";

    @Bean
    @LoadBalanced
    public WebClient.Builder usersClientBuilder() {
        return WebClient.builder()
            .defaultHeader("affinity-cache-name", "UserCache");
    }
}
Yardımcı kod şöyledir
@Configuration
public class IgniteLoadBalancerConfiguration {
  public static final String SERVICE_ID = "example";

  @Bean
  @Primary
  public ServiceInstanceListSupplier serviceInstanceListSupplier(IgniteEx ignite) {
    return new IgniteServiceInstanceListSuppler(ignite);
  }

  @Bean
  public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
    Environment environment,
    LoadBalancerClientFactory loadBalancerClientFactory) {
    String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    return new RoundRobinLoadBalancer(
      loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class),
        name);
  }
}
Açıklaması şöyle
IgniteServiceInstanceListSuppler will return instances based on the request key.
Örnek
Elimizde şöyle bir kod olsun. locahhost üzerinde çalışan 4 tane port döndürür
@Bean
public ReactiveDiscoveryClient customDiscoveryClient() {
  return new ReactiveDiscoveryClient() {
    @Override
    public String description() {
      return "Calling another API example";
    }

    @Override
    public Flux<ServiceInstance> getInstances(String serviceId) {
      log.debug("getInstances: {}", serviceId);

      return Flux.just(8080, 8081, 8082)
        .map(port -> new DefaultServiceInstance(serviceId + "-" + port, serviceId,
          "localhost", port, false));
      }

    @Override
    public Flux<String> getServices() {
      return Flux.just("ExampleApi");
    }
  };
}
Açıklaması şöyle
Implement theReactiveDiscoveryClient . It allows us to return a list of instances that can be used when a specific call is triggered.
Şöyle yaparız
@Service
public class AccountsService {
  private static final String API = "ExampleApi";
  private final WebClient apiClient;

  public AccountsService(WebClient.Builder loadBalancedWebClientBuilder) {
    this.apiClient = loadBalancedWebClientBuilder
      .build();
  }

  public Mono<String> login(String username) {
    return apiClient.post()
      .uri(uriBuilder -> uriBuilder
                        .host(API)
                        .path("/login")
                        .build())
    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .header("username", username)
    .exchangeToMono(r -> handleResponse(r));
  }
  private Mono<String> handleResponse(ClientResponse r) {
    if (r.statusCode().is2xxSuccessful()) {
      return r.bodyToMono(String.class);
    }

    return r.bodyToMono(String.class)
      .switchIfEmpty(Mono.error(new IllegalStateException("Failed: " + r.statusCode())))
      .flatMap(response -> Mono.error(new IllegalStateException("Failed: " +
        r.statusCode() + ", " + response)));
  }
}




Hiç yorum yok:

Yorum Gönder