用 SPL 编写阿里云 FC2.0 函数

前言

在数字化转型持续加速的背景下,企业越来越多地将业务逻辑以服务化方式部署至云端。阿里云函数计算(Function Compute,简称FC)作为一种无服务器计算平台,屏蔽了底层资源运维的复杂性,使开发者能够专注于核心逻辑的开发与交付。只需上传代码,即可通过HTTP请求或事件驱动灵活触发函数执行,实现弹性伸缩、按需计费的函数式计算能力。

在实际应用中,函数计算往往需要处理复杂的数据处理任务,如多源数据的汇聚、清洗与分析。然而,使用传统Java编写这类逻辑不仅代码冗长、调试困难,还缺乏灵活性,微小的逻辑变更通常也需要重新构建、打包并上传整个函数代码包。

SPL(Structured Process Language)专注于结构化数据处理,具备简洁的语法、丰富的计算函数,特别适合表达各类复杂的数据逻辑。更重要的是,SPL支持将数据处理逻辑以外部脚本形式运行,修改逻辑时只需替换脚本文件,无需重新构建或部署函数代码包,即可在下一次调用时自动生效。这种“轻量级热切换”特性,非常契合函数计算轻量、快速迭代的特性,有效提升了云端函数逻辑的可维护性与敏捷性。

此外,SPL原生支持多种数据源(如支持JDBC的数据源、NAS文件、JSON等),并具备可视化分步调试能力,是Serverless架构中应对动态数据逻辑、数据服务编排的高效利器。

本文将介绍如何结合Micronaut框架与SPL脚本,以Fat-JAR方式部署至阿里云FC2.0,构建一个通过RESTful API调用、支持逻辑热更新的无服务器计算服务。示例将展示SPL如何访问并分析MySQL数据库和NAS文件系统,帮助读者快速构建可扩展、易维护的Serverless数据服务方案。

SPL在阿里云FC中的架构图

函数开发与部署

创建项目

使用 Micronaut CLI 快速创建 Maven 项目:

mn create-app micronaut-spl --build maven

创建完成后,可在集成开发环境(如 IntelliJ IDEA)中打开项目继续开发。

集成SPL

添加依赖

在 pom.xml 中引入 SPL 与数据库驱动:

<dependency><groupId>com.scudata.esproc</groupId><artifactId>esproc</artifactId><version>20250605</version>
</dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>8.3.0</version>
</dependency>

提示:中央仓库的更新频率有限,推荐从[SPL 下载地址]下载标准版,并通过私有Maven仓库同步更新。

相关jar包位于安装目录esProc/lib/,其中两个基础jar包为:

· esproc-bin-xxxx.jar:SPL 引擎及 JDBC 驱动

· icu4j-60.3.jar:国际化支持库

准备SPL配置文件

raqsoftConfig.xml 为 SPL 的核心配置文件,负责数据源定义、脚本路径管理等。本文中RDS MySQL数据源与脚本路径的示例配置如下:

……
<DBList encryptLevel="0"><DB name="rds_mysql"><property name="url" value="jdbc:mysql://rm-xxx.mysql.rds.aliyuncs.com:3306/spltest?useCursorFetch=true"></property><property name="driver" value="com.mysql.cj.jdbc.Driver"></property><property name="type" value="10"></property><property name="user" value="dms_user"></property><property name="password" value="password"></property><property name="batchSize" value="0"></property><property name="autoConnect" value="true"></property><property name="useSchema" value="false"></property><property name="addTilde" value="false"></property><property name="caseSentence" value="false"></property></DB>
</DBList>
<esProc>
……<splPathList><splPath>/opt</splPath></splPathList>
……
</esProc>
……

特别注意:需加上useCursorFetch=true,否则JDBC驱动可能将整个结果集加载至内存,容易在 FC 的内存限制下导致连接断开或错误。

与传统项目部署方式不同,这里我们先将raqsoftConfig.xml打成zip包(raqsoftConfig.xml.zip),以供后续作为自定义层上传使用。

SPL 通用接口实现

使用 SPL 提供的 JDBC 接口,在 Micronaut 中构建统一的函数调用入口。通过 HTTP POST 请求传入参数,执行指定 SPL 脚本,并将结果以 JSON 格式返回。

该接口接收两个参数:

· splxName:脚本文件名(不带扩展名)

· jsonParam:SPL脚本所需参数(JSON字符串)

返回值中包括状态码、消息提示及脚本执行结果数据。

package micronaut.spl;import io.micronaut.http.annotation.*;
import io.micronaut.http.MediaType;import java.sql.*;
import java.util.*;@Controller("/spl")
public class SPLExecutionController {@Post(uri = "/call", consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)public Map<String, Object> execute(@Body Map<String, String> request) {Map<String, Object> response = new HashMap<>();String splxName = request.get("splxName");String jsonParam = request.get("jsonParam");if (splxName == null || splxName.isBlank()) {response.put("code", 400);response.put("message", "Missing splxName");return response;}try {Class.forName("com.esproc.jdbc.InternalDriver");try (Connection con = DriverManager.getConnection("jdbc:esproc:local://?config=/opt/raqsoftConfig.xml");CallableStatement st = con.prepareCall("call " + splxName + "(?)")) {if (jsonParam != null && !jsonParam.isEmpty()) {st.setString(1, jsonParam);} else {st.setNull(1, Types.VARCHAR);}boolean hasResult = st.execute();List<List<Object>> allResults = new ArrayList<>();while (true) {if (hasResult) {try (ResultSet rs = st.getResultSet()) {ResultSetMetaData metaData = rs.getMetaData();int columnCount = metaData.getColumnCount();List<Object> currentResult = new ArrayList<>();while (rs.next()) {if (columnCount == 1) {currentResult.add(rs.getObject(1));} else {Map<String, Object> row = new LinkedHashMap<>();for (int i = 1; i <= columnCount; i++) {row.put(metaData.getColumnLabel(i), rs.getObject(i));}currentResult.add(row);}}if (!currentResult.isEmpty()) {allResults.add(currentResult);}}}if (!st.getMoreResults() && st.getUpdateCount() == -1) {break;}hasResult = true;}if (!allResults.isEmpty()) {response.put("code", 200);response.put("message", "success");response.put("data", allResults.size() == 1 ? allResults.get(0) : allResults);} else {response.put("code", 404);response.put("message", "No result data");}}} catch (Exception e) {e.printStackTrace();response.put("code", 500);response.put("message", "Execution failed: " + e.getMessage());}return response;}
}

打包项目后,再打成zip包(micronaut-spl-0.1.jar.zip)

上传部署Fat-JAR

在阿里云 FC 控制台中创建函数,推荐配置如下:

· 创建方式:使用自定义运行时创建

· 运行环境:Java 21

· 上传方式:ZIP 上传(micronaut-spl-0.1.jar.zip)

· 启动命令:java -jar micronaut-spl-0.1.jar

· 认证方式:无需认证(测试用)

点击创建后,即可完成函数部署。

添加配置层

在函数详情中点击“编辑层”,上传打包好的 raqsoftConfig.xml.zip,新建名为 config 的自定义层。

编写SPL脚本

使用 MySQL 表数据计算

在阿里云 RDS 中创建 MySQL 实例及 orders 表,导入 TPC-H 示例数据(建库建表和导入过程略)。以下脚本 rds-mysql.splx 演示如何按订单年份与状态分组统计订单总额:

A
1=connect("rds_mysql")
2=A1.cursor@x("SELECT O_ORDERDATE, O_ORDERSTATUS, O_TOTALPRICE FROM ORDERS")
3=A2.groups(year(O_ORDERDATE):year,O_ORDERSTATUS:status;sum(O_TOTALPRICE):amount)

将脚本打zip包后,添加并创建自定义层(splx),即可在/opt下访问到该脚本。

调用示例

请求行
POST https://sss-fff-xxx.cn-xxx.fcapp.run/spl/call
Content-Type: application/json
请求体
{"splxName": "rds-mysql","jsonParam": ""
}
返回
{"code": 200,"data": [{"year": 1992,"status": "F","amount": 34330674052.43},{"year": 1993,"status": "F","amount": 34340410079.03},{"year": 1994,"status": "F","amount": 34416369052.97},{"year": 1995,"status": "F","amount": 6614961429.26},{"year": 1995,"status": "O","amount": 20822054361.33},{"year": 1995,"status": "P","amount": 7109117393.01},{"year": 1996,"status": "O","amount": 34609364760.86},{"year": 1997,"status": "O","amount": 34373633413.04},{"year": 1998,"status": "O","amount": 20212721905.53}],"message": "success"
}

使用 NAS 文件系统

通过阿里云函数配置挂载 NAS 路径(如 /mnt/nas),可在 SPL 中直接读写该路径下的文件,实现持久化与共享。

以下为 w.splx(写)和 r.splx(读)两个脚本,模拟数据生成与读取处理过程。

w.splx如下:

A
1=path=json(jsonParams).path
2=connect("rds_mysql")
3=A2.cursor@x("SELECT O_ORDERDATE, O_ORDERSTATUS, O_TOTALPRICE FROM ORDERS")
4=file(path/"orders.btx").export@b(A3)
5return "btx exported."

r.splx如下:

A
1>p=json(jsonParam),path=p.path,n=p.n,m=p.m
2=file(path/"orders.btx").cursor@b()
3=A2.skip(n)
4=A2.fetch(m)
5>A2.close()
6return A4

写脚本,通过数据库游标读取MySQL实例中的orders表,并写入orders.btx文件(path可使用配置的NAS路径,实现持久化或与其他服务共享数据)。

读脚本,通过读取指定路径文件的游标,跳过前n条记录,展示接下来的m条记录。

也可将脚本文件本身存放在 NAS 中,配合 raqsoftConfig.xml 中增加路径:

…
<splPathList><splPath>/opt;/mnt/nas</splPath>
</splPathList>
…

写入调用示例

请求行

POST https://sss-fff-xxx.cn-xxx.fcapp.run/spl/call

Content-Type: application/json

请求体
POST https://sss-fff-xxx.cn-xxx.fcapp.run/spl/call
Content-Type: application/json
返回
{"splxName": "w","jsonParam": "{path:/mnt/nas/}"
}

读取调用示例

请求行
POST https://sss-fff-xxx.cn-xxx.fcapp.run/spl/call
Content-Type: application/json
请求体
{"splxName": "r","jsonParam": "{path:/mnt/nas/,n:99,m:2}"
}
返回
{"code": 200,"data": [{"O_ORDERDATE": "1992-12-16","O_ORDERSTATUS": "F","O_TOTALPRICE": 198800.71},{"O_ORDERDATE": "1994-02-17","O_ORDERSTATUS": "F","O_TOTALPRICE": 2519.40}],"message": "success"
}

业务逻辑变更

我们将“使用 MySQL 表数据计算”的“按订单年份与状态分组统计订单总额”改为“按订单年月与状态分组统计订单总额”,只需要将 A3 中的 year(O_ORDERDATE):year 改为 month@y(O_ORDERDATE):YearMonth 即可。由于 SPL 支持将数据逻辑以外部脚本形式运行,此类修改无需重新构建和部署函数代码包,只需更新脚本内容即可在下一次函数调用时自动生效。这种“轻量级热切换”方式完美契合 Serverless 架构短生命周期、按需执行的特点,显著提升了云端数据服务的响应速度与维护效率,尤其适合频繁调整的数据分析类场景。

总结

借助 Micronaut 的轻量级框架特性与 SPL 的灵活脚本执行能力,我们成功构建了一个具备结构化数据处理能力的 Serverless 应用,并以 Fat-JAR 方式部署至阿里云函数计算 FC2.0。函数启动后可通过 REST 接口按需触发,访问 MySQL 或 NAS 等多种数据源,执行复杂的计算逻辑。

相比传统 Java 开发,SPL 显著简化了数据处理过程,使业务逻辑更清晰、更易维护。尤其在 Serverless 架构下,SPL 的“脚本热切换”能力无需重构或重新部署函数,即可在下次调用中自动生效,极大提升了系统的灵活性和运维效率。结合 NAS 文件系统,还能实现函数之间的数据共享与持久化,满足更多元的业务场景需求。

这种架构适用于需要快速迭代、规则频繁调整的数据服务场景,是企业在 Serverless 架构下构建高效、可扩展数据计算服务的有力方案。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95925.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95925.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AR 巡检与普通巡检有哪些区别,有哪些优势|阿法龙XR云平台

AR 巡检&#xff08;增强现实巡检&#xff09;与普通巡检&#xff08;传统人工巡检&#xff09;在技术应用、效率、准确性等多个维度存在显著差异&#xff0c;具体区别如下&#xff1a; 1. 巡检方式更智能 普通巡检&#xff1a;依赖人工现场观察&#xff0c;主要通过眼看、手…

Java中的volatile关键字详解

核心作用&#xff1a;解决可见性和有序性问题volatile 的主要作用可以归结为两点&#xff1a;1.保证变量的可见性 和 禁止指令重排序。2.它提供了一种轻量级的同步机制&#xff0c;3.但需要注意的是&#xff0c;它不能保证原子性。保证可见性&#xff1a;什么是可见性问题&…

【Linux】MySQL数据目录迁移步骤(含流程图踩坑经验)

在生产环境中&#xff0c;有时候你会遇到一些看似简单但实际上很棘手的问题。最近我就碰到了一次典型的服务器磁盘空间告急&#xff0c;最后通过迁移 MySQL 数据目录成功解决了问题。本文记录整个过程&#xff0c;包括我的分析思路、迁移步骤、踩坑和经验总结&#xff0c;希望对…

数据驱动下的连锁模式复制:技术科普与方法论深度解析

前言在连锁经营的赛道上&#xff0c;“复制”是核心命题&#xff0c;但绝非简单的“粘贴”。当行业进入数字化深水区&#xff0c;数据驱动正成为连锁模式突破增长瓶颈、实现高效复制的“隐形引擎”。本文将从技术科普与方法论心得两个维度&#xff0c;深度拆解数据如何重塑连锁…

数据库学习MySQL系列2、Windows11系统安装MySQL方法一.msi安装详细教程

方法一.msi安装详细教程 Windows系统下MySQL——.msi安装详细教程&#xff08;默认--只安装服务端“Server only”&#xff09;MySql官网地址&#xff1a;https://www.mysql.com/&#xff1b;快速下载通道请单击→ No thanks, just start my download.ps&#xff1a;其他资源(…

html+css+vue实现增删改查

代码如下&#xff1a;<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>优化版 Vue.js CRUD 示例&l…

(计算机网络)DNS解析流程及两种途径

在计算机网络中&#xff0c;DNS&#xff08;Domain Name System&#xff09;用于 将域名解析为 IP 地址。一个完整的解析过程涉及 递归查询、迭代查询&#xff0c;以及多个关键角色&#xff08;LDNS、本地域名服务器&#xff1b;根服务器&#xff1b;顶级域名服务器&#xff1b…

数据结构——队列(Java)

一.基本概念 队列用来存储逻辑关系为“一对一”的数据&#xff0c;是一种“特殊”的线性存储结构。 特点&#xff1a; •先进先出&#xff1a;队列中元素的添加&#xff08;入队enqueue&#xff09;和移除&#xff08;出队dequeue&#xff09;遵循先进先出的原 则。 •端点&…

【Go】:mac 环境下GoFrame安装开发工具 gf-cli——gf_darwin_arm64

当前主要是关于gf_darwin_arm64的安装步骤 如何快速给mac电脑安装gfgf是什么安装步骤方法1&#xff1a;去github下载gf-cli去git上下载对应电脑版本的gf-cli验证下载文件是否二进制文件授予该文件权限方法2&#xff1a;去goframe官网教你下载步骤验证gf是否安装成功可能遇到的问…

【新】ApiHug官方文档-ApiHug Spring Security 扩展-补充说明

概述 在上次说明中我们写了ApiHug 如何做授权的&#xff0c; 这里有个概念的混淆&#xff0c; 其实 apihug 不是在spring security 上做的安全扩展&#xff0c; 应该是 apihug spring, 安全设计框架&#xff0c; 和本身 spring security 没有半毛钱关系&#xff0c; 而如果你…

【Flask】测试平台开发,新增说明书编写和展示功能 第二十三篇

概述&#xff1a;本篇是接着上一篇&#xff0c;细分出说明书的编写部分&#xff0c;实现这个功能的需求&#xff0c;是内部很多同事反馈&#xff0c;需要有个地方存工具&#xff0c;并且可以写说明书&#xff0c;如果需要的人&#xff0c;那么可以在界面上直接下载工具和查看工…

Mac设置中的安全性缺少“任何来源”

问题&#xff1a;用Mac安装软件&#xff0c;隐私性与安全性&#xff0c;想切换“任何来源”用来下载网站的app&#xff0c;但是菜单栏找不到“任何来源”选项&#xff0c;无法安装dmg的文件终端中一行代码设置出来&#xff1a;sudo spctl --global-disable &#xff08;禁用Mac…

uniapp开发小程序,列表 点击后加载更多数据

一、需求 1.初始显示限制:将每页条数limit改为5,确保初始只显示5条数据 2.查看更多功能:添加了loadMore方法,点击"查看更多"时加载下一页数据 3.实现查看更多功能,点击后加载更多数据 4.添加loading状态防止重复请求 添加hasMore状态判断是否还有更多数据 …

Windows 部署 Gerrit 与 Apache24 配置

Windows 部署 Gerrit 与 Apache24 并配置反向代理 准备工作 下载并安装 Java JDK 确保配置 JAVA_HOME 环境变量博主这里安装openjdk21 https://jdk.java.net/archive/下载所需软件 Apache24&#xff1a;https://httpd.apache.org/download.cgi Gerrit&#xff1a;https://www.g…

从 Excel 趋势线到机器学习:拆解 AI 背后的核心框架​

引言&#xff1a;你其实早就 “玩转” 过机器学习&#xff1f;提到 “机器学习”&#xff0c;你是不是第一时间联想到复杂的代码、密密麻麻的公式&#xff0c;还有那些让人头晕的 “算法”“模型”“训练” 术语&#xff1f;仿佛它是高高在上的技术&#xff0c;离我们的日常无比…

Lenovo联想YOGA Pro 16 IAH10 2025款笔记本电脑(83L0)开箱状态预装OEM原厂Win11系统

适用机型(MTM)&#xff1a;【83L0】 链接&#xff1a;https://pan.baidu.com/s/1tDpeBb93t1u0XIgqAZ3edg?pwdqy2r 提取码&#xff1a;qy2r 联想原装系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软件、联想浏览器、电脑管家、…

Android 开发 - 一些画板第三方库(DrawBoard、FingerPaintView、PaletteLib)

一、DrawBoard 1、Dependencies 模块级 build.gradle implementation com.github.jenly1314:drawboard:1.1.02、Test &#xff08;1&#xff09;Activity Layout activity_draw_board.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout …

捷多邦揭秘超厚铜板:从制造工艺到设计关键环节​

一、超厚铜板制造工艺要点超厚铜板&#xff08;3oz 及以上&#xff09;的制造工艺对精度和稳定性要求严苛&#xff0c;核心环节需突破多重技术壁垒。蚀刻工艺中&#xff0c;因铜箔厚度达 105μm 以上&#xff0c;需采用高浓度酸性蚀刻液&#xff08;氯化铜浓度控制在 180-220g/…

【MYSQL | 高级篇 MyCat实现分库分表】

摘要&#xff1a;本文围绕分库分表展开&#xff0c;先分析单库性能瓶颈&#xff0c;介绍垂直与水平拆分策略及实现技术&#xff0c;再详述 MyCat 中间件的概述、环境准备、目录结构&#xff0c;讲解其入门配置与测试&#xff0c;深入说明核心配置文件&#xff0c;最后演示垂直和…

Docker部署Drawnix开源白板工具

Drawnix简介 Drawnix 是一款开源的在线白板工具&#xff08;SaaS&#xff09;&#xff0c;集思维导图、流程图绘制、自由画图等多种功能于一体&#xff0c;支持协作与插件扩展&#xff0c;适用于个人创作、团队协作和远程办公场景。它完全免费且开源&#xff0c;提供丰富的编辑…