- 后端
- 微服务
【免费下载链接】orleans
Cloud Native application framework for .NET
本文是 Orleans 官方配置文档(configuring-ado-dot-net-providers.md)的深度实践版,系统讲解如何用 ADO.NET 提供程序让 Orleans 的集群成员管理(Clustering)、Grain 持久化(Grain Storage)、提醒(Reminders)、Grain 目录(Grain Directory)与流式传输(Streaming)共用一套关系型数据库。读完本文,你将掌握:各能力对应的 NuGet 包与配置位置、数据库脚本的安装顺序与定制原则、SQL Server / PostgreSQL / MySQL / MariaDB / Oracle 的完整配置方法、基于DbDataSource的高级连接源注入方式,以及声明式配置与生产运维要点。
ADO.NET 提供程序与运行时能力总览
Orleans 的 ADO.NET 提供程序使用一个关系型数据库承载一种或多种运行时能力。每种能力对应独立的 NuGet 包,并可在不同端(Silo 或外部客户端)上配置:
| 能力 | 包 | 配置位置 |
|---|---|---|
| 集群(Clustering) | Microsoft.Orleans.Clustering.AdoNet | Silo 与外部客户端 |
| Grain 存储(Grain storage) | Microsoft.Orleans.Persistence.AdoNet | Silo |
| 提醒(Reminders) | Microsoft.Orleans.Reminders.AdoNet | Silo |
| Grain 目录(Grain directory) | Microsoft.Orleans.GrainDirectory.AdoNet | Silo |
| 流式传输(Streaming) | Microsoft.Orleans.Streaming.AdoNet | Silo 与外部客户端 |
安装原则:只安装应用实际用到的能力包,同时引用对应的数据库驱动包(driver package)。例如只做集群 + 持久化,就只安装 Clustering 与 Persistence 两个包,并额外引用Microsoft.Data.SqlClient等驱动。
从源码看,这些包之间的依赖是解耦的:集群能力通过 AdoNetHostingExtensions.cs 向 DI 容器注册IMembershipTable(Silo 侧)或IGatewayListProvider(客户端侧)实现;Grain 存储通过 AdoNetGrainStorageSiloBuilderExtensions.cs 提供AddAdoNetGrainStorage/AddAdoNetGrainStorageAsDefault;提醒服务通过 SiloBuilderReminderExtensions.cs 提供UseAdoNetReminderService。各能力按需注册,互不强制。
准备数据库:先运行主脚本,再运行能力脚本
每个提供程序目录旁都存放着对应的 SQL 脚本。正确的安装顺序是:先运行主脚本(Main)建立基础表与查询注册表,再运行该能力自己的脚本。以 SQL Server 上同时启用集群与持久化为例,依次执行:
src/AdoNet/Shared/SQLServer-Main.sqlsrc/AdoNet/Orleans.Clustering.AdoNet/SQLServer-Clustering.sqlsrc/AdoNet/Orleans.Persistence.AdoNet/SQLServer-Persistence.sql
其他数据库与能力的脚本对应关系如下(完整清单见 adonet-configuration.md):
| 脚本类型 | SQL Server | PostgreSQL | MySQL/MariaDB | Oracle | SQLite |
|---|---|---|---|---|---|
| 主脚本 | SQLServer-Main.sql | PostgreSQL-Main.sql | MySQL-Main.sql | Oracle-Main.sql | Sqlite-Main.sql |
| 集群 | SQLServer-Clustering.sql | PostgreSQL-Clustering.sql | MySQL-Clustering.sql | Oracle-Clustering.sql | — |
| 持久化 | SQLServer-Persistence.sql | PostgreSQL-Persistence.sql | MySQL-Persistence.sql | Oracle-Persistence.sql | Sqlite-Persistence.sql |
| 提醒 | SQLServer-Reminders.sql | PostgreSQL-Reminders.sql | MySQL-Reminders.sql | Oracle-Reminders.sql | — |
| Grain 目录 | SQLServer-GrainDirectory.sql | PostgreSQL-GrainDirectory.sql | MySQL-GrainDirectory.sql | — | — |
| 流式传输 | SQLServer-Streaming.sql | PostgreSQL-Streaming.sql | MySQL-Streaming.sql | — | — |
并非每种能力都支持每种数据库,provider 目录中是否存在对应脚本,是判断该 Orleans 版本是否支持某数据库的权威依据。例如 Grain 目录与流式传输目前没有 Oracle 脚本;SQLite 仅覆盖本地持久化场景(Sqlite-Main.sql与Sqlite-Persistence.sql)。配置前务必核实所选能力在目标数据库上有对应脚本。
[!IMPORTANT] 应使用与应用部署的 Orleans 包同一版本发布的脚本。
OrleansQuery:脚本与查询的契约机制
主脚本不只是建表。以 SQLServer-Main.sql 为例,它会创建一个OrleansQuery表(QueryKey+QueryText两列),用于注册 Orleans 运行时会用到的全部 SQL 语句;各能力脚本随后通过INSERT INTO OrleansQuery写入自己的查询定义。主脚本头部注释明确了这一契约:
- Orleans按列名和类型读取结果,按参数名和类型写入,因此脚本必须保留输入/输出的名称与类型;
- 允许针对具体厂商做部署级调优,只要不破坏接口契约;
- 各厂商脚本应尽量保留一致的约束名,便于排查问题;
- ETag 是不透明的版本列,实现类型不限(SQL Server 脚本用整数实现);
- 返回 TRUE/FALSE 的查询按“>0 为真、=0 为假”解释,异常会触发 Orleans 重试。
例如 SQLServer-Clustering.sql 创建OrleansMembershipVersionTable(以DeploymentId为主键、维护Version)与OrleansMembershipTable(记录每个 Silo 的地址、端口、代数、状态、心跳时间等),并把UpdateIAmAlivetimeKey、InsertMembershipVersionKey等查询写入OrleansQuery。运行期 provider 只通过OrleansQuery中的语句访问数据库。
生产库布局与 Schema 定制
脚本创建的是未限定名称(unqualified)的表,落在数据库用户的默认 schema 下,provider 查询也以未限定名引用这些对象。Orleans 没有提供选择 schema 或 filegroup 的配置项。如果生产库需要专用 schema、filegroup、分区或其他存储布局,必须把定制放进数据库部署流程中自行实现,并保持以下要素与 Orleans 兼容:
- 表名、列名、参数名;
OrleansQuery中存储的查询及其返回结果形状(result shape)。
脚本只是起点 schema,不是放之四海皆准的生产布局。定制后的脚本与查询,应在应用启动路径之外完成应用与验证(例如先用预发布集群验证),不要把“让 Silo 在运行时自行建表”当作常规手段,也不要给 Silo 授予 schema-owner 级别的权限。schema 变更应作为受控的部署步骤执行。
配置 SQL Server
SQL Server 使用Microsoft.Data.SqlClient驱动与Microsoft.Data.SqlClientinvariant。以下示例来自官方示例片段 HostingExamples.cs(adonet_silo与adonet_client两段),在同一 Silo 上同时启用集群、提醒与 Grain 存储:
var builder = Host.CreateApplicationBuilder(args); var connectionString = builder.Configuration.GetConnectionString("orleans") ?? throw new InvalidOperationException( "Connection string 'orleans' is required."); builder.UseOrleans(siloBuilder => { siloBuilder.UseAdoNetClustering(options => { options.Invariant = "Microsoft.Data.SqlClient"; options.ConnectionString = connectionString; }); siloBuilder.UseAdoNetReminderService(options => { options.Invariant = "Microsoft.Data.SqlClient"; options.ConnectionString = connectionString; }); siloBuilder.AddAdoNetGrainStorageAsDefault(options => { options.Invariant = "Microsoft.Data.SqlClient"; options.ConnectionString = connectionString; }); });外部客户端与 Silo 使用同一个集群数据库:
builder.UseOrleansClient(clientBuilder => { clientBuilder.UseAdoNetClustering(options => { options.Invariant = "Microsoft.Data.SqlClient"; options.ConnectionString = connectionString; }); });[!IMPORTANT]
System.Data.SqlClient不是 SQL Server 的 Orleans invariant。必须引用Microsoft.Data.SqlClient包并使用Microsoft.Data.SqlClientinvariant。
从源码看,UseAdoNetClustering在 Silo 侧注册 AdoNetClusteringTable 作为IMembershipTable实现,在客户端侧注册 AdoNetGatewayListProvider 作为IGatewayListProvider实现(见 AdoNetHostingExtensions.cs)。也就是说,客户端只读网关列表,不直接参与成员表写入。
Invariant是必填项,Orleans 用它选择数据库特有的查询与行为,而不是仅靠连接字符串自动推断。各能力 Option 类(如 AdoNetClusteringSiloOptions.cs)都包含ConnectionString、DataSource与Invariant三个核心属性,其中连接字符串与数据源属性带有[Redact]标记,日志输出时会自动脱敏。
配置其他数据库:PostgreSQL、MySQL/MariaDB 与 Oracle
PostgreSQL、MySQL/MariaDB 与 Oracle 的 Orleans 配置形状与 SQL Server 完全一致,只需同时替换三样东西:驱动包、invariant、SQL 脚本。官方对应关系如下:
| 数据库 | 驱动包 | Orleans invariant |
|---|---|---|
| SQL Server | Microsoft.Data.SqlClient | Microsoft.Data.SqlClient |
| PostgreSQL | Npgsql | Npgsql |
| MySQL/MariaDB | MySql.Data | MySql.Data.MySqlClient |
| Oracle | Oracle.ManagedDataAccess.Core | Oracle.DataAccess.Client |
此外,Orleans 还识别开源 MySQL 驱动MySqlConnector(invariant 为MySql.Data.MySqlConnector)。完整的 invariant 支持列表可以在源码 AdoNetInvariants.cs 中确认,共六项:Microsoft.Data.SqlClient、Npgsql、MySql.Data.MySqlClient、MySql.Data.MySqlConnector、Oracle.DataAccess.Client、System.Data.SQLite。
invariant 并不仅是字符串标记。从 DbConstantsStore.cs 可以看到,每个 invariant 都绑定了一组数据库常量:标识符转义字符(SQL Server 用[]、PostgreSQL 用""、MySQL 用`)、是否原生支持命令取消、是否为同步 ADO.NET 实现(MySQL 与 Oracle 标记为同步实现,执行时会被包装到线程池任务中),以及命令拦截器(Oracle 使用专门的OracleCommandInterceptor,用于改写 LIMIT 之类的语法差异)。这正是“invariant 决定数据库特定查询与行为”的底层机制。
配置 PostgreSQL 的示意:
builder.UseOrleans(siloBuilder => { siloBuilder.UseAdoNetClustering(options => { options.Invariant = "Npgsql"; options.ConnectionString = connectionString; }); });MySQL/MariaDB 只需把Invariant改为MySql.Data.MySqlClient、Oracle 改为Oracle.DataAccess.Client,并分别选用对应的脚本。
使用 DbDataSource 作为连接源
每个 ADO.NET 提供程序的 Option 类型都接受连接字符串或DbDataSource二选一。DbDataSource适合连接字符串无法表达驱动级配置的场景,例如需要定期刷新的认证令牌(token)。
配置原则与行为约束:
- 恰好配置一个连接源。Orleans 会拒绝同时提供
ConnectionString与DataSource、或两者都缺失的配置——这一点同时体现在配置验证器(AdoNetGrainStorageOptionsValidator)与运行时工厂 RelationalStorage.CreateInstance 中,两者都会抛出“必须二选一”的异常; - 即使使用数据源,仍然必须设置
Invariant,因为 Orleans 要据此选择数据库特有的查询与行为; - 将数据源注册为singleton,并通过 provider 的
OptionsBuilder配置重载解析;命名 provider 可以解析不同的keyed 数据源(keyed data source); - 生命周期归属:数据源由依赖注入容器或应用拥有并负责保持存活,Orleans 只打开与释放单个连接,不会释放数据源本身。
从 RelationalStorage.cs 的OpenConnectionAsync可以看到两种路径的分流:配置了DbDataSource时调用_dataSource.OpenConnectionAsync(...),否则通过DbConnectionFactory.CreateConnection(invariant, connectionString)手工创建连接再OpenAsync。
声明式配置(Declarative Configuration)
安装 ADO.NET 提供程序包后,会自动注册AdoNet这个声明式 provider 类型。这样便可以在配置文件(如appsettings.json)中直接声明,而无需编写代码。例如在一个应用中同时启用 AdoNet 集群、提醒与默认 Grain 存储:
{ "Orleans": { "ServiceId": "orders", "ClusterId": "orders-production", "Clustering": { "ProviderType": "AdoNet", "Invariant": "Microsoft.Data.SqlClient", "ConnectionString": "..." }, "Reminders": { "ProviderType": "AdoNet", "Invariant": "Microsoft.Data.SqlClient", "ConnectionString": "..." }, "GrainStorage": { "Default": { "ProviderType": "AdoNet", "Invariant": "Microsoft.Data.SqlClient", "ConnectionString": "..." } } } }声明式配置与代码配置最终汇聚到同一套 Option 与 provider 构建器:从 AdoNetClusteringProviderBuilder.cs 与 AdoNetGrainStorageProviderBuilder.cs 的源码结构看,它们正是声明式配置(ProviderType: AdoNet)到UseAdoNetClustering/AddAdoNetGrainStorage的桥梁。
[!IMPORTANT] 连接字符串属于机密信息,应存放在密钥提供程序(secret provider)或部署环境变量中,而不是提交到版本库的配置文件里。
生产运维指导
- 保持
ClusterOptions.ServiceId稳定:Orleans 依据它读取应用所属的行(成员表、存储表按DeploymentId隔离)。变更 ServiceId 会使其读取不到预期数据。 - 连接池规模:按“Silo 进程数 + 客户端进程数”的总量规划数据库连接池大小,避免连接池耗尽。
- 安全基线:启用连接加密(如 SQL Server 的
Encrypt=True),使用最小权限的数据库身份;能使用托管身份(managed identity)的场景优先使用托管身份。 - 监控指标:持续监控数据库延迟、限流(throttling)、死锁与连接池耗尽。
- 故障演练:在负载下测试数据库故障转移与滚动部署行为。
- 备份策略:Grain 状态备份必须遵循应用的恢复目标(RPO/RTO);成员表(membership)行是瞬态数据,不能替代状态备份。
- schema 升级:从旧版本升级时,检查并应用各 provider
Migrations目录下的升级脚本(当前仓库中可见的如 SQLServer-Clustering-3.7.0.sql、PostgreSQL-Persistence-3.6.0.sql、PostgreSQL-Reminders-3.6.0.sql 等)。升级流程建议为:按恢复策略备份数据 → 新库先跑主脚本 → 再跑各能力脚本 → 旧 schema 升级时依次审查并执行Migrations下的脚本 → 用同驱动、同数据库引擎版本的预发布集群验证。
关于 Azure SQL 的托管身份
如果连接的是 Azure SQL,Microsoft 建议使用**托管身份(managed identities for Azure resources)**作为认证方式——它是当前最安全的认证流程之一(详见 managed-identities.md 中的官方说明)。配合上文介绍的DbDataSource方案,可以在数据源层完成基于托管身份/令牌的认证配置,从而避免在连接字符串中存放静态凭据。
延伸阅读与源码导航
- 官方配套参考文档:ADO.NET database configuration(脚本与 invariant 总表)
- 官方代码示例片段:HostingExamples.cs(
adonet_silo/adonet_client/named_providers) - 共享存储层(invariant 常量、连接工厂、查询执行器、数据库常量表):src/AdoNet/Shared
- 各能力源码目录:集群 src/AdoNet/Orleans.Clustering.AdoNet、持久化 src/AdoNet/Orleans.Persistence.AdoNet、提醒 src/AdoNet/Orleans.Reminders.AdoNet、Grain 目录 src/AdoNet/Orleans.GrainDirectory.AdoNet、流式传输 src/AdoNet/Orleans.Streaming.AdoNet
- 后端
- 微服务
【免费下载链接】orleans
Cloud Native application framework for .NET
相关推荐
Orleans Google Cloud Firestore 提供程序配置指南:集群、目录、持久化与提醒服务
Orleans Google Cloud Firestore 提供程序配置指南:集群、目录、持久化与提醒服务 本指南讲解如何在 Orleans 中使用 Goog
后端微服务Orleans 关系数据库(ADO.NET)Grain 持久化实战指南:SQL Server/MySQL/PostgreSQL/Oracle/SQLite 配置与原理
Orleans 关系数据库(ADO.NET)Grain 持久化实战指南:SQL Server/MySQL/PostgreSQL/Oracle/SQLite 配置
后端微服务Orleans Grain 持久化深度指南:IPersistentState、存储提供程序与状态演化
Orleans Grain 持久化深度指南:IPersistentState、存储提供程序与状态演化 Grain 持久化(grain persistence)是
后端微服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考