乐趣区

关于java:距离-Java-开发者玩转-Serverless到底还有多远

作者 | 方剑(洛夜)Spring Cloud Alibaba 开源我的项目负责人 / 创始人之一
起源 | 阿里巴巴云原生公众号

导读:本文摘自 Spring Cloud Alibaba 开源我的项目开创团队成员方剑撰写的《深刻了解 Spring Cloud 与实战》一书,次要讲述了 Java 微服务框架 Spring Boot/Cloud 这个事实标准下如何应答 FaaS 场景。

Serverless & FaaS

2019 年,O’Reilly 对 1500 名 IT 业余人员的考察中,有 40% 的受访者在采纳 Serverless 架构的组织中工作。2020 年 DataDog 考察显示,当初有超过 50% 的 AWS 用户正在应用 Serverless 架构的 AWS Lambda。

Serverless 正在成为支流,于是就诞生了上面这幅图,从单体利用的治理到微服务利用的治理再到函数的治理。

Serverless 到目前为止还没有一个精准定义。Martin Fowler 在集体博客上有一篇《Serverless Architectures》文章,其对 Serverless 的的定义分成了 BaaS 或 FaaS。

Baas 是全称是 Backend-as-a-Service,后端即服务,FaaS 的全称是 Function-as-a-Service,函数即服务。

明天咱们来聊聊 FaaS。这是维基百科对 FaaS 的定义:

函数即服务(FaaS)是一类云计算服务,它提供了一个平台,使客户能够开发,运行和管理应用程序性能,而无需构建和保护通常与开发和启动应用程序相干的基础架构。遵循此模型构建应用程序是实现 Serverless 架构的一种办法,通常在构建微服务应用程序时应用。

对于 Python、JavaScript 这种天生反对 Lambda 的开发语言,和 FaaS 几乎是完满联合。Serverless Framework 的调研报告也很好地阐明了这一点。NodeJS、Python 是 FaaS 使用率前二的语言。

咱们晓得,因为 JVM 占用的内存比拟大,所以 Java 利用的启动会有点慢,不太适宜 FaaS 这个场景,这也是 Java 在使用率上偏低的起因。

另外,对 Java 开发者来说 Spring Boot/Cloud 曾经成为了事实标准,依赖注入是 Spring Framework 的外围,Spring Boot/Cloud 这个事实标准应答 FaaS 这个场景,会碰撞出怎么样的火花呢?这就是明天咱们要聊的 Spring Cloud Function。

Java Function

在对 Spring Cloud Function 介绍之前,咱们先来看 Java 里的外围函数定义。

JDK 1.8 推出了新个性 Lambda 表达式,java.util.function 包上面提供了很多的函数。这 3 个函数尤为重要:

1. java.util.function.Function: 须要一个参数,失去另一个后果.

@FunctionalInterface
public interface Function<T, R> {R apply(T t);
}

比方通过 Stream API 里的 map 办法能够通过 Function 把字符串从小写变成大写:

Stream.of("a", "b", "c").map(String::toUpperCase);

这里的 map 办法须要一个 Function 参数:

<R> Stream<R> map(Function<? super T, ? extends R> mapper);

2. java.util.function.Consumer: 须要一个参数进行操作,无返回值。

@FunctionalInterface
public interface Consumer<T> {void accept(T t);
}

比方通过 Stream API 里的 forEach 办法遍历每个元素,做对应的业务逻辑解决:

RestTemplate restTemplate = new RestTemplate();
Stream.of("200", "201", "202").forEach(code -> {
    ResponseEntity<String> responseEntity =
        restTemplate.getForEntity("http://httpbin.org/status/" + code, String.class);
    System.out.println(responseEntity.getStatusCode());
});

3. java.util.function.Supplier: 失去一个后果,无输出参数。

@FunctionalInterface
public interface Supplier<T> {T get();
}

比方自定义 Supplier 能够返回随机数:

Random random = new Random();

Supplier supplier100 = () -> random.nextInt(100);
Supplier supplier1000 = () -> random.nextInt(1000);

System.out.println(supplier100.get());
System.out.println(supplier1000.get());

Spring Cloud Function

Java Function 的编程模型非常简单,实质上就是这 3 个外围函数:

  • Supplier<O>
  • Function<I, O>
  • Consumer

Spring Cloud Function 是 Spring 生态跟 Serverless(FaaS) 相干的一个我的项目。它呈现的目标是加强 Java Function,次要体现在这几点:

  • 对立云厂商的 FaaS 编程模型: Spring Cloud Function 的口号是 “Write Once, Run Anywhere”。咱们写的 Spring Cloud Function 代码能够运行在本地、各个云厂商(AWS Lambda, GCP Cloud Functions, Azure Functions)。
  • 主动类型转换: 了解过 Spring MVC 或者 Spring Cloud Stream 的同学必定对 HttpMessageConverter 或者 MessageConverter 模型,这个转换器的作用是将 HTTP BODY(或者 Message Payload)、HTTP Query Parameter、HTTP HEADER(或者 Message Header)主动转换成对应的 POJO。有了这个个性后,咱们就无需关注函数的入参和返回值,用 String 参数就能够获取原始的入参信息,用 User 这个 POJO 参数就能够将原始的入参参数主动转换成 User 对象。
  • 函数组合: 能够让多个函数之间进行组合操作。
  • 函数治理: 新增 FunctionCatalog、FunctionRegistry 接口用于 Function 的治理。治理 ApplicationContext 内的 Function,动静注册 Function 等操作。
  • Reactive 反对: Spring Cloud Function 新增比方 FluxFunction、FluxSupplier、FunctionConsumer 这种 Reactive 函数。
  • 主动跟 Spring 生态外部原有的组件进行深度集成:

    • Spring Web/Spring WebFlux: 一次 HTTP 申请是一次函数调用。
    • Spring Cloud Task: 一次工作执行是一次函数调用。
    • Spring Cloud Stream: 一次音讯生产 / 生产 / 转换是一次函数调用。

这里再多介绍对立云厂商的 FaaS 编程模型,让大家对 Spring Cloud Function 更有体感。

AWS Lambda 是第一个是提供 FaaS 服务的云厂商,RequestStreamHandler 是 AWS 提供的针对 Java 开发者的接口,须要实现这个接口:

public class HandlerStream implements RequestStreamHandler {
  @Override
  public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException
  {...

Azure Functions 针对 Java 开发者提供了 @HttpTrigger 注解:

public class Function {
    public String echo(@HttpTrigger(name = "req", 
      methods = {HttpMethod.POST},  authLevel = AuthorizationLevel.ANONYMOUS) 
        String req, ExecutionContext context) {...}
}

从这两段代码能够看出,不同的云厂商要编写不同的代码。如果要变换云厂商,这个过程会很苦楚。

另外,无论是 AWS、Azure 或者 GCP 提供的接口或注解,他们没有任何 Spring 上下文相干的初始化逻辑。如果咱们是一个 Spring Boot/Cloud 利用迁徙到 FaaS 平台,须要增加 Spring 上下文初始化逻辑等改变量。

Spring Cloud Function 的呈现就是为了解决这些问题。

Spring Cloud Function 的应用

Spring Cloud Function & Spring Web:

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

    @Bean
    public Function<String, String> upperCase() {return s -> s.toUpperCase();
    }

    @Bean
    public Function<User, String> user() {return user -> user.toString();
    }

}

拜访对应的 Endpoint:

$ curl -XPOST -H "Content-Type: text/plain" localhost:8080/upperCase -d hello
HELLO
$ curl -XPOST -H "Content-Type: text/plain" localhost:8080/user -d '{"name":"hello SCF"}'
User{name\u003d\u0027hello SCF\u0027}

Spring Cloud Function & Spring Cloud Stream:

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

    @Bean
    public Function<String, String> uppercase() {return x -> x.toUpperCase();
    }

    @Bean
    public Function<String, String> prefix() {return x -> "prefix-" + x;}

}

加上 function 相干的配置(针对 input-topic 上的每个音讯,payload 转换大写后再加上 prefix- 前缀,再写到 output-topic 上):

spring.cloud.stream.bindings.input.destination=input-topic
spring.cloud.stream.bindings.input.group=scf-group

spring.cloud.stream.bindings.output.destination=output-topic

spring.cloud.stream.function.definition=uppercase|prefix

Spring Cloud Function & Spring Cloud Task:

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

    @Bean
    public Supplier<List<String>> supplier() {return () -> Arrays.asList("200", "201", "202");
    }

    @Bean
    public Function<List<String>, List<String>> function() {return (list) ->
            list.stream().map( item -> "prefix-" + item).collect(Collectors.toList());
    }

    @Bean
    public Consumer<List<String>> consumer() {return (list) -> {list.stream().forEach(System.out::println);
        };
    }

}

加上 function 相干的配置(Supplier 模仿工作的输出源,Function 模仿对工作输出源的解决,Consumer 模仿解决对 Function 解决输出源后的数据):

spring.cloud.function.task.function=function
spring.cloud.function.task.supplier=supplier
spring.cloud.function.task.consumer=consumer

《深刻了解 Spring Cloud 与实战》一书正式开始预售啦,这是一本深刻分析 Spring Cloud 全家桶的书籍,波及以下内容

  • Spring Boot 外围个性
  • Spring Cloud 服务注册 / 服务发现原理分析
  • 双注册双订阅模型实现 Eureka 迁徙至 Nacos 的案例
  • 负载平衡:Spring Cloud LoadBalancer 和 Netflix Ribbon
  • Dubbo Spring Cloud:Spring Cloud 与 Apache Dubbo 的交融
  • Spring Cloud 灰度公布案例
  • Spring 体系配置,动静刷新加载原理分析
  • Spring Cloud Circuit Breaker 形象以及 Sentinel、Hystrix、Resilience4j 熔断器比照
  • Spring 体系音讯编程模型分析
  • Spring Cloud Data Flow 实现批处理和流解决工作
  • Spring Cloud Gateway 网关分析
  • Spring 与 Serverless 的交融

点击理解详情,更有机会赢取收费图书

作者简介

方剑  Spring Cloud Alibaba 开源我的项目负责人 / 创始人之一。《深刻了解 Spring Cloud 与实战》作者,Apache RocketMQ Committer,Alibaba Nacos Committer。曾在集体博客上编写过《SpringMVC 源码剖析系列》、《SpringBoot 源码剖析系列》文章,目前,关注微服务、云原生、Kubernetes。

《深刻了解 Spring Cloud 与实战》作者方剑将缺席 1 月 9 日 Spring Cloud Alibaba 上海站,现场流动也有互动赠书流动,欢送来现场与作者面基。

点击链接参加流动报名:https://www.huodongxing.com/event/2576519081911

退出移动版