Azure Cosmos DB:全球分布式多模型数据库
Azure Cosmos DB 全球分布式多模型数据库完全入门指南
什么是 Azure Cosmos DB?
Azure Cosmos DB 是微软提供的完全托管、全球分布式、多模型数据库服务。它专为现代应用设计,允许你在全球任意数量的 Azure 区域中无缝复制数据,并提供业界领先的吞吐量、延迟、可用性和一致性保障。不同于传统的关系型数据库,Cosmos DB 支持多种数据模型(文档、键值、图、列族),你可以使用自己熟悉的 API(SQL、MongoDB、Cassandra、Gremlin、Table)进行开发。
核心理念:将数据库基础结构的管理工作全部交给 Azure,开发者只需关注数据与应用逻辑,同时获得无限弹性扩展和全球触达能力。
为什么选择 Azure Cosmos DB?
- 全球分布一键达成:只需点击按钮即可将数据复制到全球 50+ 个 Azure 区域,自动故障转移,最低延迟访问。
- 多模型灵活选择:一套数据库引擎原生支持 JSON 文档、键值对、图关系和列族数据,适配不同业务场景。
- SLA 保障的性能:任意规模都能保证 99.99% 的可用性,读写延迟在 10 毫秒以内(中位数),吞吐量按需缩放。
- 无服务器与自动扩展:无需规划容量,可按请求单元(RU/s)弹性调整或选择无服务器模式,按实际用量付费。
- 五种一致性级别:从强一致性到最终一致性,在性能与数据正确性之间精细权衡,无需牺牲可用性。
- 集成 Azure 生态:与 Azure Functions、Azure Kubernetes Service、Event Hubs、Synapse Analytics 等原生集成,构建端到端方案。
核心概念与架构
全局分布与多区域写入
Cosmos DB 的资源层级为:Azure Cosmos DB 账户 → 数据库 → 容器。一个账户可以关联多个区域,每个区域都有完整的数据副本。你可以启用多区域写入,让应用在任何区域都能同时写入数据,由 Cosmos DB 内部处理冲突解决(基于最后写入者胜出或自定义冲突解决策略)。
当创建账户时,你需要选择:
- 初始主区域
- 要启用的额外区域(多区域读取)
- 是否启用多区域写入
数据会在数分钟内复制到所有配置区域,并提供透明的自动故障转移。
多模型 API 一览
所有数据在底层以“原子记录序列”(ARS)存储,上层暴露不同 API 映射:
| API 名称 | 数据模型 | 描述 |
|---|---|---|
| Core (SQL) | 文档 | 默认 API,使用类似 SQL 的查询语法操作 JSON 文档 |
| MongoDB | 文档 | 兼容 MongoDB 协议,轻松迁移现有 MongoDB 应用 |
| Cassandra | 宽列 | 兼容 Apache Cassandra 的 CQL 查询 |
| Gremlin | 图 | 基于属性图模型,使用 Gremlin 遍历语法 |
| Table | 键值 | 兼容 Azure Table Storage,键值对模式 |
选择 API 时需在账户创建时确定,一个账户只能使用一种 API(但可以通过不同账户满足不同模型需求)。
请求单元(RU)与性能
Cosmos DB 的性能成本通过**请求单元/秒(RU/s)**来度量。一个读 1 KB 文档的点读取大约消耗 1 RU,更复杂的查询或写入根据文档大小、索引策略和一致性级别消耗更多 RU。你可以以两种方式配置吞吐量:
- 标准(预配置):手动设定 RU/s 容量,支持自动缩放,按小时计费。
- 无服务器:无需管理容量,适合间歇性或低流量工作负载,按实际请求消耗付费。
分区与水平扩展
所有数据必须存储在容器内。容器中最关键的设置是分区键。Cosmos DB 利用分区键将数据分布到底层的多个物理分区,实现无限存储和吞吐量扩展。选择分区键时需确保:
- 高基数(大量不同值,避免“热分区”)
- 读/写请求均匀分布
- 常见查询应尽量包含分区键以降低 RU 消耗
示例:如果容器存储用户订单,使用 userId 作为分区键通常是一个好选择。
动手实践:创建第一个 Cosmos DB 数据库
步骤 1:创建 Azure Cosmos DB 账户
- 登录 Azure 门户。
- 搜索并选择“Azure Cosmos DB”,点击“创建”。
- 选择 API 类型。本教程选择 Core (SQL)。
- 选择订阅、资源组,输入账户名称(全局唯一)。
- 选择位置(主区域)和容量模式(推荐无服务器用于测试)。
- 网络选项中,选择“所有网络”(开发测试)。
- 点击“审核+创建”并等待部署完成(约几分钟)。
步骤 2:添加数据库与容器
部署完成后,进入资源,点击“数据资源管理器”。选择“新建容器”:
- 数据库 ID:
ShopDB(可新建或使用已有) - 容器 ID:
Orders - 分区键:
/customerId(以斜杠开头,表示 JSON 中的 customerId 字段) - 容器吞吐量:若使用预配置模式,可选 400 RU/s(自动缩放);无服务器则无需设置
步骤 3:插入和查询数据
在数据资源管理器中,选中 Orders 容器,选择“项”。点击“新建项”并粘贴以下 JSON 文档:
{
"id": "order1",
"customerId": "cust100",
"items": [
{ "productId": "p1", "name": "Laptop", "price": 999.99 },
{ "productId": "p2", "name": "Mouse", "price": 24.99 }
],
"total": 1024.98,
"orderDate": "2025-01-15T10:30:00Z"
}
点击“保存”。再插入第二条以不同 customerId 结尾的文档以观察分区行为。
现在打开“新建 SQL 查询”,执行:
SELECT * FROM c WHERE c.customerId = 'cust100'
此查询将高效地路由到对应物理分区,消耗较少 RU。
再试试跨分区的聚合查询(消耗可能较高):
SELECT COUNT(1) FROM c
深入理解一致性级别
Cosmos DB 提供了从强到最终的五种一致性模型,让开发者可以在数据一致性和读写延迟/可用性之间取舍:
| 一致性级别 | 说明 | 适用场景 |
|---|---|---|
| 强 | 读取保证返回最新已提交的写入,性能最低但无数据歧义 | 金融交易,库存扣减 |
| 有限过时 | 读取可能滞后写入若干版本或时间间隔,可预先设定滞后上限 | 跨区域协作,社交网络 |
| 会话(默认) | 在同一客户端会话中保证单调读和写后读,跨会话可能看到过时数据 | 大多数 Web/移动应用 |
| 一致前缀 | 读取保证不会看到乱序写入,但可能落后于最新写入 | 事件流,消息队列 |
| 最终 | 无顺序保证,最终达到一致,读取延迟和可用性最高 | 用户评论、SEO 计数 |
创建账户时可选择默认一致性级别,账户下所有数据库和容器继承该设置,除非单独覆盖。对于初学者,建议保持“会话”一致性,它在绝大多数场景下提供了良好平衡。
查询文档数据(SQL API)
SQL API 使用类似 SQL 的查询语言,但专门针对 JSON 无模式数据设计。以下示例基于前述 Orders 容器。
基本查询
-- 选择所有订单
SELECT * FROM c
-- 根据 ID 点查
SELECT * FROM c WHERE c.id = 'order1'
-- 过滤与投影
SELECT c.total, c.orderDate FROM c WHERE c.total > 500
操作用户数组与子文档
当文档内包含数组时,可以使用 JOIN 展开:
-- 列出每个订单中的每个商品
SELECT o.id AS orderId, item.name, item.price
FROM c
JOIN item IN c.items
WHERE c.customerId = 'cust100'
内置函数与排序
-- 使用字符串函数
SELECT UPPER(c.id) FROM c
-- 排序
SELECT c.id, c.total FROM c ORDER BY c.total DESC
参数化查询防止注入
在生产代码中始终使用参数化查询。以 .NET SDK 为例:
var query = new QueryDefinition("SELECT * FROM c WHERE c.customerId = @custId")
.WithParameter("@custId", "cust100");
以代码操控 Cosmos DB(.NET 示例)
环境准备
使用 NuGet 安装 Microsoft.Azure.Cosmos 包。
dotnet add package Microsoft.Azure.Cosmos
连接与初始化
using Microsoft.Azure.Cosmos;
string endpoint = "https://your-account.documents.azure.com:443/";
string key = "your-primary-key";
CosmosClient client = new CosmosClient(endpoint, key);
Database database = client.GetDatabase("ShopDB");
Container container = database.GetContainer("Orders");
创建文档
dynamic order = new
{
id = "order2",
customerId = "cust200",
total = 150.75,
orderDate = DateTime.UtcNow
};
ItemResponse<dynamic> response = await container.CreateItemAsync(order, new PartitionKey("cust200"));
读取文档
ItemResponse<dynamic> readResponse = await container.ReadItemAsync<dynamic>(
"order2", new PartitionKey("cust200"));
Console.WriteLine(readResponse.Resource.total);
更新文档
dynamic existing = readResponse.Resource;
existing.total = 180.00;
await container.ReplaceItemAsync(existing, "order2", new PartitionKey("cust200"));
查询文档
var query = new QueryDefinition("SELECT * FROM c WHERE c.customerId = @custId")
.WithParameter("@custId", "cust200");
using FeedIterator<dynamic> iterator = container.GetItemQueryIterator<dynamic>(query);
while (iterator.HasMoreResults)
{
FeedResponse<dynamic> response = await iterator.ReadNextAsync();
foreach (var item in response)
{
Console.WriteLine(item);
}
}
索引策略与性能优化
默认情况下,Cosmos DB 自动为所有文档的所有属性建立索引,无需手动处理模式或索引。但对于特定场景,可以自定义索引策略以降低成本或提升写入速度。
示例:只想对 customerId 和 orderDate 建立索引,排除其他字段:
{
"indexingMode": "consistent",
"includedPaths": [
{ "path": "/customerId/?" },
{ "path": "/orderDate/?" }
],
"excludedPaths": [
{ "path": "/*" }
]
}
通过 Azure 门户或 SDK 在容器级别设置。在优化前,评估是否真正需要排除索引,因为默认索引已经非常高效。
其他性能要点:
- 使用点读取(
ReadItemAsync)代替SELECT * WHERE id = ...查询,点读取约消耗 1 RU,且延迟更低。 - 尽量让查询包含分区键,避免跨分区查询。
- 为高频查询添加必要的复合索引。
监控与成本管理
Azure Monitor 指标
在 Azure 门户的 Cosmos DB 资源中,可以查看关键指标:
- 总请求数:按状态码和区域拆分
- 请求单元消耗:平均与峰值
- 存储用量:数据和索引
- 可用性:服务可用性百分比
可通过“警报”功能设置当 RU 消耗超过阈值或出现 429 错误时自动通知。
控制 RU 成本
- 评估实际 RUs 消耗:使用 SDK 返回的
RequestCharge属性。 - 对无服务器模式,每个请求都有 RU 消耗,注意复杂查询或大文档写入的成本。
- 使用自动化缩放,设定最大 RU/s 防止意外高价。
- 定期清理陈旧数据或归档到冷存储(如 Azure Blob + Data Factory)。
常见应用场景
- 物联网遥测数据:利用 Cassandra API 或 SQL API 存储大量时序数据,按设备 ID 分区。
- 电子商务目录与购物车:SQL API 的灵活文档模型完美匹配商品结构,会话一致性保证用户看到自己的更新。
- 社交图谱:Gremlin API 构建用户关注关系和推荐路径。
- 游戏状态管理:低延迟全球分布确保各地玩家实时数据同步。
- 无服务器后端:与 Azure Functions 搭配,几乎零管理成本实现轻量 API。
最佳实践建议
- 分区键设计要深思熟虑:一次性选定后无法更改。选择读取和写入均均匀分布的字段,避免产生“热点”。常见模式:用户 ID、设备 ID、租户 ID。
- 对于重要数据开启多区域写入或多区域读取:提升灾难恢复能力和本地访问延迟。
- 始终使用 SDK 的重试和断路机制:SDK 内置处理 429(请求速率限制)的重试逻辑,无需手动实现。
- 不要在生产中频繁调用
CreateDatabaseIfNotExists或CreateContainerIfNotExists,这些管理操作消耗 RUs,应仅在初始化时调用。 - 使用最新版本的 SDK:微软持续优化性能和修复问题。
- 安全方面:使用 RBAC 和资源令牌而非主密钥分发应用权限;开启 IP 防火墙和虚拟网络服务终结点。
- 数据生命周期管理:利用生存时间(TTL)自动删除过期文档,节省存储成本。
下一步学习路径
- 官方文档:Azure Cosmos DB 文档
- 深入学习:分区与数据建模指南,多区域写入冲突解决模式。
- 动手实验:使用 Cosmos DB 与 Azure Functions 构建无服务器 API。
- 认证路径:AZ-204:为 Azure 开发解决方案,其中包含 Cosmos DB 模块。
结论
Azure Cosmos DB 不仅是一个数据库,更是面向互联网规模应用的分布式数据平台。它消除了传统数据库在全球扩展、多模型适配和高可用保障方面的复杂性。通过本教程,你已掌握创建账户、设计分区、进行查询以及利用 .NET SDK 进行开发的基本技能。现在,你可以开始构建响应速度快、全球化且始终可用的新一代云原生应用了。