NewLife.XCode是一个有15年历史的开源数据中间件,支持netcore/net45/net40,由新生命团队(2002~2020)开发完成并维护至今,以下简称XCode。
整个系列教程会大量结合示例代码和运行日志来进行深入分析,蕴含多年开发经验于其中,代表作有百亿级大数据实时计算项目。
开源地址:https://github.com/NewLifeX/X (求star, 1116+)
大部分应用系统的查询远远大于写入,在单体应用迈入分布式应用得到横向扩展能力之前,最高的一个门槛就是查询过多,以至于数据库超负荷工作!
常见的解决办法就是读写分离,把应用的查询操作分摊到一个或多个只读从库上,主库仅用于写入数据以及事务性操作。企业级应用中MySql一般主从部署,可以把从库充分利用起来,公有云数据库一般支持给数据库添加多台只读实例。
通过读写分离,扩展从库,可以轻易做到查询性能无限扩展!
!!阅读本文之前,建议阅读
如何使用读写分离
在XCode中使用读写分离,不需要修改任何代码,仅需要修改连接字符串配置即可。
如下测试代码:
var r0 = Role.FindByName("Stone"); r0?.Delete(); var r = new Role(); r.Name = "Stone"; r.Insert(); var r2 = Role.FindByName("Stone"); XTrace.WriteLine("FindByName: {0}", r2.ToJson()); r.Enable = true; r.Update(); var r3 = Role.Find(Role._.Name == "STONE"); XTrace.WriteLine("Find: {0}", r3.ToJson()); r.Delete(); var n = Role.FindCount(); XTrace.WriteLine("count={0}", n);
默认情况下只会在Membership连接上执行读写操作,我们来修改一下连接配置:
<add name="Membership" connectionString="Server=rw.mysql.rds.aliyuncs.com;Port=3306;Database=Membership;Uid=data;Pwd=Pass@word;" providerName="MySql.Data.MySqlClient"/> <add name="Membership.readonly" connectionString="Server=ro.mysql.rds.aliyuncs.com;Port=3306;Database=Membership;Uid=data;Pwd=Pass@word;" providerName="MySql.Data.MySqlClient"/>
如上,只需要在`Membership`基础上,增加一个`Membership.readonly`的连接名,指向MySql从库(或只读实例)即可。XCode在查询时将会把请求放到后一个连接上去执行。
执行结果如下:
可以看到,Insert/Update/Delete还是在`Membership`主库上执行,而Select跑到了`Membership.readonly`从库上执行。
读写分离规则
以下情况使用主库连接:
- 添删改 Insert/Delete/Update
- 查询(事务操作内部)
- 正向工程、反向工程
- 通过DAL指定主库连接名
以下情况使用从库连接:
- 查询(非事务操作)
- 实体缓存和对象缓存
- 通过DAL指定从库连接名
注意!!!如果从库同步有延迟,将有可能产生读取不到最新数据的情况,在实际应用中要做好风险评估!