ORMX分布式数据库 - 开发日志,ORMX 分布式,分片策略,读写分离,分布式事务 - ORMX 分布式数据库功能,学习分片策略、读写分离和分布式事务。

您当前正在浏览的是本站SEO版网页

请点击确认

马上提升浏览体验

ORMX分布式数据库

编程 数据库 阅读:0
2/8/2026 9:16:44 PM

ORMX 分布式数据库功能,学习分片策略、读写分离和分布式事务。 关键字:ORMX 分布式,分片策略,读写分离,分布式事务

分布式数据库

什么是分布式数据库

分布式数据库是指将数据分散存储在多个物理节点上的数据库系统。通过数据分片(Sharding)和读写分离(Read-Write Separation)等技术,分布式数据库能够提供更好的性能、可扩展性和可用性。

社会主流观点

随着数据量的爆炸式增长,单体数据库已经难以满足现代应用的需求。主流观点认为,分布式数据库是解决大数据量、高并发访问的有效方案。然而,传统分布式数据库的复杂性往往让开发者望而却步。

核心观点

ORMX 的分布式功能旨在降低分布式数据库的使用门槛,通过简洁的 API 设计和智能的路由策略,让开发者能够轻松实现数据分片和读写分离,而无需深入了解底层实现细节。ORMX 在保持高性能的同时,提供了完善的故障转移和分布式事务支持,使分布式数据库的构建变得前所未有的简单。

ORMX 分布式功能概述

ORMX 提供了完整的分布式数据库解决方案,包括以下核心功能:

基本用法

ORMX 的分布式功能通过 DistributedDbProvider 类提供,使用简单直观的 API。

核心特点:

  • 直接通过构造函数创建分布式提供者
  • 支持自定义分片键属性
  • 提供 GetTable<T>() 方法获取分布式表操作对象
  • 需要引用 JCode.ORMX.Distributed.Core.Providers 命名空间

示例:

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Sharding;

// 创建分片数据库列表
var shards = new List<IDbProvider>();

// 创建分片策略
var strategy = new HashShardStrategy();

// 创建分布式提供者(指定分片键属性)
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: strategy,
    shardKeyProperty: "Username"  // 使用 Username 属性作为分片键
);

// 获取分布式表对象
var distributedTable = distributedProvider.GetTable<User>();

重要提示:

  • 分片键属性可以是实体的任意属性,默认为 "Id"
  • GetTable<T>() 方法返回分布式表操作对象
  • 所有示例代码都已包含必要的 using 语句

数据分片(Sharding)

将数据按照一定规则分散到多个数据库节点,提高数据存储容量和查询性能。

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Sharding;
using System.Collections.Generic;

// 创建分片数据库列表
var shards = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=shard1.db"),
    new SqliteDatabaseProvider("Data Source=shard2.db"),
    new SqliteDatabaseProvider("Data Source=shard3.db")
};

// 创建哈希分片策略
var strategy = new HashShardStrategy();

// 创建分布式提供者(指定分片键属性)
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: strategy,
    shardKeyProperty: "UserId"  // 使用 UserId 属性作为分片键
);

// 获取分布式表对象
var userTable = distributedProvider.GetTable<User>();

读写分离(Read-Write Separation)

将读操作路由到从库,写操作路由到主库,提高系统并发能力。

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Router;
using JCode.ORMX.Distributed.Core.Sharding;

// 创建分片数据库列表(用于写操作)
var shards = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=shard1.db"),
    new SqliteDatabaseProvider("Data Source=shard2.db"),
    new SqliteDatabaseProvider("Data Source=shard3.db")
};

// 创建从库列表(用于读操作)
var slaveDbs = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=slave1.db"),
    new SqliteDatabaseProvider("Data Source=slave2.db")
};

// 创建读写路由器
var readWriteRouter = new ReadWriteRouter(
    master: shards.First(),  // 主库使用第一个分片
    slaves: slaveDbs
);

// 创建分布式提供者(带读写分离)
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: new HashShardStrategy(),
    readWriteRouter: readWriteRouter,
    shardKeyProperty: "UserId"
);

分布式事务(Distributed Transaction)

支持跨多个分片的事务操作,确保数据一致性。

using var transaction = distributedProvider.BeginDistributedTransaction();
transaction.Begin(IsolationLevel.ReadCommitted);

try
{
    // 执行跨分片操作
    userTable.Insert(user1);  // 分片 1
    userTable.Insert(user2);  // 分片 2
    
    transaction.Commit();
}
catch (Exception ex)
{
    transaction.Rollback();
}

分片策略

ORMX 提供了多种分片策略,满足不同的业务场景需求。

哈希分片(Hash Sharding)

根据分片键的哈希值将数据均匀分布到各个分片。

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Sharding;

// 创建分片数据库列表
var shards = new List<IDbProvider>();

// 创建哈希分片策略
var strategy = new HashShardStrategy();

// 创建分布式提供者
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: strategy,
    shardKeyProperty: "UserId"
);

适用场景:

  • 数据分布均匀
  • 查询主要基于分片键
  • 需要快速定位数据

优点:

  • 数据分布均匀
  • 查询性能稳定
  • 扩展简单

范围分片(Range Sharding)

根据分片键的范围将数据分配到不同的分片。

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Sharding;

// 创建分片数据库列表
var shards = new List<IDbProvider>();

// 创建范围分片策略
var strategy = new RangeShardStrategy();

// 创建分布式提供者
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: strategy,
    shardKeyProperty: "CreatedAt"
);

适用场景:

  • 数据有时间或数值范围特征
  • 经常需要范围查询
  • 数据访问有明显的局部性

优点:

  • 范围查询效率高
  • 数据迁移方便
  • 易于理解和管理

一致性哈希分片(Consistent Hash Sharding)

使用一致性哈希算法,减少分片变化时的数据迁移量。

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Sharding;

// 创建分片数据库列表
var shards = new List<IDbProvider>();

// 创建一致性哈希分片策略(指定虚拟节点数)
var strategy = new ConsistentHashShardStrategy(virtualNodes: 150);

// 创建分布式提供者
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: strategy,
    shardKeyProperty: "UserId"
);

适用场景:

  • 分片数量频繁变化
  • 需要最小化数据迁移
  • 对数据可用性要求高

优点:

  • 分片变化时数据迁移量小
  • 负载均衡效果好
  • 系统稳定性高

自定义分片策略

通过实现 IShardStrategy 接口,可以创建自定义的分片策略。

using JCode.ORMX.Distributed.Core.Sharding;

public class CustomShardStrategy : IShardStrategy
{
    private readonly Func<object, int> _shardSelector;
    
    public CustomShardStrategy(Func<object, int> shardSelector)
    {
        _shardSelector = shardSelector;
    }
    
    public int GetShardIndex(object shardKey, int shardCount)
    {
        return _shardSelector(shardKey) % shardCount;
    }
}

// 使用自定义分片策略
var strategy = new CustomShardStrategy(key => 
{
    // 自定义分片逻辑
    return key.GetHashCode();
});

var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: strategy,
    shardKeyProperty: "UserId"
);

读写分离

读写分离是提高数据库并发能力的重要手段,ORMX 提供了简单易用的读写分离功能。

架构说明

ORMX 的读写分离采用以下架构:

分片列表(shards):
  - Shard1.db  ← 存储 userId % 3 == 0 的数据(写操作)
  - Shard2.db  ← 存储 userId % 3 == 1 的数据(写操作)
  - Shard3.db  ← 存储 userId % 3 == 2 的数据(写操作)

从库列表(slaveDbs):
  - Slave1.db   ← 用于读操作(负载均衡)
  - Slave2.db   ← 用于读操作(负载均衡)
  - Slave3.db   ← 用于读操作(负载均衡)

工作原理:

  • 写操作:根据分片键路由到 shards 中的对应分片
  • 读操作:如果启用了读写分离,使用 slaveDbs 中的从库(轮询负载均衡);否则使用 shards 中的分片
  • 数据同步:需要外部机制将 shards 中的数据同步到 slaveDbs

重要说明:主从复制 vs 读写分离

ORMX 负责的是读写分离(路由决策),而不是主从复制(数据同步)!

  • 主从复制(Data Replication):这是数据库层面的功能,由数据库自己实现(如 MySQL 的 binlog 复制、PostgreSQL 的流复制)。ORMX 不负责数据同步。
  • 读写分离(Read-Write Splitting):这是应用层面的功能,ORMX 的 ReadWriteRouter 负责智能地选择使用主库还是从库。

工作流程:

应用层 (ORMX)
  ├─ 写操作 → GetMaster() → 主库
  └─ 读操作 → GetSlave()  → 从库
                     ↓
数据库层 (MySQL/PostgreSQL)
  └─ 主库 --binlog/流复制--> 从库 (自动同步)

生产环境配置:

  • 使用 MySQL/PostgreSQL 等支持主从复制的数据库
  • 在数据库层面配置主从复制(binlog、relay-log 等)
  • ORMX 自动利用数据库的主从架构进行读写分离

测试环境说明:

  • SQLite 不支持主从复制,所以测试中需要手动同步数据
  • 实际生产环境中,数据同步由数据库自动完成,无需手动处理

基本配置

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Router;
using JCode.ORMX.Distributed.Core.Sharding;

// 创建分片数据库列表(用于写操作)
var shards = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=shard1.db"),
    new SqliteDatabaseProvider("Data Source=shard2.db"),
    new SqliteDatabaseProvider("Data Source=shard3.db")
};

// 创建从库列表(用于读操作)
var slaveDbs = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=slave1.db"),
    new SqliteDatabaseProvider("Data Source=slave2.db"),
    new SqliteDatabaseProvider("Data Source=slave3.db")
};

// 创建读写路由器
var readWriteRouter = new ReadWriteRouter(
    master: shards.First(),  // 主库使用第一个分片
    slaves: slaveDbs
);

// 创建分布式提供者(带读写分离)
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: new HashShardStrategy(),
    readWriteRouter: readWriteRouter,
    shardKeyProperty: "UserId"
);

重要说明:

  • shards 参数是分片列表,用于数据分片和写操作
  • readWriteRouter 参数提供读写分离功能
  • slaveDbs 参数是从库列表,用于读操作
  • 需要外部机制将 shards 中的数据同步到 slaveDbs

读写路由

ORMX 会自动将写操作路由到主库,读操作路由到从库。

var userTable = distributedProvider.GetTable<User>();

// 写操作 - 自动路由到主库
userTable.Insert(new User { Name = "张三", Email = "zhangsan@example.com" });

// 读操作 - 自动路由到从库
var users = userTable.Where(u => u.Age > 25).GetList();

自定义读写路由

通过实现 IReadWriteRouter 接口,可以自定义读写路由策略。

public class CustomReadWriteRouter : IReadWriteRouter
{
    private readonly IDbProvider _master;
    private readonly List<IDbProvider> _slaves;
    private int _slaveIndex;
    
    public CustomReadWriteRouter(IDbProvider master, IEnumerable<IDbProvider> slaves, bool readWriteSeparationEnabled = true)
    {
        _master = master ?? throw new ArgumentNullException(nameof(master));
        _slaves = slaves?.ToList() ?? new List<IDbProvider>();
        _slaveIndex = 0;
    }
    
    public IDbProvider GetMaster()
    {
        return _master;
    }
    
    public IDbProvider GetSlave()
    {
        if (_slaves.Count == 0)
        {
            return _master;
        }

        // 自定义从库选择策略(例如:加权轮询)
        _slaveIndex = (_slaveIndex + 1) % _slaves.Count;
        return _slaves[_slaveIndex];
    }

    public IEnumerable<IDbProvider> GetAllSlaves()
    {
        return _slaves;
    }

    public bool IsReadWriteSeparationEnabled => _slaves.Count > 0;
}

读写分离的最佳实践

1. 理解 ORM 与数据库的职责分工

核心概念:

  • ORMX(应用层):负责读写分离,即决定哪个操作使用哪个数据库连接(路由决策)
  • 数据库(数据库层):负责主从复制,即保证主库和从库的数据一致性(数据同步)

ORMX 不做什么:

  • ❌ 不负责将数据从主库同步到从库
  • ❌ 不监控数据库的主从复制状态
  • ❌ 不处理数据库层面的复制延迟

ORMX 做什么:

  • ✅ 智能路由:写操作→主库,读操作→从库
  • ✅ 负载均衡:轮询选择从库
  • ✅ 故障转移:从库不可用时自动切换到主库

2. 数据同步

使用数据库的主从复制机制(不是 ORMX 的功能):

-- MySQL 主从复制配置示例
-- 主库配置
server-id = 1
log-bin = mysql-bin
binlog-format = ROW

-- 从库配置
server-id = 2
relay-log = mysql-relay-bin
read-only = 1

3. 从库数量

根据读操作负载调整从库数量:

// 合理配置从库数量
var slaveCount = Math.Max(2, Environment.ProcessorCount / 2);

var slaveDbs = new List<IDbProvider>();
for (int i = 0; i < slaveCount; i++)
{
    slaveDbs.Add(new SqliteDatabaseProvider(<div class="latex">$"Data Source=slave{i}.db"));
}

4. 故障处理

当从库不可用时,系统会自动回退到主库:

// ORMX 会自动处理从库故障
// 如果从库不可用,读操作会自动使用主库
var users = userTable.Where(u => u.Age > 25).GetList();

分布式事务

分布式事务确保跨多个分片的操作能够原子性地执行,保证数据一致性。

基本用法

using var transaction = distributedProvider.BeginDistributedTransaction();
transaction.Begin(IsolationLevel.ReadCommitted);

try
{
    var userTable = distributedProvider.GetTable<User>();
    var orderTable = distributedProvider.GetTable<Order>();
    
    // 执行跨分片操作
    userTable.Insert(new User { Name = "张三", Email = "zhangsan@example.com" });
    orderTable.Insert(new Order { UserId = 1, Amount = 100 });
    
    transaction.Commit();
    Console.WriteLine("事务提交成功");
}
catch (Exception ex)
{
    transaction.Rollback();
    Console.WriteLine($</div>"事务回滚:{ex.Message}");
}

事务监控

var transactionMonitor = new TransactionMonitor();
var distributedProvider = new DistributedDbProvider(
    shards,
    strategy,
    transactionMonitor: transactionMonitor
);

// 订阅事务事件
transactionMonitor.TransactionEventOccurred += (sender, e) =>
{
    Console.WriteLine(<div class="latex">$"事务事件:{e.EventType}");
    Console.WriteLine($</div>"事务 ID: {e.TransactionId}");
    Console.WriteLine(<div class="latex">$"新状态:{e.NewStatus}");
    if (e.Error != null)
    {
        Console.WriteLine($</div>"错误:{e.Error.Message}");
    }
};

事务状态查询

// 获取所有事务信息
var transactions = transactionMonitor.GetAllTransactions();

foreach (var transaction in transactions)
{
    Console.WriteLine(<div class="latex">$"事务 ID: {transaction.Key}");
    Console.WriteLine($</div>"状态:{transaction.Value.Status}");
    Console.WriteLine(<div class="latex">$"开始时间:{transaction.Value.StartTime}");
    Console.WriteLine($</div>"执行时长:{transaction.Value.Duration}");
    Console.WriteLine(<div class="latex">$"事件数量:{transaction.Value.Events?.Count}");
}

超时事务处理

// 设置事务超时时间
var timeoutThreshold = TimeSpan.FromMinutes(5);

// 检查超时事务
transactionMonitor.CheckTimeoutTransactions(timeoutThreshold);

完整示例

下面是一个完整的分布式数据库使用示例:

using JCode.ORMX.DbProvider;
using JCode.ORMX.Distributed.Core.Providers;
using JCode.ORMX.Distributed.Core.Router;
using JCode.ORMX.Distributed.Core.Sharding;
using JCode.ORMX.Attributes;

// 定义实体类
[Table(Name = "Users")]
public class User
{
    [Column(IsPrimaryKey = true, IsAutoIncrement = true)]
    public int Id { get; set; }
    
    public string Username { get; set; }
    
    public string Email { get; set; }
    
    public int Age { get; set; }
}

// 创建分片数据库(用于写操作)
var shards = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=shard1.db"),
    new SqliteDatabaseProvider("Data Source=shard2.db"),
    new SqliteDatabaseProvider("Data Source=shard3.db")
};

// 创建从库(用于读操作)
var slaveDbs = new List<IDbProvider>
{
    new SqliteDatabaseProvider("Data Source=slave1.db"),
    new SqliteDatabaseProvider("Data Source=slave2.db")
};

// 创建读写路由器
var readWriteRouter = new ReadWriteRouter(
    master: shards.First(),
    slaves: slaveDbs
);

// 创建分布式提供者(使用 Username 作为分片键)
var distributedProvider = new DistributedDbProvider(
    shards: shards,
    shardStrategy: new HashShardStrategy(),
    readWriteRouter: readWriteRouter,
    shardKeyProperty: "Username"
);

// 获取表对象
var userTable = distributedProvider.GetTable<User>();

// 在每个分片上创建表
foreach (var shard in shards)
{
    var tableManager = shard.GetTableManager();
    tableManager.Create(typeof(User));
}

// 插入数据(自动路由到对应分片)
for (int i = 1; i <= 100; i++)
{
    userTable.Insert(new User 
    { 
        Username = $</div>"用户{i}", 
        Email = <div class="latex">$"user{i}@example.com",
        Age = 20 + (i % 30)
    });
}

// 查询数据
var users = userTable.GetList(u => u.Age > 25);
Console.WriteLine($</div>"查询到 {users.Count()} 个用户");

// 分布式事务示例
using var transaction = distributedProvider.BeginDistributedTransaction();
transaction.Begin(IsolationLevel.ReadCommitted);

try
{
    // 执行跨分片操作
    userTable.Insert(new User { Username = "新用户", Email = "new@example.com", Age = 30 });
    transaction.Commit();
}
catch (Exception ex)
{
    transaction.Rollback();
}

总结

ORMX 的分布式数据库功能提供了:

  • 简单易用:直观的 API,无需深入了解分布式系统的复杂性
  • 灵活扩展:支持多种分片策略和自定义策略
  • 高性能:通过数据分片和读写分离提升系统性能
  • 数据一致性:完善的分布式事务支持
  • 生产就绪:故障转移、负载均衡等企业级特性

通过 ORMX,你可以轻松构建可扩展的分布式数据库应用,而无需被底层实现细节所困扰。