[Spring cloud realizes advertising system step by step] 19. Monitoring Hystrix Dashboard

Keywords: Java Spring SDK JSON SpringBoot

In the previous 18 articles, we have implemented the advertising system's advertising placement, advertising retrieval business functions, using service discovery Eureka, service invocation Feign, gateway routing Zuul and error fusing Spring Cloud components such as Hystrix.
Simple call relationships:

But the system will always report errors. We defined some fault-tolerant classes and methods before, but only in the console can we see the error information. We want to statistics some data, how can we see our service invocation more intuitively? Next, we discuss a new fuse monitoring component Hystrix Dashbo. Ard, as its name implies, can be seen from its name. It is a graphical interface for monitoring.

Use of Hystrix in Services

Use in conjunction with openfeign

In our actual project, the most frequently used is the combination of FeignClient#fallback and Hystrix to achieve fusing. Let's take a look at our implementation in mscx-ad-feign-sdk.

@FeignClient(value = "mscx-ad-sponsor", fallback = SponsorClientHystrix.class)
public interface ISponsorFeignClient {
    @RequestMapping(value = "/ad-sponsor/plan/get", method = RequestMethod.POST)
    CommonResponse<List<AdPlanVO>> getAdPlansUseFeign(@RequestBody AdPlanGetRequestVO requestVO);

    @RequestMapping(value = "/ad-sponsor/user/get", method = RequestMethod.GET)
    /**
     * Feign If the buried hole is a Get request, you must add {@link RequestParam} before all parameters, and you cannot use {@link Param}.
     * It is automatically forwarded as a POST request.
     */
    CommonResponse getUsers(@RequestParam(value = "username") String username);
}

In the above code, we customize a feignclient and give the client a fallback implementation class:

@Component
public class SponsorClientHystrix implements ISponsorFeignClient {
    @Override
    public CommonResponse<List<AdPlanVO>> getAdPlansUseFeign(AdPlanGetRequestVO requestVO) {
        return new CommonResponse<>(-1, "mscx-ad-sponsor feign & hystrix get plan error.");
    }

    @Override
    public CommonResponse getUsers(String username) {
        return new CommonResponse<>(-1, "mscx-ad-sponsor feign & hystrix get user error.");
    }
}

This fallback class implements our custom ISponsorFeignClient, because the fallback method must be consistent with the method signature of the original execution class, so that when execution fails, the fallback method can be mapped to the response's degraded method/fault-tolerant method by reflection.
In the mscx-ad-search service, we call our mscz-ad-sponsor service by injecting ISponsorFeignClient.

@RestController
@Slf4j
@RequestMapping(path = "/search-feign")
public class SearchFeignController {

    /**
     * Inject our custom FeignClient
     */
    private final ISponsorFeignClient sponsorFeignClient;
    @Autowired
    public SearchFeignController(ISponsorFeignClient sponsorFeignClient) {
        this.sponsorFeignClient = sponsorFeignClient;
    }

    @GetMapping(path = "/user/get")
    public CommonResponse getUsers(@Param(value = "username") String username) {
        log.info("ad-search::getUsersFeign -> {}", JSON.toJSONString(username));
        CommonResponse commonResponse = sponsorFeignClient.getUsers(username);
        return commonResponse;
    }
}
Using HystrixCommand

In fact, Hystrix itself provides a direct way to apply the method, using @ com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand. Let's take a look at the source code of this class:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface HystrixCommand {
    ...

        /**
     * Specifies a method to process fallback logic.
     * A fallback method should be defined in the same class where is HystrixCommand.
     * Also a fallback method should have same signature to a method which was invoked as hystrix command.
     * for example:
     * <code>
     *      @HystrixCommand(fallbackMethod = "getByIdFallback")
     *      public String getById(String id) {...}
     *
     *      private String getByIdFallback(String id) {...}
     * </code>
     * Also a fallback method can be annotated with {@link HystrixCommand}
     * <p/>
     * default => see {@link com.netflix.hystrix.contrib.javanica.command.GenericCommand#getFallback()}
     *
     * @return method name
     */
    String fallbackMethod() default "";

    ...
}

We focus on two main points:

  1. @ Target({ElementType.METHOD}) indicates that current annotations can only be applied to methods.
  2. Fault tolerance can be guaranteed by directly defining fallbackMethod. One drawback of this method is that it must be implemented in the same class file as the method, which will make our method appear particularly redundant and inelegant when implemented.

Take our advertisement query in mscx-ad-search as an example:

@Service
@Slf4j
public class SearchImpl implements ISearch {

    /**
     * Fault Tolerance Method for Query Advertising
     *
     * @param e The second parameter can be unspecified. If you need to track errors, specify
     * @return Returns an empty map object
     */
    public SearchResponse fetchAdsFallback(SearchRequest request, Throwable e) {

        System.out.println("Inquiry Advertising Failed to Enter Fault Tolerant Degradation : %s" + e.getMessage());
        return new SearchResponse().builder().adSlotRelationAds(Collections.emptyMap()).build();
    }

    @HystrixCommand(fallbackMethod = "fetchAdsFallback")
    @Override
    public SearchResponse fetchAds(SearchRequest request) {
        ...
    }
}

When we request an error, we go to our fallback method, which is implemented by starting the @EnableCircuitBreaker annotation at application startup. This annotation intercepts all HystrixCommand methods through AOP, integrates HystrixCommand into springboot containers, and annotates the @EnableCircuitBreaker annotation. Method is put into the hystrix thread, and once it fails, fallback method is invoked by reflection.

Create dashboard project

The above code shows two ways Hystrix implements fusing. Next, we implement a graphical interface for request monitoring and create mscx-ad-dashboard, Let's code.
Still follow our spring boot trilogy:

  1. Additional dependence

    <dependencies>
     <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix</artifactId>
      <version>1.2.7.RELEASE</version>
     </dependency>
     <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
      <version>1.2.7.RELEASE</version>
     </dependency>
     <!--eureka client-->
     <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-actuator</artifactId>
     </dependency>
     </dependencies>
  2. append notes to

    /**
    * AdDashboardApplication for Hystrix Dashboard Startup class
    *
    * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang | Ruochuan</a>
    * @since 2019/8/15
    */
     @SpringBootApplication
     @EnableDiscoveryClient
     @EnableHystrixDashboard
     public class AdDashboardApplication {
    
     public static void main(String[] args) {
         SpringApplication.run(AdDashboardApplication.class, args);
     }
     }
  3. Reconfiguration

     server:
     port: 1234
     spring:
     application:
         name: mscx-ad-dashboard
     eureka:
     client:
         service-url:
         defaultZone: http://server1:7777/eureka/,http://server2:8888/eureka/,http://server3:9999/eureka/
     management:
     endpoints:
         web:
         exposure:
             include: "*"`

Start directly and you can see the following pages:

Add the service address to be monitored:

Posted by Yueee on Thu, 15 Aug 2019 21:37:40 -0700