日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库性能优化—主从分离

發布時間:2024/4/15 数据库 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库性能优化—主从分离 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章出自:阿里巴巴十億級并發系統設計(2021版)

鏈接:https://pan.baidu.com/s/1lbqQhDWjdZe1CBU-6U4jhA?提取碼:8888?

上節課,我們用池化技術解決了數據庫連接復用的問題,這時,你的垂直電商系統雖然整體架構上沒有變化,但是和數據庫交互的過程有了變化,在你的 Web 工程和數據庫之間增加了數據庫連接池,減少了頻繁創建連接的成本,從上節課的測試來看性能上可以提升 80%。現在的架構圖如下所示:

此時,你的數據庫還是單機部署,依據一些云廠商的 Benchmark 的結果,在 4 核 8G 的 機器上運 MySQL 5.7 時,大概可以支撐 500 的 TPS 和 10000 的 QPS。這時,運營負責 人說正在準備雙十一活動,并且公司層面會繼續投入資金在全渠道進行推廣,這無疑會引發查詢量驟然增加的問題。那么今天,我們就一起來看看當查詢請求增加時,應該如何做主從 分離來解決問題。

主從讀寫分離

其實,大部分系統的訪問模型是讀多寫少,讀寫請求量的差距可能達到幾個數量級。 這很好理解,刷朋友圈的請求量肯定比發朋友圈的量大,淘寶上一個商品的瀏覽量也肯定遠 大于它的下單量。因此,我們優先考慮數據庫如何抗住更高的查詢請求,那么首先你需要把讀寫流量區分開,因為這樣才方便針對讀流量做單獨的擴展,這就是我們所說的主從讀寫分離

它其實是個流量分離的問題,就好比道路交通管制一樣,一個四車道的大馬路劃出三個車道 給領導外賓通過,另外一個車道給我們使用,優先保證領導先行,就是這個道理。 這個方法本身是一種常規的做法,即使在一個大的項目中,它也是一個應對數據庫突發讀流量的有效方法。

我目前的項目中就曾出現過前端流量突增導致從庫負載過高的問題,DBA 兄弟會優先做一 個從庫擴容上去,這樣對數據庫的讀流量就會落入到多個從庫上,從庫的負載就降了下來, 然后研發同學再考慮使用什么樣的方案將流量擋在數據庫層之上。

主從讀寫的兩個技術關鍵點

一般來說在主從讀寫分離機制中,我們將一個數據庫的數據拷貝為一份或者多份,并且寫入 到其它的數據庫服務器中,原始的數據庫我們稱為主庫,主要負責數據的寫入,拷貝的目標 數據庫稱為從庫,主要負責支持數據查詢。可以看到,主從讀寫分離有兩個技術上的關鍵點:

  • 一個是數據的拷貝,我們稱為主從復制;
  • 在主從分離的情況下,我們如何屏蔽主從分離帶來的訪問數據庫方式的變化,讓開發同學像是在使用單一數據庫一樣。
  • 接下來,我們分別來看一看。

    1.?主從復制

    我先以 MySQL 為例介紹一下主從復制。

    MySQL 的主從復制是依賴于 binlog 的,也就是記錄 MySQL 上的所有變化并以二進制形式保存在磁盤上二進制日志文件。主從復制就是將 binlog 中的數據從主庫傳輸到從庫上, 一般這個過程是異步的,即主庫上的操作不會等待 binlog 同步的完成。主從復制的過程是這樣的:首先從庫在連接到主節點時會創建一個 IO 線程,用以請求主庫更新的 binlog,并且把接收到的 binlog 信息寫入一個叫做 relay log 的日志文件中,而主庫也會創建一個 log dump 線程來發送 binlog 給從庫;同時,從庫還會創建一個 SQL 線程讀取 relay log 中的內容,并且在從庫中做回放,最終實現主從的一致性。這是一種比較常見的主從復制方式。在這個方案中,使用獨立的 log dump 線程是一種異步的方式,可以避免對主庫的主體更新流程產生影響,而從庫在接收到信息后并不是寫入從庫的存儲中,是寫入一個 relay log,是避免寫入從庫實際存儲會比較耗時,最終造成從庫和主庫延遲變長。

    你會發現,基于性能的考慮,主庫的寫入流程并沒有等待主從同步完成就會返回結果,那么在極端的情況下,比如說主庫上 binlog 還沒有來得及刷新到磁盤上就出現了磁盤損壞或者機器掉電,就會導致 binlog 的丟失,最終造成主從數據的不一致。不過,這種情況出現的概率很低,對于互聯網的項目來說是可以容忍的。

    做了主從復制之后,我們就可以在寫入時只寫主庫,在讀數據時只讀從庫這樣即使寫請求會鎖表或者鎖記錄,也不會影響到讀請求的執行。同時呢,在讀流量比較大的情況下,我們可以部署多個從庫共同承擔讀流量,這就是所說的“一主多從”部署方式,在你的垂直電商項目中就可以通過這種方式來抵御較高的并發讀流量。另外,從庫也可以當成一個備庫來使用,以避免主庫故障導致數據丟失。

    那么你可能會說,是不是我無限制地增加從庫的數量就可以抵抗大量的并發呢?實際上并不是的。因為隨著從庫數量增加,從庫連接上來的 IO 線程比較多,主庫也需要創建同樣多的 log dump 線程來處理復制的請求,對于主庫資源消耗比較高,同時受限于主庫的網絡帶寬,所以在實際使用中,一般一個主庫最多掛 3~5 個從庫

    當然,主從復制也有一些缺陷,除了帶來了部署上的復雜度,還有就是會帶來一定的主從同步的延遲,這種延遲有時候會對業務產生一定的影響,我舉個例子你就明白了。

    在發微博的過程中會有些同步的操作,像是更新數據庫的操作,也有一些異步的操作,比如 說將微博的信息同步給審核系統,所以我們在更新完主庫之后,會將微博的 ID 寫入消息隊列,再由隊列處理機依據ID 在從庫中獲取微博信息再發送給審核系統。此時如果主從數據庫存在延遲,會導致在從庫中獲取不到微博信息,整個流程會出現異常。

    這個問題解決的思路有很多,核心思想就是盡量不去從庫中查詢信息,純粹以上面的例子來 說,我就有三種解決方案:

    • 第一種方案是數據的冗余。你可以在發送消息隊列時不僅僅發送微博 ID,而是發送隊列處理機需要的所有微博信息,借此避免從數據庫中重新查詢數據。
    • 第二種方案是使用緩存。我可以在同步寫數據庫的同時,也把微博的數據寫入到 Memcached 緩存里面,這樣隊列處理機在獲取微博信息的時候會優先查詢緩存,這樣也可以保證數據的一致性。
    • 最后一種方案是查詢主庫。我可以在隊列處理機中不查詢從庫而改為查詢主庫。不過,這種方式使用起來要慎重,要明確查詢的量級不會很大,是在主庫的可承受范圍之內,否則會對 主庫造成比較大的壓力。

    我會優先考慮第一種方案,因為這種方式足夠簡單,不過可能造成單條消息比較大,從而增加了消息發送的帶寬和時間。

    緩存的方案比較適合新增數據的場景,在更新數據的場景下,先更新緩存可能會造成數據的不一致,比方說兩個線程同時更新數據,線程 A 把緩存中的數據更新為 1,此時另一個線程 B 把緩存中的數據更新為 2,然后線程 B 又更新數據庫中的數據為 2,此時線程 A 更新 數據庫中的數據為 1,這樣數據庫中的值(1)和緩存中的值(2)就不一致了。

    最后,若非萬不得已的情況下,我不會使用第三種方案。原因是這種方案要提供一個查詢主 庫的接口,在團隊開發的過程中,你很難保證其他同學不會濫用這個方法,而一旦主庫承擔 了大量的讀請求導致崩潰,那么對于整體系統的影響是極大的。

    所以對這三種方案來說,你要有所取舍,根據實際項目情況做好選擇。

    另外,主從同步的延遲,是我們排查問題時很容易忽略的一個問題。有時候我們遇到從數據庫中獲取不到信息的詭異問題時,會糾結于代碼中是否有一些邏輯會把之前寫入的內容刪 除,但是你又會發現,過了一段時間再去查詢時又可以讀到數據了,這基本上就是主從延遲 在作怪。所以,一般我們會把從庫落后的時間作為一個重點的數據庫指標做監控和報警,正 常的時間是在毫秒級別,一旦落后的時間達到了秒級別就需要告警了。

    2.?如何訪問數據庫

    我們已經使用主從復制的技術將數據復制到了多個節點,也實現了數據庫讀寫的分離,這時,對于數據庫的使用方式發生了變化。以前只需要使用一個數據庫地址就好了,現在需要使用一個主庫地址和多個從庫地址,并且需要區分寫入操作和查詢操作,如果結合下一節課 中要講解的內容“分庫分表”,復雜度會提升更多。為了降低實現的復雜度,業界涌現了很多數據庫中間件來解決數據庫的訪問問題,這些中間件可以分為兩類。

    第一類以淘寶的 TDDL( Taobao Distributed Data Layer)為代表,以代碼形式內嵌運行在應用程序內部。你可以把它看成是一種數據源的代理,它的配置管理著多個數據源,每個數據源對應一個數據庫,可能是主庫,可能是從庫。當有一個數據庫請求時,中間件將 SQL 語句發給某一個指定的數據源來處理,然后將處理結果返回。這一類中間件的優點是簡單易用,沒有多余的部署成本,因為它是植入到應用程序內部,與應用程序一同運行的,所以比較適合運維能力較弱的小團隊使用;缺點是缺乏多語言的支持,目前業界這一類的主流方案除了 TDDL,還有早期的網易 DDB,它們都是 Java 語言開 發的,無法支持其他的語言。另外,版本升級也依賴使用方更新,比較困難。

    另一類是單獨部署的代理層方案,這一類方案代表比較多,如早期阿里巴巴開源的 Cobar,基于 Cobar 開發出來的 Mycat,360 開源的 Atlas,美團開源的基于 Atlas 開發 的 DBProxy 等等。這一類中間件部署在獨立的服務器上,業務代碼如同在使用單一數據庫一樣使用它,實際上它內部管理著很多的數據源,當有數據庫請求時,它會對 SQL 語句做必要的改寫,然后發 往指定的數據源。它一般使用標準的 MySQL 通信協議,所以可以很好地支持多語言。由于它是獨立部署 的,所以也比較方便進行維護升級,比較適合有一定運維能力的大中型團隊使用。它的缺陷是所有的 SQL 語句都需要跨兩次網絡:從應用到代理層和從代理層到數據源,所以在性能上會有一些損耗。

    這些中間件,對你而言,可能并不陌生,但是我想讓你注意到是,在使用任何中間件的時候一定要保證對于中間件有足夠深入的了解,否則一旦出了問題沒法快速地解決就悲劇了。我之前的一個項目中,一直使用自研的一個組件來實現分庫分表,后來發現這套組件有一定幾率會產生對數據庫多余的連接,于是團隊討論后決定替換成 Sharding-JDBC。原本以為是一次簡單的組件切換,結果上線后發現兩個問題:一是因為使用姿勢不對,會偶發地出現分庫分表不生效導致掃描所有庫表的情況,二是偶發地出現查詢延時達到秒級別。由于缺少對于 Sharding-JDBC 足夠的了解,這兩個問題我們都沒有很快解決,后來不得已只能切回原來的組件,在找到問題之后再進行切換。

    課程小結

    本節課,我帶你了解了查詢量增加時,我們如何通過主從分離和一主多從部署抵抗增加的數據庫流量的,你除了掌握主從復制的技術之外,還需要了解主從分離會帶來什么問題以及它 們的解決辦法。這里我想讓你明確的要點主要有:

  • 主從讀寫分離以及部署一主多從可以解決突發的數據庫讀流量,是一種數據庫橫向擴展的方法;
  • 讀寫分離后,主從的延遲是一個關鍵的監控指標,可能會造成寫入數據之后立刻讀的時 候讀取不到的情況;
  • 業界有很多的方案可以屏蔽主從分離之后數據庫訪問的細節,讓開發人員像是訪問單一 數據庫一樣,包括有像 TDDL、Sharding-JDBC 這樣的嵌入應用內部的方案,也有像 Mycat 這樣的獨立部署的代理方案。
  • 其實,我們可以把主從復制引申為存儲節點之間互相復制存儲數據的技術,它可以實現數據的冗余,以達到備份和提升橫向擴展能力的作用。在使用主從復制這個技術點時,你一般會 考慮兩個問題:

  • 主從的一致性和寫入性能的權衡,如果你要保證所有從節點都寫入成功,那么寫入性能 一定會受影響;如果你只寫入主節點就返回成功,那么從節點就有可能出現數據同步失敗的 情況,從而造成主從不一致,而在互聯網的項目中,我們一般會優先考慮性能而不是數據的強一致性
  • 主從的延遲問題,很多詭異的讀取不到數據的問題都可能會和它有關,如果你遇到這類 問題不妨先看看主從延遲的數據。
  • 我們采用的很多組件都會使用到這個技術,比如,Redis 也是通過主從復制實現讀寫分離; Elasticsearch 中存儲的索引分片也可以被復制到多個節點中;寫入到 HDFS 中文件也會被 復制到多個 DataNode 中。只是不同的組件對于復制的一致性、延遲要求不同,采用的方案也不同。但是這種設計的思想是通用的,是你需要了解的,這樣你在學習其他存儲組件的 時候就能夠觸類旁通了。

    總結

    以上是生活随笔為你收集整理的数据库性能优化—主从分离的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。