資料庫分庫分表和帶來的唯一ID、分頁查詢問題的解決

来源:https://www.cnblogs.com/hanzhong/archive/2019/02/26/10440286.html
-Advertisement-
Play Games

需求緣起(用一個公司的發展作為背景) 1.還是個小公司的時候,註冊用戶就20w,每天活躍用戶1w,每天最大單表數據量就1000,然後高峰期每秒併發請求最多就10,此時一個16核32G的伺服器,每秒請求支撐在2000左右,負載合理,沒有太大壓力,基本沒有宕機風險。 2.當註冊用戶達到2000W,每天活 ...


需求緣起(用一個公司的發展作為背景)

        1.還是個小公司的時候,註冊用戶就20w,每天活躍用戶1w,每天最大單表數據量就1000,然後高峰期每秒併發請求最多就10,此時一個16核32G的伺服器,每秒請求支撐在2000左右,負載合理,沒有太大壓力,基本沒有宕機風險。

        2.當註冊用戶達到2000W,每天活躍用戶數100W,每天單表新增數據量達到50W條,高峰期請求量達到1W。經過一段時間的運行,單標數據量會越來越多,帶來的問題

      2.1 資料庫伺服器的IO,網路寬頻,CPU負載,記憶體消耗都會達到非常高,伺服器已經不堪重負

    2.2 高峰時期,單表數據量本來就很大,加上資料庫伺服器負載太高,導致性能下降,此時SQL的性能就更差了,用戶體驗賊差, 點一個按鈕要很久才有響應,如果伺服器的配置再低一點的話,資料庫可能直接宕機

   3. 實現一個基本的分庫分表的思路,將一臺資料庫伺服器變成5台資料庫,就能有5個庫,5個表,這樣可以將表中的數據按照ID分別通過同一個映射方法,分佈到這5個庫中。此時寫入數據的時候,需要藉助資料庫中間件,比如shardng-jdbc或者Mycat。查詢的時候先通過一步映射到具體的資料庫,再進行查詢。

   4. 當用戶量再次增長時,只能繼續分表,比如將一張表拆分成1024張表,這樣在操作數據的時候,需要兩次路由,一次找到在哪個資料庫,一次找到在哪張表。

   5. 除了分表,資料庫還可以做主從架構,主伺服器用以寫入,從伺服器用以查詢,根據業務需求具體實現即可。

分庫分錶帶來的問題

   1. 分庫分表之後一個必然的問題,如何獲取一個全局為一個ID?因為表中的數據是通過ID路由映射的,ID不能重覆。

   2. 就算有了全局唯一的ID,那面對分頁查詢的需求,應該怎麼處理呢?

 

  唯一ID的生成

  下麵列舉幾種常見的唯一ID生成方案,需要滿足兩大核心需求:1.全局唯一  2趨勢有序

   1. 用資料庫的auto_increment(自增ID)來生成,每次通過寫入資料庫一條記錄,利用資料庫ID自增的特性獲取唯一,有序的ID。

     優點:使用資料庫原有的功能,相對簡單;能夠保證唯一;能夠保證遞增性;ID之間的步長是固定且可以自定義的

     缺點:可用性難以保證,當生成ID的那台伺服器宕機,系統就玩不轉了;由於寫入是單點的,所以擴展性差,性能上限取決於資料庫的寫性能。

   2. 用UUID

     優點:簡單方便;全球唯一,在遇見數據遷移、合併或者變更時可以從容應對;

     缺點:沒有遞增性;UUID是很長的字元串,作為主鍵對存儲空間有一定要求,查詢效率也較低。

   3. 使用Redis生成ID,主要利用Redis是單線程的,所以也可以用來生成唯一ID。當使用的是Redis集群的時候,比如集群中有5台Redis,初始化每台Redis的值為1,2,3,4,5,設置步長為5,並且確定一個不隨機的負載均衡策略,能夠保證有序,唯一。

     優點:不依賴資料庫,靈活,且性能相對於資料庫有一定提高;使用Redis集群策略還能排除單點故障問題;ID天然有序

     缺點:如果系統中沒有Redis,還需要引入新的組件;編碼和配置工作量大

   4. 使用Twitter的snowflake演算法;其核心思想是一個64位long型ID,使用41bit作為毫秒數,10bit作為機器的ID(5個bit是數據中心,5個bit的機器ID),12bit作為毫秒內的流水號(意味著每個節點在每毫秒可以產生 4096 個 ID),最後還有一個符號位,永遠是0。具體實現的代碼可以參看https://github.com/twitter/snowflake。可以根據自身需求進行一定的修改。

    優點:不依賴資料庫,靈活方便,性能優於資料庫;ID按照時間在單機上是遞增的

    缺點:單機上遞增,但是當分散式環境下每台機器的時鐘不可能完全同步,有時並不能做做全局遞增。

   5. 使用zookeeper生成唯一ID,主要通過znode數據版本來生成序列號,可以生成32為和64為的數據版本號。很少使用,因為是多步調用API,併發情況下還需要考慮分散式鎖,不是很理想。

   6. MongoDB的ObjectID,和snowflake演算法類似。4位元組Unix時間戳,3位元組機器編碼,2位元組進程編碼,3位元組隨機數

  分庫分表下的分頁查詢

  假設有一張用戶表,經過分庫分表之後,現在均勻分佈在2台伺服器實例上。業務需要查詢“最近註冊的第3頁用戶”,雖然資料庫有分庫用的全局的ID,但是沒有排序條件time的全局視野,此時應該怎麼做呢?

   1. 全局視野法:因為不清楚按照時間排序之後的第三頁數據到底是如何分佈在資料庫上的,所以必須每個庫都返回3頁數據,所得到的6頁數據在服務層進行記憶體排序,得到全局視野,再取第3頁數據。

     優點:通過服務層修改,擴大數據查詢量,得到全局視野,業務無損,精確

     缺點(顯而易見):每個分庫都需要返回更多的數據,增大網路傳輸量;除了資料庫要按照time排序,服務層也需要二次排序,損耗性能;隨著頁碼的增大,性能極具下降,數據量和排序量都將大增,性能平方級下降。

    2. 業務折中

     2.1 禁止跳頁查詢,不提供“直接跳到指定頁面”的功能,只提供下一頁的功能。極大的降低技術方案的複雜度。第一頁的選取方法和全局視野法一樣,但是點擊下一頁時:

       2.1.1先找到上一頁的time的最大值,作為第二頁數據拉去的查詢條件,只取每頁的記錄數,

       2.2.2這樣服務層還是獲得兩頁數據,再做一次排序,獲取一頁數據。

       2.2.3改進了不會因為頁碼增大而導致數據的傳輸量和排序量增大

    3. 允許數據精度丟失:需要考慮業務員上是否接受在頁碼較大是返回的數據不是精準的數據。

     3.1在數據量較大,且ID映射分佈足夠隨機的話,應該是滿足等概率分佈的情況的,所以取一頁數據,我們在每個資料庫中取前半頁。

     3.2當然這樣的到的結果並不是精準的,但是當實際業務可以接受的話, 此時的技術方案的複雜度變大大降低。也不需要服務層記憶體排序了。

    4. 二次查詢法:既滿足業務的精確需求,也無需業務折中。現在假設每頁顯示10條數據,要查第三頁,數據分了兩個庫。 正常的語句是 select * from table order by time offset 20 limit 10,取偏移20個之後的10個

     4.1首次查詢查詢每個庫的select * from table order by time offset 10 limit 10;得到10條數據。這裡的offset是總offset/分庫數

     4.2 服務層得到來自兩個分庫的結果集,得到最小的time,也就是最頂層的time,這個time滿足最少有10條記錄在它前面,然後分別記錄每個庫的最大time

     4.3 分別再次查詢最小time->每個庫上一次的最大time的數據,得到每個庫的查詢結果

     4.4 在每個集合的最小time都是相同的,所以可以得到該最小time在整個資料庫中的offset,加起來就是這個最小time在全局庫的offset位置。

     4.5 再將第二次查詢的結果集拼起來和得到的最小time的offset,推導出 offset 20 limit 10的一頁記錄。

     優點:可以精確得到業務數據,且每次返回的數據量都非常小,不會隨著頁碼增加而數據量增大。

     缺點:需要進行兩次資料庫查詢


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

-Advertisement-
Play Games
更多相關文章
  • JavaScript: 概念 :一門客戶端腳本語言 運行在客戶端瀏覽器中的,每一個瀏覽器都有一個JavaScript的解析引擎 腳本語言:不需要編譯,直接就可以被瀏覽器解析執行了 功能: 可以用來增強用戶和html頁面的交互過程,用來控制html元素,讓頁面有一些動態效果,增強用戶的體驗 JavaS ...
  • 一 :背景 1.1 測試提出的bug,我查看了一下其他頁面選擇時間的控制項。通過對比發現別人用的glyphicon-arrow-left 爾我用的是 icon-arrow-left 而且百度也沒有找到相關問題的解決辦法。 1.2 對於這種查閱百度也找不到解決的辦法,也只能試試運氣查看源碼(bootst ...
  • Echarts堆積柱狀圖排序是按照堆積柱狀圖的柱子高度進行從大到小(或者從小到大)進行排序,方便查閱各坐標情況。以下是我自己研發的方法,有不對的地方敬請諒解,隨時歡迎指教。 排序後效果如下圖: (1)排序函數,這是一個簡單的冒泡排序,首先計算橫坐標各柱子的和,然後進行簡單的冒泡排序(因為時間緊),可 ...
  • vux VUX 是基於 WeUI 和 Vue.js 的 移動端 UI 組件庫,提供豐富的組件滿足移動端(微信)頁面常用業務需求。 在vue cli中使用步驟如下: 1、安裝: npm i vux S 2、vux2必須配合vux loader使用,並配置build/webpack.base.conf. ...
  • 實現思路: 1、 v model 一個收集所有input(除全選框外)數組checkModel ,vue會動態將其checked為true的input的value值存入數組checkModel里 2 、watch函數來監聽checkModel 屬性,當其長度==input元素時 全選按鈕選中 否則取 ...
  • 1. 在 router目錄下 的 index.js文件中,新增路由 import City from '@/pages/city/City' { path: '/city', name: 'City', component: City } 2. 在city 目錄下新建city文件夾,然後新建 Cit ...
  • ├── README.md 項目介紹├── index.html 入口頁面├── build 構建腳本目錄│ ├── webpack.base.conf.js webpack基礎配置,開發環境,生產環境都依賴 │ ├── webpack.dev.conf.js webpack開發環境配置│ ├── ...
  • 前面介紹了Util是如何封裝以降低Angular應用的開發成本。 現在把關註點移到服務端,本文將介紹分層架構各構造塊及基類,並對不同層次的開發人員應如何進行業務開發提供一些建議。 Util分層架構介紹 為了控制業務邏輯複雜性,Util引入了DDD分層架構,這意味著如果你想使用DDD,Util會為你提 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...