本节摘要:数据库和中间件是应用架构的核心组件,腾讯云提供多种托管服务。数据库按数据模型分:关系型 TDSQL(MySQL 协议)适合结构化数据和事务;Redis 缓存适合高速读写;文档型数据库适合灵活结构;时序数据库适合监控 IoT 这类带时间戳的数据。中间件里,CKafka 消息队列解耦异步通信,API 网关统一管理 API 入口。本节讲这些产品的定位和选型,重点是怎么根据数据特征选对数据库,以及托管相比自建省了什么、失去什么。
阅读完本节,你应当能够:
几乎每个应用都要存数据,而"用什么存"是个容易选错的决策。最直觉的选择是 MySQL——它通用、熟悉、能处理大多数场景。但 MySQL 不是万能的:高并发的计数器(点赞数)用 MySQL 扛不住,该用 Redis;海量的监控指标(每秒上万个时间戳)用 MySQL 查不动,该用时序数据库;灵活结构的商品属性(不同商品属性不同)用关系型要建很多表,文档型更合适。
选错数据库的代价很大。把高并发计数塞进 MySQL,要么频繁锁表、要么加缓存层层补丁;把结构化的事务数据塞进文档数据库,复杂查询性能差且没有事务保证。所以理解各类数据库的数据模型和适用边界,是架构设计的基本功。
另一个决策是托管还是自建。自建 MySQL 你要管安装、备份、主从同步、故障切换、版本升级——任何一环出错都可能丢数据或宕机。托管 TDSQL 把这些全包了,但要付溢价。多数团队,尤其是没有专职 DBA 的,托管是更稳的选择。
各类数据库的定位:
| 数据库类型 | 数据模型 | 擅长 | 不擅长 | 典型用途 |
|---|---|---|---|---|
| 关系型 TDSQL | 表 关系 | 结构化数据、事务、复杂查询 | 超高并发、灵活结构 | 用户、订单、账户 |
| Redis 缓存 | 键值 | 极高并发读写、低延迟 | 持久化、复杂查询 | 缓存、计数器、会话 |
| 文档型 | 文档 JSON | 灵活结构、嵌套数据 | 强事务 | 商品属性、内容管理 |
| 时序型 | 时间序列 | 时间戳数据、聚合降采样 | 单条随机读写 | 监控、IoT、日志 |
| 列式/数仓 | 列存 | 海量数据分析、聚合 | 单条事务 | 报表、BI、大数据分析 |
选型的核心是匹配"数据特征 + 访问模式"。结构化且要事务(转账、下单)用关系型;高速读写且能容忍丢失(缓存)用 Redis;结构灵活(商品属性各不相同)用文档型;按时间排序的指标(监控)用时序型;海量数据分析用列式数仓。
💡 关键直觉:别用一种数据库解决所有问题。一个典型应用常常是"关系型存核心业务数据 + Redis 做缓存 + 时序库存监控"的多数据库组合。每种数据库做自己擅长的事,通过应用层把它们粘合起来。强行用一种数据库通吃,要么性能差要么开发痛苦。
TDSQL 是腾讯云的托管关系型数据库,兼容 MySQL 协议(也有 PostgreSQL 等版本)。它把数据库运维的几个麻烦事外包了:
高可用:自动主从复制和故障切换。主库挂了,从库自动顶上,你不用半夜爬起来手动切。这是托管数据库最大的价值之一——自建主从切换是 DBA 的噩梦。
备份恢复:自动定期备份,支持按时间点恢复("恢复到昨天下午 3 点的状态")。自建要自己写备份脚本、验证可恢复性,很多人备份了但从没验证过能不能恢复,真出事才发现备份是坏的。
扩缩容:升级实例规格(加 CPU、加内存)通常是无感操作,厂商帮你迁。读压力大可以加只读实例。
代价是:你受限于厂商支持的版本和配置。想用一个特殊的 MySQL 插件、改个内核参数,可能不支持。对于绝大多数标准用法这不是问题,但有些深度定制需求的场景会被限制。
Redis 是内存键值存储,因为数据在内存里,读写极快(微秒级)。它在架构里通常扮演"缓存"角色——把热点数据从慢存储(磁盘上的数据库)搬到快存储(内存),减少对慢存储的压力。
典型用法:
数据缓存:把数据库查询结果缓存到 Redis,下次同样的查询直接从 Redis 取,不用再查数据库。这是最经典的用法,能大幅降低数据库压力。
会话存储:用户登录会话存 Redis,多台服务器共享(用户请求可能落到任何一台)。比存数据库快,比存每台服务器本地又能共享。
计数器/排行榜:高并发的计数(点赞数、播放量)用 Redis 的原子操作扛得住,MySQL 这种场景会锁表。
限流:用 Redis 记录请求频率做限流("每用户每分钟最多 100 次"),比在应用内存里限流更准(多台服务器共享计数)。
| 用法 | Redis 角色 | 解决问题 |
|---|---|---|
| 数据缓存 | 热点数据镜像 | 降低数据库压力 |
| 会话存储 | 共享会话 | 多机一致 |
| 计数器 | 原子计数 | 高并发写 |
| 限流 | 频率记录 | 多机一致限流 |
⚠️ 常见坑:把 Redis 当主存储。Redis 是内存数据库,虽然能持久化但本质上是为了速度而非可靠。把只能存不能丢的业务数据(用户余额、订单)放 Redis 而不落数据库,一旦内存故障或持久化没做好,数据就丢了。Redis 是缓存层,数据库是持久层,别搞反。
CKafka 是腾讯云的托管 Kafka(消息队列产品)。消息队列解决的核心问题是解耦和异步。
设想订单系统:用户下单后,要扣库存、发短信、记积分、推数据分析。如果订单系统同步调这四个服务,任何一个慢了或挂了,下单就失败或超时。用消息队列解耦:订单系统把"新订单"消息扔进队列就返回成功,库存、短信、积分各自从队列消费消息慢慢处理。订单系统不用等它们,它们之间也不互相依赖。
消息队列的几个价值:解耦(生产者不关心消费者是谁、几个)、异步(慢操作不阻塞主流程)、削峰(流量高峰时消息排队,消费者按自己节奏处理,不被压垮)、广播(一条消息多个消费者各自处理)。
托管 CKafka 相比自建 Kafka 省了集群运维(Kafka 集群的搭建、监控、扩容是出了名的麻烦),代价同样是受限于厂商版本和配置。
API 网关是放在所有后端服务前面的统一入口。它把"API 管理"这件事集中处理:
统一鉴权:所有 API 请求先过网关做身份验证,后端服务不用各自实现鉴权逻辑。
限流熔断:在网关层做限流(防止恶意刷接口)和熔断(后端服务挂了快速失败不拖垮整条链)。
协议转换:外部用 HTTP,内部服务用 gRPC,网关做转换。
监控统计:所有 API 调用的流量、延迟、错误率在网关统一统计,不用每个服务自己埋点。
灰度发布:在网关层按比例分流(10% 流量到新版本,90% 到旧版本),做灰度上线。
对于微服务架构(很多个后端服务),API 网关几乎是标配。没有它,每个服务都要重复实现鉴权、限流、监控,且没有统一视图。
用托管数据库时,两个常见优化:
连接池:应用和数据库之间的连接是昂贵的资源(建立 TCP 连接、认证)。如果每个请求都新建连接,开销大。用连接池(维护一批常驻连接,请求复用)能大幅提升性能。多数数据库驱动和 ORM 都内置连接池,配置好就行。
读写分离:写操作走主库(保证数据一致),读操作走只读实例(分担主库压力)。因为多数应用读多写少(看商品的多、下单的少),加只读实例能显著提升读性能。托管数据库通常支持配置只读实例,且读写分离的路由可以在数据库代理层自动做。
# 概念性:读写分离的路由逻辑 class ReadWriteRouter: def get_db(self, query_type): if query_type == "write": return self.master_conn # 写走主库 else: return self._pick_replica() # 读轮询只读实例 def _pick_replica(self): # 简单轮询 或按延迟选最近的只读实例 return self.replicas[self.counter % len(self.replicas)]
从自建数据库迁到托管,或者从别的云迁过来,要注意:
数据迁移:先全量迁移历史数据,再用 CDC(变更数据捕获)同步增量。切换时短暂停服或做双写过渡。
兼容性验证:托管版本的 SQL 兼容性、字符集、排序规则要和原来一致,否则查询结果可能微妙不同。迁移前在测试环境完整跑一遍。
连接信息更新:应用连数据库的地址、端口、账号要改成托管的。建议这些配置走配置中心或环境变量,切换时改配置而非改代码。
💡 关键直觉:数据库迁移是最容易出事的操作,务必在低峰期做、务必先在测试环境演练、务必有回滚方案。见过太多团队迁移时主从不同步就切流量,导致数据丢失或不一致。宁可慢,不可错。
下一节讲应用部署的两种更高层方式——容器服务和 Serverless,以及它们的运行模型差异。
补一段常见疑问的集中回答,作为本节收尾。问:缓存一致性问题托管 Redis 能解决吗?答:不能,这是应用层问题——先更新库再删缓存(而非更新缓存)是通用起点,强一致要求高的场景绕开缓存直读主库。问:消息队列选 CKafka 还是轻量队列?答:吞吐百万级、需要回放和流式生态选 Kafka 系;只是任务解耦、日百万条以内,轻量队列(如 CMQ)运维和成本都更轻,别用牛刀杀鸡。问:API 网关和负载均衡啥区别?答:CLB 工作在四层/七层转发流量,网关理解 API 语义(路由到具体接口、按调用方限流、做鉴权),网关之下通常还有一层 CLB——两者是叠加不是替代。这三问答不上时回到正文对应段落,都是生产设计评审的高频题。