Spring Cloud Ribbon

Spring Cloud Ribbon

Ribbon to load-balancer który działa po stronie klienta. W praktyce oznacza to, że ilość aktywnych instancji zwracana jest przez Service Discovery np. Eureka. Następnie wybór która usługa zwrócona przez Service Discovery zostanie wywołana leży po stronie klienta. Eureka Service Discovery umożliwia efektywne zarządzanie usługami bez konieczności deklarowania adresów kolejnych instancji na sztywno w kodzie źródłowym aplikacji. Zdecydowanie dobrą praktyką jest korzystanie z mechanizmu Service Discovery. Jeśli jednak jest uzasadnienie biznesowe do używania predefiniowanej listy serwerów to jak najbardziej jest możliwe używanie projektu Spring Cloud Ribbon bez konieczności stawiania serwera Eureki. Polecam zapoznać się z materiałem: http://bushkarl.gitbooks.io/spring-cloud/content/spring_cloud_netflix/client_side_load_balancer_ribbon.html.

W artykule tym zaprezentuję użycie mechanizmu load-balancera Ribbon właśnie bez użycia mechanizmu Service Discovery (artykuł z użyciem load-balancera i serwera Eureki dostępny jest tutaj).

[źródło] http://www.slideshare.net/ewolff/microservice-with-spring-boot-and-spring-cloud

Aplikacja serwerowa – niezbędne zależności:

<dependencies>
 
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
 
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter</artifactId>
   </dependency>
 
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
   </dependency>
 
</dependencies>

RestController:

@RestController
public class WebController {
 
    @Value("${server.port}")
    String port;
 
    @RequestMapping(value = "/")
    public String home() {
        return "Okay!";
    }
 
    @RequestMapping("/greeting")
    public String hello() {
        return "Hello from a service running at port: " + port + "!";
    }
}

Klasa startowa:

@SpringBootApplication
public class SpringCloudServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringCloudServerApplication.class, args);
	}
}

Plik application.properties:

server.port = 8092

Aplikacja ta powinna być uruchomiona na 3 różnych portach. Port modyfikujemy z poziomu pliku application.properties.

Aplikacja kliencka – niezbędne zależności:

<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
 
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
 
 
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-ribbon</artifactId>
	</dependency>
 
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-ribbon</artifactId>
	</dependency>
 
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
 
</dependencies>
 
<build>
	<plugins>
		<plugin>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-maven-plugin</artifactId>
		</plugin>
	</plugins>
</build>
 
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>Camden.SR5</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

Klasa konfiguracyjna:

public class Configuration {
 
    @Autowired
    IClientConfig ribbonClientConfig;
 
    @Bean
    public IPing ribbonPing(IClientConfig config) {
        return new PingUrl();
    }
 
    @Bean
    public IRule ribbonRule(IClientConfig config) {
        return new AvailabilityFilteringRule();
    }
}

RestController:

@RestController
public class WebController {
 
    @Autowired
    RestTemplate restTemplate;
 
    @LoadBalanced
    @Bean
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
 
    @RequestMapping("/helloworld")
    public String home() {
        return this.restTemplate.getForObject("http://helloworld/greeting", String.class);
    }
}

Klasa startowa:

@SpringBootApplication
@RibbonClient(name = "ribbon-client", configuration = Configuration.class)
public class SpringCloudClientApplication {
	public static void main(String[] args) {
		SpringApplication.run(SpringCloudClientApplication.class, args);
	}
}

Plik application.yaml:

spring:
  application:
    name: Ribbon-Client
 
helloworld:
  ribbon:
    eureka:
      enabled: false
    listOfServers: localhost:8090,localhost:8091,localhost:8092
    ServerListRefreshInterval: 1000
 
server:
  port: 8089

Po wywołaniu adresu:

http://localhost:8089/helloworld

za pomocą algorytmu load-balancera – Round Robin otrzymamy wynik:

Hello from a service running at port: 8090!

po kolejnym odświerzeniu adresu:

Hello from a service running at port: 8091!

i po następnym odświerzeniu adresu:

Hello from a service running at port: 8092!

W momencie kiedy jeden mikroserwis przestanie działać otrzymamy błąd – (niedziałająca usługa nie została wyrejestrowana – sztywna definicja w kodzie źródłowym aplikacji):

I/O error on GET request for "http://helloworld/greeting": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect

Zobacz kod na GitHubie i zapisz się na bezpłatny newsletter!

.

Leave a comment

Your email address will not be published.


*