轉轉業務開發對 TiDB 的使用心得

首先爲大家介紹 TiDB 是怎麼引入轉轉的,包括背景和具體引入過程。

TiDB 是 18 年引入轉轉的。原因是轉轉業務使用 MySQL 時遇到了一些問題,於是轉轉數據庫負責人冀浩東就主張引入 NewSQL 數據庫。

我想簡單和大家分享一下 TiDB 引用、試用、內部推廣的過程。

轉轉引入 TiDB 想解決 MySQL 的這些問題:數據量大,如何快速水平擴展存儲;大數據量下,如何快速 DDL;分庫分表造成業務邏輯非常複雜;常規 MySQL 主從故障轉移會導致業務訪問短暫不可用。

配合 DBA 啓動調研後,最終選擇 TiDB。

選型過程:

首先是調研測試,分爲功能測試和性能測試;

然後找一個業務驗證,選擇一個場景去測試,看是否符合需求;

最後是業務上線。首先是涉及到數據遷移,用的比較多的是雙寫,之後切流量。

我們對 TiDB 做了一些測試,左邊的這組數據是讀寫情況比較均勻的時候 TiDB 的性能表現,每上一個臺階併發數會高一些。右邊是讀多寫少,比較符合互聯網的應用場景,這塊明顯比讀寫均勻要好很多了,這是對 TiDB 的一個摸底。

接下來是業務場景。我們選擇了電商場景下非常重要的 IM 業務來做試接入。選擇 IM 的原因第一是非常相信 TiDB 這個產品,第二是相信我們自己的判斷。IM 實際上是一個比較複雜的系統,比如說羣消息、用戶、聯繫人,我們就又瘋狂了一把,選擇了最複雜的業務——聯繫人。選擇它的原因是根據測試數據發現 TiDB 在讀寫均勻的情況下性能會下降。聯繫人的收發都伴隨着許多讀寫,屬於讀寫比較均勻的業務,如果這個業務都沒問題,大部分場景應該都可以適應。我們驗證的步驟是:第一步是構造數據從線上扒一份數據拉到線下,再自己寫數據去模擬線上流量。

看右邊的三個圖,最上面只有 MySQL 時的情況,很多毛刺。接入 TiDB 後延時變高,但是平滑,對業務體驗更好。如果從性能角度來說, TiDB 在單個場景下很難比得過 MySQL,但在吞吐量大的情況下,不管寫入怎麼樣,TiDB 都很平滑,這就是我們選擇 TiDB 很重要的一個原因。

測試合格之後就是上線,數據遷移先主從同步,再雙寫遷移。

我們的方法是:先拉一份從庫到 TiDB,再保持主從同步,當數據追齊之後開雙寫(我們一般用 MQ),之後可以觀察一下,沒問題切讀流量,一點點分比例切,最後再把寫切過去,這樣業務就基本上線。

接下來和大家說一下我們使用 TiDB 時遇到的一些問題和應對辦法。

首先向大家介紹一個場景,手機推送。需要我們維護一個用戶 — 設備 ID 的映射關係,因爲推送是基於設備 ID 的,業務場景是 UID — 設備 ID — 第三方服務。

數據變更場景有 1 個賬號登錄多個手機也有 1 個手機登錄多賬號的情況。之前用 MySQL 的時候的時候,有的手機取不到設備號,我們會寫個默認值。遷到 TiDB 後發現了一個奇怪的場景,默認值這條記錄會被頻繁併發更新。我們的解決方式是業務進行優化,過濾默認值數據,但根本原因在鎖這塊。

還有一個是樂觀鎖的問題。比如商品狀態的流轉場景,發佈者發佈商品後狀態是 0,發佈者可以把商品下架,狀態從 0 變成 1。但是買家想買商品的話,拍下後狀態從 0 變成 2。我們來看一下這兩張表的事務:

第一個事務 Begin,我想把它下架既狀態設成 1,同時用 where id=1 and status=0 做條件,才能下架成功,同時判斷我影響的行數是不是 1 條,是的話就 Commit

第二個線程是買家,他想把狀態更新成 2,他也判斷是不是影響了 1 條行數,是的話就 Commit。

MySQL 的處理方式是:

假設這一時刻,線程 1 執行到左圖藍箭頭處,線程 2 執行到右圖藍箭頭處,線程 2 想提交 update 時就會被鎖住。等線程 1 Commit 之後線程 2 發現影響記錄不是 1 條, 線程 2 更新失敗,商品下架不能購買。

TiDB 的處理方式是:

因爲TiDB 不是行級鎖,是樂觀鎖,先 Commit 看能不能成功。左邊 Commit 成功,右邊就會因爲有衝突 Commit 失敗。

我們遇到的問題場景是:萬一我需要發 MQ 或做RPC 記錄怎麼辦?買家買下商品後生成訂單要 RPC,但是事務 Commit 失敗了,RPC 回滾不了。

TiDB 在開啓一個事務的時候,我的一段讀寫操作都是有緩存的,所以在提交的時候纔去判斷是否成功。

這裏想和大家聊的是事務的實現方式 — 兩階段提交。

假設 TiDB 的處理方式是:TS1 線程 1 開始,TS2 線程 2 開始,TS3 線程 1 提交,TS2 線程 2 提交。誰先開始不重要,關鍵是誰先提交。

它的實現方式其實就是 L 列和 W 列,我也嘗試去研究了一下,但是發現真的很複雜,我儘量簡化模型。

假設我有一個表,它有一個 status。我爲了實現這個事務會給它額外兩列,一個 lock 一個 write。lock 列可以鎖一些行,write 列可以寫一些更新的信息。 線程 1 嘗試提交的那一刻先嚐試加鎖, 如果發現數據沒被加鎖,則判斷 W 列的時間戳是不是大於 X,如果大於就有衝突,都沒問題就加鎖。加完鎖以後,就要寫數據,寫完之後更新時間戳 T3,提交事務,然後釋放鎖。

第一步先 Prewrite,加鎖寫數據,然後再 Commit 提交變更。

TS4 是 2 事務提交時間,2 事務開始時間小於 TS3,提交時發現 TS2 < TS3,有衝突,這個事務就不能提交。

知道這個原理之後我們怎麼做呢?在數據庫層併發可能會出問題時,業務就把它串行化處理

最後一個部分是對未來的展望。

業務方面想把 TiDB 與 MySQL 互補, 根據數據量和應用場景選擇和使用 TiDB。

作者介紹

陳東,轉轉基礎架構部負責人

本文轉載自 AskTUG

原文鏈接

https://asktug.com/t/tidb/1024

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章