XiHan Framework 处于预览阶段

查看获取方式
跳转到内容

XiHan.Framework.MultiTenancy.InMemory ​

多租户的默认实现:启动时从配置装载租户,存在进程内存里,有容量上限,运行时可增删。它提供 multitenancy.context@1 与 multitenancy.sharding@1,适用于租户数量少、随配置发布的应用,以及开发与测试。

项内容
包 IDXiHan.Framework.MultiTenancy.InMemory
环层Ring 3(实现)
能力提供 multitenancy.context@1、multitenancy.sharding@1;依赖 kernel.hosting@1
特性入口InMemoryMultiTenancyFeature(清单 xihan.multitenancy.inmemory,role: default)
配置节XiHan:MultiTenancy(含 Tenants 与 InMemory 子节)
依赖XiHan.Framework.MultiTenancy.Abstractions
AOT兼容
稳定性Preview

概述 ​

InMemoryTenantStore 是一张按租户 ID 索引的并发字典,读取无锁,新增与替换在同一把锁里先查容量再写入,并发新增不会越过上限。特性在 Configure 里只为被选中的能力注册:

  • 总是注册 MultiTenancyOptions(从配置读取)与作用域服务 TenantShardScope(与是否选中分片无关)。
  • 租户上下文能力被选中时:InMemoryMultiTenancyOptions、InMemoryTenantStore 与 ITenantStore;解析器 ClaimTenantResolver → BaggageTenantResolver,注册顺序即解析顺序;Tenant 阶段的 TenantResolutionMiddleware;健康项 multitenancy.inmemory.capacity,由存储自己同步计算。
  • 分片能力被选中时的 TenantStoreShardResolver。

清单角色是 default:装配一个显式的多租户 Provider(如 MultiTenancy.Database)后本包被顶替,不装配、不启动。应用自带的 Provider 只提供 multitenancy.context@1 时,本包只提供分片:存储、解析器、健康项与 Tenant 阶段中间件都由应用的 Provider 注册(它可以复用抽象包的 TenantResolutionMiddleware),分片从它的 ITenantStore 推出。

何时使用 ​

  • 租户随配置发布、数量在千级以内,或开发、演示、自动化测试:用本包。
  • 租户由管理后台在运行时增删、多实例共享同一份目录:用 MultiTenancy.Database。

安装与启用 ​

bash
dotnet add package XiHan.Framework.MultiTenancy.InMemory --prerelease

当前是预览版,安装要带 --prerelease;从源码或本地包源引用见快速上手。Profiles.Standard 与 Profiles.Full 已包含本包;单独装配时:

csharp
using XiHan.Framework.Hosting.AspNetCore;
using XiHan.Framework.MultiTenancy.InMemory;

var builder = WebApplication.CreateBuilder(args);
builder.AddXiHan(xihan => xihan.UseFeature<InMemoryMultiTenancyFeature>());

var app = builder.Build();
app.UseXiHan();
app.Run();

配置 ​

键类型缺省说明
XiHan:MultiTenancy:Tenants:<id>:DisplayNamestring无显示名;节名 <id> 就是租户 ID,按租户 ID 文法校验
XiHan:MultiTenancy:Tenants:<id>:IsEnabledbooltrue是否启用;只接受 true / false
XiHan:MultiTenancy:Tenants:<id>:Properties:<key>string无租户属性,分片键见下表
XiHan:MultiTenancy:InMemory:MaxTenantsint1000租户上限,正整数

DefaultTenant、RequireTenant、ValidateAgainstStore、TenantClaim 四个解析选项也在 XiHan:MultiTenancy 下,见 MultiTenancy.Abstractions。

json
{
  "XiHan": {
    "MultiTenancy": {
      "RequireTenant": false,
      "InMemory": { "MaxTenants": 1000 },
      "Tenants": {
        "acme": {
          "DisplayName": "Acme Corp",
          "Properties": {
            "ConnectionString": "Host=localhost;Database=acme",
            "DatabaseProvider": "postgresql"
          }
        },
        "beta": { "DisplayName": "Beta" },
        "globex": { "DisplayName": "Globex", "IsEnabled": false }
      }
    }
  }
}

分片能力被选中时,TenantStoreShardResolver 从租户属性推出分片:

属性键含义
ConnectionString有值即该租户分库
DatabaseProvider数据库提供者名,可选,转成小写
Shard.<key>去掉前缀后作为 <key> 透传给持久化 Provider

上例里 acme 分库,beta 与 globex 共库。

主要类型 ​

类型说明
InMemoryMultiTenancyFeature特性入口;HealthName = multitenancy.inmemory.capacity
InMemoryMultiTenancyOptionsMaxTenants(缺省 1000)、Tenants(启动时装载的租户);FromConfiguration 读取上面的配置
InMemoryTenantStoreITenantStore 与健康项贡献者:Set(tenant) 新增或替换、Remove(tenantId) 删除、Capacity、Count

使用示例 ​

运行时增删租户。Set 与 Remove 不会自动失效分片缓存,改了租户连接后要调用 ITenantShardResolver.Invalidate:

csharp
using XiHan.Framework.MultiTenancy.Abstractions.Sharding;
using XiHan.Framework.MultiTenancy.Abstractions.Tenants;
using XiHan.Framework.MultiTenancy.InMemory;
using XiHan.Framework.Primitives;

public sealed class TenantAdministration(InMemoryTenantStore store, ITenantShardResolver shards)
{
    public Result MoveToOwnDatabase(string tenantId, string connectionString)
    {
        var updated = store.Set(new TenantInfo
        {
            Id = tenantId,
            Properties = new Dictionary<string, string>(StringComparer.Ordinal) { [TenantShardKeys.ConnectionString] = connectionString },
        });

        // 解析器缓存了旧结果(包括"无分片"),不失效就继续落旧库
        if (updated.IsSuccess)
        {
            shards.Invalidate(tenantId);
        }

        return updated;
    }
}

ITenantShardResolver 只在分片能力被选中时注册。本包同时提供两个能力,单独装配本包时两者都由它提供。

行为与限制 ​

  • 容量:新增超过 MaxTenants 时 Set 返回 MULTITENANCY_UNAVAILABLE_001;替换已有租户不占新容量。配置里的租户超过上限时,构造存储即抛出 FrameworkException。
  • 健康项 multitenancy.inmemory.capacity:租户数达到上限即 Degraded(原因 MULTITENANCY_UNAVAILABLE_001),否则 Ready。
  • ID 区分大小写;ListAsync 按 ID 序数排序返回全部租户。
  • 数据只在进程内存里:多实例部署时各实例各有一份,运行时的增删不会同步到其他实例,重启后恢复为配置内容。
  • 分片缓存容量由 XiHan:MultiTenancy:ShardCacheSize 决定,缺省 10000,必须是正整数。

相关 ​

Released under The MIT License