0 environment

System environment: Win10

Editor: IDEA

Springcloud: H

1 introduction

Hystrix is called a circuit breaker/fuse. Fuse equivalent

  • Micro service in multiple services can be directly call service Call a sudden failure (often walk by the river Which have not wet shoes) may the entire system cold (service avalanche effect – > [| similar paragraph time are short of people actually hypothesis Metaphor may be inappropriate in food supermarket A – > B – > C | A expediting raw material factory –> B needs raw materials to urge the delivery –> C has no staff, B can only urge C and so on, there are goods, and A constantly urge B, B can only continue to urge C so cold]) solve this problem through Hystrix A model

The block failed and the whole system worked through something that we had configured

2 Basic Usage

  • Create a springboot project configuration dependent into project | configuration yml – > port set application name had been | open circuit breaker connection…
  • Eureka Server, Provider and Hystrix are used in the project

2.1 Creating a Project

2.2 yml configuration

spring:
  application:
    name: hystrix
server:
  port: 3000

eureka:
  client:
    service-url:
      defaultZone: http://localhost:1234/eureka
Copy the code

2.3 Enabling circuit Breakers and Providing RestTemplate instances

// Start the circuit breaker
@SpringCloudApplication
public class HystrixBaseApplication {

    public static void main(String[] args) {
        SpringApplication.run(HystrixBaseApplication.class, args);
    }

    // Provide the RestTemplate instance
    @Bean
    @LoadBalanced
    RestTemplate restTemplate(a){
        return newRestTemplate(); }}Copy the code

2.4 Hystrix interface

2.4.1 Differences between Consumer and Hystrix

  • Annotation type
// hystrix
@Service
public class HelloService {
    @Autowired
    RestTemplate restTemplate;
	/ * * *@DescriptionIn this method we will make a remote call to the Hello interface provided by provider * but this call may fail * we need to add it to the method@HystrixCommandAnnotations configure the fallbackMethod property * this property indicates that if you call a method and it fails, you can replace it with a temporary method * (the more degraded the service is -> The easier it is to get data but the accuracy of the data is degraded) * The ignoreExceptions property is used to learn to ignore an exception *@Param* : []@return: java.lang.String
	    * @Author: 
	    * @Date: 2020xx/xx
	*/
// @HystrixCommand(fallbackMethod = "error")
    @HystrixCommand(fallbackMethod = "error", ignoreExceptions = ArithmeticException.class)
    public String hello(a){
        // Exception handling is not the provider's fault but the consumer's own exception
// int i = 1/0;
        return restTemplate.getForObject("http://provider/hello", String.class);
    }
/ * * *@DescriptionThe method name must be the same as the name in the fallbackMethod property and the return type must be the same@Param:
    * @return:
    * @Author: 
    * @Date: 2020/xx/xx
    */
    public String error(a){
        return "error"; }}Copy the code
// hystrix
@RestController
public class HelloController {
    @Autowired
    HelloService helloService;
	/ * * *@Description: In the first place, an instance of the Provider in Eureka shuts down the server acquisition. * It will take time to tell the consumer (another scenario is request delay) and an error screen will appear * until the consumer is notified * Then Hystrix will jump out of the eroor string instead of an error screen to show the user an interface (isn't that much better) *@Param:
	     * @return:
	     * @Author: 
	     * @Date: 2020/xx/xx
    */
    @GetMapping("/hello")
    public String hello(a){
        returnhelloService.hello(); }}Copy the code
// provider
@RestController
public class HelloController {

    @Value("${server.port}")
    Integer port;

    @GetMapping("/hello")
    public String hello(a){
        return "hello>>>"+ port; }}Copy the code
  • Package provider find target location java-jar XXXX –server.port= XXX open window 2 set two different proTs and start Eureka server
  • Experience the difference between a consumer call and a Hystrix call (if the call fails, check to the server to see if it is registered)
  • Start the Consumer (the previous code will do) and close the provider by calling CTRL + C. An error page will be displayed when the call is made, indicating that the provider port will wait for a while before being displayed. The closed port will have a delivery time when the Consumer receives it and will display normally
  • Restart the closed provider port. Start Hystrix. Invoke the Hello interface to refresh the URL for several times

3 Request Commands

  • Inheritance implementation

The basic use

// hystrix
// The thread isolation policy is used by default (some parameters of the thread pool can be configured) and the semaphore policy can be configured
public class HelloCommand extends HystrixCommand<String> {

    @Autowired
    RestTemplate restTemplate;
	
	public HelloCommand(Setter setter, RestTemplate restTemplate) {
        super(setter);
        this.restTemplate = restTemplate;
    }
	
	@Override
    protected String run(a) throws Exception {
// int i = 1 / 0;
// Get the current thread name
// System.out.println(Thread.currentThread().getName());
        return restTemplate.getForObject("http://provider/hello", String.class);
// return restTemplate.getForObject("http://provider/hello2? name={1}", String.class, name);}}Copy the code
// hystrix controller
/ * * *@Description: An instance can be executed only once, either directly or after being queued@Param:  
    * @return:  
    * @Author: 
    * @Date: 2020/xx/xx
    */
    @GetMapping("/hello1")
    public void hello1(a){
        HelloCommand learn = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("learn")), restTemplate);
        // Execute directly
        String execute = learn.execute();
        System.out.println("Direct execution:" + execute);

        HelloCommand helloCommand = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("learn")), restTemplate);
        Future<String> queue = helloCommand.queue();

        try {
            // Team up first
            String s = queue.get();
            System.out.println(s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch(ExecutionException e) { e.printStackTrace(); }}Copy the code

Start eureka Server and Provider and hystrix to access hello1 and view the results on the console

Hystrix inheritance implements degradation

public class HelloCommand extends HystrixCommand<String> {

    @Autowired
    RestTemplate restTemplate;

    String name;

    public HelloCommand(Setter setter, RestTemplate restTemplate, String name) {
        super(setter);
        this.name = name;
        this.restTemplate = restTemplate;
    }

    public HelloCommand(Setter setter, RestTemplate restTemplate) {
        super(setter);
        this.restTemplate = restTemplate;
    }

    // The cache needs to override this method
    @Override
    protected String getCacheKey(a) {
        return name;
    }

    /* * Failed to request callback * * */
    @Override
    protected String getFallback(a) {
        return "error_extends";
    }

    @Override
    protected String run(a) throws Exception {
// int i = 1 / 0;
        return restTemplate.getForObject("http://provider/hello", String.class);
        // Get the current thread name
// System.out.println(Thread.currentThread().getName());}}Copy the code

Restart the Hystrix project to access Hello1 (start 2Provider is registered before closing a refresh to see the effect similar to the original annotated approach)

  • Annotations enable asynchronous invocation of the request
/ / hystrix controller layer
@GetMapping("/hello2")
    public void hello2(a){
        Future<String> stringFuture = helloService.hello1();

        try {
            String s = stringFuture.get();
            System.out.println(s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch(ExecutionException e) { e.printStackTrace(); }}Copy the code
// hystrix service
/ * * *@DescriptionRequest asynchronous invocation * via annotations@Param:
    * @return:
    * @Author: 
    * @Date: 2020/xx/xx
    */
    @HystrixCommand(fallbackMethod = "error")
    public Future<String> hello1(a){
        return new AsyncResult<String>(){

            @Override
            public String invoke(a) {
                return restTemplate.getForObject("http://provider/hello", String.class); }}; }Copy the code

Restart the Hystrix project to access Hello2

4 Exception Handling

  • Annotated implementation
	// hystrix controller
	@GetMapping("/hello")
	public String hello(a){
	     return helloService.hello();
	}
Copy the code
// hystrix service
@Service
public class HelloService {
    @Autowired
    RestTemplate restTemplate;

    / * * *@DescriptionIn this method we will make a remote call to the Hello interface provided by provider * but this call may fail * we need to add it to the method@HystrixCommandAnnotations configure the fallbackMethod property * this property indicates that if you call a method and it fails, you can replace it with a temporary method * (the more degraded the service is -> The easier it is to get data but the accuracy of the data is degraded) * The ignoreExceptions property is used to learn to ignore an exception *@Param* : []@return: java.lang.String
    * @Author: 
    * @Date: 2020/xx/xx
    */
// @HystrixCommand(fallbackMethod = "error")
    @HystrixCommand(fallbackMethod = "error", ignoreExceptions = ArithmeticException.class)
    public String hello(a){
        // Exception handling is not the provider's fault but the consumer's own exception
        int i = 1/0;
        return restTemplate.getForObject("http://provider/hello", String.class);
    }
     / * * *@DescriptionThe method name must be the same as the name in the fallbackMethod property and the return type must be the same@Param:
    * @return:
    * @Author:
    * @Date: 2020/xx/xx
    */
    public String error(Throwable throwable){
        return "error: "+ throwable.getMessage(); }}Copy the code
  • Inheritance implementation
public class HelloCommand extends HystrixCommand<String> {

    @Autowired
    RestTemplate restTemplate;
    
    public HelloCommand(Setter setter, RestTemplate restTemplate) {
        super(setter);
        this.restTemplate = restTemplate;
    }

    /* * Failed to request callback * * */
    @Override
    protected String getFallback(a) {
        // There is an exception in the inheritance method because it is overridden so we cannot add Throwable to the argument
        // call with getExecutionException
        return "error_extends: " + getExecutionException().getMessage();
    }

    @Override
    protected String run(a) throws Exception {
        int i = 1 / 0;
        return restTemplate.getForObject("http://provider/hello", String.class);
        // Get the current thread name
// System.out.println(Thread.currentThread().getName());}}Copy the code

Restart Hystrix separately to access the Hello Hello1 interface

5 Request Caching

Call the same interface if the parameters are consistent cache

5.1 add cache

	// Add the hello2 interface to provider
    @GetMapping("/hello2")
    public String hello2(String name){
        System.out.println(new Date() + "- >" + name);
        return "hello " + name;
    }
Copy the code
  • Annotation type
// Hystrix service
	@HystrixCommand(fallbackMethod = "error1")
    // This annotation indicates that the result of the method request is cached
    // By default the cache key is the combination of n arguments to the method and the cache value is the return value of the method
    // key(n param combinations) : value
    @CacheResult
    public String hello2(String name){
        return restTemplate.getForObject("http://provider/hello2? name={1}", String.class, name);
    }

    @HystrixCommand(fallbackMethod = "error1")
    // This annotation indicates that the result of the method request is cached
    // By default the cache key is the combination of n arguments to the method and the cache value is the return value of the method
    // key(n param combinations) : value
    // Add @cacheKey to the key if only one parameter is required
    // If there are multiple requests with the same name, even if the id is different, the second request will use the result of the first request.
    @CacheResult
    public String hello3(@CacheKey String name, Integer id){
        return restTemplate.getForObject("http://provider/hello2? name={1}", String.class, name);
    }
	
	public String error1(String name){
        return "error1" + name;
    }
Copy the code
// hystrix controller
/ * * *@Description: Annotation *@Param:
    * @return:
    * @Author: Water walking *@Date: 2020/3/15 * /
    @GetMapping("/hello3")
    public void hello3(a){
        // It needs to be initialized or an error will be reported
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        // Cache data
        String learn = helloService.hello2("learn");
        // Use cache
        learn = helloService.hello2("learn");
        / / close
        context.close();
    }
Copy the code
  • Inheriting type
public class HelloCommand extends HystrixCommand<String> {

    @Autowired
    RestTemplate restTemplate;

    String name;

    public HelloCommand(Setter setter, RestTemplate restTemplate, String name) {
        super(setter);
        this.name = name;
        this.restTemplate = restTemplate;
    }

    public HelloCommand(Setter setter, RestTemplate restTemplate) {
        super(setter);
        this.restTemplate = restTemplate;
    }
	
	HystrixRequestCache is used to clear the cache based on the key returned by getCacheKey. This method is called in controller to clear the cache
	
    // The cache needs to override this method
    @Override
    protected String getCacheKey(a) {
        return name;
    }

    /* * Failed to request callback * * */
    @Override
    protected String getFallback(a) {
        // There is an exception in the inheritance method because it is overridden so we cannot add Throwable to the argument
        // call with getExecutionException
        return "error_extends: " + getExecutionException().getMessage();
    }

    @Override
    protected String run(a) throws Exception {
// int i = 1 / 0;
// return restTemplate.getForObject("http://provider/hello", String.class);
        // Get the current thread name
// System.out.println(Thread.currentThread().getName());
        return restTemplate.getForObject("http://provider/hello2? name={1}", String.class, name); }}Copy the code
// hystrix controller
@GetMapping("/hello5")
    public void hello5(a){
        // It needs to be initialized or an error will be reported
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        HelloCommand learn = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("learn")), restTemplate, "learn");
        // Execute directly
        String execute = learn.execute();
        System.out.println("Direct execution:" + execute);

        HelloCommand helloCommand = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("learn")), restTemplate, "learn");
        Future<String> queue = helloCommand.queue();

        try {
            // Team up first
            String s = queue.get();
            System.out.println("Streamline:" + s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }

        / / close
        context.close();
    }
Copy the code

Restart Hystrix and access the Provider hello3 port on the console to see the Provider interface output does show only once the cache is valid

5.2 Removing Cache

// hystrix controller
@GetMapping("/hello4")
    public void hello4(a){
        // It needs to be initialized or an error will be reported
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        // Cache data
        String learn = helloService.hello2("learn");
        // Delete the cache
        helloService.delUserByName("learn");
        // Request to provider because cache data is deleted
        learn = helloService.hello2("learn");
        / / close
        context.close();
    }
Copy the code
// hystrix service
@HystrixCommand(fallbackMethod = "error1")
    // This annotation indicates that the result of the method request is cached
    // By default the cache key is the combination of n arguments to the method and the cache value is the return value of the method
    // key(n param combinations) : value
    @CacheResult
    public String hello2(String name){
        return restTemplate.getForObject("http://provider/hello2? name={1}", String.class, name);
    }

    @HystrixCommand(fallbackMethod = "error1")
    // This annotation indicates that the result of the method request is cached
    // By default the cache key is the combination of n arguments to the method and the cache value is the return value of the method
    // key(n param combinations) : value
    // Add @cacheKey to the key if only one parameter is required
    // If there are multiple requests with the same name, even if the id is different, the second request will use the result of the first request.
    @CacheResult
    public String hello3(@CacheKey String name, Integer id){
        return restTemplate.getForObject("http://provider/hello2? name={1}", String.class, name);
    }

    public String error1(String name){
        return "error1" + name;
    }

    / * * *@DescriptionWhen we delete database data, we also delete cache data -->@CacheRemoveEnter * delete cache where cache (specified) such as delete a specified method * use@CacheRemoveWith the commandKey attribute --> Specifies the cache to which the * commandKey attribute specifies a method to delete@Param: [name]
     * @return: java.lang.String
     * @Author: Water walking *@Date: 2020/3/15 * /
    @HystrixCommand
    // Delete the cache
    @CacheRemove(commandKey = "hello2")
    public String delUserByName(String name){
        return null;
    }
Copy the code

Restart Hystrix and provider access hello3 port on the console to view the Provider interface output showing that the cache has been removed twice

6 Requesting a Merger

Frequent calls to the Provider interface are wasteful because there is a way to combine multiple requests into one

// Provide the request merge interface in the provider
@RestController
public class UserController {
    / * * *@Description: if the consumer sends an id(1,2,3,4,5.... Such a format) requires a format conversion * the interface handles a single request/merges (multiple) requests after *@Param:
    * @return:
    * @Author: Water walking *@Date: 2020/3/15 * /
    @GetMapping("/user/{ids}")
    public List<User> getUserByIds(@PathVariable String ids){
        System.out.println("ids: " + ids);
        // String is cut into a string array
        String[] split = ids.split(",");

        List<User> list = new ArrayList<>();

        // Add string traversal as an attribute in user to the list collection
        for (String s : split) {
            User user = new User();
            // String converts int
            user.setId(Integer.parseInt(s));
            list.add(user);

        }

        returnlist; }}Copy the code
// Hystrix pom.xml adds the Commons module<dependency>
	  <groupId>xxx</groupId>
	  <artifactId>commons</artifactId>
	  <version>1.0 the SNAPSHOT</version>
	</dependency>
Copy the code
  • Annotation type
// hystrix service
@Service
public class UserService {

    @Autowired
    RestTemplate restTemplate;

    @HystrixCollapser(batchMethod = "getUserByIds",collapserProperties = {@HystrixProperty(name = "timerDelayInMilliseconds",value = "200")})
    public Future<User> getUsersByIds(Integer id){
        return null;
    }

    @HystrixCommand
    public List<User> getUserByIds(List<Integer> ids){
        Class because the List. Class result is a map --> class attribute :value is cumbersome to handle
        // And the array needs to be converted to string
        User[] users = restTemplate.getForObject("http://provider/user/{1}", User[].class, StringUtils.join(ids, ","));

        returnArrays.asList(users); }}Copy the code
// hystrix controller
@GetMapping("/hello7")
    public void hello7(a) throws ExecutionException, InterruptedException {
        // It needs to be initialized or an error will be reported
        HystrixRequestContext context = HystrixRequestContext.initializeContext();

        Future<User> queue = userService.getUsersByIds(74);
        Future<User> queue1 = userService.getUsersByIds(64);
        Future<User> queue2 = userService.getUsersByIds(54);
        Future<User> queue3 = userService.getUsersByIds(44);

        User user = queue.get();
        User user1 = queue1.get();
        User user2 = queue2.get();
        User user3 = queue3.get();
        System.out.println(user);
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);

        / / close
        context.close();
    }
Copy the code
  • Inheritance (understand)
// hystrix
public class UserBatchCommand extends HystrixCommand<List<User>> {

    private List<Integer> ids;
    private UserService userService;

    public UserBatchCommand(List<Integer> ids, UserService userService) {
        / / write to death
        super(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("batchCmd")).andCommandKey(HystrixCommandKey.Factory.asKey("batchKey")));
        this.ids = ids;
        this.userService = userService;
    }

    @Override
    protected List<User> run(a) throws Exception {
        returnuserService.getUserByIds(ids); }}Copy the code
// hystrix
// request merge
public class UserCollapseCommand extends HystrixCollapser<List<User>, User.Integer> {

    private Integer id;
    private UserService userService;

    public UserCollapseCommand(UserService userService, Integer id) {
        / / write to death
        super(HystrixCollapser.Setter.withCollapserKey(HystrixCollapserKey.Factory.asKey("userCollapseCommand")).andCollapserPropertiesDefaults(HystrixCollapserProperties.Setter().withTimerDelayInMilliseconds(200)));
        this.id = id;
        this.userService = userService;
    }

    // Request parameters
    @Override
    public Integer getRequestArgument(a) {
        return id;
    }

    // request the merge method
    @Override
    protected HystrixCommand<List<User>> createCommand(Collection<CollapsedRequest<User, Integer>> collection) {
        List<Integer> list = new ArrayList<>(collection.size());
        for (CollapsedRequest<User, Integer> integerCollapsedRequest : collection) {
            list.add(integerCollapsedRequest.getArgument());
        }
        return new UserBatchCommand(list, userService);
    }

    // Request results distribution
    @Override
    protected void mapResponseToRequests(List<User> users, Collection<CollapsedRequest<User, Integer>> collection) {
        int count = 0;
        for(CollapsedRequest<User, Integer> userIntegerCollapsedRequest : collection) { userIntegerCollapsedRequest.setResponse(users.get(count++)); }}}Copy the code
/ / service implementation
@Service
public class UserService {

    @Autowired
    RestTemplate restTemplate;

    @HystrixCommand
    public List<User> getUserByIds(List<Integer> ids){
        Class because the List. Class result is a map --> class attribute :value is cumbersome to handle
        // And the array needs to be converted to string
        User[] users = restTemplate.getForObject("http://provider/user/{1}", User[].class, StringUtils.join(ids, ","));

        returnArrays.asList(users); }}Copy the code
// hystrix controller
@GetMapping("/hello6")
    public void hello6(a) throws ExecutionException, InterruptedException {
        // It needs to be initialized or an error will be reported
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        UserCollapseCommand cmd = new UserCollapseCommand(userService, 99);
        UserCollapseCommand cmd1 = new UserCollapseCommand(userService, 88);
        UserCollapseCommand cmd2 = new UserCollapseCommand(userService, 77);
        UserCollapseCommand cmd3 = new UserCollapseCommand(userService, 66);

        // Join the queue
        Future<User> queue = cmd.queue();
        Future<User> queue1 = cmd1.queue();
        Future<User> queue2 = cmd2.queue();
        Future<User> queue3 = cmd3.queue();

        User user = queue.get();
        User user1 = queue1.get();
        User user2 = queue2.get();
        User user3 = queue3.get();
        System.out.println(user);
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);


        / / close
        context.close();
    }
Copy the code

7 summary

Degraded handling annotations (@hystrixCommand (fallbackMethod = “XXX “)) and inherited (override getFallback()) caching annotations @Cacheresult and override getCacheKey() @hystrixcollapser (batchMethod = “getUserByIds”,collapserProperties = {@hystrixProperty (name = “TimerDelayInMilliseconds “,value = “200”)}) –> Request merge latency and @hystrixCommand