According to industry consensus, the work of senior software developers and architects is largely about finding trade-offs between the advantages and disadvantages of certain solutions and identifying "good enough solutions" for the tasks at hand.
When we asked ourselves the question of moving to a microservice architecture, we encountered a number of similar trade-offs. After conducting a series of experiments and decoupling from our product-specific business requirements, we tried to formulate questions that any development team can face, regardless of product requirements. And, of course, give answers to them - no one likes unanswered questions.
As an applied addition to the reasoning, we will develop several Proof of Concept, accompany their development with short explanations and attach the PoC source code.
For us, the "native" stack is Java 8 and Spring Boot 2, so the attached demos will be written based on these technologies with a fair amount of Spring Cloud. We will also try to offer several isolated typical solutions for problems that, as it seemed to us, may arise in the future for developers.
About us
- "", IoT- "". , , . (, , , , ), ( , ML), , .
, Spring Cloud , .
, .
, , Spring Cloud.
Spring Cloud , , , , .
, 5-6 , Gartner Hype Cycle.
, . .
Spring Cloud
Spring Cloud - , Spring-based .
, Spring Cloud
@sqshq , .
-
Spring Cloud
Spring Cloud. Spring Cloud Spring Initializr , starters Spring Cloud pom-, Spring Boot, dependency management:
<properties>
<spring-cloud.version>2020.0.3</spring-cloud.version>
</properties>
...
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
1. ?
, . , . .
|
|
- |
Client-side rendering, Server-side rendering, Mixed |
|
, , - |
, |
, HTTP, WS, |
Service Discovery |
HTTP |
( , , ) :
Spring Security ,
,
,
, . .
1.1
, , .
, HTML- . (Client-side rendering, CSR) (Server-side rendering, SSR).
.
HTML- (, - , ) . JS- HTML- .
( , ).
, JS- ;
.
:
JSP;
Thymeleaf;
Mustache;
+ JS-;
, , JS-. , React JSX, , .
.
, JS , . JS-.
1.2 ,
middleware-, PUB/SUB. PUB/SUB - - .
, : .
: ? , HTTP -? .
, :
, , ( );
, ;
( Kafka ) .
, HTTP :
;
;
, .
, HTTP- - . , .
“”
. HTTP- . , :
( , );
(, );
Service Discovery ( Service Discovery ) HTTP ;
API gateway backend- . API gateway ;
, . , , .
:
Service Discovery;
API Gateway.
Service Discovery - , . , , , , . , .
. , HTTP API, .
, API Gateway , , , , , . , API Gateway , .
API Gateway , . , "" backend , Web-.
- 1- , API Gateway HTTP . HTTP API “” API Gateway, .
API Gateway Service Discovery WebSocket . , . backend-. WS- , WS. API Gateway - .
, :
HTTP- - ;
API Gateway HTTP;
HTTP- Service Discovery. ;
HTTP - , .
Spring Cloud Gateway
java- Spring Cloud Gateway:
Spring Cloud Gateway , , , .
, , , backend-.
, Spring Cloud Gateway :
java-. API-gateway. , , , " " (, Spring Cloud Config), , , , , .
Spring Cloud Gateway, .
1: request path . /google/hello http://google.com/search?q=hello.
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder
.routes()
.route(r -> r
.path("/google/**")
.filters(gatewayFilterSpec -> gatewayFilterSpec.rewritePath("/google/(?<appendix>.*)", "/search?q=${appendix}"))
.uri("http://google.com"))
.build();
}
2: path 1 . /yandex/hello/123 http://yandex.ru/hello/123
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder
.routes()
.route(r -> r
.path("/yandex/**")
.filters(gatewayFilterSpec -> gatewayFilterSpec.stripPrefix(1))
.uri("[http://yandex.ru](http://yandex.ru)"))
.build();
}
3: URI , path .
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder
.routes()
.route(r -> r
.path("/service/**")
.filters(gatewayFilterSpec -> gatewayFilterSpec.changeRequestUri(serverWebExchange -> {
ServerHttpRequest originalRequest = serverWebExchange.getRequest();
URI oldUri = serverWebExchange.getRequest().getURI();
UriComponentsBuilder newUri = UriComponentsBuilder.fromUri(oldUri)
.host(originalRequest.getPath().subPath(3, 4).toString() + ".com") // 0,1,2,3 - /service/<serviceName>,
.port(null)
.replacePath(originalRequest.getPath().subPath(4).toString());
return Optional.of(newUri.build().toUri());
}))
.uri("http://ignored-URI")) // URI
.build();
}
4: route . , route, localhost:8090.
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder
.routes()
.route(r -> r
.order(Integer.MAX_VALUE)
.path("/**")
.uri("[http://localhost:8090](http://localhost:8090)"))
.build();
}
1.3
.
- UI. , , , .
, .
- UI .
- , . , N, , - . .
. , , .
UI. , , . , .
. , .
, .
, , . , , .
1 - UI-
backend- , - .
.
.
Spring Web + JSP/Thymeleaf .
2 - UI Gateway
API Gateway. UI Gateway - .
, , UI.
, API Gateway - . UI .
Spring Web + JSP/Thymeleaf .
3 - Page UI-
, UI- , .
UI-, .
.
UI, , , .
Spring Web + JSP/Thymeleaf .
1.4 Service Discovery
Service Discovery - , (, , ) . Service Discovery Service Registry - . , . ( ) , . , .
Spring Cloud Eureka
Eureka Server - , Service Discovery Service Registry. Eureka Spring Cloud. Eureka Java, Consul Zookeeper.
Eureka-server , - Eureka-, heartbeat- .
, Spring Cloud.
: , eureka.server
, -, eureka.instance
eureka.client
- , .
: Eureka-
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
server.port = 8888
( - 8761)
Eureka-
eureka.client.register-with-eureka=false
,eureka.client.fetch-registry=false
Eureka-,
@EnableEurekaServer
Main- .
: Eureka-:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
URL Eureka-:
eureka.client.serviceUrl.defaultZone = http://localhost:8888/eureka/
, . :
1.
spring.application.name
, , .
eureka.instance.instanceId
. InstanceId - . : instanceId Eureka . , eureka.instance.instanceId, , spring.application.name. , UNKNOWN.
Eureka-,
@EnableEurekaClient
Main- .
Eureka Service Discovery API Gateway. @EnableEurekaClient
API Gateway, URI lb://service-name
(lb - load balancing, , , Service Registry).
: API Gateway , Service Discovery, , , , eureka.client.register-with-eureka=false
, Eureka-, ( + ), service-registry, .
: Healthcheck Eureka ClassNotFoundException
. Heartbeat- - , , ( ). Healthcheck = Heartbeat + ( Spring Boot Actuator).
Eureka healthcheck-. .
healthcheck, :
Eureka- .
eureka.client.healthcheck.enabled = true
.
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.actuate.health.SimpleStatusAggregator
. : Spring Boot Actuator.
: Self-Preservation and renewal
- Eureka : EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.. , .
Eureka- , , , heartbeat- .
eureka.server.expected-client-renewal-interval-seconds
Eureka- ( 30)
heartbeat- , Eureka- . eureka.instance.lease-expiration-duration-in-seconds
( - 90) heartbeat .
, eureka.server.eviction-interval-timer-in-ms
( - , Eureka-), eureka-.
Self-preservation - Eureka, , heartbeats . Spring Cloud SD- ( ).
self-preservation . eureka.server.enable-self-preservation = false
.
self-preservation eureka.server.renewalPercentThreshold
eureka.instance.leaseRenewalIntervalInSeconds
:
https://stackoverflow.com/a/41217806/7757009
https://dzone.com/articles/the-mystery-of-eurekas-self-preservation
https://www.baeldung.com/eureka-self-preservation-renewal
2.
, .
PoC 1: API Gateway + SSR + HTTP + SD + UI-service
:
;
, .
, :
|
|
service-registry |
localhost:8888 |
api-gateway |
localhost:8080 |
ui-service |
localhost:8090 |
api-hello-service |
localhost:8081 |
api-goodbye-service |
localhost:8082 |
API Gateway. /view UI-, /api - .
@Bean
public RouteLocator customRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r
.path("/view/**")
.uri("lb://ui-service/"))
.route(r -> r
.path("/api/hello/**")
.uri("lb://api-hello-service/"))
.route(r -> r
.path("/api/goodbye/**")
.uri("lb://api-goodbye-service/"))
.build();
}
UI- ,
@Controller
@RequestMapping("view")
public class ViewController {
@GetMapping("hello_view")
public String helloView() {
return "hello_view";
}
@GetMapping("goodbye_view")
public String goodbyeView() {
return "goodbye_view";
}
}
localhost:8080/view/hello_view;
view;
API Gateway UI-;
UI- view;
JS-, API-.
API Gateway API-;
API- JSON;
, API .
, 1.
PoC 2: API Gateway + Microfrontends + SD + UI-service
,
|
|
service-registry |
localhost:8888 |
api-gateway |
localhost:8080 |
ui-service |
localhost:8090 |
hello-service |
localhost:8081 |
goodbye-service |
localhost:8082 |
localhost:8080/view;
view;
API Gateway UI-;
UI- view;
JS-, ;l
API Gateway hello goodbye;
", HTML";
, API .
WebSocket;
Kafka backend-.
:
, - .
, .
Java + Spring Boot + Spring Cloud, .
, , .
, , :
, " . ( "");
-
Spring Cloud:
-
YouTube- SpringDeveloper;
-
:
Spring Cloud Kotlin. , Ribbon, Hystrix, OpenFeign, Sleuth, API gateway .properties, Spring Security.
-
-
-
: