分佈式數據庫排序及優化

作者:vivo 互聯網數據庫團隊 - Xia Qianyong

一、背景

1.1 分佈式數據庫架構

當前分佈式數據庫架構有不少,但是總體架構相差不大,主要組件都包含協調節點、數據分片、元數據節點、全局時鐘。一種常見的分佈式架構如下圖:

圖片

1.2 排序問題

分佈式數據庫中排序也是一種重要的功能。一條查詢排序語句 select *from t1 order by field1,需要查詢的數據可能會分佈在不同的數據分片中。這就需要 proxy 對爲不同數據分片返回的有序數據進行重排序,然後後給 client 返回全局有序的數據。

當相關的數據量不大時,proxy 可把不同數據分片返回的數據保存在內存中,然後對內存中的數據重排序後返回給 client。當相關的數據量比較大時,如果把待重排序數據放到內存中則可能會導致 OOM,如果把待重排序數據暫存在 proxy 的磁盤中,則也有耗盡磁盤的風險並且會存在大量的磁盤 IO。下面將介紹一種分佈式數據庫排序及優化方法。

二、解決方案

2.1 排序方案介紹

爲了提高分佈式排序的性能,每個數據分片本身也要參與排序。這樣在 proxy 上得到分片返回的數據是有序的,proxy 對有序的數據重排序可以採用歸併排序或者優先級隊列排序方法,大大減輕 proxy 的壓力。

可以根據 proxy 內存大小配置 sort buffer 大小,通常默認爲 10M。如果一次查詢語句關聯 N 個數據分片,則需要到 sort buffer 按照 N 份進行切分,每個數據分片對應切分後的 sort buffer 大小爲 10M/N。

直接在內存中進行,具體步驟如下圖:

圖片

2.2 排序方案缺陷

這種方法只能滿足小數據量排序,當排序的數據量較大我們可以選擇調大 proxy 上的 sort buffer。但是調大 sort buffer 會佔用更多的內存資源,所以不能無限制的調大 sort  buffer。

2.3 排序優化思路

把數據分片返回的有序數據保存到磁盤上,然後對磁盤數據進行重排序。下面將介紹一種優化方案,針對大數據量進行分佈式排序的方法。

三、優化方案

3.1 排序方案介紹

由於內存的限制,在內存中對大數據量數據進行歸併排序方案不可行,針對這種情況需要把數據分片返回的數據暫存在磁盤中。具體優化方案步驟如下圖:

圖片

1)client 向 proxy 下發排序查詢語句 select *from t1 order by id。

2)proxy 根據分片鍵向相關的數據分片 group1、group2 下發排序查詢語句 select *from t1 order by id。

3)數據分片在本地對數據進行查詢排序後,發送有序數據到 proxy。

4)proxy 把數據分片返回的有序數據存儲在數據分片對應的磁盤文件中。

5)使用優先級隊列排序方法進行重排序:

3.2 排序方案缺陷

3.3 排序優化思路

這種方法是 proxy 把相關數據分片的有序數據全部拉取到 proxy 上,然後再進行排序。我們是否分批從數據分片拉取數據,批量數據處理後再從數據分片拉取下一批數據呢?下面將介紹一種分批排序的方法。

四、最終方案

4.1 排序方案介紹

proxy 上磁盤上不保存數據分片數據,一次從數據分片拉取固定大小的有序數據,proxy 把拉取的數據填充到分片對應的 sort buffer,sort buffer 中數據使用完後再次從對應的數據分片上拉取。具體步驟如下圖:

圖片

1)client 向 proxy 下發排序查詢語句 select *from t1 order by id。

2)proxy 根據分片鍵向相關的數據分片 group1、group2 下發排序查詢語句 select *from t1 order by id。

3)數據分片在本地對數據進行查詢排序後,發送固定大小有序數據到 proxy。

4)proxy 把數據分片返回的有序數據存儲在數據分片對應的 sort buffer 中。

5)優先級隊列排序。

4.2 排序方案分析

針對優化方案 3.2 存在的三個缺陷的解決情況。

缺陷 1:proxy 需要收集完所有相關數據分片的有序數據存入磁盤可以解決內存不夠的問題,但是磁盤也是有限的,當數據量太大在 proxy 上磁盤也可能無法容納需要排序的數據。

解決情況:從圖中可以看出 proxy 的磁盤上不保存數據分片的數據。

缺陷 2 :proxy 上把數據存在磁盤,存在大量的磁盤 IO。

解決情況:proxy 的磁盤上不保存數據分片的數據,所以不存在磁盤壓力太大問題。

缺陷 3:select * from t1 order by field1 limit 100w 爲例:如果本次查詢的數據在 50 個數據分片上,則 proxy 節點需要從每個數據分片上拉取 100w 數據然後保存到磁盤上,需要保存 5000W 數據 (100w*50),而 client 只需要 100w 條數據,浪費了很多網絡帶寬和磁盤 IO。

解決情況:每次從數據分片拉取固定大小的數據,邊排序邊給客戶端返回數據,當給客戶端返回的數據達到 100W 時則完成本次查詢,網絡帶寬浪費得到大大改善。

假設 proxy 上數據分片對應的 sort buffer 大小爲 2M,從數據分片拉取的數據量:

4.3 方案使用限制

1)數據分片節點本身支持排序,絕大多數數據分片都是支持排序的。

2)數據分片需要支持分批讀取。

以 MySQL 作爲數據分片爲例,則需要 proxy 上可以使用流式查詢或者遊標查詢。另外有些分佈式數據庫在設計時就考慮到一些分佈式的問題,它們數據分片節點在查詢結束前一直保留上下文,它們的分批讀取性能更高,這裏就不在舉例。

五、參考文獻

1.JDBC 操作 MySQL(3)—查詢

2.MySQL JDBC StreamResult 通信原理淺析

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/42t4S93sJhXC2r_7DvYSZA