原創: 孫正方後端
4月12日,GOPS全球運維大會在深圳隆重召開,全球運維大會是國內第一個運維行業大會,愛可開源社區在基礎架構及DevOps解決方案專場分享了《基於分佈式中間件的SQL改造指南》的主題演講。網絡
本文由根據演講內容進行整理,但願有助於你們對分佈式架構的理解及SQL改造實踐。架構
在通常SQL中,一個單表查詢的SQL每每是最簡單的,而在中間件中也沒什麼區別,中間件中將一個對於單表的字段查詢做爲最簡單的SQL進行處理。運維
下面先來簡單的回顧下中間件中的表格處理的最基礎方式。分佈式
中間件會按照在配置文件中既定的數據拆分的設置,對於「用戶表」這個表格的數據進行拆分,將每條經過中間件插入的數據按照規則進行分佈,圖上給的例子是按照「用戶表」的ID奇偶性進行了數據的拆分。優化
有了合理的數據分佈以後就是中間件是如何在須要的時候取用數據,在中間件中,對於基礎SQL,也就是單表的數據查詢分爲一下兩個狀況:spa
在查詢的簡單SQL附帶有分片條件時,中間件根據SQL語義解析的結果,根據這個分片條件對於數據可能存在的DB進行計算,最終把SQL轉發到對應的DB中進行執行,查詢出最終的正確結果。中間件
在這個過程當中就存在一個現象,即「這一個查詢須要等待最慢的那個DB查詢結束」。blog
上文中有說起廣播類型的簡單SQL存在一個特徵「須要等待最慢的那個DB查詢結束」,當分片數量持續上升的時候,以下圖所示的場景,須要等待的鏈接數量會持續變多。排序
能夠經過幾率的方法分析下當鏈接數量增加的時候會發生什麼變化:
經過Matlab對於中間件廣播查詢的場景進行了以下的模擬,能夠發如今隨着須要等待鏈接數量的上升,總體的中間件響應速度會有一個成倍的降低,從單個鏈接平均5ms的查詢延遲一直上升到100鏈接時候的接近15ms的總體延遲。
針對以上的場景,提出在中間件中進行單表查詢的時候,儘可能下降單個SQL涉及到的後端DB數量,具體方法是在SQL中給表格添加分片列的限定條件,就像select * from 用戶表 where ID = 1中的這個條件ID =1。
單表查詢不能覆蓋應用對於SQL的需求,中間件中就引入了ER關係的概念。
ER關係指的是兩個表格在邏輯上就擁有的從屬關係,以下圖中所示的用戶表和訂單表:
當兩個表或者更多的表格存在這樣邏輯上的從屬關係的時候,在中間件中把這些關係定義爲ER關係,而且當一個查詢語句有且僅有存在ER關係的表格關聯組成的時候,這個SQL被稱爲「ER表格JOIN」。
當兩個表格可以被定義爲ER關係的時候,中間件可以按照之間的關聯關係組織數據的存儲,最後的存儲方式以下圖所示:
能夠看到大體的結果就是子表(訂單表)的數據會被存放在父表(用戶表)對應數據的DB節點。
當出現這種數據分佈的時候,就能夠在DB1中查詢到上例中張三的用戶和他的全部數據,因此中間件就能直接把SQL語句下發到對應節點進行執行。
能夠看到ER的這種查詢方式是有必定的侷限的,須要把查詢的表格聲明爲ER關係,而且ER關係仍是單向的,就是一個表只能是某一個表的子表,一個分片表不能擁有兩個父表。
其次就是因爲這個ER關聯的查詢處理是和上文的簡單查詢在本質上是同樣的,就是查詢SQL下發到DB中來執行,因此在注意事項上也是一致的,儘可能在使用的時候提供可以肯定分片的限定條件。
事實上上文全部的查詢方法限制都是很是大的,可是每每應用的SQL沒法知足於被限制在這麼侷限的範圍內,那中間件中就有另外一種機制來實現更普遍意義上的SQL執行,跨庫表格關聯查詢。
當個人SQL內容沒法被定義進入上文的兩個「簡單SQL」或者是「ER SQL」的時候,中間件就會使用這種跨庫表格JOIN的方式來處理這個問題,固然並不是全部的中間件都有實現對應的功能,在這裏僅討論實現的部分中間件的實現邏輯。
如下是在中間件中執行跨庫表查詢的這麼一個大體執行邏輯圖,圖中能夠看到總體的執行邏輯是從每一個DB中分別取TABLEA和TABLEB的數據,最終在中間件中進行數據的整理組織和對比:
具體的跨庫查詢的執行過程能夠被概括爲如下的幾個步驟:
根據配置文件中對於TABLEA和TABLEB的描述將表格的數據分別從DB中進行查詢
對於查詢獲得的表格數據進行整理,分別按照ID的值(關聯列的值)進行排序和歸檔
對於歸檔完成的數據進行ID值的對比,計算關聯結果
在這個過程當中會產生幾個方面的資源消耗:
組織數據產生的臨時內存存儲消耗
對比數據產生的CPU消耗
查詢每個存在DB中的表數據產生的鏈接數以及網絡消耗
另外一個方面就是中間件因爲不能存儲真實的數據,因此沒法像MySQL優化器同樣提早計算不一樣表格的聚合代價,這麼一來,中間件就直接按照SQL中原有的表格聚合順序進行數據的聚合和整理,這可能帶來如下的SQL執行的計劃。
案例中用戶表因爲表格順序的問題先和沒有直接關係的商品表進行了表關聯,這樣一來這裏的中間結果就出現了一個笛卡爾積,也就是無條件無字段的關聯結果,其結果爲雙邊數據的乘積:
1000X1000=1000000
若是SQL中的表格順序進行進一步的優化,則能夠在一樣的SQL中得到如下圖中的執行順序。
此次咱們優化完成以後的查詢中間結果將由用戶表和有關係的訂單表優先聚合完成,由於他們之間的關係,最多存在2000條中間結果,相比與上例中的1000000條來講,整個SQL執行效率上獲得了很大的優化。
針對以上的幾種消耗類型,能夠經過如下的幾個手段進行下降消耗的量以獲取最好的執行效果:
添加足夠的限定條件
使用重複率低的列進行關聯
經過手動調整SQL中表格順序的手段來進行執行計劃的調整
從DB存儲到真正成熟的分佈式DB,分佈式中間件的架構是整個過程當中的重要一環,在分佈式架構的過程當中,對SQL的規範和使用存在一些特別要求,應用在向這方面進行改造和適應的過程當中須要更多的考慮到中間件架構帶來的限制及相關注意事項。總體概括可分爲如下內容:
1.在中間件中儘可能使用分片條件進行數據的查詢,不論整個SQL是屬於簡單SQL,ER查詢或者是複雜查詢。
2.在複雜查詢的狀態下,優化方向爲中間件中處理的數據儘可能少,此目標能夠經過給表格添加限定條件,選擇更加劇復率低的關聯列以及調整SQL中的表格關聯順序來達成。