欢迎大家来到IT世界,在知识的湖畔探索吧!
这段时间,一直在总结电商系统的相关基础技术和架构,写了很多东西。但是还是发现一个很重要,很基础的方面没有讲到,那就是数据库读写分离的主从架构。可能发展到大型成熟的公司之后,主从架构已经落伍了,取而代之的是更加复杂的数据库集群。但是作为一个小型电商公司,数据库的主从架构应该是最基础的。任何大型的系统架构,都是不断演进的。主从架构便是数据库架构中,最基础的架构。所以研究完主从架构,也就能看懂更加复杂的架构了。
首先为什么要读写分离?
对于一个小型网站,可能单台数据库服务器就能满足需求,但是在一些大型的网站或者应用中,单台的数据库服务器可能难以支撑大的访问压力,升级服务器性能,成本又太高,必须要横向扩展。还有就是,单库的话,读、写都是操作一个数据库,数据多了之后,对数据库的读、写性能就会有很大影响。同时对于数据安全性,和系统的稳定性,也是挑战。
数据库的读写分离的好处?
1. 将读操作和写操作分离到不同的数据库上,避免主服务器出现性能瓶颈;
2. 主服务器进行写操作时,不影响查询应用服务器的查询性能,降低阻塞,提高并发;
3. 数据拥有多个容灾副本,提高数据安全性,同时当主服务器故障时,可立即切换到其他服务器,提高系统可用性;
读写分离的基本原理就是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE)操作,而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到其他从数据库。以SQL为例,主库负责写数据、读数据。读库仅负责读数据。每次有写库操作,同步更新到读库。写库就一个,读库可以有多个,采用日志同步的方式实现主库和多个读库的数据同步。
一:Sql Server 读写分离的配置
SQL Server 提供了三种技术,可以用于主从架构之间的数据同步的实现:日志传送、事务复制和SQL 2012 中新增的功能Always On 技术。各自优劣,具体的大家自己去百度吧,这里提供网上的朋友的配置方式,仅供参考。
1. 日志传送:SQL Server 2008 R2 主从数据库同步。
2. 事务复制:SQL Server 复制:事务发布
(PS:此图为网上找的,具体的原文地址已经找不到了,故无法标明作者,请见谅。)
二:C# 数据库读写操作
C#的请求数据库操作,单数据库和主从架构的数据库还是不一样的。主从架构的数据库,为了保证数据一致性,一般主库可读可写,从库只负责读,不负责写入。所以,实际C#在请求数据库的时候,还是要区别对待。
1. 最简单的就是:配置两个数据库连接,然后在各个数据库调用的位置,区分读写请求相应的数据库服务器,如下图
2. 第二种解决方案就是判断SQL语句是写语句(insert 、update、Create、 Alter)还是读语句(Select)。demo 下载
(PS:此demo为本人总结,跟实际生产中的DLL 不太相同,但是原理是一样的,大家字节总结封装吧。)
/// <summary>
/// 根据数据库的语句,选择相应的DB
/// </summary>
/// <param name="sql"></param>
/// <param name="commandType"></param>
/// <returns></returns>
public static DB SelectDB(string sql, CommandType commandType)
{
bool redirect2WritableDB = false;
sql = sql.Trim().TrimStart('\r').TrimStart('\n');
if (sql.IndexOf("UPDATE", StringComparison.OrdinalIgnoreCase) >= 0)
redirect2WritableDB = true;
if (sql.IndexOf("DELETE", StringComparison.OrdinalIgnoreCase) >= 0)
redirect2WritableDB = true;
if (sql.IndexOf("INSERT", StringComparison.OrdinalIgnoreCase) >= 0)
redirect2WritableDB = true;
if (sql.IndexOf("CREATE", StringComparison.OrdinalIgnoreCase) >= 0)
redirect2WritableDB = true;
if (sql.IndexOf("ALTER", StringComparison.OrdinalIgnoreCase) >= 0)
redirect2WritableDB = true;
//// 如果是存储过程,则默认是取Writable DB。
if (redirect2WritableDB || commandType == CommandType.StoredProcedure)
{
return DBConfiguration.WritableDB;
}
else
{
int random = GenerateRandomNumber();
int dbIndex = random % DBConfiguration.ReadDBs.Count;
return DBConfiguration.ReadDBs[dbIndex];
}
}
欢迎大家来到IT世界,在知识的湖畔探索吧!
同时,增加相关的数据库配置
欢迎大家来到IT世界,在知识的湖畔探索吧!<?xml version="1.0" encoding="utf-8" ?>
<ConnectionString>
<WritableDB>Data Source=192.168.99.242; Initial Catalog=DBTest; Uid=sa;pwd=test123; MultipleActiveResultSets=True</WritableDB>
<ReadDBs>
<DB>Data Source=192.168.99.241; Initial Catalog=DBTest; Uid=sa;pwd=test123; MultipleActiveResultSets=True</DB>
</ReadDBs>
</ConnectionString>
推荐阅读:
SpringBoot入门系列(十一)实现统一异常处理,就这么简单!
Spring Boot整合定时任务Task,一秒搞定定时任务
Spring Boot入门系列(十)如何使用拦截器,一学就会!
Spring Boot入门系列(六)Spring整合Mybatis详解「附详细步骤」
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/17612.html