1, RestTemplate service interface call
- getForEntity: the returned object is the object converted from the data in the response body, which can be basically understood as Json;
- getForObject: the returned object is the ResponseEntity object, which contains some important information in the response, such as response header, response status code, response body, etc;
- postForEntity: getBody() is required to obtain body data;
- postForObject: directly return body data;
1. Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing
2, Ribbon load balancing service call
1. What is it
- Spring Cloud Ribbon is a set of client-side load balancing tools based on Netflix Ribbon;
In short, Ribbon is an open source project released by Netflix. Its main function is to provide software load balancing algorithms and service calls on the client. - The Ribbon client component provides a series of complete configuration items, such as connection timeout, Retry, etc;
Simply put, list all the machines behind the Load Balancer (LB) in the configuration file. The Ribbon will automatically help you connect these machines based on certain rules (such as simple polling, random connection, etc.). We can easily use Ribbon to implement a custom load balancing algorithm.
1.1 Ribbon architecture description
- Ribbon works in two steps:
- The first step is to select Eureka Server, which gives priority to servers with less load in the same region;
- The second step is to select an address from the service registration list obtained from the Server according to the policy specified by the user;
- Ribbon provides a variety of strategies: such as polling, random, and weighting according to response time.
- Summary: Ribbon is actually a client component of soft load balancing. It can be used in combination with other clients requiring requests. The combination with Eureka is just one example.
1.2 Eureka client integrated ribbon
<!--eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--eureka-client Integrated ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
2. What can I do
2.1 what is load balancing
- Simply put, the user's requests are evenly distributed to multiple services, so as to achieve the HA (high availability) of the system;
- Centralized load balancing
That is, an independent LB facility (either hardware such as F5 or software such as Nginx) is used between the service consumer and the service provider, and the facility is responsible for forwarding the access request to the service provider through some policy; - In process load balancing
Integrate LB logic into the consumer. The consumer knows which addresses are available from the service registry, and then selects an appropriate server from these addresses;
- Common load balancing software includes Nginx, LVS, hardware F5, etc;
2.2 client load balancing VS server load balancing
- Ribbon local load balancing, when calling the micro service interface, will obtain the registration information service list in the registry and cache it to the local JVM, so as to realize the RPC remote service call technology locally.
- Nginx is server load balancing. All client requests will be handed over to nginx, and then nginx will forward the requests; That is, load balancing is realized by the server.
3. Ribbon core component IRule
IRule: select a service to be accessed from the service list according to a specific algorithm;
3.1 polling
com.netflix.loadbalancer.RoundRobinRule
3.2 random
com.netflix.loadbalancer.RandomRule
3.3 first obtain the service according to the roundrobin rule policy. If the service acquisition fails, it will retry within the specified time to obtain the available service
com.netflix.loadbalancer.RetryRule
3.4 for the extension of roundrobin rule, the faster the response speed, the greater the instance selection weight, and the easier it is to be selected
WeightedResponseTimeRule
3.5 first filter out the services in the circuit breaker tripping state due to multiple access faults, and then select a service with the least concurrency
BestAvailableRule
3.6 filter out fault instances first, and then select smaller concurrent instances
AvailabilityFilteringRule
3.7 the default rule is to judge the performance of the region where the Server is located and the availability of the Server, and select the Server
ZoneAvoidanceRule
4. Modify random strategy
cloud-consumer-order-eureka80
4.1 modifying RestTemplate
RestTemplate annotated @ LoadBalanced
@Configuration public class ApplicationContextBean { // applicationContext.xml > <bean id="" class="" /> @Bean // Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing // Customize the load balancing policy without @ LoadBalanced annotation @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
4.2 create a new class - com.qs.rule.MySelfRule
The official document clearly gives a warning: this custom configuration class cannot be placed under the current package and sub package scanned by @ ComponentScan, otherwise our custom configuration class will be shared by all Ribbon clients and the purpose of special customization will not be achieved.
@Configuration public class MySelfRule { @Bean public IRule myRule() { // Modify random strategy return new RandomRule(); } }
4.3 main startup
Annotate @ RibbonClient
@SpringBootApplication // Enable EurekaClient @EnableEurekaClient // When the microservice is started, we can load our custom Ribbon configuration class to make the configuration take effect @RibbonClient(name = "PROVIDER-PAYMENT-SERVICE", configuration = MySelfRule.class) public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class, args); } }
4.4 testing
5. Polling algorithm
- The Rest interface count starts from 1 after each service restart
Number of requests for Rest interface% total number of server clusters = actual call server location subscript
List<ServiceInstance> instances = discoveryClient.getInstances("PAYMENT-SERVICE-SERVICE"); List [0] instances = 127.0.0.1:8002; List [1] instances = 127.0.0.1:8001; 8001 + 8002 They are combined into clusters. There are 2 machines in total, and the total number of clusters is 2. According to the principle of polling algorithm: When the total number of requests is 1: 1 % 2 =1 If the corresponding subscript position is 1, the service address is 127.0.0.1:8001 When the total request digit is 2: 2 % 2 =0 If the corresponding subscript position is 0, the service address is 127.0.0.1:8002 When the total request digit is 3: 3 % 2 =1 If the corresponding subscript position is 1, the service address is 127.0.0.1:8001 When the total request digit is 4: 4 % 2 =0 If the corresponding subscript position is 0, the service address is 127.0.0.1:8002 And so on......
6. Customize polling policy
cloud-consumer-order-eureka80
6.1 modifying RestTemplate
RestTemplate remove annotation @ LoadBalanced
@Configuration public class ApplicationContextBean { // applicationContext.xml > <bean id="" class="" /> @Bean // Use the @ LoadBalanced annotation to give RestTemplate the ability of load balancing // Customize the load balancing policy without @ LoadBalanced annotation // @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
6.2 new interface - com.qs.springcloud.lb.LoadBalancer
public interface LoadBalancer { ServiceInstance instances(List<ServiceInstance> serviceInstances); }
6.3 create a new class - com.qs.springcloud.lb.MyLoadBalancer
@Component @Slf4j public class MyLoadBalancer implements LoadBalancer { private AtomicInteger atomicInteger = new AtomicInteger(0); public final int getAndIncrement() { int current, next; do { current = atomicInteger.get(); next = current >= 2147483647 ? 0 : current + 1; // Spin lock } while (!atomicInteger.compareAndSet(current, next)); log.info("next: " + next); return next; } /** * Load balancing algorithm: * The Rest interface count starts from 1 after each service restart * Rest Number of interface requests% total number of server clusters = actual call server location subscript */ @Override public ServiceInstance instances(List<ServiceInstance> serviceInstances) { int index = getAndIncrement() % serviceInstances.size(); return serviceInstances.get(index); } }
6.4 main startup
@SpringBootApplication // Enable EurekaClient @EnableEurekaClient public class OrderMain80 { public static void main(String[] args) { SpringApplication.run(OrderMain80.class, args); } }
6.5 testing
3, OpenFeign service interface call
1. What is it
Official website explanation ,GitHub
- Feign is a declarative web service client. Using feign can make it easier to write a web service client;
- Its usage method is to define a service interface and then add annotations on it. Feign also supports pluggable encoders and decoders;
- Spring Cloud encapsulates Feign to support Spring MVC standard annotations and HttpMessageConverters;
- Feign can be used in combination with Eureka and Ribbon to support load balancing.
2. What can I do
- Feign aims to make it easier to write Java Http clients;
- When Ribbon+RestTemplate is used earlier, a set of template calling methods is formed by encapsulating Http requests with RestTemplate. However, in actual development, because there may be more than one invocation of service dependencies, and often one interface will be invoked in multiple places, some client classes are usually encapsulated for each micro service to package the invocation of these dependent services;
- Therefore, Feign made further encapsulation on this basis to help us define and implement the definition of dependent service interfaces. Under the implementation of Feign, we only need to create an interface and configure it by annotation (previously, the Dao interface was marked with Mapper annotation, but now it is a micro service interface marked with Feign annotation), so as to complete the interface binding to the service provider, which simplifies the development of automatically encapsulating the service call client when using the Spring cloud Ribbon.
2.1 Feign integrates Ribbon
- The Ribbon is used to maintain the service list information of Payment, and the load balancing of the client is realized through polling;
- Unlike Ribbon, Feign only needs to define the service binding interface, and implements the service invocation gracefully and simply in a declarative way.
3. Differences between feign and OpenFeign
3.1 Feign
- Feign is a lightweight RESTful HTTP service client in the Spring Cloud component;
- Feign has built-in Ribbon, which is used for client load balancing to call the service of the service registry;
- Feign is used by using feign's annotation to define an interface. By calling this interface, you can call the service of the service registry.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
3.2 OpenFeign
- OpenFeign is a Spring Cloud that supports spring MVC annotations based on Feign, such as @ RequesMapping;
- OpenFeign's @ FeignClient can parse the interface under the @ RequestMapping annotation of spring MVC, generate implementation classes through dynamic proxy, implement load balancing in the classes and call other services.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
4. Steps for using openfeign
4.1 create a new module cloud consumer order feign80
4.2 POM
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud-2020</artifactId> <groupId>com.qs.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-order80-feign</artifactId> <dependencies> <!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--eureka-client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--actuator--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--custom API General package--> <dependency> <groupId>com.qs.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--Hot deployment--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
4.3 YML
server: port: 80 eureka: client: # false indicates whether to register yourself with EurekaServer. The default is true register-with-eureka: false service-url: defaultZone: http://localhost:7001/eureka
4.4 main startup
@SpringBootApplication // Open @ FeignClient annotation @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class, args); } }
4.5 new interface PaymentFeignService
@Component @FeignClient("PROVIDER-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping("/payment/get/{id}") CommonResult get(@PathVariable("id") Long id); @GetMapping(value = "/payment/feignTimeOut") String feignTimeOut(); }
4.6 new class - OrderFeignController
@RestController @RequestMapping("order") @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping("get/{id}") public CommonResult get(@PathVariable("id") Long id) { CommonResult commonResult = paymentFeignService.get(id); log.info("commonResult = " + commonResult); return commonResult; } @GetMapping("feignTimeOut") public String feignTimeOut() { return paymentFeignService.feignTimeOut(); } }
4.7 testing
4.8 modifying PaymentController
Thread pause for 3 seconds (Feign default timeout of 1 second)
@RestController @RequestMapping("payment") @Slf4j public class PaymentController { /** * Test Feign connection timeout * @return */ @GetMapping("feignTimeOut") public String feignTimeOut() { // Thread pause for 3 seconds (Feign default timeout of 1 second) try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } log.info("serverPort = " + serverPort); return serverPort; } }
4.9 timeout test
http://localhost/order/feignTimeOut
5. OpenFeign timeout control
- OpenFeign will wait for 1 second by default, and an error will be reported after it is exceeded;
- By default, the Feign client only waits for 1 second, but the server processing takes more than 1 second. As a result, the Feign client does not want to wait and directly returns an error.
To avoid this situation, sometimes we need to set the timeout control of Feign client.
## OpenFeign timeout control ## Set Feign client timeout (OpenFeign supports Ribbon by default) ribbon: # It refers to the time taken to establish a connection, which is applicable to the time taken to connect both ends under normal network conditions ReadTimeout: 5000 # It refers to the time taken to read available resources from the server after the connection is established ConnectTimeout: 5000
6. OpenFeign log printing function
- Feign provides the log printing function. We can adjust the log level through configuration to understand the details of Http requests in feign;
- To put it bluntly, it is to monitor and output the call of Feign interface;
- Log level:
- NONE: default, no logs are displayed;
- BASIC: only record the request method, URL, response status code and execution time;
- HEADERS: in addition to the information defined in BASIC, there are also header information of request and response;
- FULL: in addition to the information defined in HEADERS, there are also the body and metadata of the request and response.
6.1 create FeignConfig
@Configuration public class FeignConfig { /** * OpenFeign Log printing function * @return */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
6.2 YML
## OpenFeign log printing function logging: level: # At what level does Feign log monitor which interface com.qs.springcloud.service.PaymentFeignService: debug