ShardingCore 如何呈现“完美”分表
這篇文章是我針對efcore的分表的簡單介紹,如果您有以下需求那么可以自己選擇是否使用本框架,本框架將一直持續更新下去,并且免費開源為.net生態做貢獻,如果您覺得不錯那么請幫忙點個star謝謝,框架地址[`sharding-core`](https://github.com/xuejmnet/sharding-core) 您的支持是對我最大的動力。
如果您對分表有以下痛點那么不妨試試我這邊開源的框架sharding-core?,是否需要無感知使用分表組件,是否需要支持abp,是否需要支持自定義分表規則,是否需要支持自定義分表鍵,是否需要支持特定的efcore版本,是否希望框架不帶任何三方框架干凈,是否需要支持讀寫分離,是否需要動態添加表,是否需要支持join,group等操作,是否需要支持追蹤特性,是否想在不修改原先代碼的基礎上擴展分表功能,如果一起上幾個條件任意組合且你在市面上沒辦法找到可替代的框架可以試試本框架。如何使用代碼具體可以參考github 將代碼下載下來如果本地裝了sqlserver直接運行單元測試或者Sample.SqlServer程序會自動在本地新建數據庫新建數據庫表結構,目前初始化數據為用戶信息和用戶對應的月薪信息表,用戶表以用戶id取模,用戶月薪表以月份分表。
首先需要了解本框架的一個版本號不然將對您的使用產生一定的分歧,目前框架分為3個版本分別是2.x,3.x,5.x3個版本,分別對應efcore 2.x efcore 3.x efcore 5.x,有人要問為什么不支持6.x呢(小弟剛剛在上周完成對本框架的開發重構,目前還未對efcore 6.x進行著手不過將在不遠的將來即將支持(目測1-2個星期內))。
目前efcore生態下有著許許多多的分表、分庫的解決方案,但是目前來講都有其不足點,比如需要手動設置分表后綴、需要大量替換現有代碼、不支持事務等等一系列問題,所以在這個大前提下我之前開源了sharding-core?分表組件,這個分表組件是目前來說個人認為比較“完美”的分表組件,這個分表組件目前是參考了sharding-jdbc來實現的,但是比sharding-jdbc更加強大(因為C#的表達式)。首先我們來看下目前市面上有的分表組件的缺點我們來針對其缺點進行痛點解決。
efcore支持情況
| 2.x | 支持 |
| 3.x | 支持 |
| 5.x | 支持 |
| 6.x | 即將支持 |
數據庫支持情況
| SqlServer | 支持 |
| MySql | 支持 |
| PostgreSql | 支持 |
| SQLite | 支持 |
| Oracle | 支持 |
| 其他 | 支持(只要efcore支持) |
理論上只要是efcore對應版本支持的數據庫,sharding-core都將支持。
如何開始使用
1.創建一個數據庫對象繼承IShardingTable并且在對應的分表字段上進行[ShardingTableKey]特性的標注
/// <summary>/// 用戶表/// </summary>public class SysUserMod : IShardingTable{/// <summary>/// 用戶Id用于分表/// </summary>[ShardingTableKey(TailPrefix = "_")]public string Id { get; set; }/// <summary>/// 用戶名稱/// </summary>public string Name { get; set; }/// <summary>/// 用戶姓名/// </summary>public int Age { get; set; }}2.創建對應的實體表對應配置 推薦?fluent api
public class SysTestMap:IEntityTypeConfiguration<SysTest>{public void Configure(EntityTypeBuilder<SysTest> builder){builder.HasKey(o => o.Id);builder.Property(o => o.Id).IsRequired().HasMaxLength(128);builder.Property(o => o.UserId).IsRequired().HasMaxLength(128);builder.ToTable(nameof(SysTest));}}3.創建對應的分表規則 取模分表,參數2代表后綴2位就是00-99最多100張表,3表示模3== key.hashcode() %3
public class SysUserModVirtualTableRoute : AbstractSimpleShardingModKeyStringVirtualTableRoute<SysUserMod>{public SysUserModVirtualTableRoute() : base(2,3){}}4創建對應執行的dbcontext 這一步除了繼承IShardingTableDbContext外其他和普通dbcontext一樣
public class DefaultTableDbContext: DbContext,IShardingTableDbContext{public DefaultTableDbContext(DbContextOptions<DefaultTableDbContext> options) :base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfiguration(new SysUserModMap());}public IRouteTail RouteTail { get; set; }}5.添加分表dbcontext
public class DefaultShardingDbContext:AbstractShardingDbContext<DefaultTableDbContext>{public DefaultShardingDbContext(DbContextOptions<DefaultShardingDbContext> options) : base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){base.OnModelCreating(modelBuilder);modelBuilder.ApplyConfiguration(new SysUserModMap());}public override Type ShardingDbContextType => this.GetType();}6.添加配置
public void ConfigureServices(IServiceCollection services){services.AddControllers();//原先的dbcontext可以用也可以不用如果原先的dbcontext還在用就繼續//services.AddDbContext<DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx3;Integrated Security=True"));services.AddShardingDbContext<DefaultShardingDbContext, DefaultTableDbContext>(o => o.UseSqlServer("Data Source=localhost;Initial Catalog=ShardingCoreDBxx2;Integrated Security=True;"), op =>{op.EnsureCreatedWithOutShardingTable = true;op.CreateShardingTableOnStart = true;op.UseShardingOptionsBuilder((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger),//使用dbconnection創建dbcontext支持事務(conStr,builder) => builder.UseSqlServer(conStr).UseLoggerFactory(efLogger));//使用鏈接字符串創建dbcontextop.AddShardingTableRoute<SysUserModVirtualTableRoute>();});}public void Configure(IApplicationBuilder app, IWebHostEnvironment env){...//添加啟動項app.UseShardingCore();...}public static class ShardingCoreExtension{public static IApplicationBuilder UseShardingCore(this IApplicationBuilder app){var shardingBootstrapper = app.ApplicationServices.GetRequiredService<IShardingBootstrapper>();shardingBootstrapper.Start();return app;}}7.控制器使用
private readonly DefaultShardingDbContext _defaultTableDbContext;public ValuesController(DefaultShardingDbContext defaultTableDbContext){_defaultTableDbContext = defaultTableDbContext;}[HttpGet]public async Task<IActionResult> Get(){var resultx11231 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Age == 198198).Select(o=>o.Id).ContainsAsync("1981");var resultx1121 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").SumAsync(o=>o.Age);var resultx111 = await _defaultTableDbContext.Set<SysUserMod>().FirstOrDefaultAsync(o => o.Id == "198");var resultx2 = await _defaultTableDbContext.Set<SysUserMod>().CountAsync(o => o.Age<=10);var resultx = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").FirstOrDefaultAsync();var resultx33 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").Select(o=>o.Id).FirstOrDefaultAsync();var resulxxt = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Id == "198").ToListAsync();var result = await _defaultTableDbContext.Set<SysUserMod>().ToListAsync();var sysUserMod98 = result.FirstOrDefault(o => o.Id == "98");_defaultTableDbContext.Attach(sysUserMod98);sysUserMod98.Name = "name_update"+new Random().Next(1,99)+"_98";await _defaultTableDbContext.SaveChangesAsync();return Ok(result);}自定義分表鍵,自定義分表規則
目前市面上有的框架要么對分表字段有限制比如僅支持DateTime類型或者int等,要么對分表規則有限制:僅支持按天、按月、取模...等等,但是基于分表規則和分表字段是業務規則所以本框架遵循將其由業務系統自己定義,最大化來實現分表庫的適用性,基本上滿足一切分表規則,且sharding-core目前默認提供一些常用的分表規則可以快速集成。
默認路由
| AbstractSimpleShardingModKeyIntVirtualTableRoute | 取模 | 0,1,2... | = |
| AbstractSimpleShardingModKeyStringVirtualTableRoute | 取模 | 0,1,2... | = |
| AbstractSimpleShardingDayKeyDateTimeVirtualTableRoute | 按時間 | yyyyMMdd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingDayKeyLongVirtualTableRoute | 按時間戳 | yyyyMMdd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingWeekKeyDateTimeVirtualTableRoute | 按時間 | yyyyMMdd_dd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingWeekKeyLongVirtualTableRoute | 按時間戳 | yyyyMMdd_dd | >,>=,<,<=,=,contains |
| AbstractSimpleShardingMonthKeyDateTimeVirtualTableRoute | 按時間 | yyyyMM | >,>=,<,<=,=,contains |
| AbstractSimpleShardingMonthKeyLongVirtualTableRoute | 按時間戳 | yyyyMM | >,>=,<,<=,=,contains |
| AbstractSimpleShardingYearKeyDateTimeVirtualTableRoute | 按時間 | yyyy | >,>=,<,<=,=,contains |
| AbstractSimpleShardingYearKeyLongVirtualTableRoute | 按時間戳 | yyyy | >,>=,<,<=,=,contains |
所謂的索引就是通過改對應的條件操作符可以縮小減少指定表的范圍,加快程序的執行
如果以上默認分表無法滿足您的需求您還可以自定義分表,如何分表可以通過繼承 AbstractShardingOperatorVirtualTableRoute<TEntity,TKey>來實現自定義分表規則(近乎90%的規則都可以實現)
動態添加分表信息
很多分表組件默認不帶動態分表信息導致很多分表沒辦法根據業務系統來進行動態創建,sharding-core默認提供動態建表接口可以支持動態按時間,按租戶等不需要數據做遷移的動態分表信息,
如果需要請參考Samples.AutoByDate.SqlServer
支持select,join,group by等連表聚合函數
目前sharding-core支持select按需查詢,join分表連表查詢,group by聚合查詢,雖然本框架支持但是出于性能原因本框架還是不建議使用join操作符來操作,因為過多的表路由會導致笛卡爾積,會導致需要查詢的表集合增長對數據庫連接比較考驗。
以下代碼來自github的單元測試中,SysUserMod表示用戶表,SysUserSalary表示用戶月薪表用戶表按id取模,用戶月薪表按月分表
分頁
我們常說的分頁是分表的難點也是最考驗分表組件的
1我們首先來看普通的分表組件如何分頁
首先我們定義一組組數據比如是1-100的連續數字,然后分成兩張表按奇偶分表
| table1 | 1,3,5,7,9... |
| table2 | 2,4,6,8,10... |
這個情況是我們常見的也是最簡單的分頁,但是這個情況僅僅適用于數據量小的時候,如果用戶不小心點到了分頁的最后一頁那么結果將是災難性的這是毋庸置疑的
那么sharding-core是如何處理的呢
無感知使用
目前的分表框架很少有做到無感知使用的,你在使用的時候好一點的框架不依賴三方,一般一點的不但要依賴很多三方框架并且在使用的時候還有一大堆限制,必須使用他的東西還沒辦法做到和dbcontext原生的使用方法。
sharding-core目前使用的是一種類似dbcontext的wrap模式,用一個新的dbcontext來包裝真實的dbcontext,這個包裝的dbcontext我們成為shardingdbcontext,shardingDbContext因為本身也是集成于DbContext所以它的使用方法和原生dbcontext沒有差別。并且僅需少量改動即可支持abp和abp.next
讀寫分離的支持
目前sharding-core已經支持單node節點的讀寫分離操作,將在不久的未來(1-2)天內支持多節點的讀寫分離
services.AddShardingDbContext<ShardingDefaultDbContext, DefaultDbContext>(o => o.UseSqlServer(hostBuilderContext.Configuration.GetSection("SqlServer")["ConnectionString"]),op =>{op.EnsureCreatedWithOutShardingTable = true;op.CreateShardingTableOnStart = true;op.UseShardingOptionsBuilder((connection, builder) => builder.UseSqlServer(connection).UseLoggerFactory(efLogger),(conStr,builder)=> builder.UseSqlServer("read db connection string").UseLoggerFactory(efLogger));op.AddShardingTableRoute<SysUserModVirtualTableRoute>();op.AddShardingTableRoute<SysUserSalaryVirtualTableRoute>();});未來計劃將支持分庫,支持強制路由,顯示路由等...
最后具體如何使用且使用方式可以參考github(https://github.com/xuejmnet/sharding-core) 當然我也會在后續出一系列的博客來對框架進行支持的介紹
最后的最后
該文檔是我晚上趕工趕出來的也想趁熱打鐵希望更多的人關注,也希望更多的人可以交流。
憑借各大開源生態圈提供的優秀代碼和思路才有的這個框架,希望可以為.Net生態提供一份微薄之力,該框架本人會一直長期維護,有大神技術支持可以聯系下方方式歡迎star ????
博客
QQ群:771630778
個人QQ:326308290(歡迎技術支持提供您寶貴的意見)
個人郵箱:326308290@qq.com
總結
以上是生活随笔為你收集整理的ShardingCore 如何呈现“完美”分表的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊一聊对外API接口的存活检查可以怎么做
- 下一篇: 最近看了两本低代码的书