SPRING CLOUD micro service DEMO- Part II

1 Hystix

1.1 Introduction

Hystix open source Netflix is ​​a delay and fault-tolerant library to isolate remote access service, third-party libraries, to prevent cascading failures.

I feel difficult to explain, in view of the next demo project basically will not use this module, forget the code over again.

1.2 configure and test

Simulate what fuse : Once the request exceeds the maximum 1s no longer continue to respond to the request, started to realize defined rollback function that returns a message.
Note: Ribbon of retry mechanism and Hystrix the fuse mechanism to some extent.

1.2.1 introduced dependence

A service to the user-consume caller pom file inside to add hystrix dependence.

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

1.2.2 open fuse

Add in the UserConsumeApplication@EnableCircuitBreaker

Annotations can see a little bit more, it can be used @SpringCloudApplicationinstead of the above three notes

//@EnableDiscoveryClient // 开启EurekaClient功能
//@EnableCircuitBreaker  //开启熔断
//@SpringBootApplication
@SpringCloudApplication   //三合一注解

1.2.3 reform consume

That transformation consume consumer calls the method, time-consuming record interface calls, writing calls timeout rollback method.

@HystrixCommand(fallbackMethod="queryUserByIdFallback"): Declare a failure rollback handler queryUserByIdFallback, when queryUserById execution timeout (default is 1000 milliseconds), will perform fallback function that returns the error.

@Component
public class UserDao {
    @Autowired
    private RestTemplate restTemplate;

    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);

    @HystrixCommand(fallbackMethod = "queryUserByIdFallback")
    public User queryUserById(Long id){
        long begin = System.currentTimeMillis();
        String url = "http://user-service/user/" + id;
        User user = this.restTemplate.getForObject(url, User.class);
        long end = System.currentTimeMillis();
        // 记录访问用时:
        logger.info("访问用时:{}", end - begin);
        return user;
    }

    public User queryUserByIdFallback(Long id){
        User user = new User();
        user.setId(id);
        user.setUsername("用户信息查询出现异常!");
        return user;
    }
}
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        ids.forEach(id -> {
            // 我们测试多次查询,
            users.add(this.userDao.queryUserById(id));
        });
        return users;
    }
}

1.2.4 transformation service

Namely the transformation of the service provider, the method of random delay, analog out.

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;

    public User queryById(Long id)  throws InterruptedException {
        // 为了演示超时现象,我们在这里然线程休眠,时间随机 0~2000毫秒
        Thread.sleep(new Random().nextInt(2000));
        return this.userMapper.selectByPrimaryKey(id);
    }
}

1.2.5 results

Clearly, more than 1000ms the rollback request is processed off method.

1.2.6 Set Hystrix timeout

Before we set Robbin's ReadTimeoutis 1000ms, an interface that is more than 1000ms request did not respond to a request to another interface with the same functionality and Hystrix timeout default is 1000ms, to observe the phenomenon seen that first triggered the fuse. But this is unreasonable, obviously you can request another interface to get results, results triggered fuse, returns no results.
So note that: Hystrix timeout must be greater than the retry time Robbin.

hystrix:
  command:
    default:
        execution:
          isolation:
            thread:
              timeoutInMillisecond: 6000 # 设置hystrix的超时时间为6000ms

2. Feign

2.1 Introduction

Feign Rest request can be hidden, disguised as such as SpringMVC the Controller. You do not have to own stitching url, splicing operation parameters, etc., to do everything to Feign.

2.2 Feign

Feign introduction and arranged in consume all the

2.2.1 introduced dependence

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2.2.2 UserConsumeApplication add annotations

@EnableFeignClients

2.2.3 write UserClient Interface

Add client package in the project, the following new UserClient Interface

@FeignClient("user-service")
public interface UserClient {
    @GetMapping("/user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}
  • First, this is an interface, Feign dynamic proxies will help us generate the implementation class. This is much like with mybatis the mapper
  • @FeignClient, This statement is a Feign client, similar @Mappercomments. By the same time valueattribute specifies the name of the service
  • The method defined interface, complete with SpringMVC notes, Feign will help us generate a URL based on annotations, and get access to the results

2.2.4 request data using UserClient

Transformation UserService, instead use UserClient request data

@Service
public class UserService {
    //@Autowired
    //private UserDao userDao;

    @Autowired
    private UserClient userClient;    //注入UserClient

    public List<User> queryUserByIds(List<Long> ids) {
        List<User> users = new ArrayList<>();
        ids.forEach(id -> {
            //使用UserClient请求接口
            users.add(userClient.queryUserById(id));
            //users.add(this.userDao.queryUserById(id));
        });
        return users;
    }
}

2.3 Load Balancing

Feign request is encapsulated in itself Ribbon integrated load balancing. It can be configured, and the writing of the same separate Robbin

user-service:
  ribbon:
    ConnectTimeout: 250 # 连接超时时间(ms)
    ReadTimeout: 1000 # 通信超时时间(ms)
    OkToRetryOnAllOperations: true # 是否对所有操作重试
    MaxAutoRetriesNextServer: 1 # 同一服务不同实例的重试次数
    MaxAutoRetries: 1 # 同一实例的重试次数

2.4 Hystrix support

Feign also integrated Hystrix.

You need to configure to open Hystrix

feign:
  hystrix:
    enabled: true # 开启Feign的熔断功能

Rollback method is not as written before, to define a special class.

@Component
public class UserFeignClientFallback implements UserClient {
    @Override
    public User queryUserById(Long id) {
        User user = new User();
        user.setId(id);
        user.setUsername("用户查询出现异常");
        return user;
    }
}

Configuration rollback based on the interface UserClient

@FeignClient(value = "user-service", fallback = UserFeignClientFallback.class)
public interface UserClient {
    @GetMapping("/user/{id}")
    User queryUserById(@PathVariable("id") Long id);
}

2.5. Request Compression

Spring Cloud Feign support GZIP compression requests and responses, in order to reduce performance losses during communication. By the following parameters to open request and response compression:

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
    response:
      enabled: true # 开启响应压缩

At the same time, we can request the data type, and the lower limit of the size of the trigger compression also be set:

feign:
  compression:
    request:
      enabled: true # 开启请求压缩
      mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
      min-request-size: 2048 # 设置触发压缩的大小下限

NOTE: The above data type, the compressed size lower limit are the default values.

3. Zuul Gateway

3.1 Introduction

Zuul is open source Netflix micro-services gateway, it can and Eureka, Ribbon and Hystrix and other components used in conjunction. The core is a series of filters to complete the authentication and rights management , dynamic routing , stress testing and other functions.

Workflow shown below

Whether from the client (PC or mobile terminal) requests, or internal service call. All requests are for services through Zuul this gateway, then the gateway to achieve authentication, dynamic routing, etc. operations. Zuul is to unify the entrance of our services.

3.2 build

3.2.1 build a new module

Other steps have already said, the choice can be selected Zuul module.

3.2.2 introduced dependence

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

3.2.3 Add notes

@SpringBootApplication
@EnableZuulProxy        //开启zuul网关
@EnableDiscoveryClient  //开启Eureka客户端发现功能
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

3.3 Routing function

Prior to testing first before adding a user-service random delays to comment out

Zuul routing functions:

  • Configuration
server:
  port: 10010 #服务端口
spring:
  application:
    name: api-gateway #指定服务名

eureka:
  client:
    registry-fetch-interval-seconds: 5 # 获取服务列表的周期:5s
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
  instance:
    prefer-ip-address: true
    ip-address: 127.0.0.1

zuul:
  prefix: /api # 添加路由前缀
  routes:
    user-service: # 路由id,一般与服务名相同
      path: /user-service/** # 映射路径
      serviceId: user-service
  • He explained: Zuul from Eureka pulls the list of services, if someone requests /api/user-service/**, forwards the request to the service list

    user-serviceservice.

Pit father thing: Before the test when Zuul have been reported errors could not find user-service services, some time later to find their own good.

No longer reproduced to, I do not know why. If errors are reported, you can try to reimport using maven, and then try and so on.

  • Since generally the same route id and service name, zuul thus provides a simplified configuration, perform the same function as above
zuul:
  prefix: /api # 添加路由前缀
  routes:
    user-service: /user-service/** # 这里是映射路径

Visit http: // localhost: 10010 / api / user-service / user / 20 to get the results.

3.4 Filtering

3.4.1 ZuulFilter

ZuulFilter是过滤器的顶级父类,我们自己实现的过滤器都要继承自它。我们看看其中重要的四个方法:

public abstract ZuulFilter implements IZuulFilter{
    abstract public String filterType();
    abstract public int filterOrder();
    boolean shouldFilter();
    Object run() throws ZuulException;
}
  • shouldFilter:返回布尔值,判断过滤器是否需要执行。true表示执行,false反之。
  • run:表示具体的过滤逻辑。
  • filterType:返回字符串,表示本过滤器的类型
    • pre:请求在被路由之前执行。
    • routing:在路由请求时调用
    • post:在routing和errror过滤器之后调用
    • error:处理请求时发生错误调用
  • filterOrder:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。

3.4.2 生命周期

  • 正常流程:
    • 请求到达首先会经过pre类型过滤器,而后到达routing类型,进行路由,请求就到达真正的服务提供者,执行请求,返回结果后,会到达post过滤器。而后返回响应。
  • 异常流程:
    • 整个过程中,pre或者routing过滤器出现异常,都会直接进入error过滤器,再error处理完毕后,会将请求交给post过滤器,最后返回给用户。
    • 如果是error过滤器自己出现异常,最终也会进入POST过滤器,而后返回。
    • 如果是post过滤器出现异常,会跳转到error过滤器,但是与pre和routing不同的时,请求不会再到达post过滤器了。

3.4.3 使用场景

  • 请求鉴权:一般放在pre类型,如果发现没有访问权限,直接就拦截了
  • 异常处理:一般会在error类型和post类型过滤器中结合来处理。
  • 服务调用时长统计:pre和post结合使用。

3.4.4 模拟登录校验

添加登录过滤器

@Component
public class LoginFilter extends ZuulFilter {
    @Override
    public String filterType() {
        // 登录校验,肯定是在前置拦截
        return "pre";
    }
    @Override
    public int filterOrder() {
        // 顺序设置为1
        return 1;
    }
    @Override
    public boolean shouldFilter() {
        // 返回true,代表过滤器生效。
        return true;
    }
    @Override
    public Object run() {
        // 登录校验逻辑。
        // 1)获取Zuul提供的请求上下文对象
        RequestContext ctx = RequestContext.getCurrentContext();
        // 2) 从上下文中获取request对象
        HttpServletRequest req = ctx.getRequest();
        // 3) 从请求中获取token
        String token = req.getParameter("access-token");
        // 4) 判断
        if(token == null || "".equals(token.trim())){
            // 没有token,登录校验失败,拦截
            ctx.setSendZuulResponse(false);
            // 返回401状态码。也可以考虑重定向到登录页。
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        // 校验通过,可以考虑把用户信息放入上下文,继续向后执行
        return null;
    }
}

3.5 负载均衡和熔断功能

Zuul内部集成了Ribbon负载均衡和Hystrix熔断器,需要配置

zuul:
  retryable: true
ribbon:
  ConnectTimeout: 250 # 连接超时时间(ms)
  ReadTimeout: 2000 # 通信超时时间(ms)
  OkToRetryOnAllOperations: true # 是否对所有操作重试
  MaxAutoRetriesNextServer: 2 # 同一服务不同实例的重试次数
  MaxAutoRetries: 1 # 同一实例的重试次数
hystrix:
  command:
    default:
        execution:
          isolation:
            thread:
              timeoutInMillisecond: 6000 # 熔断超时时长:6000ms

总结

一直在想着如何配置,如何实现,容易犯一叶障目不见泰山的毛病,下面就概括一下。

Eureka 注册中心

服务提供者在里面注册,服务消费者拉取服务列表,根据服务列表去发请求并获取数据。

这其中涉及到最重要的一个问题:如何保证服务列表里面的服务是有效的

  • 对于提供者,这个问题是:你怎么才能知道我什么时候可用,什么时候不可用?

Eureka和提供者就形成了约定:提供者准备好后在Eureka里面注册,Eureka知道提供者可用了。注册后提供者每隔一段时间向Eureka发个消息说我还活着,Eureka就知道提供者依旧可用。Eureka每隔一段时间就会扫描整个服务列表,把很长时间没报告过的服务剔除出去。这样注册中心的服务列表就能始终更新,始终可用。

  • 对于消费者,这个问题是:我怎么知道你不行了?

消费者每隔一段时间就从注册中心拉取服务列表,注册中心和服务提供者的约定保证了这个列表可以信任,我就根据这个列表发出请求,得到数据。

注意上面的三个时间段,这都是可以配置的,怎么配置就根据实际情况来了。

Robbin 负载均衡

服务的消费者在拉取服务列表后,针对同一业务可能有多个可选的服务提供者。

如果一直使用其中一个,那就是传说中的"一核有难,八核围观",表现差劲,浪费资源,这就需要负载均衡了。

Ribbon提供了诸如随机、轮询等多种策略可选。

它还提供了重试机制:选择了一个服务后,如果这个服务坏了(毕竟每隔一段时间才拉取服务列表,服务列表也是每隔一段时间才更新),或者说反应太慢,到了一定时间就考虑再换一个服务。

Hystrix 熔断机制

为了避免一个模块的错误拖垮整个系统,因此将其隔离起来。

不要让一颗老鼠屎坏了一锅汤?这个机制我不太能讲清楚。

但是注意它和Ribbon的联系,一个服务没有反应,应该先用Ribbon进行重试,而不是先熔断。然后这又引出来一个问题,一个错误如果每次都被重试机制掩盖了,那系统还会被拖垮吗?还是说这个业务的服务都坏了,试来试去找不到一个好用的,才触发熔断?想不清楚,真遇到了再说吧。

Feign 请求封装

封装了RestTemplate,让请求的编码更简单。

请求必然涉及负载均衡和熔断问题,所以Feign里面也可以配置Robbin和Hystrix。

但不光如此,Feign还提供了请求压缩等小功能。

Zuul 网关

微服务提供者的接口是暴露在外的,要是谁都能用那就乱套了。

就像学校的器材室有各种器材,但是谁都能自由取用就乱了。因此我们需要一个管理器材的老师,拿器材的人来了,先判断他有没有老师的批准,再根据老师的批准决定他能拿什么器材,最后把他带到对应的器材室拿相应的器材。

Zuul就像是这个老师,负责鉴权(判断一个人能不能拿器材,能拿什么器材)、路由(领到地方拿器材)。

Zuul虽然不发请求,但是对请求有很强的干预能力,所以它也可以配置负载均衡和熔断。

写在最后

这篇文章基本上是照抄网上流传的黑马乐优商城的资料,外加自己的一点点见解。
虽然培训班的名声不太好,但只要能学到知识,我不管知识是从哪里来的,别人随便鄙视,无所谓。
最后还是要感谢让我学到知识的那些人。

Guess you like

Origin www.cnblogs.com/qianbixin/p/10936458.html