電商系列(三)如何構建數據庫的主從架構

  這段時間,一直在總結電商系統的相關基礎技術和架構,寫了很多東西。但是還是發現一個很重要,很基礎的方面沒有講到,那就是數據庫讀寫分離的主從架構。可能發展到大型成熟的公司之後,主從架構已經落伍了,取而代之的是更加複雜的數據庫集群。但是作為一個小型電商公司,數據庫的主從架構應該是最基礎的。任何大型的系統架構,都是不斷演進的。主從架構便是數據庫架構中,最基礎的架構。所以研究完主從架構,也就能看懂更加複雜的架構了。

  首先為什麼要讀寫分離?

  對於一個小型網站,可能單臺數據庫服務器就能滿足需求,但是在一些大型的網站或者應用中,單臺的數據庫服務器可能難以支撐大的訪問壓力,升級服務器性能,成本又太高,必須要橫向擴展。還有就是,單庫的話,讀、寫都是操作一個數據庫,數據多了之後,對數據庫的讀、寫性能就會有很大影響。同時對於數據安全性,和系統的穩定性,也是挑戰。

  數據庫的讀寫分離的好處?

    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 不太相同,但是原理是一樣的,大家字節總結封裝吧。)

<code>       
         
         
         
         
         
        

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

;

if

(redirect2WritableDB || commandType == CommandType.StoredProcedure) {

return

DBConfiguration.WritableDB; }

else

{

int

random = GenerateRandomNumber();

int

dbIndex = random % DBConfiguration.ReadDBs.Count;

return

DBConfiguration.ReadDBs[dbIndex]; } }/<code>

    同時,增加相關的數據庫配置

<code> 

<

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

>

/<code>

推薦閱讀:

電商系列(二)聊一聊服務器日誌與監控系統的解決方案

電商系列(一)中小型電商系統的基礎架構!

SpringBoot入門系列(十一)實現統一異常處理,就這麼簡單!

Spring Boot整合定時任務Task,一秒搞定定時任務

Spring Boot入門系列(十)如何使用攔截器,一學就會!

Spring Boot入門系列(六)Spring整合Mybatis詳解「附詳細步驟」


分享到:


相關文章: