Serverless 数据库最怕什么?不是没连接,而是连接“太多了”

简介: Serverless 数据库最怕什么?不是没连接,而是连接“太多了”

Serverless 数据库最怕什么?不是没连接,而是连接“太多了”

大家好,我是 Echo_Wish

这几年 Serverless 越来越火。

以前我们部署一个 Web 服务,习惯是:

买几台服务器 → 部署应用 → 配连接池 → 连数据库 → 慢慢跑。

现在变成:

请求来了 → 函数启动 → 执行业务 → 函数结束。

看起来非常爽。

不用管服务器,不用操心扩容,流量来了自动加实例。

但问题也来了:

应用可以无限弹性,数据库连接却没有无限弹性。

这恰恰是很多 Serverless 项目上线之后才发现的“坑”。

尤其是数据库连接管理。

很多人第一次做 Serverless,会很自然地写出这样的代码:

def handler(event, context):
    conn = pymysql.connect(
        host="db.example.com",
        user="root",
        password="123456",
        database="order"
    )

    cursor = conn.cursor()
    cursor.execute("SELECT * FROM orders LIMIT 10")

    result = cursor.fetchall()

    conn.close()

    return result

本地测试:

没问题。

测试环境:

没问题。

上线:

数据库连接数爆了。

然后数据库开始疯狂报错:

Too many connections

这时候你可能会很委屈:

“我明明每次请求结束都 close 了,为什么还是连接爆炸?”

问题就出在 Serverless 的运行模型上。


一、传统连接池,在 Serverless 里可能变成“放大器”

我们先理解传统应用为什么喜欢连接池。

假设一台服务器启动一个 Java 服务。

它创建一个连接池:

Application
    │
    ├── Connection 1
    ├── Connection 2
    ├── Connection 3
    ├── Connection 4
    └── Connection 5
              │
              ▼
           Database

比如配置:

maximumPoolSize: 20
minimumIdle: 5

通常问题不大。

因为:

一台服务器 = 一个连接池。

但是 Serverless 不一样。

假设你的函数突然扩容成 100 个实例。

每个实例都创建:

Pool Size = 20

那么数据库理论上可能面对:

100 × 20 = 2000

个连接。

这还只是数学题。

现实中还可能出现:

实例数 × 最大连接池连接数

再加上:

  • 数据库管理连接
  • 其他微服务连接
  • 定时任务
  • 后台任务
  • 开发人员工具
  • 慢连接
  • 连接泄漏

数据库很容易直接跪下。

所以我一直觉得:

Serverless 最大的数据库连接问题,不是连接池太小,而是连接池被复制了太多份。


二、Serverless 为什么特别容易把数据库打爆?

关键就在于它的“弹性”。

假设平时只有 5 个实例。

每个实例:

Pool = 10

数据库连接:

5 × 10 = 50

看起来很健康。

突然来了促销活动。

Serverless 从:

5 instances

扩展到:

200 instances

那么:

200 × 10 = 2000 connections

数据库可能根本扛不住。

更麻烦的是,Serverless 还存在冷启动。

新实例启动:

请求
 ↓
创建实例
 ↓
初始化数据库连接池
 ↓
创建连接
 ↓
执行 SQL

流量一上来,就可能出现一波非常明显的连接创建峰值。

这就是所谓的:

Connection Storm,连接风暴。

它特别像什么?

像高速公路收费站。

平时 5 个车道够用。

突然来了 200 辆车。

你不是把汽车扩容了就完事了。

因为收费站还是那几个。


三、所以 Serverless 最重要的组件之一:数据库 Proxy

这时候,数据库 Proxy 就开始发挥作用了。

简单理解:

不要让 Serverless 函数直接怼数据库,让 Proxy 夹在中间。

架构从:

Function
   │
   ▼
Database

变成:

Function
   │
   ▼
Database Proxy
   │
   ▼
Database

Proxy 干什么?

其中一个非常重要的工作就是:

帮你管理数据库连接。

例如:

Function A ─┐
Function B ─┤
Function C ─┤
Function D ─┤
Function E ─┤
             ▼
       ┌───────────┐
       │   Proxy   │
       │ Connection│
       │   Pool    │
       └───────────┘
             │
       ┌─────┴─────┐
       ▼           ▼
    Database    Database

函数实例可以很多。

但 Proxy 到数据库的连接可以被控制。

比如:

1000 个函数实例
        ↓
      Proxy
        ↓
   100 个数据库连接
        ↓
      MySQL

当然,具体连接数量还是要根据数据库规格、SQL 类型和业务负载压测出来。

但思路非常重要:

把“连接管理”从函数实例手里拿回来。


四、Proxy 并不是“万能盾牌”

这里特别容易产生一个误区。

有的人一听:

“用了数据库 Proxy,就不会连接爆炸了。”

这其实是不对的。

Proxy 能解决的是:

数据库连接管理和复用问题。

但是它不能解决:

  • SQL 写得烂
  • 查询特别慢
  • 单个事务持续几十秒
  • 数据库 CPU 已经 100%
  • 大量全表扫描
  • 索引设计错误
  • 请求突然暴涨
  • 函数疯狂重试

比如:

SELECT *
FROM orders
WHERE user_name LIKE '%abc%';

你前面加一个 Proxy。

后面还是:

1000 个请求
      ↓
1000 个慢 SQL
      ↓
Proxy
      ↓
Database CPU 100%

Proxy 也只能干瞪眼。

所以:

Proxy 解决的是“连接问题”,不是“数据库性能问题”。

这个边界一定要搞清楚。


五、那连接池到底要不要?

要。

但是不能再用传统服务器思维来配置。

传统应用可能喜欢:

minimumIdle = 10
maximumPoolSize = 50

Serverless 就要谨慎很多。

尤其是:

minimumIdle

这个参数。

为什么?

因为 Serverless 实例可能大量存在,又可能突然消失。

假设:

100 个实例
minimumIdle = 10

那么理论上就可能有:

100 × 10 = 1000

个空闲连接。

这些连接可能根本没有业务请求。

但它们依然占着数据库资源。

所以 Serverless 里我更倾向于:

让连接池足够小,让连接复用交给更合适的中间层。

例如:

const pool = mysql.createPool({
   
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,

    connectionLimit: 2,

    waitForConnections: true,
    queueLimit: 10
});

这里的思路不是:

“连接池越大越好。”

而是:

每一个 Serverless 实例都要对自己的连接预算负责。


六、真正需要关注的是“连接预算”

我特别建议做 Serverless 的时候,别只看:

QPS

还要算:

数据库最大连接数

比如:

数据库最大连接数:

max_connections = 1000

不要直接认为:

1000

都可以给 Serverless 用。

你可能还需要预留:

100     管理连接
100     其他应用
100     运维工具

那么真正给 Serverless 的预算可能只有:

700

假设:

最大实例数 = 200

那么平均下来:

700 / 200 = 3.5

也就是说:

每个实例连接池最好不要轻易超过 3 个左右。

当然,这只是帮助理解的计算模型。

实际设计还要考虑:

  • 并发请求数
  • SQL 执行时间
  • 事务时间
  • Proxy 行为
  • 数据库 CPU
  • 读写比例
  • 连接复用率

但至少你开始有了一个非常重要的概念:

连接预算。


七、还有一个经常被忽略的问题:数据库密码

很多 Serverless 项目一开始特别简单。

环境变量:

DB_HOST=xxx
DB_USER=root
DB_PASSWORD=123456

然后直接部署。

方便是方便。

但安全性呢?

函数环境变量一旦管理不严谨,数据库凭据就可能随着:

  • 日志
  • 配置文件
  • CI/CD
  • 镜像
  • 调试信息

到处传播。

我的建议是:

数据库密码不要硬编码。

例如:

import os

db_user = os.getenv("DB_USER")
db_password = os.getenv("DB_PASSWORD")

进一步可以使用云平台的 Secret 管理能力。

架构变成:

Function
   │
   │ 获取 Secret
   ▼
Secret Manager
   │
   ▼
Database Credential

这样做最大的好处不是“密码绝对不会泄露”。

而是:

你终于可以集中管理密码,而不是让密码散落在项目的各个角落。


八、数据库账号也别直接给 root

这一点看起来很基础,但现实项目中非常常见。

比如业务只需要:

SELECT
INSERT
UPDATE

结果直接给:

root

这就相当于:

你只是想让员工开门,结果把整个公司的保险柜钥匙都给他了。

应该遵循:

最小权限原则。

例如:

CREATE USER 'app_user'@'%'
IDENTIFIED BY 'strong_password';

GRANT SELECT, INSERT, UPDATE
ON order_db.*
TO 'app_user'@'%';

甚至可以进一步拆分:

Read User
    ↓
只读

Write User
    ↓
读 + 写

Admin User
    ↓
数据库管理

Serverless 函数使用的账号,最好不要拥有:

DROP DATABASE
CREATE USER
GRANT
ALTER SYSTEM

之类的高危权限。


九、网络安全也不能只靠用户名和密码

如果你的架构是:

Internet
   ↓
Function
   ↓
Database

那我会非常警惕。

更推荐:

Internet
   ↓
API Gateway
   ↓
Serverless Function
   ↓
Private Network
   ↓
Database Proxy
   ↓
Database

数据库尽量不要直接暴露公网。

同时可以配合:

  • Security Group
  • VPC
  • 私有子网
  • 白名单
  • TLS
  • 数据库身份认证
  • Secret Manager
  • IAM 权限

形成多层防护。

因为真正靠谱的安全策略从来不是:

“我密码够复杂,所以数据库很安全。”

而是:

就算密码泄露,攻击者也很难直接碰到数据库。


十、别忘了 Serverless 的“重试”

还有一个非常容易被低估的问题:

重试机制。

假设你的函数执行失败。

平台可能自动重试:

Request
  ↓
Function
  ↓
失败
  ↓
Retry
  ↓
Function
  ↓
失败
  ↓
Retry

如果一次请求会创建一个数据库连接。

那么一次业务请求可能变成:

1 Request
↓
3 Function Attempts
↓
3 Database Connections

如果同时有:

1000 Requests

问题就来了。

因此 Serverless 数据库架构一定要考虑:

重试 × 并发 × 连接数

甚至可以简单建立一个估算模型:

最大连接压力
≈
最大并发实例数
×
单实例最大连接数
×
重试放大系数

这不是严格的数据库容量公式。

但作为架构设计阶段的“报警器”,非常有用。


十一、事务时间越长,Serverless 越危险

还有一个问题:

BEGIN;

UPDATE orders
SET status = 'PAID'
WHERE id = 10001;

-- 中间干了一堆事情

COMMIT;

如果这个函数因为某个外部 API 卡住:

Database Transaction
       ↓
等待 5 秒
       ↓
等待 10 秒
       ↓
等待 30 秒

那么连接就一直被占用。

如果大量函数都这么干:

100 functions
×
1 long transaction
=
100 occupied connections

所以 Serverless 特别需要注意:

数据库事务里面尽量只做数据库相关的事情。

不要:

BEGIN
 ↓
UPDATE DB
 ↓
调用第三方支付
 ↓
请求 AI
 ↓
调用库存系统
 ↓
等待网络
 ↓
COMMIT

更合理的是:

数据库事务
   ↓
快速完成
   ↓
提交

然后
   ↓
异步处理其他事情

十二、我认为 Serverless 数据库真正靠谱的架构

如果让我自己设计一个生产环境,我更倾向于:

                 Internet
                    │
                    ▼
              API Gateway
                    │
                    ▼
            Serverless Function
                    │
          ┌─────────┴─────────┐
          │                   │
          ▼                   ▼
     Secret Manager       Cache/Queue
          │
          ▼
      DB Proxy
          │
          ▼
       Database

这里每一层解决的问题其实不一样。

组件 主要解决问题
API Gateway 流量入口、认证、限流
Serverless 弹性计算
Secret Manager 凭据管理
DB Proxy 数据库连接复用
Cache 减少数据库查询
Queue 削峰填谷、异步处理
Database 最终数据存储

千万不要把所有压力都扔给数据库。

尤其是查询型业务:

用户
 ↓
Function
 ↓
Redis
 ↓
命中?
 ├── 是 → 返回
 └── 否
       ↓
    DB Proxy
       ↓
    Database

数据库压力一下就能降很多。


十三、最后总结一下

Serverless 最大的魅力是什么?

弹性。

Serverless 最大的坑是什么?

也是弹性。

因为:

计算资源
可以无限扩

但是:

数据库
不能无限扩

所以传统架构里一句:

“给连接池调大一点。”

到了 Serverless 世界,可能直接变成:

“恭喜你,把数据库连接数调爆了。”

我个人认为,Serverless 数据库连接管理应该建立三个意识。

第一,连接不是越多越好

连接本身就是资源。

Function
    ↓
Connection Pool
    ↓
Proxy
    ↓
Database

每一层都应该控制连接规模。

第二,不要让数据库裸奔

数据库应该尽可能处于:

Private Network
+
Proxy
+
TLS
+
Secret
+
Least Privilege

的保护体系里面。

第三,数据库永远是瓶颈候选人

Serverless 可以一分钟扩容 100 倍。

数据库可不会因为你喊一句:

“流量来了,给我扩!”

就立刻扩 100 倍。

所以做 Serverless 架构时,真正应该问的不是:

“我的函数能扛多少 QPS?”

而应该问:

“我的数据库能承受多少连接、多少事务、多少 SQL,以及这些压力会不会随着函数扩容一起被放大?”

这才是 Serverless 数据库架构真正应该考虑的问题。

Serverless 不是“没有服务器”,而是把服务器的复杂度转移了。

而数据库连接管理,就是这个复杂度里非常容易被忽略、却又非常致命的一块。

我是 Echo_Wish

如果你也正在折腾 Serverless,记住一句特别朴素的话:

函数可以疯狂扩,数据库连接千万别跟着疯。

目录
相关文章
人工智能 缓存 前端开发
6143 18
人工智能 JavaScript 开发工具
3037 4
缓存 JavaScript Shell
1386 1
|
12天前
|
存储 弹性计算 缓存
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
本文更新了2026年阿里云全系列云服务器租赁活动报价,所有特惠资源均可前往阿里云活动中心选购,整体覆盖从个人入门到企业级高性能场景的全梯度需求。其中轻量应用服务器主打极致性价比,2核2G峰值200M带宽配置每日10点、15点限时抢购价仅38元/年,2核4G配置379元/年起;高性价比的经济型e实例、通用算力型u2i实例覆盖2核4G至4核32G全档位,适配开发测试与中小型企业业务;搭载英特尔至强6处理器的第九代c9i企业级实例算力较上代提升20%,支撑高并发生产环境,不同实例规格价差清晰,用户可根据自身业务负载与预算灵活选型。
2067 121
阿里云服务器租赁费用:新版租赁收费标准及活动报价参考
|
13天前
|
人工智能 程序员 API
Codex 接入 DeepSeek-V4-Flash:还能补上识图,提供两套方案
Codex 接入 DeepSeek-V4-Flash 怎么配?本文覆盖 CLI 与桌面端,再用 qwen3-vl-flash 补识图,两套方案可直接照做
1667 13
缓存 人工智能 算法
639 1
|
10天前
|
编解码 弹性计算 云计算
MiniMax-H3 视频生成模型 — 一键部署与使用指南
MiniMax-H3是MiniMax开源的33B全模态视频生成模型,支持文生视频、图生视频、参考生视频三种模式,原生输出2K/15秒带立体声音频视频,已原生适配ComfyUI,并可通过阿里云计算巢一键部署。(239字)
|
11天前
|
人工智能 API 开发工具
2026 零基础本地 AI 漫剧完整实操教程(8G 笔记本显卡可用|附可直接复制命令与代码)
本方案提供完全离线、本地运行的漫剧全自动制作流程:RTX3060/4050 8G显卡即可驱动,涵盖Qwen写分镜→ComfyUI统一角色绘图→LTX2.3图生微动画→Qwen3-TTS本地配音→FFmpeg自动合成,全程无水印、免API、不限次。专为低显存优化,解决变脸、闪烁、爆内存三大痛点。(239字)
|
19天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1983 10
阿里云联动百位企业安全专家,共识Agent防御最佳实践

热门文章

最新文章