03

数据与 AWS 组件:为何不是一库到底

这个平台选了 PostgreSQL、DynamoDB、Redis、S3、CloudFront、SQS 组合拳。看上去复杂,其实每一件都在解决一种不同的数据性格与流量压力。

先别背服务名,先认数据性格

最实用的架构眼光,不是记住 AWS 名词,而是先问:这份数据更像账本、流水、临时状态,还是大文件?问对这句,选型通常就八九不离十。

🧾

Aurora PostgreSQL

适合用户、租户、好友、群组、角色这类关系密、查询规则复杂、要事务一致的核心业务数据。

💬

DynamoDB

扛聊天正文这类高写入、按会话和时间翻页读取的数据,避免主库被海量消息拖慢。

Redis

拿来装未读数、在线状态、缓存等“要快、可重算、可失效”的状态值。

📦

S3 + CloudFront

文件不经业务服务中转,而是直传对象存储,再通过 CloudFront 或签名 URL 做下载与加速。

📮

SQS

把异步任务从主请求链摘出来,用来削峰、解耦、重试与后台补账。

💡
选型不是“哪个更高级”,而是“哪种压力更适合谁”

行业里常见的好架构,几乎都不是单库万能,而是把一致性、吞吐、延迟、成本分给不同组件去扛。

真实代码:下载链路区分公开 URL 与签名 URL

这段来自 `cloudfront-client.js`。它说明文件访问不是一刀切,而是按场景决定“直接公开”还是“临时签名后访问”。

代码

const cloudfrontClient = isLocal
  ? {
      getSignedUrl: async (objectKey, options = {}) => {
        return await s3Client.getPresignedUrl(
          process.env.S3_PRIVATE_BUCKET,
          objectKey,
          options
        );
      },
      getPublicUrl: (objectKey) => {
        const endpoint = process.env.S3_ENDPOINT || "http://localhost:4566";
        const bucket = process.env.S3_PUBLIC_BUCKET;
        return `${endpoint}/${bucket}/assets/${objectKey}`;
      },
    }
  : new CloudFrontClientWrapper({
      region: process.env.AWS_REGION,
      distributionDomain: process.env.CLOUDFRONT_DOMAIN,
      keyPairId: process.env.CLOUDFRONT_KEY_PAIR_ID,
      privateKeyPath: process.env.CLOUDFRONT_PRIVATE_KEY_PATH,
    });
          
白话

本地环境先走简化模式:私有文件直接生成预签名 S3 地址,公开文件拼一个公开 URL。

真正线上环境则交给 `CloudFrontClientWrapper`,说明文件访问已被当成正式能力来治理。

它要求区域、分发域名、密钥对 ID 与私钥路径,表示私有内容访问是带签名校验的。

这比“把所有文件都挂成公网地址”更稳,也比“每次都让业务服务器自己转发文件”更省资源。

拖一拖:把数据交给更像它的服务

这不是考试,而是训练你的架构直觉。以后你跟 AI 说“这块应该放哪”,说的就是这一层判断。

租户配置与角色权限
聊天消息正文
在线状态与未读角标
图片、视频、附件原文件
补发通知、异步修正、后台派生任务

结构稳定、关系复杂、需要事务一致

Drop here

吞吐高、访问模式偏按键与时序

Drop here

极快读取、可重算、适合短期状态

Drop here

大对象、媒体文件、要和 CDN 配合

Drop here

先接住事件,后续慢慢处理和重试

Drop here

小测:你会怎样做 AWS 侧取舍

如果用户大量上传视频,哪种做法更像这套架构的思路?

为什么“未读数”这类状态更适合 Redis,而不是只靠 PostgreSQL 现算?

系统为何把部分任务丢给 SQS,而不是每次请求同步做完所有收尾?