Five components of spring cloud in the growth of Rookies

Posted by grilldor on Sun, 02 Jan 2022 14:52:22 +0100

Ribbon (load balancing)

 

In a production environment, one server is often not enough. Building clusters is essential. After the cluster is set up and registered with Eureka, how does Eureka know which to call each time? Call the same one every time? The cluster is the same as not built. Random call? China is OK, I think so! But I think it's better to configure the same server one by one. So Ribbon was born.

There is no need to introduce any jar package to use ribbon because ribbon and Eureka are produced by the same company. Eureka was designed with load balancing in mind. You only need to open it with a comment.

Using the ribbon process:

  1. Add the @ LoadBalanced annotation on the consumer RestTemplate class. Because the consumer invokes the service remotely through HTTP. RestTemplate encapsulates http. After load balancing is enabled, your service list is pulled by RestTemplate. Here is a code snippet:
    package com.zhao.user;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.client.loadbalancer.LoadBalanced;
    import org.springframework.context.annotation.Bean;
    import org.springframework.web.client.RestTemplate;
    
    @SpringBootApplication
    @EnableDiscoveryClient   //Enable eureka client discovery
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    
        @Bean
        @LoadBalanced
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    

    Modify the Controller to access the service id.

    package com.zhao.user.controller;
    
    import com.zhao.user.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.cloud.client.ServiceInstance;
    import org.springframework.cloud.client.discovery.DiscoveryClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    import java.util.List;
    
    
    @RestController
    @RequestMapping("/consumer")
    public class UserController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @GetMapping("/{id}")
        public User queryById(@PathVariable Long id){
    
            String url = "http://user-service/user/"+id;
            
            //Get the instance of user service registered in eureka
            return restTemplate.getForObject(url, User.class);
    
        }
    
    }
    

  2. Register multiple service s, no more demo
  3. Source tracking

As can be seen from the figure above, ribbon load balancing uses polling by default and accesses one by one. In fact, there are 7 load balancing strategies by default

Policy classnamedescribe
RandomRuleRandom strategyRandomly select server
RoundRobinRuleround-robin policy Polling selection, polling index, and selecting the Server corresponding to the index;
RetryRuleRetry policyFor the on-board retry mechanism of the selected load balancing policy, if the server selection is unsuccessful within a configured time period, it has been trying to select an available server by using the subRule method
BestAvailableRuleMinimum concurrency policyCheck the servers one by one. If the server circuit breaker is open, ignore it, and then select the server with the lowest concurrent link
AvailabilityFilteringRuleAvailable filtering policiesFilter out the servers that fail all the time and are marked as circuit tripped, filter out those servers with high concurrency links (active connections exceed the configured threshold), or use an availability predict to include the logic of filtering servers, which is actually to check the running status of each server recorded in the status;
ResponseTimeWeightedRuleResponse time weighted weight strategyThe weight is allocated according to the response time of the server. The longer the response time, the lower the weight, and the lower the probability of being selected. The shorter the response time, the higher the weight, and the higher the probability of being selected. This strategy is very appropriate and integrates various factors, such as network, disk, io, etc., which directly affect the response time
ZoneAvoidanceRuleRegional weight strategyComprehensively judge the performance of the area where the server is located and the availability of the server, poll and select the server, judge whether the operation performance of an AWS Zone is available, and eliminate all servers in the unavailable Zone

Modify by setting yml file

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Hystrix (fuse)

Minor sequence:

My name is porcupine, also known as Zhugang hyena. My nickname is Jie Jie, and my number is Wuneng. Everyone calls me the messenger of the net altar. In short, I'm covered with thorns to protect myself.

Text:

When I call a service, the thread has been blocking the provider. In this way, the thread pool resources of our consumer will be exhausted before long. This is not what I want to see, but it is inevitable. So Zhugang hyena came. She was like a rich woman. She saw through my strength and let me take off all my disguises and walk into her heart.

How safe is she? For example, as long as your consumer integrates Hystrix, it will allocate a small thread pool for your service. If the thread pool is full or the request times out, it will be degraded. Queuing is not used by default to speed up the failure determination time.

Take you to experience:

  1. Introducing jar package on the consumer side:
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
             </dependency>
  2. Add the @ enablercircuitbreaker annotation above the startup class to start the service
    /*@SpringBootApplication
    @EnableDiscoveryClient   //Enable eureka client discovery
    @EnableCircuitBreaker    //Open service fuse*/
    
    @SpringCloudApplication   //The above three annotations can be combined into one annotation
    public class ConsumerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
  3. Write a service degradation method to give users a friendly prompt.
    public String queryByIdFallBack(Long id){
            log.error("Failed to query user information. id: {}", id);
            return "Sorry, the Internet is too crowded!";  //Sometimes this line appears when you grab tickets because the server has hung up
        }
  4. Add @ HystrixCommand(fallbackMethod = "queryByIdFallBack") above the method to be degraded and indicate the name of the degraded method
        @GetMapping("/{id}")
        @HystrixCommand(fallbackMethod = "queryByIdFallBack")
        public String queryById(@PathVariable Long id){
            if (id == 1){
                throw new RuntimeException("invalid id");
            }
    
            String url = "http://user-service/user/"+id;
    
            //Get the instance of user service registered in eureka
            return restTemplate.getForObject(url, String.class);
    
        }
  5. Test the effect yourself, but remind me that when you test for the first time, it will show "sorry, the network is too crowded!", This is because java code compilation takes time. If the consumer calls the provider for more than 1 second, the service degradation will be triggered, and the retest will be normal after compilation. Timeout waiting can be modified through configuration
    hystrix:
      command:
        default:
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 2000

Eureka inexplicably removed me from the registration center list last time, just because I was a little late because of my network delay. In the end, he made both compensation and land cutting, which made me very uncomfortable. There are similar scenarios in Hystrix. There is a common thing in everyone's home, the electric switch, which has a fuse made of aluminum antimony alloy. When the current passing through it is too large, it will fuse itself to protect the safety of the circuit.

Put it on the Hystrix, that is, you have a request that always fails. But there's no problem with other requests. Now a hacker knows this, and he is always happy to call your failed requests. Your thread pool will soon be full of useless requests. Other available requests can only be watched! The uncle can bear it, neither can the aunt!

Pig ganghyena's solution is that if you call useless requests more than 20 times, and half or more of the call results fail. I think you're here to do something. I'll turn on the service fuse and downgrade all services of your interface. I go to sleep for five seconds and wake up. I will release some requests and take a sneak look. If the request for something is still there, I will sleep for another 5 seconds. This cycle. If the trouble maker is gone, I'll turn off the fuse until I meet the next one

effect:

Implementation steps:

  1. Set the fusing duration and the minimum number of fusing trigger requests
    hystrix:
      command:
        default:
          circuitBreaker:
            errorThresholdPercentage: 50   # Trigger fusing error proportional threshold, default 50%
            sleepWindowInMilliseconds: 10000   # Sleep duration after fusing, the default value is 5 seconds
            requestVolumeThreshold: 10   # The minimum number of fuse trigger requests. The default value is 20
          execution:
            isolation:
              thread:
                timeoutInMilliseconds: 2000   # Fuse timeout setting, the default is 1 second
  2. Modify controller
        @GetMapping("/{id}")
        @HystrixCommand()
        public String queryById(@PathVariable Long id){
    
            if (id == 1){
                time++;
                System.out.println(time);
                throw new RuntimeException("invalid id");
            }
    
            String url = "http://user-service/user/"+id;
    
            //Get the instance of user service registered in eureka
            return restTemplate.getForObject(url, String.class);
    
        }

    Just ask http://localhost:8080/consumer/1 It's bound to go wrong

    Just ask http://localhost:8080/consumer/ 3. You will succeed

  3. The effect is shown in the figure above. If the request id is 1 for more than 10 times, an error is reported for 10 times, triggering the fuse mechanism. After 10 seconds, request the correct address again, and the fuse is half closed and open. You can request the correct results. ​​​​​​​ 

Feign (disguise)

Now most of the requirements of spring cloud are met, but the only thing that bothers me is that the address of my consumer calling server needs to be spliced manually. If you don't pay attention, you'll splice it wrong. Take a closer look at this address:

String url = "http://user-service/user/"+id;

I should always have a service address id and protocol for calling the service provider. The protocol stipulates that HTTP is commonly used. I know which service name and path to call myself. At this point, I can use dynamic proxy to http://user-service/user/ This section is packed. The packaging process is as follows:

  • The consumer introduces feign component jar package
  •         <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
  • Create proxy interface
    package com.zhao.user.client;
    
    
    import com.zhao.user.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient("user-service"). //@FeignClient, declare that this is a Feign client, and specify the service name through the value attribute
    public interface UserClient {
    
        @GetMapping("/user/{id}")
        public User queryById(@PathVariable("id") long id);
    
    }
    

  • Write a new controller and use UserClient access (the above proxy interface can be regarded as the interface of mapper layer)
  • package com.zhao.user.controller;
    
    
    import com.zhao.user.client.UserClient;
    import com.zhao.user.pojo.User;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/cf")
    public class ConsumerFeignController {
    
        @Autowired
        private UserClient userClient;
    
        @GetMapping("/{id}")
        public User queryById(@PathVariable Long id) {
            return userClient.queryById(id);
        }
    
    
    }
    
  • Visit http://localhost:8080/cf/3 Success!

     

Access process: access the cf/3 interface -- > call the fegin client (create a proxy class and access the provider) - > call the provider service -- > get the result and return it

The above is to achieve the effect that there is no need to manually splice url addresses, but what should I do with my load balancing and service fusing? Don't worry, fegin has already figured it out for you. It has integrated Ribbon and Hystrix into its own project. By default, the service provider calls the provider for more than 1 second and times out to degrade the service. The configuration in fegin is as follows

ribbon:
  ConnectTimeout: 1000 # Connection timeout duration
  ReadTimeout: 3000 # Call the service, and the total time returned by the service is equivalent to the fuse timeout setting above
  MaxAutoRetries: 0 # Number of retries for the current server
  MaxAutoRetriesNextServer: 0 # How many service retries
  OkToRetryOnAllOperations: false # Do you want to retry all request methods
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Remember! The above configuration is only configured by the fegin integration ribbon. In other words, you can configure this configuration only when you use the fegin client.

Load balancing is realized. How should the service be configured? The configuration is as follows:
 

  • Turn on the fuse function of fegin in the yml of the consumer
    feign:
      hystrix:
        enabled: true # Turn on the fusing function of Feign
  • Write service degradation class
    package com.zhao.user.client.fallback;
    
    import com.zhao.user.client.UserClient;
    import com.zhao.user.pojo.User;
    import org.springframework.stereotype.Component;
    
    @Component
    public class UserClientFallback implements UserClient {
    
        @Override
        public User queryById(long id) {
            User user = new User();
            user.setId(id);
            user.setName("User exception");
            return user;
        }
    }
    
  • Specify the service degradation class in the fegin client
    package com.zhao.user.client;
    
    
    import com.zhao.user.client.fallback.UserClientFallback;
    import com.zhao.user.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "user-service",fallback = UserClientFallback.class) //fallback indicates the service degradation class
    public interface UserClient {
    
        @GetMapping("/user/{id}")
        public User queryById(@PathVariable("id") long id);
    
    }
    
  • When the service provider sleeps for 2 seconds, it will definitely timeout. After timeout, the service will be degraded and the effect will be worse

Sometimes the amount of data requested or responded to is too large, so your transmission process will be very slow. To be ridiculous, you have transmitted half of it, and the server is down. You are in a hurry! So transmission speed is very important. fegin supports request / response compression. The configuration is as follows

Add configuration in the consumer yml

feign:
  hystrix:
    enabled: true # Turn on the fusing function of Feign
  compression:
    request:
      enabled: true # Turn on request compression
      mime-types: text/html,application/xml,application/json # Set compressed data type
      min-request-size: 2048 # Sets the lower limit of the size that triggers compression
    response:
      enabled: true # Turn on response compression

Effect, I'm sorry, I can't find a larger format to test. As long as the startup does not report an error, it is feasible by default

Log level of fegin. The spring boot configuration log level is to add logging. XML in yml level.** = debug (* * indicates the package name). This is not the case in fegin. When the client modified by @ FeignClient} annotation is proxied, a new instance of Fegin.Logger will be created. We need to specify the level of this log. The process is as follows:

  1. Added to the consumer yml
    logging:
      level:
        com.zhao.user: debug
  2. Write config class
    package com.zhao.user.config;
    
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class FeignConfig {
        @Bean
        Logger.Level feignLoggerLevel() {
            //Record the details of all requests and responses, including header information, request body and metadata
            return Logger.Level.FULL;
        }
    }
    
  3. Add the debug log class in the fegin client interface
    package com.zhao.user.client;
    
    
    import com.zhao.user.client.fallback.UserClientFallback;
    import com.zhao.user.config.FeignConfig;
    import com.zhao.user.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient(value = "user-service",fallback = UserClientFallback.class,configuration = FeignConfig.class)
    public interface UserClient {
    
        @GetMapping("/user/{id}")
        public User queryById(@PathVariable("id") long id);
    
    }
    
  4. The test has no effect of adding logs

  5. Added log effect

Aside, fegin supports 4 log levels

  • NONE: no log information is recorded, which is the default value.
  • BASIC: only record the requested method, URL, response status code and execution time
  • HEADERS: on the basis of BASIC, additional header information of request and response is recorded
  • FULL: records the details of all requests and responses, including header information, request body and metadata.

FULL is used in the above code, and the last one

Spring cloud gateway (Gateway)

Whether the request comes from the client (PC or mobile terminal) or the internal call of the service, all requests for the service can pass through the Gateway, and then the Gateway can realize authentication, dynamic routing and other operations. The Gateway is the unified entrance of our service.

The composition of route information: it consists of an ID, a destination URL, a group of assertion factories and a group of filters. If the route assertion is true, it indicates that the request URL matches the configured route.

The input type of the assertion function in Spring Cloud Gateway is ServerWebExchange in Spring 5.0 framework. The assertion function of Spring Cloud Gateway allows developers to define and match any information from Http Request, such as request header and parameters.

Filter is a standard Spring WebFilter. There are two types of filters in Spring Cloud Gateway: Gateway Filter and Global Filter. The filter will modify requests and responses.

In my understanding of routing, when your front-end request comes and accesses my gateway layer, you should do it according to my rules. You have to visit whoever you want to visit.

For the understanding of assertions, my request path contains some values, but if you don't carry them, I assert that you access through the interface. If you don't follow the right path, you won't be released. Once my assertion is true, your visit fails

For the understanding of the filter, have you heard of it? Once someone approaches the emperor, search first and turn in all your weapons. Maybe you will wear special clothes to see the driver. Protect the server from malicious attacks.

Take you one by one:

Create a new project "gateway"

  1. Import jar package
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-gateway</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>

  2. Create boot class
    package com.zhao.geteway;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    
    @SpringBootApplication
    @EnableDiscoveryClient   //You need to register with the eureka registry. The eureka client discovery function must be enabled
    public class GatewayApplication {
        public static void main(String[] args) {
            SpringApplication.run(GatewayApplication.class, args);
        }
    }
    
  3. Set yml file
    server:
      port: 10010
    spring:
      application:
        name: api-gateway
      cloud:
        gateway:
          routes:
          # The routing id can be written at will
            - id: user-service-route
              # Service address of agent
              uri: http://127.0.0.1:9091
              # Route assertion, you can configure the mapping path
              predicates:
                - Path=/user/**
    eureka:
      client:
        service-url:
          defaultZone: http://zhao:123456@localhost:10086/eureka
      instance:
        prefer-ip-address: true # Prefer to use ip rather than host name
  4. Visit http://localhost:10010/user/8

  5. Effect

I visited 10010, but I actually visited the service provider of 9091. Isn't it amazing! The gateway is equivalent to a forwarding operation.

The above operations still have some disadvantages. For example, I write the url of the provider to death, which makes it difficult for the instance under the same service id. the gateway's solution is that you give me the service id name and decide which one to call. Just modify the configuration

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
      # The routing id can be written at will
        - id: user-service-route
          # The service address of the agent; lb means to obtain specific services from eureka
          uri: lb://user-service
          # Route assertion, you can configure the mapping path
          predicates:
            - Path=/**
          filters:
          # Add prefix to request path
            - PrefixPath=/user
eureka:
  client:
    service-url:
      defaultZone: http://zhao:123456@localhost:10086/eureka
  instance:
    prefer-ip-address: true # Prefer to use ip rather than host name

Adding the request path prefix above means that the original address to access the service is

http://localhost:10010/user/2

Now you don't need to add / user for access. You can access it directly

http://localhost:10010/2  

If you are not satisfied with the provider's address and the front end wants to add some inexplicable rules, how can you ensure that the route is routed to the correct provider?

Very simple, refer to the following configuration

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes:
      # The routing id can be written at will
        - id: user-service-route
          # The service address of the agent; lb means to obtain specific services from eureka
          uri: lb://user-service
          # Route assertion, you can configure the mapping path
          predicates:
            - Path=/api/user/**
          filters:
          # It means filtering 1 path, 2 means two paths, and so on
            - StripPrefix=1
eureka:
  client:
    service-url:
      defaultZone: http://zhao:123456@localhost:10086/eureka
  instance:
    prefer-ip-address: true # Prefer to use ip rather than host name

Visit http://localhost:10010/api/user/2 You can get the correct return

Filter: divided into global filter and local filter.

Global filter adding method 1

Add filter to yml file

server:
  port: 10010
spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      default-filters:
        # The response header filter sets the header attribute name of the output response as X-Response-Default-MyName and the value as zhao; If there are multiple parameters, override one line to set different parameters
        - AddResponseHeader=X-Response-Default-MyName, zhao
      routes:
      # The routing id can be written at will
        - id: user-service-route
          # The service address of the agent; lb means to obtain specific services from eureka
          uri: lb://user-service
          # Route assertion, you can configure the mapping path
          predicates:
            - Path=/api/user/**
          filters:
          # It means filtering 1 path, 2 means two paths, and so on
            - StripPrefix=1
eureka:
  client:
    service-url:
      defaultZone: http://zhao:123456@localhost:10086/eureka
  instance:
    prefer-ip-address: true # Prefer to use ip rather than host name

The obtained response header contains information with the value zhao

Global filter addition method 2

  1. Create global filter class
    package com.zhao.geteway.filter;
    
    import org.apache.commons.lang.StringUtils;
    import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    import org.springframework.cloud.gateway.filter.GlobalFilter;
    import org.springframework.core.Ordered;
    import org.springframework.http.HttpStatus;
    import org.springframework.stereotype.Component;
    import org.springframework.web.server.ServerWebExchange;
    import reactor.core.publisher.Mono;
    
    @Component
    public class MyGlobalFilter implements GlobalFilter, Ordered {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            System.out.println("-----------------Global filter MyGlobalFilter------------------- --");
            String token = exchange.getRequest().getQueryParams().getFirst("token");
            if (StringUtils.isBlank(token)) {
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                return exchange.getResponse().setComplete();
            }
            return chain.filter(exchange);
        }
    
        @Override
        public int getOrder() {
            //The smaller the value, the earlier the execution
            return 1;
        }
    }
    

  2. The access does not carry a token

  3. Carry token

Local filter

  1. Create local filter class
    package com.zhao.geteway.filter;
    
    import org.springframework.cloud.gateway.filter.GatewayFilter;
    import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
    import org.springframework.http.server.reactive.ServerHttpRequest;
    import org.springframework.stereotype.Component;
    
    import java.util.Arrays;
    import java.util.List;
    
    @Component
    public class MyParamGatewayFilterFactory extends AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {
    
        static final String PARAM_NAME = "param";
    
        public MyParamGatewayFilterFactory() {
            super(Config.class);
        }
    
        public List<String> shortcutFieldOrder() {
            return Arrays.asList(PARAM_NAME);
        }
    
        @Override
        public GatewayFilter apply(Config config) {
            return (exchange, chain) -> {
                // http://localhost:10010/api/user/8?name=itcast   config.param ==> name
                //Gets the parameter value of the parameter name corresponding to param in the request parameter
                ServerHttpRequest request = exchange.getRequest();
                if(request.getQueryParams().containsKey(config.param)){
                    request.getQueryParams().get(config.param).
                            forEach(value -> System.out.printf("------------Local filter--------%s = %s------", config.param, value));
                }
                return chain.filter(exchange);
            };
        }
    
    
        public static class Config{
            //Corresponds to the parameter name specified when configuring the filter
            private String param;
    
            public String getParam() {
                return param;
            }
    
            public void setParam(String param) {
                this.param = param;
            }
        }
    }
    

  2. Add filter parameters to yml
          routes:
          # The routing id can be written at will
            - id: user-service-route
              # The service address of the agent; lb means to obtain specific services from eureka
              uri: lb://user-service
              # Route assertion, you can configure the mapping path
              predicates:
                - Path=/api/user/**
              filters:
              # It means filtering 1 path, 2 means two paths, and so on
                - StripPrefix=1
                # Custom filter
                - MyParam=name
  3. Test: http://localhost:10010/api/user/8?name=zhao&token=zhao The console gets the results and prints them

The Gateway configures the service provider's load balancing and fusing, and adds the configuration in yml. As long as there is no error and the access path can be accessed, the default configuration has taken effect

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 6000
ribbon:
  ConnectTimeout: 1000
  ReadTimeout: 2000
  MaxAutoRetries: 0
  MaxAutoRetriesNextServer: 0

Gateway cross domain configuration

Cross domain: in js request access, if the access address is inconsistent with the domain name, ip or port number of the current server, it is called cross domain request. If it is not solved, the return result of the corresponding address cannot be obtained.

It is not difficult to understand that when someone accesses my server, because it is not the same domain, the request is sent from js. I suspect that others are attacking me and will prohibit access. When I set the access permission for a url, it can access my service through js. The configuration is as follows:

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      globalcors:
        corsConfigurations:
          '[/**]':
            #allowedOrigins: * # This way of writing or the following can be used, * means all
            allowedOrigins:
              - "http://docs.spring.io"
            allowedMethods:
              # Indicates that it can be accessed through get requests
              - GET

Start without error, and the default is feasible! Well, I admit I'm too lazy

The provider services registered in Eureka can be load balanced through rabbit. How does Ga teway registered in Eureka perform load balancing? Very simple, load balancing can be achieved through nginx. Nginx can distribute services by polling or randomly. Then you can call the distributed gateway from Eureka.

                                

Spring Cloud Config (distributed configuration center)

Is it annoying to configure so many of the above configurations? Besides, it is only the configuration of one server. If it is the configuration of multiple servers, it is even more troublesome to modify them at the same time. Is there a way to centralize conventional configurations and pull them when they are used?

Yes, that's what we're going to talk about now. How does it do it? It is first like this, then like that, and finally like this. Genius is lonely, especially what he said. Fortunately, I can barely be an interpreter. It starts by creating a central repository in Git with regular configuration files. Then you can pull from git when you need it, and finally cache the pulled configuration locally.

The process is as follows:

  • Create a git warehouse and place the service provider's application YML file. Code cloud is recommended for git warehouse practice. (Note: be careful when naming the document, because you need to use it when pulling)
  • Create a new project
  1. Import jar package
        <dependencies>
            <!--Service to register with eureka In, the index is to be imported eureka of jar package-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-config-server</artifactId>
            </dependency>
        </dependencies>
  2. Create boot class
    package com.zhao.config;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.config.server.EnableConfigServer;
    
    @SpringBootApplication
    @EnableConfigServer  //Flag of configuration center service
    public class ConfigServerApplication {
        public static void main(String[] args) {
            SpringApplication.run(ConfigServerApplication.class, args);
        }
    }
    
  3. Create application yml

    server:
      port: 12000
    spring:
      application:
        name: config-server
      cloud:
        config:
          server:
            git:
              # git address of remote warehouse
              uri: https://gitee.com/Iso-8859-2/zhao-config.git
    eureka:
      client:
        service-url:
          # The service needs to be registered with the registry
          defaultZone: http://zhao:123456@localhost:10086/eureka
  4. Start test, access address http://localhost:12000/user-dev.yml (note) user-dev Is the file name created by my git repository)

  5. The association between java and git is completed!

The above git warehouse is configured by our service provider!

  1. Add dependency to provider
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
                <version>2.1.1.RELEASE</version>
            </dependency>
  2. Delete service provider application yml
  3. Add bootstrap. In the provider YML file. (the bootstrap.yml file is also the default configuration file for Spring Boot, and its loading time is earlier than that of application.yml.)
    spring:
      cloud:
        config:
          # Be consistent with the application of the configuration file in the warehouse
          name: user
          # Keep consistent with the profile of the configuration file in the warehouse
          profile: dev
          # It should be the same as the version (Branch) to which the configuration file in the warehouse belongs
          label: master
          discovery:
            # Use configuration center
            enabled: true
            # Configuration center service name
            service-id: config-server
      # Configure rabbitmq information; If both are consistent with the default values, no configuration is required
    
    
    eureka:
      client:
        service-url:
          defaultZone: http://zhao:123456@localhost:10086/eureka
  4. Future configurations can be pulled directly from the configuration center
  5. Start test

So far, a modification has been completed, and the effect can be obtained everywhere. However, every time you pull the cache to the local, it is carried out when the service is just started. If you don't take the initiative to pull it, you won't get the latest notice! This is simple. Let me design it. When I finish modifying the configuration file in the warehouse, I will actively notify you through message oriented middleware. You can pull the latest configuration and update the cache.  

Spring Cloud Bus (Service Bus)

The current service pulling process of our service provider is: config first obtains the service configuration file from git, and then the service provider obtains the configuration file from the config center and caches it locally. However, the configuration file config and provider are modified on git, but the latest notification is not available. It's really a headache. But I can take the initiative to inform you after every modification. The implementation process is as follows:

  1. Add the dependency of bus and rabbitmq in the config Center
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-bus</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
            </dependency>
  2. Add rabbitmq and the address of the service exposure center to yml
    server:
      port: 12000
    spring:
      application:
        name: config-server
      cloud:
        config:
          server:
            git:
              # git address of remote warehouse
              uri: https://gitee.com/Iso-8859-2/zhao-config.git
      rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest
    eureka:
      client:
        service-url:
          # The service needs to be registered with the registry
          defaultZone: http://zhao:123456@localhost:10086/eureka
    management:
      endpoints:
        web:
          exposure:
            # Expose the address of the trigger message bus, notify through this address every time, and re obtain the latest configuration file after notification
            include: bus-refresh

Configuration process of service provider

  1. Import jar package
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-bus</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-actuator</artifactId>
            </dependency>
  2. Add configuration of rabbitmq in yml
    # Configure rabbitmq information; If both are consistent with the default values, no configuration is required
      rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest
  3. Add @ RefreshScope annotation to provider controller
  4. Modify the configuration file in git and send the url through postman: http://127.0.0.1:12000/actuator/bus-refresh Test the config configuration center
  5. The provider has been updated
  6. Visit the provider controller to get the latest news. The test is successful

So far, the five components of spring cloud have been demonstrated!