日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

彩虹橋架構演進之路-性能篇

來源: 責編: 時間:2023-11-02 09:09:37 317觀看
導讀一、前言一年前的《彩虹橋架構演進之路》側重探討了穩定性和功能性兩個方向。在過去一年中,盡管業務需求不斷增長且流量激增了數倍,彩虹橋仍保持著零故障的一個狀態,算是不錯的階段性成果。而這次的架構演進,主要分享一下

一、前言

一年前的《彩虹橋架構演進之路》側重探討了穩定性和功能性兩個方向。在過去一年中,盡管業務需求不斷增長且流量激增了數倍,彩虹橋仍保持著零故障的一個狀態,算是不錯的階段性成果。而這次的架構演進,主要分享一下近期針對性能層面做的一些架構調整和優化。其中最大的調整就是 Proxy-DB 層的線程模式從 BIO 改造成了性能更好的 NIO。下面會詳細介紹一下具體的改造細節以及做了哪些優化。zjl28資訊網——每日最新資訊28at.com

閱讀本文預計需要 20~30 分鐘,整體內容會有些枯燥難懂,建議閱讀前先看一下上一篇彩虹橋架構演進的文章(彩虹橋架構演進之路)以及 MySQL 協議相關基礎知識。zjl28資訊網——每日最新資訊28at.com

二、改造前的架構

先來復習一下彩虹橋的全景架構圖:zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

Proxy三層模塊

針對 Proxy 這一層,可以大致分成 Frontend、Core、Backend 三層:zjl28資訊網——每日最新資訊28at.com

Frontend-服務暴露層:使用 Netty 作為服務器,按照 MySQL 協議對接收&返回的數據進行編解碼。zjl28資訊網——每日最新資訊28at.com

Core-功能&內核層:通過解析、改寫、路由等內核能力實現數據分片、讀寫分離、影子庫路由等核心功能。zjl28資訊網——每日最新資訊28at.com

Backend-底層DB交互層:通過 JDBC 實現與數據庫交互、對結果集改列、歸并等操作。zjl28資訊網——每日最新資訊28at.com

BIO模式下的問題

這里 Core 層為純計算操作,而 Frontend、Backend 都涉及 IO 操作,Frontend 層使用 Netty 暴露服務為 NIO 模式,但是 Backend 使用了數據庫廠商提供的傳統 JDBC 驅動,為 BIO 模式。所以 Proxy 的整體架構還是 BIO 模式。在 BIO 模型中,每個連接都需要一個獨立的線程來處理。這種模型有一些明顯的缺點:
zjl28資訊網——每日最新資訊28at.com

  • 高資源消耗:每個請求創建獨立線程,伴隨大量線程開銷。線程切換與調度額外消耗 CPU。
  • 擴展性受限:受系統線程上限影響,處理大量并發連接時,性能急劇下降。
  • I/O阻塞:BIO 模型中,讀/寫操作均為阻塞型,導致線程無法執行其他任務,造成資源浪費。
  • 復雜的線程管理:線程管理和同步問題增加開發和維護難度。

我們看最簡單的一個場景:在 JDBC 在發起請求后,當前線程會一直阻塞直到數據庫返回數據,當出現大量慢查或者數據庫出現故障時,會導致大量線程阻塞,最終雪崩。在上一篇彩虹橋架構演進文章中,我們做了一些改進來避免了 BIO 模型下的一些問題,比如使用線程池隔離來解決單庫阻塞導致全局雪崩的問題。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

但是隨著邏輯庫數量的增多,最終導致 Proxy 的線程數膨脹。系統的可伸縮性和吞吐量都受到了挑戰。因此有必要將現有的基于 JDBC 驅動的阻塞式連接升級為采用 NIO(非阻塞 I/O)方式連接數據庫。zjl28資訊網——每日最新資訊28at.com

三、改造后的架構

  • BIO->NIO

想把 Proxy 整體架構從 BIO->NIO,最簡單的方式就是把傳統的 BIO 數據庫驅動 JDBC 換成 NIO 的數據庫驅動,但是在調研過后發現開源的 NIO 驅動并不多,而且基本上沒有什么最佳實踐。最后在參考 ShardingSphere 社區之前做的調研后(https://github.com/apache/shardingsphere/issues/13957),決定使用 Vertx 來替換 JDBC。最開始使用 Vert.x 的原因,第一是 Vertx 的異步編碼方式更友好,編碼復雜度相對較低,第二是因為它實現了主流數據庫的驅動。但最終的結果不盡人意,由于 Vertx 相關抽象化的架構,導致鏈路較長時,整個調用棧深非??鋸?。最終壓測出來的吞吐量提升只有 5% 不到,而且存在很多兼容性問題。于是推倒重來,決定自研數據庫驅動和連接池。zjl28資訊網——每日最新資訊28at.com

  • 跳過不必要的編解碼階段

由于 JDBC 驅動會自動把 MySQL 的字節數據編解碼成 Java 對象,然后 Proxy 再把這些結果集經過一些加工(元信息修正、結果集歸并)后再進行編碼返回給上游。如果自研驅動的話,就可以把編解碼流程控制的更細致一些,把 Proxy 不需要加工的數據直接轉發給上游,跳過無意義的編解碼。后面會介紹一下哪些場景是不需要 Proxy 對結果集進行加工的。zjl28資訊網——每日最新資訊28at.com

自研NIO數據庫驅動

數據庫驅動主要是封裝了與 DB 層交互協議,封裝成高級 API。下面 2 張圖是 java.sql 包中的 Connection 和 Statement 的一些核心接口。

圖片圖片zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

所以首先我們需要了解一下,如何與數據庫進行數據交互,以 MySQL 為例,使用 Netty 連接 MySQL,簡單的交互流程如下。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

使用 Netty 與 MySQL 連接建立后,我們要做的就是按照 MySQL 協議規定的數據格式,先鑒權后再發送具體的命令包即可。下面是 MySQL 官方文檔中鑒權流程和命令執行流程:zjl28資訊網——每日最新資訊28at.com

  • 鑒權流程:https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_connection_phase.html
  • 執行命令流程:https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_command_phase.html

下面就是按照 MySQL 的文檔,去實現編解碼 Handle,我們簡單看一下實現的代碼。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

  • decode 解碼

就是針對 MySQL 返回的數據包解碼,根據長度解析出 Palyload 封裝成 MySQLPacketPayload 傳給對應的 Handle 處理。zjl28資訊網——每日最新資訊28at.com

  • encode 編碼

把具體的命令類轉換成具體的 MySQL 數據包,這里的 MySQLPacket 有多個實現類,跟 MySQL的Command 類型一一對應。zjl28資訊網——每日最新資訊28at.com

現在還需要一個類似 java.sql.Connection 的實現類,來組裝 MySQLPacket 并寫入到 Netty 通道中,并且解析編碼后的 MySQLPacketPayload 轉換成 ResultSet。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

看起來比較簡單,交互流程和傳統的 JDBC 幾乎一樣,但是由于現在是異步化流程,所有的 Response 都是通過回調返回,所以這里有 2 個難點:zjl28資訊網——每日最新資訊28at.com

  • 由于 MySQL 在上一條命令沒結束前無法接受新的命令,所以如何控制單個連接的命令串行化?
  • 如何將 MySQL 返回的數據包和發起命令的 Request 一一綁定?

首先 NettyDbConnection 引入了一個無鎖化非阻塞隊列 ConcurrentLinkedQueue。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

在發送 Command 時,如何沒有正在進行中的 Command,則直接發送,如果有正在進行中的 Command,直接扔到隊列中,等待上一條 Command 處理完成后推動下一條命令的執行。保證了單個連接命令串行化。zjl28資訊網——每日最新資訊28at.com

其次,NettyDbConnection 在執行命令時,傳入一個 Promise,在 MySQL 數據包全部返回后,這個 Promise 將會被設置完成,即可于發起命令的 Request 一一綁定。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

自研NIO數據庫連接池

前面介紹了 NettyDbConnection 這個類,實現了與 MySQL 的交互,并且提供了執行 SQL 的高級 API,但實際使用過程中,不可能每次都創建一個連接執行完 SQL 就關閉。所以需要對 NettyDbConnection 進行池化,統一管理連接的生命周期。其功能類似于傳統連接池 HikariCP,在完成基本能力的基礎上,做了很多性能優化。
zjl28資訊網——每日最新資訊28at.com

  • 連接生命周期管控
  • 連接池動態伸縮
  • 完善的監控
  • 連接異步保活
  • 超時控制
  • EventLoop 親和性

這里除了 EventLoop 親和性,其他幾個功能只要用過傳統的數據庫連接池應該都比較熟悉,這里不做過多展開。這里主要針對 EventLoop 親和性展開介紹一下。zjl28資訊網——每日最新資訊28at.com

在文章開頭我們說到 Proxy 的三層模塊,Frontend、Core、Backend,如果現在我們把 Backend 層于數據庫交互的組件換成了我們自研的驅動,那么 Proxy 就即是Netty Server,也是Netty Client,所以 Frontend 和 Backend 可以共用一個 EventLoopGroup。為了降低線程上下文切換,在單個請求從 Frontend 接收、經過 Core 層計算后轉發到 MySQL ,再到接收 MySQL 服務響應,以及最終的回寫給 Client 端,這一些列操作盡量放在一個 EventLoop 線程中處理。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

具體的做法就是 Backend 在選擇與數據庫連接時,優先選擇與當前 EventLoop 綁定的連接。也就是前面提到的 EventLoop 親和性,這樣就能保證大部分場景下一次請求從頭到尾都由同一個 EventLoop 處理,下面我們看一下具體的代碼實現。zjl28資訊網——每日最新資訊28at.com

在 NettyDbConnectionPool 類中使用一個 Map 存儲連接池中的空閑連接,Key 為 EventLoop,Value 為當前 EventLoop 綁定的空閑連接隊列。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

在獲取時,優先獲取當前 EventLoop 綁定的連接,如果當前 EventLoop 未綁定連接,則會借用其他 EventLoop 的連接。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

為了提高 EventLoop 命中率,需要注意幾點配置:zjl28資訊網——每日最新資訊28at.com

  • EventLoop 線程數量盡量與 CPU 核心數保持一致。
  • 連接池最大連接數超過 EventLoop 線程數越多,EventLoop 命中率越高。

下面放一張壓測環境(8C16G、連接池最大連接數 10~30)的命中率監控,大部分保持在 75% 左右。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

跳過不必要的編解碼

前面說到,有部分 SQL 的結果集是不需要 Proxy 進行加工的,也就是可以直接把 MySQL 返回的數據流原封不動轉發給上游,直接省去編解碼操作。那什么 SQL 是不需要 Proxy 進行加工的呢,我們舉個例子說明一下。
zjl28資訊網——每日最新資訊28at.com

假設邏輯庫 A 里面有一張表 User 做了分庫,分了 2 個庫 DB1 和 DB2,分片算法是 user_id%2。zjl28資訊網——每日最新資訊28at.com

  • SQL 1
SELECT id, name FROM user WHERE user_id in (1, 2)
  • SQL 2
SELECT id, name FROM user WHERE user_id in (1)

很顯然 SQL 1由于有 2 個分片 Value,最終匹配到了 2 個節點,SQL 2 只會匹配到 1 個節點。zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

SQL 1 由于需要對結果集進行歸并,所以無法跳過編解碼,SQL 2 不需要對結果集歸并,只需要把結果集中的列定義數據做修正后,真正的 Row 數據無需處理,這種情況就可以把 Row 數據直接轉發至上游。zjl28資訊網——每日最新資訊28at.com

全鏈路異步化

Backend 層用自研連接池+驅動替換原先的 HikariCP+JDBC 后,從 Frontend-Core-Backend 全鏈路涉及到阻塞的操作需要全部替換成異步化編碼,也就是通過 Netty 的 Promise 和 Future 來實現。
zjl28資訊網——每日最新資訊28at.com

圖片圖片zjl28資訊網——每日最新資訊28at.com

由于部分場景拿到 Future 時,可能當前 Future 已經完成了,如果每次都是無腦的加 Listener 會讓調用棧加長,所以我們定義了一個通用的工具類來處理 Future,即 future.isDone() 時直接執行,反之才會 addListener,最大化降低整個調用棧的深度。zjl28資訊網——每日最新資訊28at.com

圖片zjl28資訊網——每日最新資訊28at.com

兼容性

除了以上基本代碼的改造外,還需要做大量的兼容工作:
  • 特殊數據庫字段類型處理
  • JDBC URL 參數兼容
  • ThreadLocal 相關數據全部需要遷移至 ChannelHandlerContext 中
  • 日志 MDC、TraceContext 相關數據傳遞
  • ……

四、性能表現

經過幾輪性能壓測后,NIO架構相較于BIO架構性能有較大提升:
zjl28資訊網——每日最新資訊28at.com

  • 整體最大吞吐量提升 67%
  • LOAD 下降 37% 左右
  • 高負載情況下 BIO 多次出現進程夯住現象,NIO 相對較穩定
  • 線程數減少 98% 左右

五、總結

NIO 架構的改造工作量相當巨大,中間也經歷了一些曲折,但是最終的結果令人滿意。得益于 ShardingShpere 本身內核層面的高性能加上本次 NIO 改造后,彩虹橋在 DAL 中間件性能層面基本上可以算是第一梯隊了。zjl28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-16532-0.html彩虹橋架構演進之路-性能篇

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 聽說你會架構設計?來,弄一個微信群聊系統

下一篇: 使用Ray輕松進行Python分布式計算

標簽:
  • 熱門焦點
  • 小米降噪藍牙耳機Necklace分享:聽一首歌 讀懂一個故事

    在今天下午的小米Civi 2新品發布會上,小米還帶來了一款新的降噪藍牙耳機Necklace,我們也在發布結束的第一時間給大家帶來這款耳機的簡單分享?,F在大家能見到最多的藍牙耳機
  • iPhone賣不動了!蘋果股價創年內最大日跌幅:市值一夜蒸發萬億元

    8月5日消息,今天凌晨美股三大指數高開低走集體收跌,道指跌0.41%;納指跌0.36%;標普500指數跌0.52%。熱門科技股也都變化極大,其中蘋果報181.99美元,跌4.8%,創
  • 三言兩語說透設計模式的藝術-單例模式

    寫在前面單例模式是一種常用的軟件設計模式,它所創建的對象只有一個實例,且該實例易于被外界訪問。單例對象由于只有一個實例,所以它可以方便地被系統中的其他對象共享,從而減少
  • “又被陳思誠騙了”

    作者|張思齊 出品|眾面(ID:ZhongMian_ZM)如今的國產懸疑電影,成了陳思誠的天下。最近大爆電影《消失的她》票房突破30億斷層奪魁暑期檔,陳思誠再度風頭無兩。你可以說陳思誠的
  • 阿里大調整

    來源:產品劉有媒體報道稱,近期淘寶天貓集團啟動了近年來最大的人力制度改革,涉及員工績效、層級體系等多個核心事項,目前已形成一個初步的“征求意見版”:1、取消P序列
  • 馮提莫簽約抖音公會 前“斗魚一姐”消失在直播間

    來源:直播觀察提起“馮提莫”這個名字,很多網友或許聽過,但應該不記得她是哪位主播了。其實,作為曾經的“斗魚一姐”,馮提莫在游戲直播的年代影響力不輸于現
  • 造車兩年股價跌六成,小米的估值邏輯變了嗎?

    如果從小米官宣造車后的首個交易日起持有小米集團的股票,那么截至2023年上半年最后一個交易日,投資者將浮虧59.16%,同區間的恒生科技指數跌幅為52.78%
  • 三星Galaxy Z Fold/Flip 5國行售價曝光 :最低7499元/12999元起

    據官方此前宣布,三星將于7月26日也就是明天在韓國首爾舉辦Unpacked活動,屆時將帶來帶來包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy
  • 2299元起!iQOO Pad明晚首銷:性能最強天璣平板

    5月23日,iQOO如期舉行了新品發布會,除了首發安卓最強旗艦處理器的iQOO Neo8系列新機外,還在發布會上推出了旗下首款平板電腦——iQOO Pad,其最大的賣點
Top 主站蜘蛛池模板: 冷水江市| 安庆市| 沂源县| 宕昌县| 鲁山县| 南皮县| 宁阳县| 玉溪市| 铜鼓县| 临湘市| 梅州市| 昌江| 茂名市| 万全县| 剑阁县| 沧州市| 景德镇市| 长白| 长泰县| 稻城县| 苗栗县| 杭州市| 嘉祥县| 崇州市| 华宁县| 九龙坡区| 岗巴县| 基隆市| 金塔县| 乌恰县| 勐海县| 从江县| 广南县| 浦北县| 安徽省| 昌江| 沅陵县| 望奎县| 苗栗市| 龙井市| 库伦旗|