距离 Java 开发者玩转 Serverless,到底还有多远?
本文摘自 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
Function<I, O>
Consumer<I>
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:
@SpringBootApplicationpublic 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:
@SpringBootApplicationpublic 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-groupspring.cloud.stream.bindings.output.destination=output-topicspring.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 Alibaba 开源项目负责人/创始人之一。Apache RocketMQ Committer,Alibaba Nacos Committer。目前就职于阿里巴巴集团。
曾在个人博客上编写过《Spring MVC源码分析系列》、《Spring Boot源码分析系列》文章。目前,关注微服务、云原生、Kubernetes。
图书推荐
▊《深入理解Spring Cloud与实战》
方剑 编著
Spring Cloud Alibaba创始人倾力打造
理论与实践相结合,核心知识点辅以案例讲解
这是一本深入剖析 Spring Cloud 全家桶的书籍,主要介绍Spring Cloud各个核心组件的设计原理,以及目前流行的Spring Cloud Alibaba和 Netflix组件,并且剖析Spring Cloud对流处理、批处理,以及目前业界流行的Serverless的支持。在介绍各部分内容时,本书将理论与实践相结合,对每个核心知识点都给出了具体的案例应用,以帮助读者掌握核心组件的设计理念。
抽奖赠书
截止时间:2021年2月1日 17:00
如何抽奖:扫描下方二维码,关注公众号,回复关键词 :20210127
下次你更希望我们送哪本书呢?
留言告诉我们!
距离 Java 开发者玩转 Serverless,到底还有多远?相关推荐
- 云原生开发者训练营启动!3天教会你玩转Serverless
立即报名:https://developer.aliyun.com/learning/trainingcamp/serverless/1?accounttraceid=cb96a7edbf404ca9 ...
- java 搭建企业应用框架_溯源微服务开发体系:一位Java开发者的转型思考
作者丨赵钰莹 简单来说,微服务是将大型单体应用程序和服务拆分为数个甚至数十个微服务,可扩展单个组件而不是整个应用程序堆栈,从而满足服务等级协议.然而,这个过程涉及很多问题需要解决,比如拆分原则.容量规 ...
- Java 开发者每天都在做什么?
作为一名 在大.中.小微企业都待过 的 Java 开发者,今天和大家分享下自己在不同公司的工作日常和收获.包括一些个人积累的工作提升经验,以及一些 Java 学习的方法和资源. 先从我的第一份 Jav ...
- Java开发者薪资最低?程序员只能干到30岁?国外真的没有996?Intellij真的比Eclipse受欢迎?
Stack Overflow作为全球最大的程序设计领域的问答网站,每年都会出据一份开发者调查报告.近日,Stack Overflow公布了其第9次年度开发者调查报告(https://insights. ...
- 2021 年 Java 开发者生产力报告
责编 | 丁恩华 出品 | CSDN(ID:CSDNnews) 新的 2021 年,Perforce 公司依然没有 "爽约".前不久,这家公司发布了其第九份年度全球 Java 开发 ...
- Java 开发者希望未来使用 Python 和 Go
作者 | 段段段落 本文经授权转载自开源中国(ID:oschina2013) 去年秋天,JetBrains 对超过 1500 名 Java 开发者的学习模式和偏好进行了调查.不妨看看公布的调查报告中一 ...
- 调查 10,500 名 Java 开发者发现,收费的 OracleJDK 仍是主流、IntelliJ IDEA 最受欢迎...
昨日,作为"第一家"公开宣布将裁员 15% 的滴滴,一时之间被大众推向了舆论的风口浪尖,但与此同时,因为其不变相且透明的裁员举措也为自己赢得了一片叫好声.然不可否认的是,从此事件乃 ...
- 真相:Java 开发者钟爱 Kotlin 的五个原因
[CSDN编者按]现在Kotlin语言越来越流行.它不仅广泛用在移动应用开发上,也能用于服务器端系统上.你也许知道,Kotlin是个运行在JVM上的静态类型编程语言. Kotlin之所以流行的主要原因 ...
- 【Java开发者专场】阿里专家梁笑:2018双十一下单成功率99.9%!供应链服务平台如何迎接大促...
本篇文章来自于2018年12月22日举办的<阿里云栖开发者沙龙-Java技术专场>,梁笑专家是该专场第一位演讲的嘉宾,本篇文章是根据梁笑专家在<阿里云栖开发者沙龙-Java技术专场& ...
最新文章
- SAP WM高阶之上架策略B (Bulk Storage)
- numpy学习2:数组创建方式
- Android图片转换类 1. Bitmap去色,转换为黑白的灰度图, 2. Bitmap图片加圆角效果
- 【MySQL】MySQL 两种排序算法
- 从 Microsoft Dynamics CRM 4.0 server迁移到 Microsoft Dynamics CRM 2013 Server
- 基于modbus协议的工业自动化网络规范_一种基于Modbus的工业通信网关设计
- kubernetes endpoints是什么
- 项目总结 -谷粒学院
- aucc2018插件_Voxengo音频插件合集2018最新版
- 基本磁盘转换动态磁盘,再转换为基本磁盘,分区数据丢失
- 链桨PaddleDTX系列 - xdb源码分析(一)
- 云计算需要学什么?学习云计算能从事什么岗位?
- Docker技术之容器与外部相连
- Uni-app 实现离线打包 安卓篇
- matlab算非齐次方程,matlab-线性代数 非齐次方程组 判断是否有唯一解
- flex布局对行内子元素的影响
- 利用python和Sen2cor对Sentinel2进行批量大气校正
- 认证管理(锐捷网关篇)
- 接口隔离原则:接口里的方法,你都用得到吗?
- 联发科MT6580_datasheet/规格书资料分享