多對多,資料庫水平切分架構

来源:http://www.cnblogs.com/mantianxing/archive/2017/08/04/7285342.html
-Advertisement-
Play Games

轉載微信公眾號“ 架構師之路“文章 其實看完我還是有些地方不明白,先留著以後慢慢消化~~ 本文將以“好友中心”為例,介紹“多對多”類業務,隨著數據量的逐步增大,資料庫性能顯著降低,資料庫水平切分相關的架構實踐。 一、什麼是多對多關係 所謂的“多對多”,來自資料庫設計中的“實體-關係”ER模型,用來描 ...


轉載微信公眾號“ 架構師之路“文章

其實看完我還是有些地方不明白,先留著以後慢慢消化~~

 

本文將以“好友中心”為例,介紹“多對多”類業務,隨著數據量的逐步增大,資料庫性能顯著降低,資料庫水平切分相關的架構實踐。

一、什麼是多對多關係

所謂的“多對多”,來自資料庫設計中的“實體-關係”ER模型,用來描述實體之間的關聯關係,一個學生可以選修多個課程,一個課程可以被多個學生選修,這裡學生與課程時間的關係,就是多對多關係。

 

二、好友中心業務分析

好友關係主要分為兩類,弱好友關係強好友關係,兩類都有典型的互聯網產品應用。

弱好友關係的建立,不需要雙方彼此同意

  • 用戶A關註用戶B,不需要用戶B同意,此時用戶A與用戶B為弱好友關係,對A而言,暫且理解為“關註”;

  • 用戶B關註用戶A,也不需要用戶A同意,此時用戶A與用戶B也為弱好友關係,對A而言,暫且理解為“粉絲”;

微博粉絲是一個典型的弱好友關係應用。

強好友關係的建立,需要好友關係雙方彼此同意

  • 用戶A請求添加用戶B為好友,用戶B同意,此時用戶A與用戶B則互為強好友關係,即A是B的好友,B也是A的好友;

QQ好友是一個典型的強好友關係應用。

好友中心是一個典型的多對多業務,一個用戶可以添加多個好友,也可以被多個好友添加,其典型架構為:

  • friend-service:好友中心服務,對調用者提供友好的RPC介面

  • db:對好友數據進行存儲

三、弱好友關係-元數據簡版實現

通過弱好友關係業務分析,很容易瞭解到,其核心元數據為:

  • guanzhu(uid, guanzhu_uid);

  • fensi(uid, fensi_uid);

其中:

  • guanzhu表,用戶記錄uid所有關註用戶guanzhu_uid

  • fensi表,用來記錄uid所有粉絲用戶fensi_uid

需要強調的是,一條弱關係的產生,會產生兩條記錄,一條關註記錄,一條粉絲記錄。

例如:用戶A(uid=1)關註了用戶B(uid=2),A多關註了一個用戶,B多了一個粉絲,於是:

  • guanzhu表要插入{1, 2}這一條記錄,1關註了2

  • fensi表要插入{2, 1}這一條記錄,2粉了1

如何查詢一個用戶關註了誰呢?

回答:在guanzhu的uid上建立索引:

select * from guanzhu where uid=1;

即可得到結果,1關註了2

如何查詢一個用戶粉了誰呢?

回答:在fensi的uid上建立索引:

select * from fensi where uid=2;

即可得到結果,2粉了1

四、強好友關係-元數據實現一

通過強好友關係業務分析,很容易瞭解到,其核心元數據為:

  • friend(uid1, uid2);

其中:

  • uid1,強好友關係中一方的uid

  • uid2,強好友關係中另一方的uid

uid=1的用戶添加了uid=2的用戶,雙方都同意加彼此為好友,這個強好友關係,在資料庫中應該插入記錄{1, 2}還是記錄{2,1}呢?

回答:都可以

為了避免歧義,可以人為約定,插入記錄時uid1的值必須小於uid2

例如:有uid=1,2,3三個用戶,他們互為強好友關係,那邊資料庫中可能是這樣的三條記錄

{1, 2}

{2, 3}

{1, 3}

如何查詢一個用戶的好友呢?

回答:假設要查詢uid=2的所有好友,只需在uid1和uid2上建立索引,然後:

select * from friend where uid1=2

union

select * from friend where uid2=2

即可得到結果。

作業,為何不使用:

select * from friend uid1=2 or uid2=2

五、強好友關係-元數據實現二

強好友關係是弱好友關係的一個特例,A和B必須互為關註關係(也可以說,同時互為粉絲關係),即也可以使用關註表和粉絲表來實現:

  • guanzhu(uid, guanzhu_uid);

  • fensi(uid, fensi_uid);

例如:用戶A(uid=1)和用戶B(uid=2)為強好友關係,即相互關註:

用戶A(uid=1)關註了用戶B(uid=2),A多關註了一個用戶,B多了一個粉絲,於是:

  • guanzhu表要插入{1, 2}這一條記錄

  • fensi表要插入{2, 1}這一條記錄

同時,用戶B(uid=2)也關註了用戶A(uid=1),B多關註了一個用戶,A多了一個粉絲,於是:

  • guanzhu表要插入{2, 1}這一條記錄

  • fensi表要插入{1, 2}這一條記錄

六、數據冗餘是實現多對多關係水平切分的常用實踐

對於強好友關係的兩類實現:

  • friend(uid1, uid2)

  • 數據冗餘guanzhu表與fensi表(後文稱正表T1與反表T2

在數據量小時,看似無差異,但數據量大時,數據冗餘的優勢就體現出來了:

  • friend表,數據量大時,如果使用uid1來分庫,那麼uid2上的查詢就需要遍歷多庫

  • 正表T1與反表T2通過數據冗餘來實現好友關係,{1, 2}{2,1}分別存在於兩表中,故兩個表都使用uid來分庫,均只需要進行一次查詢,就能找到對應的關註與粉絲,而不需要多個庫掃描

數據冗餘,是多對多關係,在數據量大時,數據水平切分的常用實踐。

七、如何進行數據冗餘

接下來的問題轉化為,好友中心服務如何來進行數據冗餘,常見有三種方法。

方法一:服務同步冗餘

顧名思義,由好友中心服務同步寫冗餘數據,如上圖1-4流程:

  • 業務方調用服務,新增數據

  • 服務先插入T1數據

  • 服務再插入T2數據

  • 服務返回業務方新增數據成功

優點

  • 不複雜,服務層由單次寫,變兩次寫

  • 數據一致性相對較高(因為雙寫成功才返回

缺點

  • 請求的處理時間增加(要插入次,時間加倍)

  • 數據仍可能不一致,例如第二步寫入T1完成後服務重啟,則數據不會寫入T2

如果系統對處理時間比較敏感,引出常用的第二種方案

方法二:服務非同步冗餘

數據的雙寫並不再由好友中心服務來完成,服務層非同步發出一個消息,通過消息匯流排發送給一個專門的數據複製服務來寫入冗餘數據,如上圖1-6流程:

  • 業務方調用服務,新增數據

  • 服務先插入T1數據

  • 服務向消息匯流排發送一個非同步消息(發出即可,不用等返回,通常很快就能完成)

  • 服務返回業務方新增數據成功

  • 消息匯流排將消息投遞給數據同步中心

  • 數據同步中心插入T2數據

優點

  • 請求處理時間短(只插入1次)

缺點

  • 系統的複雜性增加了,多引入了一個組件(消息匯流排)和一個服務(專用的數據複製服務)

  • 因為返回業務線數據插入成功時,數據還不一定插入到T2中,因此數據有一個不一致時間視窗(這個視窗很短,最終是一致的)

  • 在消息匯流排丟失消息時,冗餘表數據會不一致

如果想解除“數據冗餘”對系統的耦合,引出常用的第三種方案

方法三:線下非同步冗餘

數據的雙寫不再由好友中心服務來完成,而是由線下的一個服務或者任務來完成,如上圖1-6流程:

  • 業務方調用服務,新增數據

  • 服務先插入T1數據

  • 服務返回業務方新增數據成功

  • 數據會被寫入到資料庫的log

  • 線下服務或者任務讀取資料庫的log

  • 線下服務或者任務插入T2數據

優點

  • 數據雙寫與業務完全解耦

  • 請求處理時間短(只插入1次)

缺點

  • 返回業務線數據插入成功時,數據還不一定插入到T2中,因此數據有一個不一致時間視窗(這個視窗很短,最終是一致的)

  • 數據的一致性依賴於線下服務或者任務的可靠性

上述三種方案各有優缺點,可以結合實際情況選取。

數據冗餘固然能夠解決多對多關係的資料庫水平切分問題,但又帶來了新的問題,如何保證正表T1與反表T2的數據一致性呢?

八、如何保證數據的一致性

上一節的討論可以看到,不管哪種方案,因為兩步操作不能保證原子性,總有出現數據不一致的可能,高吞吐分散式事務是業內尚未解決的難題,此時的架構優化方向並不是完全保證數據的一致,而是儘早的發現不一致,並修複不一致。

最終一致性,是高吞吐互聯網業務一致性的常用實踐。更具體的,保證數據最終一致性的方案有三種。

方法一:線下掃面正反冗餘表全部數據

如上圖所示,線下啟動一個離線的掃描工具,不停的比對正表T1和反表T2,如果發現數據不一致,就進行補償修複

優點

  • 比較簡單,開發代價小

  • 線上服務無需修改,修複工具與線上服務解耦

缺點

  • 掃描效率低,會掃描大量的“已經能夠保證一致”的數據

  • 由於掃描的數據量大,掃描一輪的時間比較長,即數據如果不一致,不一致的時間視窗比較長

有沒有隻掃描“可能存在不一致可能性”的數據,而不是每次掃描全部數據,以提高效率的優化方法呢?

方法二:線下掃描增量數據

每次只掃描增量的日誌數據,就能夠極大提高效率,縮短數據不一致的時間視窗,如上圖1-4流程所示:

  • 寫入正表T1

  • 第一步成功後,寫入日誌log1

  • 寫入反表T2

  • 第二步成功後,寫入日誌log2

當然,我們還是需要一個離線的掃描工具,不停的比對日誌log1和日誌log2,如果發現數據不一致,就進行補償修複

優點

  • 雖比方法一複雜,但仍然是比較簡單的

  • 數據掃描效率高,只掃描增量數據

缺點

  • 線上服務略有修改(代價不高,多寫了2條日誌)

  • 雖然比方法一更實時,但時效性還是不高,不一致視窗取決於掃描的周期

有沒有實時檢測一致性併進行修複的方法呢?

方法三:實時線上“消息對”檢測

這次不是寫日誌了,而是向消息匯流排發送消息,如上圖1-4流程所示:

  • 寫入正表T1

  • 第一步成功後,發送消息msg1

  • 寫入反表T2

  • 第二步成功後,發送消息msg2

這次不是需要一個周期掃描的離線工具了,而是一個實時訂閱消息的服務不停的收消息。

假設正常情況下,msg1和msg2的接收時間應該在3s以內,如果檢測服務在收到msg1後沒有收到msg2,就嘗試檢測數據的一致性,不一致時進行補償修複

優點

  • 效率高

  • 實時性高

缺點

  • 方案比較複雜,上線引入了消息匯流排這個組件

  • 線下多了一個訂閱匯流排的檢測服務

however,技術方案本身就是一個投入產出比的折衷,可以根據業務對一致性的需求程度決定使用哪一種方法。

九、總結

文字較多,希望儘量記住如下幾點:

  • 好友業務是一個典型的多對多關係,又分為強好友與弱好友

  • 數據冗餘是一個常見的多對多業務數據水平切分實踐

  • 冗餘數據的常見方案有三種

             (1)服務同步冗餘

             (2)服務非同步冗餘

             (3)線下非同步冗餘

  • 數據冗餘會帶來一致性問題,高吞吐互聯網業務,要想完全保證事務一致性很難,常見的實踐是最終一致性

  • 最終一致性的常見實踐是,儘快找到不一致,並修複數據,常見方案有三種

             (1)線下全量掃描法

             (2)線下增量掃描法

             (3)線上實時檢測法


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 選中Project 然後滑鼠右鍵,將Compact Empty Moiddle Packages 的勾取消 輸入新名稱點擊 Preview輸入新名稱點擊 Preview輸入新名稱點擊 Preview輸入新名稱點擊 Preview輸入新名稱點擊 Preview輸入新名稱點擊 Preview輸入新名稱點 ...
  • 前言 Oracle Database 2 Day DBA是一個資料庫管理快速入門指南,教您如何執行日常資料庫管理任務。本書的目的是幫助您瞭解Oracle資料庫背後的概念。它教你如何執行保持資料庫運行所需的所有常見管理任務,包括如何執行基本故障排除和性能監控活動。 讀者 Oracle Database ...
  • 本文將介紹信息量,熵,交叉熵,相對熵的定義,以及它們與機器學習演算法中代價函數的定義的聯繫。轉載請保留原文鏈接:http://www.cnblogs.com/llhthinker/p/7287029.html 1. 信息量 信息的量化計算: 解釋如下: 信息量的大小應該可以衡量事件發生的“驚訝程度”或 ...
  • 在測試過程中需要清空資料庫中的幾張表,在PL/SQL客戶端中使用DELETE語句,然而出現瞭如下錯誤: ,出現這個錯誤的原因是DELETE操作會將刪除的數據暫存在一個UNDOTBS文件中,便於事務的回滾,然而對於數據量特別大的表,例如百萬以上的數據表,DELETE操作產生的臨時數據會占滿UNDOTB ...
  • 1.創建資料庫 2.刪除資料庫 3.mysql所支持的存儲引擎: InnoDB存儲引擎:是事物型資料庫的首選,支持事物安全表(ACID),支持鎖定和外鍵,mysql5.5.5之後,InnoDB作為預設存儲引擎。特性如下: (1)給mysql提供了具有提交、回滾和崩潰恢復能力的事物安全存儲引擎。 (2 ...
  • 在本地裝了centos 7的虛擬機,先要裝環境,選擇的mysql是5.6,以下是安裝的過程: 到此資料庫安裝完畢 啟動的過程中報錯了 是因為/var/log/mariadb這文件夾不存在,我們創建 再啟動 成功 ...
  • mysql 命令導出 Select *from 表名 into outfile "地址";導入 Source D:/mydb.sql /*將外部的sql文件導入到資料庫中*/ dos 命令mysqldump -uroot –p123456 test > c:/a.sql 在dos 視窗下,輸入該命令 ...
  • 原因:中間存在回車符或者換行符,所以要先將此符號替換掉; LTRIM(RTRIM(REPLACE(REPLACE( A,char(13),''),char(10),'') )) LTRIM(A) 去換左邊空格 RTRIM(A) 去換右邊空格 REPLACE( A,char(13),'') 將回車符替 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...