8

Spring Cloud Netflix Zuul 使用自带的 Hystrix 实现回退机制 , 并实现请求在Zuul内部...

 3 years ago
source link: https://www.skypyb.com/2019/06/jishu/903/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Spring Cloud Netflix Zuul 使用自带的 Hystrix 实现回退机制 , 并实现请求在Zuul内部的聚合功能

上篇文章主要是搭建了一下Zuul的服务,并且实现了Zuul过滤器的自定义需求。

里边讲到了,Zuul 已经集成了 Ribbon、Hystrix ; 而 Ribbon无需配置,会在请求路由时自动给你进行负载均衡。

但是在Zuul服务路由不到对应微服务时,是没有对应的回退机制的,还是得自己手动写一下。

实现路由失败回退机制,首先需要继承 FallbackProvider 类,实现其getRoute() 和 fallbackResponse() 方法。

getRoute方法是指定你需要回退的线路,返回一个服务名就行。它会在路由该服务发生故障时调用 fallbackResponse 方法从而返回你一个 ClientHttpResponse 对象。

我写的回退代码:

package com.skypyb.sc.hystrix;
import com.netflix.hystrix.exception.HystrixTimeoutException;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
* 用户微服务不可访问时触发的响应
* <p>继承 {@link org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider} 以实现 hystrix 的回退
@Component
public class UserMicroserviceFallBack implements FallbackProvider {
    @Override
    public String getRoute() {
        return "sc-demo-microservice-user";
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        if (cause instanceof HystrixTimeoutException) {
            return response(HttpStatus.GATEWAY_TIMEOUT);
        } else {
            return response(HttpStatus.INTERNAL_SERVER_ERROR);
    private ClientHttpResponse response(HttpStatus status) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return status;
            @Override
            public int getRawStatusCode() throws IOException {
                return status.value();
            @Override
            public String getStatusText() throws IOException {
                return status.getReasonPhrase();
            @Override
            public void close() {
            @Override
            public InputStream getBody() throws IOException {
                return new ByteArrayInputStream("服务不可用,请稍后再试".getBytes());
            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                MediaType mt = new MediaType("application", "json", Charset.forName("UTF-8"));
                headers.setContentType(mt);
                return headers;

这个代码会在路由到sc-demo-microservice-user这个服务出错时触发,然后根据不同的异常给出不同的响应(我这就是变了个Status哈)

配上一个回退机制后,就让Zuul服务更加完善健壮了,这样子,就算路由的服务挂掉了,我也能返回个东西让前端显示,也能做一些其余的抢救操作。

Zuul这个服务到这,其实也就差不多了,该有的都有,虽说也有Zuul这个服务挂掉的可能,但是Zuul也是可以集群的呀,前端可以访问一个负载均衡的服务器(比如Nginx),让他来转发请求到集群Zuul服务上边,这样子,整个微服务架构就非常健壮了(像这种Nginx服务一般不会挂哈,就一个纯走流量的服务器都能挂了,那你的流量是有多猛   除非硬件问题,那没辙)

咳咳, 说起来Zuul服务搭是搭好了,但是你就做一个服务路由+负载均衡,那也不是个事啊,我客户端那边请求服务,我要是需要多个数据,我是不是要发多个请求?

每个请求都要走–>zuul–>service 这一套流程,是不是不大好,毕竟我发多个请求来请求多个服务,总会有性能损耗。

那要是我就发一个请求到Zuul Server ,然后由Zuul 来帮我聚合请求多个微服务,包装成一个数据返回响应给我好不好鸭,那当然是极好的。这些微服务所在的服务器八成是在一个局域网里(除非你买的实例所在地区不同甚至供应商都不同哈) 那个网络传输速度,快的飞起来。

这个是我写请求聚合的代码:

package com.skypyb.sc.controller;
import com.google.common.collect.Maps;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.skypyb.sc.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.Map;
* 请求聚合
* 客户端只需要发送一个请求到 zuul server ,由 zuul 帮忙将多个请求的数据合并
@RestController
@RequestMapping("/aggregate")
public class AggregationController {
    private Logger logger = LoggerFactory.getLogger(AggregationController.class);
    @Autowired
    private RestTemplate restTemplate;
    @HystrixCommand(fallbackMethod = "fullbackUserAndMovieUser")
    @GetMapping("/user/user_movie/{id}")
    public Map<String, User> userAndMovieUser(@PathVariable Long id) {
        User user = restTemplate.getForObject("http://sc-demo-microservice-user/user/{id}", User.class, id);
        User movieUser = restTemplate.getForObject("http://sc-demo-microservice-movie/movie/user/{id}", User.class, id);
        Map map = Maps.newHashMap();
        map.put("user", user);
        map.put("movieUser", movieUser);
        return map;
    //异常回退
    public Map<String, User> fullbackUserAndMovieUser(Long id) {
        return Collections.EMPTY_MAP;

我这就请求了zuul一个服务,然后就全权交给zuul给我把我要的数据都拿到了,组合成一个数据响应给我,是不是非常nice。我客户端的请求代码编写,也变得简单了。

到现在为止,整个Zuul架构就差不多了。自定义过滤器、回退、请求聚合、我还提供了一个zuul的集群高可用方案。基本上可以满足大多生产需求。

我的项目地址:Github


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK