Spring Cloud Gateway

发布时间 2023-05-29 11:26:46作者: 我不想学编丿程

Spring Cloud Gateway

学习了 Eureka 之后我们知道了 服务提供者 是 消费者 通过 [Eureka] Server 进行访问的,即[Eureka] Server 是 服务提供者的统一入口。那么整个应用中存在那么多 消费者 需要用户进行调用,这个时候用户该怎样访问这些 消费者工程 呢?当然可以像之前那样直接访问这些工程。但这种方式没有统一的消费者工程调用入口,不便于访问与管理.

1.什么是网关

网关是微服务最边缘的服务直接暴露给用户,用来做用户和微服务的桥梁

image-20230303160113732

  1. 没有网关:客户端直接访问我们的微服务,会需要在客户端配置很多的 ip:port,如果

user-service 并发比较大,则无法完成负载均衡

  1. 有网关:客户端访问网关,网关来访问微服务,(网关可以和注册中心整合,通过服务名

称找到目标的 ip:prot)这样只需要使用服务名称即可访问微服务,可以实现负载均衡,可

以实现 token 拦截,权限验证,限流等操作

2.Spring Cloud Gateway 简介

你们项目里面 用的什么网关? gateway zuul

它是 Spring Cloud 官方提供的用来取代 zuul(

netflix****)的新一代网关组件

zuul:1.0 , 2.0 ,zuul 的本质,一组过滤器,根据自定义的过滤器顺序来执行,本质就是

web 组件 web 三大组件(监听器 过滤器 servlet****)

拦截 springmvc

Zuul1.0 使用的是 BIO(

Blocking IO) tomcat7.0 以前都是 BIO 性能一般

Zuul2.0 性能好 NIO

AIO 异步非阻塞 io

a+nio = aio = async + no blocking io

它基于 spring5.x,springboot2.x 和 ProjectReactor 等技术。

它的目地是让路由更加简单,灵活,还提供了一些强大的过滤器功能,例如:熔断、限流、重

试,自义定过滤器等 token 校验 ip 黑名单等

SpringCloud Gateway作为Spring Cloud生态的网关,目标是替代Zuul,在SpringCloud2.0

以上的版本中,没有对新版本的 zuul2.0 以上的最新高性能版本进行集成,仍然还是使用的

zuul1.x[可以看项目依赖找到]非 Reactor 模式的老版本。而为了提升网关的性能,

SpringCloud Gateway 是基于 webFlux 框架实现的,而 webFlux 框架底层则使用了高性能

的 Reactor 模式通信框架的 Netty

NIO(非阻塞式 io) BIO 你只需要了解网关能做什么? 网关里面写什么代码 就可以了

3.Spring Cloud Gateway 工作流程

image-20230303162206546

客户端向 springcloud Gateway 发出请求,然后在 Gateway Handler Mapping 中找到与

请求相匹配的路由,将其发送到 Gateway Web Handler。

Handler 再通过指定的过滤器来将请求发送到我们实际的服务的业务逻辑,然后返回。 过滤器之间用虚线分开是因为过滤器可能会在发送爱丽请求之前【pre】或之后【post】执行业务

逻辑,对其进行加强或处理。

Filter 在 【pre】 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转

换等

在【post】 类型的过滤器中可以做响应内容、响应头的修改、日志的输出,流量监控等有着

非常重要的作用。

总结:Gateway 的核心逻辑也就是 路由转发 + 执行过滤器链

4.Spring Cloud Gateway 三大核心概念

4.1 Route(路由)(重点 和 eureka 结合做动态路由)

路由信息的组成:

由一个 ID、一个目的 URL、一组断言工厂、一组 Filter 组成。

如果路由断言为真,说明请求 URL 和配置路由匹配。

4.2 Predicate(断言)(就是一个返回 bool 的表达式)

Java 8 中的断言函数。 lambda 四大接口 供给形,消费性,函数型,断言型

Spring Cloud Gateway 中 的 断 言 函 数 输 入 类 型 是 Spring 5.0 框 架 中 的

ServerWebExchange。Spring Cloud Gateway 的断言函数允许开发者去定义匹配来自于

Http Request 中的任何信息比如请求头和参数

4.3 Filter(过滤) (重点)

一个标准的 Spring WebFilter。

Web 三大组件****(servlet listener filter) mvc

interceptor

Spring Cloud Gateway 中的 Filter 分为两种类型的 Filter,分别是 Gateway Filter 和

Global Filter。过滤器 Filter 将会对请求和响应进行修改处理。

一个是针对某一个路由(路径)的 filter 对某一个接口做限流

一个是针对全局的 filter token ip 黑名单

5.Nginx 和 Gateway 的区别

Nginx 在做路由,负载均衡,限流之前,都有修改 nginx.conf 的配置文件,把需要负载均衡,

路由,限流的规则加在里面。Eg:使用 nginx 做 tomcat 的负载均衡

但是 gateway 不同,gateway 自动的负载均衡和路由,gateway 和 eureka 高度集成,实现

自动的路由,和 Ribbon 结合,实现了负载均衡(

lb),gateway 也能轻易的实现限流和权限验证。

Nginx(c)比 gateway(java)的性能高一点。

本质的区别呢?

Nginx

(更大 服务器级别的)

Gateway

(项目级别的)

image-20230303162454689

6. Gatewa的两种路由配置方式

8.1 代码路由方式(掌握)

package com.example.getawayserver.config;

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class RouteConfig {
    /**
     * 代码的路由  和yml不冲突  都可以用
     * 如果你的uri后面给了一个访问地址 和匹配地址相同 那么就不会再凭借
     * @param builder
     * @return
     */

    @Bean
    public RouteLocator  customRouteLocator(RouteLocatorBuilder builder){
        return builder.routes()
                .route("path_route", r -> r.path("/get").uri("http://httpbin.org"))
                .build();
    }
}

8.2 使用 yml 方式(重点)

server:
  port: 80 # 网关一般是80

spring:
  application:
    name: gateway-server

  cloud:
    gateway:
      enabled: true
      routes:
        - id: login-service-route  # 这个是路由的id 保持唯一即可
          #                    uri: http://localhost:8081   # uri统一资源定位符   url 统一资源标识符
          uri: http://127.0.0.1:8081
          predicates:
            - Path=/doLogin/**   # 匹配规则  只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上

9.Gateway 微服务名动态路由,负载均衡

9.1 概述

从之前的配置里面我们可以看到我们的 URL 都是写死的,这不符合我们微服务的要求,我们

微服务是只要知道服务的名字,根据名字去找,而直接写死就没有负载均衡的效果了

默认情况下 Gateway 会根据注册中心的服务列表,以注册中心上微服务名为路径创建动态路

由进行转发,从而实现动态路由的功能

需要注意的是 uri 的协议为 lb(

load Balance****),表示启用 Gateway 的负载均衡功能。

lb://serviceName 是 spring cloud gateway 在微服务中自动为我们创建的负载均衡 uri

协议:就是双方约定的一个接头暗号

http://

9.2 配置文件

server:
  port: 80 # 网关一般是80

spring:
  application:
    name: gateway-server

  cloud:
    gateway:
      enabled: true # =只要加了依赖 默认开启
      routes: # 如果一个服务里面有100个路径  如果我想做负载均衡 ??   动态路由
        - id: login-service-route  # 这个是路由的id 保持唯一即可
          #uri: http://localhost:8081   # uri统一资源定位符   url 统一资源标识符
          uri: lb://login-service   # uri统一资源定位符   url 统一资源标识符
          predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
                - Path=/doLogin  # 匹配规则  只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
                - After=2022-03-22T08:42:59.521+08:00[Asia/Shanghai]
                - Method=GET,POST
      discovery:
        locator:
          enabled: true  # 开启动态路由  开启通用应用名称 找到服务的功能
          lower-case-service-id: true  # 开启服务名称小写

# 向eureka组成,得到负载均衡功能
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
    registry-fetch-interval-seconds: 3 # 网关拉去服务列表的时间缩短
  instance:
    hostname: localhost
    instance-id: ${eureka.instance.hostname}:${spring.application.name}:${server.port}

9.3 两种访问方式

http://localhost/login-service/doLogin login-service(服务名称)

http://localhost/doLogin

10. Predicate 断言工厂的使用【了解】

在 gateway 启动时会去加载一些路由断言工厂(判断一句话是否正确 一个 boolean 表达式 )

image-20230304110437012

10.1 什么是断言,Gateway 里面有哪些断言

断言就是路由添加一些条件(丰富路由功能的)

通俗的说,断言就是一些布尔表达式,满足条件的返回 true,不满足的返回 false。

Spring Cloud Gateway 将路由作为 Spring WebFlux HandlerMapping 基础架构的一部分

进行匹配。Spring Cloud Gateway 包括许多内置的路由断言工厂。所有这些断言都与 HTTP

请求的不同属性匹配。您可以将多个路由断言可以组合使用

Spring Cloud Gateway 创建对象时,使用 RoutePredicateFactory 创建 Predicate 对象,

Predicate 对象可以赋值给 Route

image-20230304110636031

10.2如何使用这些断言

我们常用yml配置文件的方式进行配置

cloud:
  gateway:
    enabled: true # =只要加了依赖 默认开启
    routes: # 如果一个服务里面有100个路径  如果我想做负载均衡 ??   动态路由
      - id: login-service-route  # 这个是路由的id 保持唯一即可
        #uri: http://localhost:8081   # uri统一资源定位符   url 统一资源标识符
        uri: lb://login-service   # uri统一资源定位符   url 统一资源标识符
        predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
              - Path=/doLogin  # 匹配规则  只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
              - After=2022-03-22T08:42:59.521+08:00[Asia/Shanghai]
              - Method=GET,POST
              - Query=name,admin.   #正则表达式的值
              
         predicates: #断言匹配
- Path=/info/** #和服务中的路径匹配,是正则匹配的模式
- After=2020-01-20T17:42:47.789-07:00[Asia/Shanghai] #此断言匹配发生在指定
日期时间之后的请求,ZonedDateTime dateTime=ZonedDateTime.now()获得
- Before=2020-06-18T21:26:26.711+08:00[Asia/Shanghai] #此断言匹配发生在指定
日期时间之前的请求
-
Between=2020-06-18T21:26:26.711+08:00[Asia/Shanghai],2020-06-18T21:32:26.711+08:00[Asia/Shanghai]
#此断言匹配发生在指定日期时间之间的请求
- Cookie=name,xiaobai #Cookie 路由断言工厂接受两个参数,Cookie 名称和 regexp(一
个 Java 正则表达式)。此断言匹配具有给定名称且其值与正则表达式匹配的 cookie
- Header=token,123456 #头路由断言工厂接受两个参数,头名称和 regexp(一个 Java 正
则表达式)。此断言与具有给定名称的头匹配,该头的值与正则表达式匹配。
- Host=**.bai*.com:* #主机路由断言工厂接受一个参数:主机名模式列表。该模式是一
个 ant 样式的模式。作为分隔符。此断言匹配与模式匹配的主机头
- Method=GET,POST #方法路由断言工厂接受一个方法参数,该参数是一个或多个参数:
要匹配的 HTTP 方法
- Query=username,cxs #查询路由断言工厂接受两个参数:一个必需的 param 和一个
可选的 regexp(一个 Java 正则表达式)。
- RemoteAddr=192.168.1.1/24 #RemoteAddr 路由断言工厂接受一个源列表(最小大小 1),
这些源是 cidr 符号(IPv4 或 IPv6)字符串,比如 192.168.1.1/24(其中 192.168.1.1 是 IP 地址,24 是子网掩码)


还有一个访问权重的设置,意思是说:
80%的请求,由 https://weighthigh.org 这个 url 去处理
20%的请求由 https://weightlow.org 去处理

routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2

11. Filter 过滤器工厂(重点)

11.1 概述

gateway 里面的过滤器和 Servlet 里面的过滤器,功能差不多,路由过滤器可以用于修改进入

Http 请求和返回 Http 响应

11.2 分类

11.2.1 按生命周期分两种

pre 在业务逻辑之前

post 在业务逻辑之后

11.2.2 按种类分也是两种

GatewayFilter 需要配置某个路由,才能过滤。如果需要使用全局路由,需要配置 Default

Filters。

GlobalFilter

全局过滤器,不需要配置路由,系统初始化作用到所有路由上

全局过滤器 统计请求次数 限流 token 的校验 ip 黑名单拦截 跨域本质(filter)

144 开头的电话 限制一些 ip 的访问

11.3 官方文档查看过滤器

11.3.1 单一过滤器(31个)

11.3.2 全局过滤器(9 个

11.4 自定义网关过滤器(重点)

11.4.1 自定义全局过滤器

全局过滤器的优点的初始化时默认挂到所有路由上,我们可以使用它来完成 IP 过滤,限流等

功能

11.4.2 创建配置类

/**
 * 定义了一个过滤器
 * 十个过滤器
 */
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {

    /**
     * 这个就是过滤的方法
     * 过滤器链模式
     * 责任链模式
     * 网关里面有使用  mybatis的 二级缓存有变种责任链模式
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 针对请求的过滤  拿到请求  header  url 参数 ....
        ServerHttpRequest request = exchange.getRequest();
        // HttpServletRequest  这个是web里面的
        // ServerHttpRequest  webFlux里面 响应式里面的
        String path = request.getURI().getPath();
        System.out.println(path);
        HttpHeaders headers = request.getHeaders();
        System.out.println(headers);
        String methodName = request.getMethod().name();
        System.out.println(methodName);
        String ip = request.getHeaders().getHost().getHostString();
        System.out.println(ip);
        // 响应相关的数据
        ServerHttpResponse response = exchange.getResponse();
        // 用了微服务 肯定是前后端分离的 前后端分离 一般前后通过 json
        // {"code":200,"msg":"ok"}
        // 设置编码 响应头里面置
        response.getHeaders().set("content-type","application/json;charset=utf-8");
        // 组装业务返回值
        HashMap<String, Object> map = new HashMap<>(4);
        map.put("code", HttpStatus.UNAUTHORIZED.value());
        map.put("msg","你未授权");
        ObjectMapper objectMapper = new ObjectMapper();
        // 把一个map转成一个字节
        byte[] bytes = new byte[0];
        try {
            bytes = objectMapper.writeValueAsBytes(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 通过buffer工厂将字节数组包装成 一个数据包
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(wrap));
        // 放行 到下一个过滤器了
//        return chain.filter(exchange);
    }

    /**
     * 指定顺序的方法
     * 越小越先执行
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }
}

12. IP 认证拦截实战

12.1 创建 IPGlobalFilter

/**
 * 网关里面 过滤器
 * ip拦截
 * 请求都有一个源头
 * 电话 144  027  010
 * 请求------->gateway------->service
 * 黑名单 black_list
 * 白名单 white_list
 * 根据数量
 * 像具体的业务服务 一般黑名单
 * 一般像数据库 用白名单
 */
@Component
public class IPCheckFilter implements GlobalFilter, Ordered {

    /**
     * 网关的并发比较高 不要再网关里面直接操作mysql
     * 后台系统可以查询数据库 用户量 并发量不大
     * 如果并发量大 可以查redis 或者 在内存中写好
     */
    public static final List<String> BLACK_LIST = Arrays.asList("127.0.0.1", "144.128.232.147");

    /**
     * 1.拿到ip
     * 2.校验ip是否符合规范
     * 3.放行/拦截
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String ip = request.getHeaders().getHost().getHostString();
        // 查询数据库 看这个ip是否存在黑名单里面   mysql数据库的并发
        // 只要是能存储数据地方都叫数据库 redis  mysql
        if (!BLACK_LIST.contains(ip)) {
            return chain.filter(exchange);
        }
        // 拦截
        ServerHttpResponse response = exchange.getResponse();
        response.getHeaders().set("content-type","application/json;charset=utf-8");
        HashMap<String, Object> map = new HashMap<>(4);
        map.put("code", 438);
        map.put("msg","你是黑名单");
        ObjectMapper objectMapper = new ObjectMapper();
        byte[] bytes = new byte[0];
        try {
            bytes = objectMapper.writeValueAsBytes(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        DataBuffer wrap = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(wrap));
    }

    @Override
    public int getOrder() {
        return -5;
    }
}

13. 限流实战(会问)

13.1 什么是限流

通俗的说,限流就是限制一段时间内,用户访问资源的次数,减轻服务器压力,限流大致分为

两种:

1. IP 限流(5s 内同一个 ip 访问超过 3 次,则限制不让访问,过一段时间才可继续访问)

2. 请求量限流(只要在一段时间内(窗口期),请求次数达到阀值,就直接拒绝后面来的访问了,

过一段时间才可以继续访问)(粒度可以细化到一个 api(url),一个服务)

13.2 本次限流模型

限流模型:漏斗算法 ,令牌桶算法,窗口滑动算法 计数器算法

image-20230304220356837

入不敷出

1)、所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;

2)、根据限流大小,设置按照一定的速率往桶里添加令牌;

3)、桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;

4)、请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完

业务逻辑之后,将令牌直接删除;

5)、令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令

牌,以此保证足够的限流;

13.3 Gateway 结合 redis 实现请求量限流

Spring Cloud Gateway 已经内置了一个 RequestRateLimiterGatewayFilterFactory,我们

可以直接使用。

目前 RequestRateLimiterGatewayFilterFactory 的实现依赖于 Redis,所以我们还要引入

spring-boot-starter-data-redis-reactive。

13.3.1 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

13.3.2 修改配置文件

spring:
  application:
    name: gateway-server

  cloud:
    gateway:
      enabled: true # =只要加了依赖 默认开启
      routes: # 如果一个服务里面有100个路径  如果我想做负载均衡 ??   动态路由
        - id: login-service-route  # 这个是路由的id 保持唯一即可
          #uri: http://localhost:8081   # uri统一资源定位符   url 统一资源标识符
          uri: lb://login-service   # uri统一资源定位符   url 统一资源标识符
          predicates: # 断言是给某一个路由来设定的一种匹配规则 默认不能作用在动态路由上
                - Path=/doLogin  # 匹配规则  只要你Path匹配上了/doLogin 就往 uri 转发 并且将路径带上
                - After=2022-03-22T08:42:59.521+08:00[Asia/Shanghai]
                - Method=GET,POST
                - Query=name, admin.   #正则表达式的值

          filters:
            - name: RequestRateLimiter  # 这个是过滤器的名称
              args: # 这个过滤器的参数
                key-resolver: '#{@ipKeyResolver}' # 通过spel表达式取 ioc容器中bean的值
                redis-rate-limiter.replenishRate: 1  # 生成令牌的速度
                redis-rate-limiter.burstCapacity: 3  # 桶容量

13.3.3 配置文件说明

在上面的配置文件,配置了 redis 的信息,并配置了 RequestRateLimiter 的限流过滤器,

该过滤器需要配置三个参数:

burstCapacity:令牌桶总容量。

replenishRate:令牌桶每秒填充平均速率。

key-resolver:用于限流的键的解析器的 Bean 对象的名字。它使用 SpEL 表达式根据 #{@beanName}从 Spring 容器中获取 Bean 对象

13.3.4 创建配置类 RequestRateLimiterConfig

/**
 * 自定义请求限制的
 */
@Configuration
public class RequestLimitConfig {

    // 针对某一个接口 ip来限流  /doLogin    每一个ip 10s只能访问3次
    @Bean
    @Primary // 主候选的
    public KeyResolver ipKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getHeaders().getHost().getHostString());
    }

    // 针对这个路径来限制  /doLogin
    // api 就是 接口  外面一般把gateway    api网关  新一代网关
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }


}

14. 跨域配置

跨域? ajax 同源策略

8080

8081

因为网关是微服务的边缘 所有的请求都要走网关 跨域的配置只需要写在网关即可

第一种 java配置

@Configuration
public class CorsConfig {


    @Bean
    public CorsWebFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        source.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(source);
    }
}

第二种 yml配置

spring:
  cloud:
    gateway:
      globalcors:
        cors-configurations:
        # 仅在开发环境设置为*
          '[/**]':
            allowedOrigins: "*"
            allowedHeaders: "*"
            allowedMethods: "*"

15. 总结和面试

  1. 你们网关用的什么 ? Gateway zuul

  2. 你们网关里面写什么代码?

跨域,路由(动态路由,负载均衡)****ip 黑名单拦截,****Token 的校验,对请求进行过滤(请求

参数校验) 对响应做处理(状态码,响应头) 熔断 限流

微服务的网关,可以很好地将具体的服务和浏览器隔离开,只暴露网关的地址给到浏览器

在微服务网关中,可以很好的实现校验认证,负载均衡(

lb****),黑名单拦截,限流等。

15.1 Gateway 和 zuul 的区别 ZuulFilter

Zuul 也是 web 网关,本质上就是一组过滤器,按照定义的顺序,来执行过滤操作

二者的区别:

1. 两者均是 web 网关,处理的是 http 请求

2. Gateway 是 springcloud 官方的组件,zuul 则是 netflix 的产品

springcloudnetflix alibaba

nacossentineldubbo zkseatarocketmq****)

3. gateway 在 spring 的支持下,内部实现了限流、负载均衡等,扩展性也更强,但同时也

限制了仅适合于 Spring Cloud 套件。而 zuul 则可以扩展至其他微服务框架中,其内部没有

实现限流、负载均衡等

4. Gateway(Netty NIO)很好的支持异步(spring5.x ,webFlux 响应式编程默认是异步的),

而 zuul****1.0 仅支持同步 BIO zuul2.0 以后也支持异步了

15.2 Nginx 在微服务中的地位

最后简单聊一下 nginx,在过去几年微服务架构还没有流行的日子里,nginx 已经得到了广大

开发者的认可,其性能高、扩展性强、可以灵活利用 lua 脚本构建插件的特点让人没有抵抗力。

nginx 的请求转发 最大并发是多个次,每秒 5w-10w 左右) 3w 左右

有一个能满足我所有需求还很方便我扩展的东西,还免费,凭啥不用??

但是,如今很多微服务架构的项目中不会选择 nginx,我认为原因有以下几点:

微服务框架一般来说是配套的,集成起来更容易

如今微服务架构中,仅有很少的公司会面对无法解决的性能瓶颈,而他们也不会因此使用

nginx,而是选择开发一套适合自己的微服务框架(很多公司会对现有框架进行修改)

spring boot 对于一些模板引擎如 FreeMarker、themleaf 的支持是非常好的,很多应用还没

有达到动、静态文件分离的地步,对 nginx 的需求程度并不大。

动静分离: css js

可以放在 nginx

单体项目需要部署 对 nginx 的使用的需求还是比较大的

斗鱼 不是使用后端技术 如何实现大规模缓存

使用 Nginx 做大规模的静态资源缓存

不是为了用技术而用技术 按照实际业务来 目的是盈利

无论如何,nginx 作为一个好用的组件,最终使不使用它都是由业务来驱动的,只要它能为我

们方便的解决问题,那用它又有何不可呢?

找工作思想: 不要为了用技术而去用技术

ssm 吃一辈子 稳定 挣钱

你想技术提升 跳大厂

先入行 一年就跳槽

15.3 关于限流,面试不会直接问,而是间接来问 问 不卖超

比如:如果在抢购过程中,用户量请求非常大,怎么确保商品不会卖超

Redis 单线程 (

IO 为什么快,因为我们现在的处理器是多核心数的,redis 底层使用的是

IO 的多路复用

一般人只会在意商品卖超,而忘记了限流的重要性

Mq(限流 削峰,异步,解耦合)