The following is an excerpt from SpinrgCloud microservice architecture development practice
Service governance
There are two options for spring cloud service governance, Consul and Neiflix's Eureka.
Eureka is an open-source service governance product of Netflix. Spirng Cloud has secondary encapsulated it to form the Spirng Cloud Netflix sub project. Erueka provides a service registry, a service discovery client, and a UI application for registering services. From Eureka's point of view, nodes are equal to each other. Stopping some registration will not affect the whole application. Only one node can survive in time and can also manage services normally. Even if all service registration nodes are down, the service instance list information cached in Eureka client can enable service consumers to work normally, so as to ensure the robustness of mutual calls between microservices and the elasticity of applications.
Client load balancing
Spring cloud realizes client load balancing by encapsulating the Netflix open source project ribbon. Ribbon integrates seamlessly with Eureka by default. When the client starts, it obtains a service registration list from Eureka server and maintains it locally. When the service consumer needs to call the service, ribbon will select an appropriate service provider for access according to the load balancing strategy. By integrating the Feign project of Netflix, spring cloud provides developers with declarative service calls, which simplifies the call processing between microservices. In addition, the default Feign project inherits the ribbon, so that the declarative call also supports the balancing function of the client.
Microservice, fault tolerance, degradation
In SpirngCloud, by integrating the Netflix subproject hystrix and the @ HystrixCommand annotation provided, we can provide fault tolerance, fallback, degradation and other functions for the microservices we develop. By default, hystrix is also integrated into the Feign subproject. Hystrix is created according to the "circuit breaker" mode. When hystrix monitors that a service unit fails, it will enter the service fuse Chul and Bing will return a qualified service fallback to the caller instead of waiting for a long time or throwing a call exception, so as to ensure that the orange of the service caller will not be occupied unnecessarily for a long time, Avoid the avalanche effect caused by the spread of applause in English red. The hystrix Dashboard can monitor the time, request, success rate, etc. consumed by each service call.
Version used in this test
SpringBoot: 2.6.2
SpringCloud: 2021.0.0
Eureka service registry
maven configuration
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.2</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.demo</groupId> <artifactId>service-discovery</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-discovery</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
In addition to the basic version number configuration of SpringBoot and SpringCloud, the maven dependency of Eureka server must be added. The web module dependency can be omitted. If not, the default dependent web module of Eureka server will be used
Startup class
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class ServiceDiscoveryApplication { public static void main(String[] args) { SpringApplication.run(ServiceDiscoveryApplication.class, args); } }
The @ EnableEurekaServer annotation must be added
Parameter configuration
server.port=9999 eureka.instance.appname=eureka eureka.instance.hostname=127.0.0.1 eureka.instance.prefer-ip-address=true ## Currently, it is the eureka registration service center and is a stand-alone version. It is not necessary to register the current service with eureka. Set it to false eureka.client.register-with-eureka=false ## You do not need to pull the service list from the eureka registration service center and set it to false eureka.client.fetch-registry=false ## eureka registration service center address eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/ eureka.server.wait-time-in-ms-when-sync-empty=0 eureka.server.enable-self-preservation=false
At this point, the Eureka service registration center is set up. After startup, access the address http://127.0.0.1:9999/ , you can access the Eureka registration management interface, where you can see the registered services and other information
Service provider
maven configuration
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.2</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.demo</groupId> <artifactId>service-product</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-product</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2021.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
In addition to the basic version number configuration of SpringBoot and SpringCloud, the maven dependency of Eureka client must be added. Since the provided is a web service, the web related starter dependency also needs to be added
controller
package com.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.demo.entity.ResultEntity; @RestController @RequestMapping public class ServerController { private Logger logger = LoggerFactory.getLogger(ServerController.class); @RequestMapping("/getData/{id}") public Object getData(@PathVariable String id) { logger.info("server receive id: {}", id); return new ResultEntity(true, "result: "+id); } }
Return entity class
package com.demo.entity; public class ResultEntity { private boolean success; private String msg; public ResultEntity(boolean success, String msg) { this.success = success; this.msg = msg; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
Startup class
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * The @ EnableDiscoveryClient can be omitted for later versions * @author admin * */ @SpringBootApplication //@EnableDiscoveryClient public class ServiceProductApplication { public static void main(String[] args) { SpringApplication.run(ServiceProductApplication.class, args); } }
Parameter configuration
## Automatic port allocation. If automatic allocation will have an impact, you can specify a port. For example, if the specified port can be accessed through the firewall, you need to specify a port server.port=0 spring.application.name=service-provider eureka.client.register-with-eureka=true eureka.client.fetch-registry=false eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka/
Service consumers
maven configuration
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.2</version> <relativePath /> <!-- lookup parent from repository --> </parent> <groupId>com.demo</groupId> <artifactId>service-consumer</artifactId> <version>0.0.1-SNAPSHOT</version> <name>service-consumer</name> <description>Demo project for Spring Boot</description> <properties> <spring-cloud.version>2021.0.0</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
In addition to the basic version number configuration of SpringBoot and SpringCloud, the maven dependency of Eureka client must be added. Web projects also need to add web related dependencies. Since fegin is used, feign related dependencies also need to be added.
controller
package com.demo.controller; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.demo.entity.ResultEntity; import com.demo.service.ConsumerService; @RestController @RequestMapping public class ConsumerController { private Logger logger = LoggerFactory.getLogger(ConsumerController.class); @Autowired private ConsumerService ConsumerService; @RequestMapping("/getData/{id}") public Object getData(@PathVariable String id) { logger.info("concumer id: {}", id); ResultEntity data = ConsumerService.getData(id); return data; } }
Receiving entity class (corresponding to the returned entity class of the service provider)
package com.demo.entity; public class ResultEntity { private boolean success; private String msg; public ResultEntity(boolean success, String msg) { this.success = success; this.msg = msg; } public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
Startup class
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication //@EnableDiscoveryClient @EnableFeignClients public class ServiceConsumerApplication { public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
Parameter configuration
## Automatic port assignment server.port=8081 spring.application.name=service-consumer eureka.client.register-with-eureka=false eureka.client.fetch-registry=true eureka.client.service-url.defaultZone=http://127.0.0.1:9999/eureka/
For testing, start the eureka registry first, start the service provider, and finally start the service consumer. Access the interface: http://127.0.0.1:8081/getData/11 , the returned results are as follows
Where 11 is id, other values can also be used, and will be returned as is in the result.
At this point, a complete service governance process demo of service registration and consumption in eureka service registration ends.
matters needing attention:
1. In the lower version of spring cloud, both server providers and service consumers need to add the @ enablediscovery client annotation, but not in the higher version. Spring cloud will automatically open the eureka client according to the introduced starter
2. If the service provider returns a string and only uses Object to receive the results obtained remotely, the following exceptions may occur:
org.springframework.web.client.UnknownContentTypeException: Could not extract response:
no suitable HttpMessageConverter found for response type [class java.lang.Object] and content type [text/plain;charset=UTF-8]
You can use the entity object or map instead, or directly use the string to receive. If you use the entity object to return and receive data, you need to add get and set methods to the entity class, otherwise the following exceptions may occur
Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]
3. Both @ EnableEurekaClient and @ EnableDiscoveryClient can let the registry discover and scan the service. The former is only valid for Eureka, and the latter can be valid for Eureka, Zookeeper, Consul and other registries;
4. If feign is used for remote call, you must add @ EnableFeignClients on the service consumer side, otherwise the feign call will not work. In addition, if you remove the implementation class callback that implements the customized fegin related interface, the fegin interface call cannot be injected into the controller, and the following errors may occur when the service is started
Field ConsumerService in com.demo.controller.ConsumerController required a bean of type 'com.demo.service.ConsumerService' that could not be found.