前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >第二代网关GateWay搭建流程

第二代网关GateWay搭建流程

作者头像
算法之名
发布2019-12-19 19:29:02
2.8K0
发布2019-12-19 19:29:02
举报
文章被收录于专栏:算法之名算法之名

Spring Cloud第二代网关GateWay是由纯Netty开发,底层为Reactor,WebFlux构建,不依赖任何Servlet容器,它不同于Zuul,使用的是异步IO,性能较Zuul提升1.6倍。搭建过程如下(本次搭建的为子项目,主项目可以参考Nacos搭建流程 )

pom

代码语言:javascript
复制
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
   <groupId>com.alibaba.cloud</groupId>
   <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

配置文件

代码语言:javascript
复制
server:
  port: 8040
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true

以上的意思不仅是把自己给注册到nacos,并且获取nacos的所有注册服务。

启动网关项目,现在就可以进行网络路由了。访问格式为 ip:端口/服务注册名/restfulapi-url

比方说我们现在有两个微服务项目,一个为user(端口8082),一个为nacos(端口8081).

三大核心概念

  • Route(路由) Spring Cloud Gateway的基础元素,可简单理解成一条转发的规则。包含:ID,目标的URL,Predicate集合以及Filter集合。
  • Predicate(谓词) 即java.util.function.Predicate,Spring Cloud Gateway使用Predicate实现路由的匹配条件。这是一个可以进行条件判断的函数式接口,具体可以参考本人博客Java函数式编程整理
  • Filter(过滤器) 修改请求以及响应。

由于我们使用了nacos来进行服务发现,所以我们使用了之前的配置文件,但如果不使用服务发现,只做常规的转发如下

代码语言:javascript
复制
spring:
  cloud:
    gateway:
      routes:
        - id: some_route
          uri: http://www.baidu.com
          predicates:
            - Path=/user/1
          filtes:
            - AddRequestHeader=X-Request-Foo, Bar

这段配置的意思是说,当我们请求/user/1的url的时候,会添加AddRequestHeader=X-Request-Foo, Bar过滤器做一些处理,然后路由到http://www.baidu.com

路由谓词配置工厂

路由谓词配置工厂由一整套谓词来进行配置转发的不同情况。

谓词工厂

备注

After

此谓词匹配当前日期时间之后发生的请求。

Before

此谓词匹配在当前日期时间之前发生的请求。

Between

此谓词匹配datetime1之后和datetime2之前发生的请求。 datetime2参数必须在datetime1之后。

Cookie

Cookie Route Predicate Factory有两个参数,cookie名称和正则表达式。此谓词匹配具有给定名称且值与正则表达式匹配的cookie。

Header

Header Route Predicate Factory有两个参数,标题名称和正则表达式。与具有给定名称且值与正则表达式匹配的标头匹配。

Host

Host Route Predicate Factory采用一个参数:主机名模式。该模式是一种Ant样式模式“.”作为分隔符。此谓词匹配与模式匹配的Host标头。

Method

Method Route Predicate Factory采用一个参数:要匹配的HTTP方法。

Path

匹配请求的path

Query

Query Route Predicate Factory有两个参数:一个必需的参数和一个可选的正则表达式。

RemoteAddr

RemoteAddr Route Predicate Factory采用CIDR符号(IPv4或IPv6)字符串的列表(最小值为1),例如, 192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。

路由到指定URL

  • 通配

现在我们去掉nacos的配置,不由nacos来发现

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

此时访问

将跳转到

  • 谓词After
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #在2019-12-14日20:26后允许该转发
        - After=2019-12-14T20:26:15.667+08:00[Asia/Shanghai]
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

这里表示在该时间后允许转发,如果我们将该时间设置为

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #在2019-12-15日20:26后允许该转发
        - After=2019-12-15T20:26:15.667+08:00[Asia/Shanghai]
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

则转发失败,返回404

我们可以通过以下方法来获取这里的时间设置

代码语言:javascript
复制
public class TimeTest {
    public static void main(String[] args) {
        System.out.println(ZonedDateTime.now());
    }
}

运行结果

2019-12-14T20:43:34.755+08:00Asia/Shanghai

  • 谓词Before

现在我们将上面的15号改为Before

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #在2019-12-15日20:26前允许该转发
        - Before=2019-12-15T20:26:15.667+08:00[Asia/Shanghai]
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

此时就可以正常转发,而改成14号则会失败。

  • 谓词Between
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #在2019-12-14日20:26到2019-12-15日20:26之间允许该转发
        - Between=2019-12-14T20:26:15.667+08:00[Asia/Shanghai],2019-12-15T20:26:15.667+08:00[Asia/Shanghai]
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
  • 谓词Cookie

我们在user模块增加一个带cookie的Controller

代码语言:javascript
复制
@Slf4j
@RestController
public class CookieController {
    @GetMapping("/welcome")
    public Boolean handle(HttpServletRequest request,
                               HttpServletResponse response) throws Exception {
        Cookie cookie = new Cookie("test","value");
        cookie.setMaxAge(Integer.MAX_VALUE);
        response.addCookie(cookie);
        log.info("welcome");
        return true;
    }
}

此时我们访问该Controller为

此时网关这边配置为

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #只有带上Cookie名为test,并且值符合正则value的cookie时,才允许被转发
        - Cookie=test,value
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
  • 谓词Header

现在我们给user模块添加一个Controller的方法

代码语言:javascript
复制
@GetMapping("/header")
public String header(@RequestHeader("item") String item) {
    return item;
}

我们通过postman给该方法的访问添加请求头

在网关中的配置为

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #只有带上请求头名为item,并且值符合正则123.p,才会转发
        - Header=item,123.p
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

这里正则.可以匹配一个单字符

如果我们在请求头item中设置错误的字符则无法转发

  • 谓词Host

要配置Host,我们需要给服务器的hosts文件添加一个域名映射,当然在互联网上需要一个域名来做DNS解析。

我这里给自己的域名添加为local.register.com

访问user的find方法

给网关添加配置

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #只有带上请求头Host,且值匹配**.register.com:8040才能通过转发
        - Host=**.register.com:8040
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

此时我们通过网关访问如下

  • 谓词Method
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #只有当HTTP请求方法是GET时才能转发
        - Method=GET
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
  • 谓词Query

现在我们给user模块增加一个Controller方法

代码语言:javascript
复制
@GetMapping("/query")
public String query(@RequestParam("name") String name) {
    return name;
}

访问如下

网关配置如下

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #只有当请求带上参数名称为name时才能通过转发
        - Query=name
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

如果不带上该参数则无法转发,如

  • 谓词RemoteAddr
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    gateway:
      routes:
      - id: gate
        uri: http://127.0.0.1:8082
        predicates:
        #由/user来匹配跳转
        - Path=/user/**
        #只有当请求为192.168.20.1/24网段(IP地址从192.168.20.1到192.168.20.254)才会转发
        - RemoteAddr=192.168.20.1/24
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

例如

但是使用127.0.0.1却无法访问

现在我们恢复nacos的服务发现

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

为了跟不做任何配置相区别,我们这里谓词Path写了user-center

自定义路由谓词工厂

假设现在我们的一个API只有在上午9点到下午5点允许转发

配置的文件如下

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        - TimeBetween=上午9:00,下午5:00
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1

由于这个TimeBetween并不是gateway默认的谓词工厂,所以我们需要自己来实现一个谓词工厂,我们先定义一个时间的配置类

代码语言:javascript
复制
@Data
public class TimeBetweenConfig {
    private LocalTime start;
    private LocalTime end;
}

然后自定义一个谓词工厂类,该工厂类名称必须以自定义谓词开头(这里是TimeBetween),以RoutePredicateFactory结尾,并继承AbstractRoutePredicateFactory抽象类

代码语言:javascript
复制
@Component
public class TimeBetweenRoutePredicateFactory extends AbstractRoutePredicateFactory<TimeBetweenConfig>{
    public TimeBetweenRoutePredicateFactory() {
        super(TimeBetweenConfig.class);
    }

    @Override
    public Predicate<ServerWebExchange> apply(TimeBetweenConfig config) {
        LocalTime start = config.getStart();
        LocalTime end = config.getEnd();
        return exchange -> {
            LocalTime now = LocalTime.now();
            return now.isAfter(start) && now.isBefore(end);
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("start","end");
    }
}

内置过滤器工厂

1 AddRequestHeader GatewayFilter Factory

2 AddRequestParameter GatewayFilter Factory

3 AddResponseHeader GatewayFilter Factory

4 DedupeResponseHeader GatewayFilter Factory

5 Hystrix GatewayFilter Factory

6 FallbackHeaders GatewayFilter Factory

7 PrefixPath GatewayFilter Factory

8 PreserveHostHeader GatewayFilter Factory

9 RequestRateLimiter GatewayFilter Factory

10 RedirectTo GatewayFilter Factory

11 RemoveHopByHopHeadersFilter GatewayFilter Factory

12 RemoveRequestHeader GatewayFilter Factory

13 RemoveResponseHeader GatewayFilter Factory

14 RewritePath GatewayFilter Factory

15 RewriteResponseHeader GatewayFilter Factory

16 SaveSession GatewayFilter Factory

17 SecureHeaders GatewayFilter Factory

18 SetPath GatewayFilter Factory

19 SetResponseHeader GatewayFilter Factory

20 SetStatus GatewayFilter Factory

21 StripPrefix GatewayFilter Factory

22 Retry GatewayFilter Factory

23 RequestSize GatewayFilter Factory

24 Modify Request Body GatewayFilter Factory

25 Modify Response Body GatewayFilter Factory

26 Default Filters

  • AddRequestHeader
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.10.172:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #增加一个名称为X-Request-Foo,值为Bar的请求头
        - AddRequestHeader=X-Request-Foo,Bar

这里需要注意的是新增的这个请求头是转发以后添加进去的,所以我们请求网关的时候在浏览器中是找不到的,我们可以使用command+N(Windows中idea为Ctrl+N)来查找NettyRoutingFilter类,并且在filter方法中设置断点,由以下图中可以看到它是被添加进去了。

  • AddRequestParameter

由于在user模块中有这么一个方法

代码语言:javascript
复制
@GetMapping("/query")
public String query(@RequestParam("name") String name) {
    return name;
}

所以我们在网关配置时

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #增加一个名称为name,值为locky的请求参数
        - AddRequestParameter=name,locky

所以我们在网关中请求就可以不写参数,直接访问

  • AddResponseHeader
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #增加一个名称为X-Response-Foo,值为Bar的响应头
        - AddResponseHeader=X-Response-Foo, Bar
  • DedupeResponseHeader

Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。

它的主要作用是去重,例如

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        - Cookie=test,value
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #在Http响应报文头中进行去重,去重目标为跨域请求
        - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin
  • Hystrix
代码语言:javascript
复制
Hystrix是Spring Cloud第一代中的容错组件,不过已经进入维护模式。未来,Hystrix会被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J。

此处不做具体设置了

  • FallbackHeaders

也是对Hystrix的支持,不做具体设置了

  • PrefixPath

为匹配的路由添加前缀,我们在user模块的find添加一层访问路径

代码语言:javascript
复制
@GetMapping("/test/find")
@SuppressWarnings("unchecked")
public Result<User> findStr() {
    log.info("访问成功");
    return Result.success(new User(1,"张三",23));
}

网关配置

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #跳转后添加前缀/test
        - PrefixPath=/test

一致。

  • PreserveHostHeader

如果不设置,那么名为 Host 的Header由Http Client控制;如果设置了,那么会设置一个请求属性(preserveHostHeader=true),路由过滤器会检查从而去判断是否要发送原始的、名为Host的Header。这里主要是通过网关是否向代理服务器转发请求头中的Host属性。

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #转发客户端的请求报文头Host给后端代理服务器
        - PreserveHostHeader
  • RequestRateLimiter

Gateway自带的限流服务,但后续我们会整合Gateway和Sentinel来进行限流和熔断。

  • RedirectTo

转发到后端服务后再重定向到一个url.

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #转发到Path,并且携带一个http://www.baidu.com到Location的响应头
        - RedirectTo=302,http://www.baidu.com

从以上图中可以看出,其实我们请求的是http://127.0.0.1:8040/user-center/find,但是被重定向到了百度。这里HTTP状态码应该是HTTP状态码300序列,例如301.302,具体状态码可以参考[HTTP协议整理 ](https://cloud.tencent.com/developer/article/1540271)

  • RemoveHopByHopHeadersFilter

移除转发请求的Header,多个用","分隔。默认情况下移除如下Header。

  1. Connection
  2. Keep-Alive
  3. Proxy-Authenticate
  4. Proxy-Authorization
  5. TE
  6. Trailer
  7. Transfer-Encoding
  8. Upgrade
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
      filter:
        #移除转发请求
        remove-hop-by-hop:
          headers: Keep-Alive,Connection
  • RemoveRequestHeader

移除原始请求头

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #移除原始请求头X-Request-Foo
        - RemoveRequestHeader=X-Request-Foo

spring cloud zuul网关的作用 可知,在跨域转发中,我们需要移除这些请求头

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #移除原始跨域请求头
        - RemoveRequestHeader=Access-Control-Allow-Origin
      filter:
        #移除转发请求
        remove-hop-by-hop:
          headers: Access-Control-Allow-Credentials,Access-Control-Allow-Origin,Vary,X-Frame-Options,token
  • RemoveResponseHeader

移除响应头

我们在user中添加一个Controller方法

代码语言:javascript
复制
@GetMapping("/addhead")
public String addHeader(HttpServletRequest request, HttpServletResponse response) {
    response.addHeader("X-Response-Foo","Foo");
    return "header";
}

网关配置

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #移除响应头X-Response-Foo
        - RemoveResponseHeader=X-Response-Foo

通过网关转发,我们可以看到无此X-Response-Foo的响应头。

  • RewritePath

重写请求路径

代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #配置成原始路径正则, 重写后的路径的正则
        - RewritePath=/user-center/(?<segment>.*), /$\{segment}

以上配置会将/user-center/find变成/find再转发

直接访问user

网关请求的

  • RewriteResponseHeader

重写响应头部分内容,根据正则来修改

之前在user中有一个Controller方法

代码语言:javascript
复制
@GetMapping("/addhead")
public String addHeader(HttpServletRequest request, HttpServletResponse response) {
    response.addHeader("X-Response-Foo","Foo");
    return "header";
}
代码语言:javascript
复制
spring:
  application:
    name: gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      routes:
      - id: gate
        uri: lb://user
        predicates:
        #由/user-center来匹配跳转
        - Path=/user-center/**
        filters:
        #跳转后省略第一个通配
        - StripPrefix=1
        #重写响应头X-Response-Foo的值Foo为dee,内容可根据正则匹配
        - RewriteResponseHeader=X-Response-Foo,Foo,dee

访问user的/addhead,X-Response-Foo响应头的值为Foo.

通过网关访问/addhead,X-Response-Foo响应头的值为dee

  • SaveSession
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档