TiDB 助力客如雲餐飲 SaaS 服務

客如雲成立於 2012 年,是全球領先、 國內最大的 SaaS 系統公司。 目前面向餐飲、 零售等服務業商家, 提供軟硬一體的新一代智能化前臺、收銀等 SaaS 雲服務,包括預訂、排隊、外賣、點餐、收銀、會員管理、進銷存等系統服務,並將數據實時傳達雲端。我們是客如雲的大數據基礎架構組,負責公司的大數據架構和建設工作,為公司提供大數據基礎數據服務。

業務發展遇到的痛點

1. 隨著公司業務架構越來越複雜,技術架構組需要在服務器端與應用端儘可能的通過微服務化實現業務解耦,同時需要第三方熔斷服務機制來保證核心業務正常運行。數據庫層面,為了保證高併發的實時寫入、實時查詢、實時統計分析,我們針對地做了很多工作,比如對實時要求較高的服務走緩存、對大表進行分庫分表操作、對有冷熱屬性的大表進行歸檔、庫分離,雖然用大量人力資源解決了部分問題,但是同時也帶來了歷史數據訪問、跨庫分表操作、多維度查詢等問題。

2. 大數據量下,MySQL 稍微複雜的查詢都會很慢,線上業務也存在單一複雜接口包含執行幾十次 SQL 的情況,部分核心交易大庫急需解決訪問性能。

3. 餐飲行業有明顯的業務訪問高峰時間,高峰期期間數據庫會出現高併發訪問,而有些業務,比如收銀,在高峰期出現任何 RDS 抖動都會嚴重影響業務和用戶體驗。

4. 傳統的數倉業務往往有複雜的 T+1 的 ETL 過程,無法實時的對業務變化進行動態分析和及時決策。

TiDB 助力客如雲餐飲 SaaS 服務

業務描述

大數據的 ODS(Operational Data Store)以前選型的是 MongoDB,ODS 與支持 SaaS 服務的 RDS 進行數據同步。初期的設想是線上的複雜 SQL、分析 SQL,非核心業務 SQL 遷移到大數據的 ODS 層。同時 ODS 也作為大數據的數據源,可以進行增量和全量的數據處理需求。但是由於使用的 MongoDB,對業務有一定侵入,需要業務線修改相應查詢語句,而這點基本上遭到業務線的同學不同程度的抵制。同時目前大數據使用的是 Hadoop + Hive 存儲和訪問方案,業務線需要把歷史明細查詢遷移到 Hadoop ,然後通過 Impala、Spark SQL、Hive SQL 進行查詢,而這三個產品在併發度稍微高的情況下,響應時間都會很慢,所以大數據組在提供明細查詢上就比較麻煩。

同時更為棘手的是,面對客戶查詢服務(歷史細則、報表等),這類查詢的併發會更高,而且客戶對響應時間也更為敏感,我們首先將處理後的數據(歷史細則等)放在了 MongoDB 上(當時 TiDB 1.0 還沒有 GA,不然就使用 TiDB 了),然後針對 OLAP 查詢使用了 Kylin ,先解決了明細查詢的問題。 但是由於業務很複雜, 數據變更非常頻繁,一條數據最少也會經過五六次變更操作。報表展現的不僅是當天數據,涉及到掛賬、跨天營業、不結賬、預定等複雜狀況,生產數據的生命週期往往會超過一個月以上。所以當前的 OLAP 解決方案還有痛點,所以後續我們要把 OLAP 查詢移植一部分到 TiDB 上面去,來減輕 Kylin 的壓力並且支持更加靈活的查詢需求,這個目前還在論證當中。

同時,我們發現 TiDB 有一個子項目 TiSpark, TiSpark 是建立在 Spark 引擎之上,Spark 在機器學習領域裡有諸如 MLlib 等諸多成熟的項目,算法工程師們使用 TiSpark 去操作 TiDB 的門檻非常低,同時也會大大提升算法工程師們的效率。我們可以使用 TiSpark 做 ETL,這樣我們就能做到批處理和實時數倉,再結合 CarbonData 可以做到非常靈活的業務分析和數據支持,後期根據情況來決定是否可以把一部分 Hive 的數據放在 TiDB 上。

新老框架如下圖:

TiDB 助力客如雲餐飲 SaaS 服務

圖:老的框架

TiDB 助力客如雲餐飲 SaaS 服務

圖:新的框架

TiDB 測試應用

1. 配置

阿里雲服務器:

  • TiDB / PD:3 臺 i1 型 機器,16c 64g ;
  • TiKV :5 臺 i2 型機器,16c 128g, 1.8T*2 每臺機器部署兩個 KV;
  • 監控機一臺。

目前我們將線上 RDS 中三個庫的數據通過 Binlog 同步到 TiDB ,高峰期 QPS 23k 左右,接入了業務端部分查詢服務;未來我們會將更多 RDS 庫數據同步過來,並交付給更多業務組使用。因為 TiDB 是新上項目,之前的業務線也沒有線上 SQL 遷移的經歷,所以在寫入性能上也沒有歷史數據對比。

TiDB 助力客如雲餐飲 SaaS 服務

2. 性能對比

(1)查詢一個索引後的數字列,返回 10 條記錄,測試索引查詢的性能。

TiDB 助力客如雲餐飲 SaaS 服務

(2)查詢兩個索引後的數字列,返回 10 條記錄(每條記錄只返回 10 字節左右的 2 個小字段)的性能,這個測的是返回小數據量以及多一個查詢條件對性能的影響。

TiDB 助力客如雲餐飲 SaaS 服務

(3)查詢一個索引後的數字列,按照另一個索引的日期字段排序(索引建立的時候是倒序,排序也是倒序),並且 Skip 100 條記錄後返回 10 條記錄的性能,這個測的是 Skip 和 Order 對性能的影響。

TiDB 助力客如雲餐飲 SaaS 服務

(4)查詢 100 條記錄的性能(沒有排序,沒有條件),這個測的是大數據量的查詢結果對性能的影響。

TiDB 助力客如雲餐飲 SaaS 服務

(5)TiDB 對比 MySQL 複雜 SQL 執行速率:

  • Table 1 TiDB 數據量 5 千萬,MySQL數據量 2.5 千萬;
  • Table 2 TiDB 數據量 5 千萬,MySQL數據量 2.5 千萬;
  • Table 3 TiDB 數據量 5 千萬,MySQL數據量 2.5 千萬。

a. 對應 SQL:

SELECT sum(p.exempt_amount) exempt_amount FROM table1 p JOIN table2 c ONp.relate_id=c.id AND p.is_paid = 1
andp.shop_identy in(BBBBB)
andp.brand_identy=AAAAA
andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8
WHEREc.brand_identy = AAAAA
ANDc.shop_identy in(BBBBB)
ANDc.trade_type in(1,3,4,2,5)
ANDc.recycle_status=1
AND c.trade_statusIN (4,5,10)
ANDp.payment_time BETWEEN '2017-08-11 16:56:19' AND '2018-01-13 00:00:22'
ANDc.status_flag = 1
ANDc.trade_pay_status in(3,5)
AND c.delivery_type in(1,2,3,4,15)
TiDB 助力客如雲餐飲 SaaS 服務

b. 對應 SQL:

SELECT sum(c.sale_amount)tradeAmount,sum(c.privilege_amount) privilege_amount,sum(c.trade_amount)totalTradeAmount,sum(c.trade_amount_before) tradeAmountBefore 
FROM (SELECTc.sale_amount,c.privilege_amount,c.trade_amount,c.trade_amount_before
FROM table1p
JOIN table2c ON p.relate_id=c.id
andp.shop_identy in(BBBBB)
andp.brand_identy=AAAAA
andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8
and c.brand_identy = AAAAA
ANDc.shop_identy in(BBBBB)
ANDc.trade_type in(1,3,4,2,5)
ANDc.recycle_status=1 AND c.trade_statusIN (4,5,10)
ANDp.payment_time BETWEEN '2017-07-31 17:38:55' AND '2018-01-13 00:00:26'
ANDc.status_flag = 1
ANDc.trade_pay_status in(3,5)
ANDc.delivery_type in(1,2,3,4,15)
ANDp.payment_type not in(4,5,6,8,9,10,11,12)
GROUP BY p.relate_id ) c
TiDB 助力客如雲餐飲 SaaS 服務

c. 對應 SQL:

SELECT SUM(if(pay_mode_id=-5 or pay_mode_id = -6,0,IFNULL(pi.face_amount, 0) - IFNULL(pi.useful_amount, 0) -IFNULL(pi.change_amount, 0))) redundant
FROM table2c
JOIN table1 p ON c.id = p.relate_id AND c.brand_identy=p.brand_identy
JOIN table3pi ON pi.payment_id=p.id AND pi.pay_status in (3,5,10)
AND pi.brand_identy=p.brand_identy ANDpi.pay_mode_id!=-23
andp.shop_identy in(BBBBB)
andp.brand_identy=AAAAA
andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8
WHEREc.brand_identy = AAAAA
ANDc.shop_identy in(BBBBB)
ANDc.trade_type in(1,3,4,2,5)
ANDc.recycle_status=1
AND c.trade_statusIN (4,5,10)
ANDp.payment_time BETWEEN '2017-07-31 17:38:55' AND '2018-01-13 00:00:26'
ANDc.status_flag = 1
ANDc.trade_pay_status in(3,5)
AND c.delivery_type in(1,2,3,4,15)
TiDB 助力客如雲餐飲 SaaS 服務

d. 對應 SQL:

SELECT t.id tradeId,sum(t.trade_amount - t.trade_amount_before) AS roundAmount, sum(-p.exempt_amount) AS exemptAmount
FROM table2t
LEFT JOINtable1 p ON p.relate_id = t.id
LEFT JOINtable3 pi ON pi.payment_id = p.id
WHEREt.brand_identy =AAAAA AND t.trade_status IN (4,5,10)
ANDt.trade_pay_status IN (3,4,5,6,8) ANDp.payment_type IN (1,2)
ANDpi.pay_mode_id !=-23 ANDp.is_paid=1 AND t.status_flag=1
AND t.shop_identy IN(<123個商戶號碼>)
GROUP BY t.id
TiDB 助力客如雲餐飲 SaaS 服務

e. 對應 SQL:

SELECT t.id tradeId, 
sum(t.trade_amount- t.trade_amount_before) AS roundAmount,

sum(-p.exempt_amount)AS exemptAmount
FROM table2t
JOIN table1 p ON t.id = p.relate_id
WHERE t.brand_identy = AAAA
ANDt.trade_status IN(4,5,10)
ANDt.trade_pay_status IN (3,4,5,6,8)
ANDp.is_paid=1 AND t.status_flag=1
group by t.id ;
TiDB 助力客如雲餐飲 SaaS 服務

(6)OLTP 對比測試結果:

TiDB 助力客如雲餐飲 SaaS 服務

TiDB 助力客如雲餐飲 SaaS 服務

TiDB 助力客如雲餐飲 SaaS 服務

(7)簡單測試結論:

  • 不管是索引查詢、分頁查詢、線上業務級的負載查詢,大數據量下 TiDB 的性能都比 MySQL 更強;
  • TiDB 整體性能表現滿足我們業務的需求。

生產使用情況

目前線上已經存儲超過 6 個月的數據,總數據量幾 T,支持線上的查詢和分析需求,很多一般複雜度 OLAP 查詢都能夠在秒級返回結果。TiSpark 我們也調試通過,準備移植一些支持 OLAP 的 ETL 應用做到實時 ETL。目前 TiDB 生產還有很多優化的空間,比如系統參數,SQL 的使用姿勢,索引的設計等等。

未來規劃

  • 已經有一個交易量很大業務部門在向我們瞭解 TiDB,有可能要使用 TiDB 作為線上交易系統;
  • 後續大數據也會使用 TiSpark 來做 OLAP 查詢和數據處理,同時也可能會作為 Kylin 的數據源;
  • 可以預見將來不管是 OLTP,還是 OLAP 場景,TiDB 都會在客如雲發揮越來越重要的作用。


分享到:


相關文章: