首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Serverless 架构模式深度解析

Serverless 架构模式深度解析

作者头像
果酱带你啃java
发布2026-04-14 13:55:52
发布2026-04-14 13:55:52
600
举报

一、引言:Serverless不是“无服务器”,而是“无需关心服务器”

在云计算从IaaS、PaaS演进到SaaS的全链路中,Serverless(无服务器架构)是近十年最具颠覆性的架构模式之一。根据CNCF(云原生计算基金会)2025年度调研报告,全球Serverless市场规模已突破800亿美元,年复合增长率达35%,超过60%的中大型企业已将至少20%的业务迁移至Serverless架构。

很多开发者对Serverless的第一认知是“不用管服务器了”,这是典型的认知偏差——Serverless的核心不是“没有服务器”,而是开发者无需关注服务器的采购、部署、扩容、运维、安全补丁 等底层基础设施工作,只需聚焦业务逻辑本身。这种架构模式彻底重构了传统的开发、部署和运维流程,带来了“按需付费、弹性伸缩、快速迭代”的核心价值。

二、Serverless核心概念与底层逻辑

2.1 权威定义:Serverless的官方边界

根据CNCF对Serverless的权威定义,符合以下两个核心特征的架构可被称为Serverless:

  1. 无服务器管理:开发者无需感知底层服务器的存在,云厂商负责基础设施的全生命周期管理;
  2. 事件驱动+弹性伸缩:应用以事件为触发源运行,资源自动根据请求量扩缩容(甚至缩容至0);
  3. 按量计费:仅为实际运行的计算资源付费,空闲时不产生任何成本。

2.2 Serverless vs 传统架构 vs 微服务:核心差异

维度

传统单体架构

微服务架构

Serverless架构

服务器管理

自研/采购,全量运维

容器化部署,部分运维

云厂商托管,零运维

资源伸缩

手动扩容,资源固定

自动扩缩容,需配置阈值

毫秒级弹性,缩容至0

计费模式

按服务器资源付费

按容器/实例数付费

按执行时长+调用次数付费

开发聚焦点

全栈开发(含运维)

业务逻辑+服务治理

纯业务逻辑

冷启动问题

存在(可优化)

状态管理

本地/数据库

分布式缓存/数据库

无状态(需依赖BaaS服务)

2.3 Serverless底层运行原理(流程图)

原理拆解

  1. 事件触发:用户请求、定时任务、消息队列等事件通过API网关/事件源进入云厂商调度系统;
  2. 实例调度:调度系统检查是否有预热的函数实例,有则直接执行,无则初始化运行时(如JVM)、加载代码;
  3. 函数执行:执行完业务逻辑后返回结果,空闲时资源自动释放(或保留少量预热实例减少冷启动)。

2.4 Serverless核心特性

  1. 无状态性:函数实例不保存任何本地状态,每次执行都是独立的(需状态时依赖Redis/MongoDB等BaaS服务);
  2. 事件驱动:函数的执行必须由事件触发(HTTP请求、MQ消息、定时任务等),无事件则函数不运行;
  3. 按需付费:以阿里云FC为例,计费单位是“GB·秒”,即内存规格×执行时长,空闲时费用为0;
  4. 毫秒级弹性:支持每秒数万次的请求峰值,云厂商自动扩容,无需人工配置;
  5. 零运维:无需关注服务器的补丁、监控、故障转移,云厂商全托管。

三、Serverless关键架构模式(2025主流)

3.1 函数即服务(FaaS)模式(核心)

FaaS(Function as a Service)是Serverless的核心载体,开发者将业务逻辑封装为“函数”,部署到云厂商的FaaS平台(如AWS Lambda、阿里云FC、腾讯云SCF),平台负责函数的运行、扩容、运维。

核心特征:
  • 函数是最小部署单元,独立运行、独立扩缩容;
  • 函数生命周期短(毫秒到分钟级),避免长时间占用资源;
  • 支持多语言(Java/Go/Python/Node.js等),2025年主流FaaS平台已全面支持JDK 17。

3.2 后端即服务(BaaS)模式

BaaS(Backend as a Service)是FaaS的补充,指云厂商提供的开箱即用的后端服务,无需开发者自建和运维,常见的BaaS服务包括:

  • 数据库服务:MySQL/Redis/MongoDB托管版;
  • 消息队列:RocketMQ/Kafka托管版;
  • 存储服务:对象存储OSS;
  • 认证服务:OAuth2.0/SSO托管版。

FaaS+BaaS是Serverless的经典组合:FaaS负责业务逻辑,BaaS负责基础能力,开发者只需聚焦业务代码。

3.3 事件驱动架构(EDA)+ Serverless

事件驱动是Serverless的核心运行模式,事件生产者(如用户请求、订单创建、文件上传)产生事件,事件总线(如阿里云EventBridge)将事件路由到对应的FaaS函数,函数处理完后可产生新事件触发下一个函数,形成“事件流”。

3.4 微服务Serverless化模式

传统微服务需要部署到K8s/容器平台,仍需关注容器编排、资源调度;微服务Serverless化则将每个微服务拆分为多个FaaS函数,通过API网关聚合,核心优势:

  • 每个函数独立扩缩容,避免“一损俱损”;
  • 降低微服务的部署和运维成本;
  • 按需付费,减少闲置资源浪费。

3.5 批处理Serverless模式

针对大数据批处理场景(如日志分析、数据ETL),Serverless批处理模式无需搭建Hadoop/Spark集群,直接通过FaaS函数并行处理数据,优势:

  • 弹性扩容,处理速度随数据量自动提升;
  • 处理完成后资源自动释放,成本仅为传统集群的10%-30%;
  • 2025年主流FaaS平台已支持函数的“批量触发”和“结果聚合”能力。

四、Serverless核心技术栈与生态(2025最新)

4.1 云厂商FaaS产品

云厂商

FaaS产品

2025最新特性

AWS

Lambda

支持JDK 17、冷启动优化至10ms内

阿里云

函数计算FC

支持Spring Cloud Function原生集成、GPU函数

腾讯云

云函数SCF

与微信生态深度融合、Serverless容器

华为云

函数工作流FunctionGraph

支持跨区域函数编排

4.2 开源Serverless框架

  • Serverless Framework:跨云厂商的部署工具,支持一键部署函数到AWS/阿里云/腾讯云;
  • Knative:基于K8s的Serverless框架,将容器转换为Serverless服务;
  • OpenFaaS:轻量级开源FaaS平台,支持私有化部署;
  • Spring Cloud Function:Spring官方出品,将Spring应用转换为云函数,支持多云厂商适配。

五、企业级实战:基于Spring Cloud Function + 阿里云FC构建Serverless订单服务

5.1 需求背景

构建一个Serverless订单查询服务,满足以下需求:

  1. 支持根据订单ID查询订单详情(HTTP触发);
  2. 支持根据用户ID查询今日订单列表(HTTP触发);
  3. 数据存储在MySQL 8.0,使用MyBatisPlus操作数据库;
  4. 接口需接入Swagger3文档;
  5. 部署到阿里云FC,支持弹性扩缩容;
  6. 符合阿里Java开发手册,代码规范、无空指针等常见问题。

5.2 技术选型(2025最新稳定版)

技术栈

版本号

说明

JDK

17

符合阿里手册,长期支持版

Maven

3.9.6

项目构建工具

Spring Boot

3.2.5

基础框架

Spring Cloud Function

4.1.0

Serverless函数核心框架

MyBatisPlus

3.5.5

持久层框架

MySQL

8.0.36

关系型数据库

Lombok

1.18.30

简化代码

Fastjson2

2.0.49

JSON处理

Swagger3

2.2.0

接口文档

Alibaba Cloud FC SDK

2.7.0

阿里云FC适配SDK

Guava

33.2.1-jre

集合工具类

Spring Context Support

6.1.6

上下文支持

5.3 项目结构

代码语言:javascript
复制
com.jam.demo
├── config/            # 配置类
│   ├── MyBatisPlusConfig.java
│   └── SwaggerConfig.java
├── entity/            # 实体类
│   └── OrderEntity.java
├── mapper/            # Mapper接口
│   └── OrderMapper.java
├── service/           # 服务层
│   ├── OrderService.java
│   └── impl/
│       └── OrderServiceImpl.java
├── function/          # Serverless函数
│   └── OrderFunction.java
├── util/              # 工具类
│   └── DateUtil.java
├── Application.java   # 启动类
└── pom.xml            # 依赖配置

5.4 完整代码实现

5.4.1 pom.xml(核心依赖)
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.5</version>
        <relativePath/>
    </parent>
    <groupId>com.jam.demo</groupId>
    <artifactId>serverless-order-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>serverless-order-demo</name>
    <description>Serverless订单服务示例</description>
    <properties>
        <java.version>17</java.version>
        <mybatis-plus.version>3.5.5</mybatis-plus.version>
        <fastjson2.version>2.0.49</fastjson2.version>
        <guava.version>33.2.1-jre</guava.version>
        <swagger.version>2.2.0</swagger.version>
        <lombok.version>1.18.30</lombok.version>
        <aliyun-fc.version>2.7.0</aliyun-fc.version>
    </properties>
    <dependencies>
        <!-- Spring Boot核心 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-undertow</artifactId>
        </dependency>
        <!-- Spring Cloud Function -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-web</artifactId>
            <version>4.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-adapter-aws</artifactId>
            <version>4.1.0</version>
        </dependency>
        <!-- MyBatisPlus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${mybatis-plus.version}</version>
        </dependency>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.36</version>
            <scope>runtime</scope>
        </dependency>
        <!-- Lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>
        <!-- Fastjson2 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>${fastjson2.version}</version>
        </dependency>
        <!-- Guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>${guava.version}</version>
        </dependency>
        <!-- Swagger3 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-boot-starter</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <!-- 阿里云FC SDK -->
        <dependency>
            <groupId>com.aliyun.fc.runtime</groupId>
            <artifactId>fc-java-core</artifactId>
            <version>${aliyun-fc.version}</version>
        </dependency>
        <!-- Spring工具类 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>6.1.6</version>
        </dependency>
        <!-- 测试 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.jam.demo.Application</mainClass>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <!-- 打包为可执行JAR -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.6.0</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>com.jam.demo.Application</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
5.4.2 配置文件(application.yml)
代码语言:javascript
复制
spring:
  application:
    name:serverless-order-demo
datasource:
    driver-class-name:com.mysql.cj.jdbc.Driver
    url:jdbc:mysql://localhost:3306/serverless_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
    username:root
    password:root123456
cloud:
    function:
      definition:getOrderById;getTodayOrdersByUserId# 定义函数名称
mybatis-plus:
configuration:
    map-underscore-to-camel-case:true
    log-impl:org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
    db-config:
      logic-delete-field:deleted
      logic-delete-value:1
      logic-not-delete-value:0
mapper-locations:classpath:mapper/**/*.xml
server:
port:8080
springdoc:
swagger-ui:
    path:/swagger-ui.html
    enabled:true
api-docs:
    enabled:true
5.4.3 MyBatisPlus配置类
代码语言:javascript
复制
package com.jam.demo.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MyBatisPlus配置类
 * @author ken
 * @date 2025-05-20
 */
@Configuration
@MapperScan("com.jam.demo.mapper")
publicclass MyBatisPlusConfig {

    /**
     * 分页插件配置
     * @return MybatisPlusInterceptor
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
5.4.4 Swagger3配置类
代码语言:javascript
复制
package com.jam.demo.config;

import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Swagger3配置类
 * @author ken
 * @date 2025-05-20
 */
@Configuration
publicclass SwaggerConfig {

    /**
     * 配置API文档信息
     * @return OpenAPI
     */
    @Bean
    public OpenAPI customOpenAPI() {
        returnnew OpenAPI()
                .info(new Info()
                        .title("Serverless订单服务API文档")
                        .version("1.0.0")
                        .description("基于Spring Cloud Function + 阿里云FC的Serverless订单服务"));
    }
}
5.4.5 日期工具类
代码语言:javascript
复制
package com.jam.demo.util;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

/**
 * 日期工具类
 * @author ken
 * @date 2025-05-20
 */
publicclass DateUtil {

    /**
     * 获取今日开始时间(00:00:00)
     * @return LocalDateTime
     */
    public static LocalDateTime getStartOfDay() {
        return LocalDate.now().atStartOfDay();
    }

    /**
     * 获取今日结束时间(23:59:59.999999999)
     * @return LocalDateTime
     */
    public static LocalDateTime getEndOfDay() {
        return LocalDate.now().atTime(LocalTime.MAX);
    }
}
5.4.6 订单实体类
代码语言:javascript
复制
package com.jam.demo.entity;

import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.math.BigDecimal;
import java.time.LocalDateTime;

/**
 * 订单实体类
 * @author ken
 * @date 2025-05-20
 */
@Data
@TableName("t_order")
@Schema(description = "订单实体")
publicclass OrderEntity {

    /**
     * 订单ID
     */
    @TableId(type = IdType.AUTO)
    @Schema(description = "订单ID")
    private Long id;

    /**
     * 用户ID
     */
    @Schema(description = "用户ID")
    private Long userId;

    /**
     * 订单金额
     */
    @Schema(description = "订单金额")
    private BigDecimal amount;

    /**
     * 订单状态(0-待支付,1-已支付,2-已取消)
     */
    @Schema(description = "订单状态")
    private Integer status;

    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    @Schema(description = "创建时间")
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @Schema(description = "更新时间")
    private LocalDateTime updateTime;

    /**
     * 逻辑删除标识(0-未删除,1-已删除)
     */
    @TableLogic
    @Schema(description = "逻辑删除标识")
    private Integer deleted;
}
5.4.7 订单Mapper接口
代码语言:javascript
复制
package com.jam.demo.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.jam.demo.entity.OrderEntity;
import org.apache.ibatis.annotations.Param;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单Mapper接口
 * @author ken
 * @date 2025-05-20
 */
publicinterface OrderMapper extends BaseMapper<OrderEntity> {

    /**
     * 根据用户ID和时间范围查询订单列表
     * @param userId 用户ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 订单列表
     */
    List<OrderEntity> selectByUserIdAndTimeRange(
            @Param("userId") Long userId,
            @Param("startTime") LocalDateTime startTime,
            @Param("endTime") LocalDateTime endTime);
}
5.4.8 订单Mapper XML(resources/mapper/OrderMapper.xml)
代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jam.demo.mapper.OrderMapper">
    <select id="selectByUserIdAndTimeRange" resultType="com.jam.demo.entity.OrderEntity">
        SELECT * FROM t_order
        WHERE user_id = #{userId}
        AND create_time >= #{startTime}
        AND create_time <= #{endTime}
        AND deleted = 0
    </select>
</mapper>
5.4.9 订单服务接口
代码语言:javascript
复制
package com.jam.demo.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.jam.demo.entity.OrderEntity;

import java.util.List;

/**
 * 订单服务接口
 * @author ken
 * @date 2025-05-20
 */
publicinterface OrderService extends IService<OrderEntity> {

    /**
     * 根据订单ID查询订单详情
     * @param orderId 订单ID
     * @return 订单详情
     * @throws IllegalArgumentException 订单ID为空时抛出
     */
    OrderEntity getOrderById(Long orderId);

    /**
     * 根据用户ID查询今日订单列表
     * @param userId 用户ID
     * @return 今日订单列表
     * @throws IllegalArgumentException 用户ID为空时抛出
     */
    List<OrderEntity> getTodayOrdersByUserId(Long userId);
}
5.4.10 订单服务实现类
代码语言:javascript
复制
package com.jam.demo.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.jam.demo.entity.OrderEntity;
import com.jam.demo.mapper.OrderMapper;
import com.jam.demo.service.OrderService;
import com.jam.demo.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 订单服务实现类
 * @author ken
 * @date 2025-05-20
 */
@Service
@Slf4j
publicclass OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> implements OrderService {

    /**
     * 根据订单ID查询订单详情
     * @param orderId 订单ID
     * @return 订单详情
     * @throws IllegalArgumentException 订单ID为空时抛出
     */
    @Override
    public OrderEntity getOrderById(Long orderId) {
        // 判空校验(符合阿里手册)
        if (ObjectUtils.isEmpty(orderId)) {
            log.error("查询订单详情失败:订单ID为空");
            thrownew IllegalArgumentException("订单ID不能为空");
        }
        OrderEntity order = this.getById(orderId);
        if (ObjectUtils.isEmpty(order)) {
            log.warn("查询订单详情失败:订单ID={}不存在", orderId);
            returnnull;
        }
        log.info("查询订单详情成功:订单ID={}", orderId);
        return order;
    }

    /**
     * 根据用户ID查询今日订单列表
     * @param userId 用户ID
     * @return 今日订单列表
     * @throws IllegalArgumentException 用户ID为空时抛出
     */
    @Override
    public List<OrderEntity> getTodayOrdersByUserId(Long userId) {
        // 判空校验(符合阿里手册)
        if (ObjectUtils.isEmpty(userId)) {
            log.error("查询今日订单失败:用户ID为空");
            thrownew IllegalArgumentException("用户ID不能为空");
        }
        LocalDateTime startTime = DateUtil.getStartOfDay();
        LocalDateTime endTime = DateUtil.getEndOfDay();
        List<OrderEntity> orderList = baseMapper.selectByUserIdAndTimeRange(userId, startTime, endTime);
        // 空集合处理(避免返回null)
        List<OrderEntity> result = ObjectUtils.isEmpty(orderList) ? Lists.newArrayList() : orderList;
        log.info("查询今日订单成功:用户ID={},订单数量={}", userId, result.size());
        return result;
    }
}
5.4.11 Serverless函数实现类
代码语言:javascript
复制
package com.jam.demo.function;

import com.alibaba.fastjson2.JSON;
import com.jam.demo.entity.OrderEntity;
import com.jam.demo.service.OrderService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;

/**
 * 订单Serverless函数
 * @author ken
 * @date 2025-05-20
 */
@Component
@Slf4j
@RequiredArgsConstructor
@Tag(name = "订单函数接口", description = "基于Serverless的订单查询接口")
publicclass OrderFunction {

    privatefinal OrderService orderService;

    /**
     * 根据订单ID查询订单详情函数
     * @param request 请求参数(JSON格式,包含orderId)
     * @return 订单详情JSON字符串
     */
    @Operation(summary = "根据订单ID查询订单详情", description = "Serverless函数:根据订单ID查询订单详情")
    public String getOrderById(
            @Parameter(description = "请求参数,格式:{\"orderId\":1}") String request) {
        // 参数校验
        if (!StringUtils.hasText(request)) {
            log.error("查询订单详情失败:请求参数为空");
            return JSON.toJSONString(Map.of("code", 400, "msg", "请求参数不能为空"));
        }
        try {
            Map<String, Object> paramMap = JSON.parseObject(request);
            Long orderId = Long.valueOf(paramMap.get("orderId").toString());
            OrderEntity order = orderService.getOrderById(orderId);
            if (order == null) {
                return JSON.toJSONString(Map.of("code", 404, "msg", "订单不存在", "data", null));
            }
            return JSON.toJSONString(Map.of("code", 200, "msg", "查询成功", "data", order));
        } catch (IllegalArgumentException e) {
            log.error("查询订单详情失败:参数非法", e);
            return JSON.toJSONString(Map.of("code", 400, "msg", e.getMessage()));
        } catch (Exception e) {
            log.error("查询订单详情失败:系统异常", e);
            return JSON.toJSONString(Map.of("code", 500, "msg", "系统异常"));
        }
    }

    /**
     * 根据用户ID查询今日订单列表函数
     * @param request 请求参数(JSON格式,包含userId)
     * @return 今日订单列表JSON字符串
     */
    @Operation(summary = "根据用户ID查询今日订单列表", description = "Serverless函数:根据用户ID查询今日订单列表")
    public String getTodayOrdersByUserId(
            @Parameter(description = "请求参数,格式:{\"userId\":1}") String request) {
        // 参数校验
        if (!StringUtils.hasText(request)) {
            log.error("查询今日订单失败:请求参数为空");
            return JSON.toJSONString(Map.of("code", 400, "msg", "请求参数不能为空"));
        }
        try {
            Map<String, Object> paramMap = JSON.parseObject(request);
            Long userId = Long.valueOf(paramMap.get("userId").toString());
            List<OrderEntity> orderList = orderService.getTodayOrdersByUserId(userId);
            return JSON.toJSONString(Map.of("code", 200, "msg", "查询成功", "data", orderList));
        } catch (IllegalArgumentException e) {
            log.error("查询今日订单失败:参数非法", e);
            return JSON.toJSONString(Map.of("code", 400, "msg", e.getMessage()));
        } catch (Exception e) {
            log.error("查询今日订单失败:系统异常", e);
            return JSON.toJSONString(Map.of("code", 500, "msg", "系统异常"));
        }
    }
}
5.4.12 启动类
代码语言:javascript
复制
package com.jam.demo;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.function.context.config.EnableFunctionRegistrar;

/**
 * 应用启动类
 * @author ken
 * @date 2025-05-20
 */
@SpringBootApplication
@EnableFunctionRegistrar
@MapperScan("com.jam.demo.mapper")
publicclass Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
5.4.13 MySQL表结构(t_order)
代码语言:javascript
复制
CREATE DATABASEIFNOTEXISTS serverless_demo DEFAULTCHARACTERSET utf8mb4 COLLATE utf8mb4_unicode_ci;
USE serverless_demo;

CREATETABLEIFNOTEXISTS t_order (
    idBIGINT AUTO_INCREMENT COMMENT'订单ID',
    user_id BIGINTNOTNULLCOMMENT'用户ID',
    amount DECIMAL(10,2) NOTNULLCOMMENT'订单金额',
    statusTINYINTNOTNULLDEFAULT0COMMENT'订单状态(0-待支付,1-已支付,2-已取消)',
    create_time DATETIME NOTNULLDEFAULTCURRENT_TIMESTAMPCOMMENT'创建时间',
    update_time DATETIME NOTNULLDEFAULTCURRENT_TIMESTAMPONUPDATECURRENT_TIMESTAMPCOMMENT'更新时间',
    deleted TINYINTNOTNULLDEFAULT0COMMENT'逻辑删除标识(0-未删除,1-已删除)',
    PRIMARY KEY (id),
    INDEX idx_user_id (user_id),
    INDEX idx_create_time (create_time)
) ENGINE=InnoDBDEFAULTCHARSET=utf8mb4 COMMENT='订单表';

-- 插入测试数据
INSERTINTO t_order (user_id, amount, status) VALUES (1, 99.99, 1);
INSERTINTO t_order (user_id, amount, status) VALUES (1, 199.99, 0);
INSERTINTO t_order (user_id, amount, status) VALUES (2, 299.99, 1);

5.5 本地测试

  1. 启动MySQL 8.0,执行上述表结构和测试数据SQL;
  2. 启动Spring Boot应用(JDK 17环境);
  3. 访问Swagger文档:http://localhost:8080/swagger-ui.html,测试接口:
    • 测试getOrderById:请求参数{"orderId":1},返回订单详情;
    • 测试getTodayOrdersByUserId:请求参数{"userId":1},返回今日订单列表。

5.6 部署到阿里云FC

5.6.1 打包应用

执行Maven命令打包:

代码语言:javascript
复制
mvn clean package -DskipTests

打包完成后,生成serverless-order-demo-0.0.1-SNAPSHOT-jar-with-dependencies.jar文件。

5.6.2 创建阿里云FC函数
  1. 登录阿里云FC控制台,创建“自定义运行时”函数;
  2. 上传上述JAR包;
  3. 配置函数入口:com.jam.demo.Application
  4. 配置环境变量(数据库连接信息):
    • SPRING_DATASOURCE_URL: jdbc:mysql://xxx.xxx.xxx.xxx:3306/serverless_demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    • SPRING_DATASOURCE_USERNAME: root
    • SPRING_DATASOURCE_PASSWORD: root123456
  5. 配置触发器:创建HTTP触发器,支持公网访问。
5.6.3 线上测试

调用阿里云FC的HTTP触发器地址,测试接口:

代码语言:javascript
复制
# 测试getOrderById
curl -X POST -H "Content-Type: application/json" -d "{\"orderId\":1}" https://xxx.cn-shanghai.fcapp.run/getOrderById

# 测试getTodayOrdersByUserId
curl -X POST -H "Content-Type: application/json" -d "{\"userId\":1}" https://xxx.cn-shanghai.fcapp.run/getTodayOrdersByUserId

六、Serverless架构的坑与避坑指南

6.1 冷启动问题(最核心的坑)

问题本质:

首次调用函数时,云厂商需要初始化运行时环境(如JVM)、加载代码、初始化依赖(如数据库连接池),导致响应时间变长(Java函数冷启动通常100ms-3s)。

避坑方案:
  1. 预热实例:阿里云FC/腾讯云SCF支持配置“预留实例”,保持一定数量的预热实例,避免冷启动;
  2. 运行时优化
    • Java函数使用GraalVM编译为原生镜像,冷启动时间可降至10ms内;
    • 减少不必要的依赖(如移除无用的JAR包),缩小包体积;
  3. 函数拆分:将大函数拆分为小函数,减少初始化时间;
  4. 触发策略:定时触发函数(如每分钟调用一次),保持实例预热。

6.2 状态管理问题

问题本质:

Serverless函数是无状态的,无法在本地保存状态(如用户会话、缓存数据),多次调用可能使用不同的实例。

避坑方案:
  1. 使用BaaS服务:将状态存储在Redis/MongoDB等托管服务中;
  2. 避免本地缓存:不要在函数中使用本地缓存(如HashMap),改用Redis分布式缓存;
  3. 幂等性设计:函数需支持幂等性(如通过订单号+流水号去重),避免重复执行导致数据错误。

6.3 性能与成本平衡

问题本质:

高内存规格的函数执行速度快,但计费更高;低内存规格的函数计费低,但执行速度慢(甚至超时)。

避坑方案:
  1. 性能测试:通过压测确定最优内存规格(阿里云FC推荐Java函数使用1GB内存);
  2. 超时配置:根据函数执行时间合理配置超时时间(避免过早终止,也避免过长占用资源);
  3. 批量处理:批处理场景下,将小批量任务合并为大批量任务,减少函数调用次数。

6.4 监控与排障

问题本质:

Serverless函数的日志分散,难以定位问题;函数实例是临时的,无法远程调试。

避坑方案:
  1. 日志聚合:将函数日志输出到阿里云SLS/腾讯云CLS,统一聚合分析;
  2. 链路追踪:接入阿里云ARMS/OpenTelemetry,实现全链路追踪;
  3. 本地调试:使用云厂商提供的本地调试工具(如阿里云FC Local),模拟线上环境调试。

七、Serverless架构的适用场景与不适用场景

7.1 适用场景

  1. 突发流量场景:秒杀、促销、直播带货等流量波动大的场景,Serverless可弹性扩容;
  2. 定时任务场景:数据同步、报表生成、日志清理等定时任务,按需执行,成本低;
  3. 事件驱动场景:订单创建、支付回调、文件上传等事件触发的业务;
  4. 长尾流量场景:访问量低且分散的接口(如后台管理系统),Serverless按需付费,成本仅为传统部署的10%;
  5. 微服务拆分场景:将微服务拆分为多个小函数,独立部署、独立扩缩容。

7.2 不适用场景

  1. 长连接场景:WebSocket、TCP长连接等需要长时间保持连接的业务;
  2. 高CPU/IO密集型场景:视频转码、大数据计算等长时间占用资源的业务(推荐使用容器/裸金属);
  3. 低延迟要求场景:金融交易、实时风控等要求响应时间<10ms的业务(冷启动无法满足);
  4. 强状态场景:需要大量本地缓存、会话管理的业务(无状态设计成本过高)。

八、Serverless架构未来趋势(2025-2030)

  1. Serverless 4.0:云厂商将推出“零冷启动”函数,通过智能预热和运行时优化,将冷启动时间降至10ms内;
  2. 分布式Serverless:Serverless从单云厂商走向跨云、跨地域分布式部署,支持全球弹性;
  3. 边缘计算+Serverless:函数部署到边缘节点(如CDN节点),降低访问延迟,支持本地化计算;
  4. AI+Serverless:云厂商推出AI原生的Serverless函数,支持一键集成大模型能力,简化AI应用开发;
  5. 私有化Serverless:开源Serverless框架(如Knative)将更成熟,企业可在私有云部署Serverless平台。

九、总结

Serverless架构不是银弹,但它是云计算发展的必然趋势——它彻底改变了开发者的工作模式,让开发者从“全栈运维”中解放出来,聚焦业务价值。本文从底层逻辑出发,拆解了Serverless的核心架构模式,实现了企业级订单服务案例,同时给出了避坑指南和场景选型建议。

要掌握Serverless架构,核心是理解“无服务器不是没有服务器,而是无需关心服务器”,在实际落地时,需结合业务场景选择合适的架构模式,平衡性能、成本和可维护性。随着云厂商技术的不断迭代,Serverless将在更多场景下替代传统架构,成为企业数字化转型的核心技术选择。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-12-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 果酱带你啃java 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、引言:Serverless不是“无服务器”,而是“无需关心服务器”
    • 二、Serverless核心概念与底层逻辑
      • 2.1 权威定义:Serverless的官方边界
      • 2.2 Serverless vs 传统架构 vs 微服务:核心差异
      • 2.3 Serverless底层运行原理(流程图)
      • 2.4 Serverless核心特性
    • 三、Serverless关键架构模式(2025主流)
      • 3.1 函数即服务(FaaS)模式(核心)
      • 3.2 后端即服务(BaaS)模式
      • 3.3 事件驱动架构(EDA)+ Serverless
      • 3.4 微服务Serverless化模式
      • 3.5 批处理Serverless模式
    • 四、Serverless核心技术栈与生态(2025最新)
      • 4.1 云厂商FaaS产品
      • 4.2 开源Serverless框架
    • 五、企业级实战:基于Spring Cloud Function + 阿里云FC构建Serverless订单服务
      • 5.1 需求背景
      • 5.2 技术选型(2025最新稳定版)
      • 5.3 项目结构
      • 5.4 完整代码实现
      • 5.5 本地测试
      • 5.6 部署到阿里云FC
    • 六、Serverless架构的坑与避坑指南
      • 6.1 冷启动问题(最核心的坑)
      • 6.2 状态管理问题
      • 6.3 性能与成本平衡
      • 6.4 监控与排障
    • 七、Serverless架构的适用场景与不适用场景
      • 7.1 适用场景
      • 7.2 不适用场景
    • 八、Serverless架构未来趋势(2025-2030)
    • 九、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档