Categories
程式開發

TiDB on Kubernetes 最佳實踐


隨著Kubernetes(K8s) 的全面成熟,越來越多的組織開始大規模地基於K8s 構建基礎設施層。 然而,考慮到數據庫在架構中的核心地位與K8s 在有狀態應用編排上的短板,仍有不少組織認為在K8s 上運行核心數據庫會帶來頗高的風險。 事實上,在K8s 上運行TiDB 不僅能實現企業技術棧的統一,降低維護成本,還能帶來更高的可用性與安全性。 本次分享將介紹TiDB 在K8s 上的運維管理系統TiDB Operator,再從各類故障場景入手剖析TiDB on K8s 如何實現高效的故障自愈並保障數據安全。 最後,我們會分享來自國內外一線公司的TiDB Operator 生產環境案例,並總結出一套TiDB on K8s 最佳實踐。

要不要在Kubernetes 上運行TiDB ?

這個問題其實一直以來也有很多的爭議。 大家都知道,Kubernetes 的很​​多概念是為無狀態應用(比如微服務)所設計的。 由於雲原生技術的不斷普及,Kubernetes 目前在國內外的很多技術領域都得到大規模的落地,有一種全盤上Kubernetes 的趨勢。 但在這期間也有不少人提出了質疑,比如:是不是所有的業務場景都適合Kubernetes ? 我們的組織是不是真的需要Kubernetes? 這樣的爭議,其實這背後的各種聲音都有各自的出發點。

首先Kubernetes 有沒有價值? 肯定有價值,它的普及度就是很好的證明。 那Kubernetes 有沒有問題? 當然也有問題,比如, Kubernetes 會增上技術上的複雜度,此外它還有有比較大的遷移成本。

回到TiDB 要不要在Kubernetes 上面運行這個問題。 答案其實往往來自於你當前的技術棧和技術團隊。

舉個例子,假如你的大部分應用已經上了Kubernetes,而且你的工程師也對Kubernetes 很熟悉,在Kubernetes 上去做一些業務,他感覺非常舒服,那麼TiDB 就不該成為一個例外。 換句話說,如果當前整個組織的業務都已經上Kubernetes 了,但還需要專門招一個運維團隊在虛擬機上運維TiDB 的話,不僅會增加額外的維護成本,也沒辦法發揮出技術棧投資的規模優勢。

那麼,在K8s 運行TiDB,我們想要什麼呢? 通常,我們想要的是TiDB 可以和我們在K8s 上運行的微服務一樣,可以做到聲明式管理,通過K8s 實現TiDB 的自動化運維以及彈性資源配置。 我想擴容的時候,並不需要去專門開新的物理機,專門購買一批機器,而是直接從整個的K8s 資源池中,彈性的給TiDB 分配一些資源進行擴容,然後再縮容之後又把這些資源還回去。

可是,現在的情況是,即使很多公司已經上了K8s,但對於把數據庫放在K8s 上運行還是有一定的擔憂,這個擔憂主要在哪兒呢?

從我個人了解到的信息來說,核心是穩定性,穩定性,最後還是穩定性 ,因為畢竟我們要上的是數據庫。 幾年前,大家剛開始上K8s 的時候,會覺得我的業務上在K8s 上用的很爽,那要不要把數據庫也搞上去? 那總會有一種聲音是,數據庫怎麼能上K8s 呢? 我們數據庫的穩定性要求比K8s 還要高啊! 假如K8s 掛了,那可能只是線上的微服務無法提供服務,但是假如數據庫掛了,我們不僅無法提供服務,還有可能面臨數據丟失的風險。 所以通常來說,在組織中,數據庫可靠性是處於一個核心地位的,也因此在數據庫上K8s 時,一個核心的擔憂就是可靠性。

那麼,我們在部署傳統數據庫應用的時候,是怎麼保證穩定性的? 一般來說,是開幾台固定的物理機,然後我們會把數據庫的Binary 傳上去運行起來,這時候要點就是,運行起來之後只要不出問題就不要再動它(If it works don’t touch it)。 即使要動它,也需要經過一個非常嚴苛的審計流程和預演,保證它最佳的穩定性。 聽起來,對於傳統的關係型數據庫而言,高度動態化的K8s 環境並不是一個很好的解決方案。

那為什麼還會推薦大家把TiDB 放在K8s 上運行呢?

第一點,TiDB 本身能夠適應動態化的K8s 環境。

  • TiDB 可以多副本做容錯,當掛掉一個集群當中的小數節點並不會對整個集群的運行產生影響;
  • TiDB 能夠很好的借助K8s 環境做水平伸縮;
  • TiDB 提供了開箱自用的可觀測性,大家基本上把TiDB 部署起來,就可以看到TiDB 的所有指標,即使是在一個動態化混部的環境裡面,也能很清楚的明白TiDB 現在的狀態是什麼,即使有副本掛掉,也沒有問題。

第二點,反回來,K8s 也能很高效的去撬動TiDB 的潛力。

  • 聲明式API 簡化集群管理,作為一個分佈式數據庫,TiDB 的管理會比傳統的單機數據庫相對複雜一點,而在K8s 上,它的聲明是API,就能把這一點多出來的複雜度很好的消化掉;
  • 彈性資源池簡化擴容縮與故障轉移, TiDB 的故障容忍和無限的水平伸縮都需要額外的資源,比如說,我們去橫向擴張TiDB 集群時,需要申請一部分新的資源進來,在故障容錯之後,要做故障轉移把故障副本數補齊。 那麼K8s 的彈性資源池就能很好的把TiDB 在水平伸縮和故障容忍上的潛力發揮出來。

因此, TiDB 和K8s 能夠非常好的進行一個結合,並且釋放出更大的潛力達成1+1 大於2 的效果的。 這當然不是一個巧合,這背後的原因是,TiDB 和K8s 都遵循同樣的雲原生最佳實踐原則。 那麼假如說我們已經熟悉TiDB 和K8s 的知識,只要稍微花費一些工夫,用K8s 的雲原生對象就可以部署一個TiDB 集群,而且能運行的不錯。

但是,TiDB 和Kuberentes 都有大量的最佳實踐,基本上你想快速看完是有點困難的。 那麼,我們在K8s 上部署TiDB 的時候,應該怎樣去遵守最佳實踐呢? 一個基本的辦法就是把這些坑都了解清楚,並且寫非常多的run book 來告訴SRE team,怎麼去運維好它們。 run book 需要口口相傳,需要不斷的進行知識的交互、交流。 但其實大家都知道,程序員一般不喜歡做這個。

我們更喜歡把這些知識寫成代碼,做自動化。 那麼,我們怎麼樣把這些東西寫成代碼自動化呢?

TiDB on Kubernetes 運維專家:TiDB Operator

答案就是TiDB Operator 。 TiDB Operator 是什麼? 本質就是利用K8s 本身的擴展機制,把領域性的運維知識編寫成代碼,大家可以把TiDB Operator 理解為在K8s 上運行TiDB 的運維專家,把一個專家型人物對TiDB 和K8s 的所有知識都編寫成了代碼。

TiDB Operator 首先添加了一組自定義類型,比如說TiDB Cluster,代表一個TiDB 集群,可以在這些類型裡描述你想要的TiDB 長什麼樣;第二,TiDB Operator 添加了一組自定義控制器,這組自定義控制器就是這些運維知識的集合,它會用這些代碼化的知識幫助你自動化的運維K8s 上的TiDB 集群。

看一個例子:首先是自定義類型,當TiDB Operator 把自定義類型添加到K8s 中後,作為用戶就可以提交資源定義到K8s 裡面,比如我們需要一個TiDB 集群,這個集群要的版本是什麼,要多少PD,要多少KV。 以及我們可以定義一個TiDBMonitor 對象,用來監控TiDB,在對象定義裡則只需要定義我們要監控哪一個TiDB 就可以了。

那麼,大家可以發現,我們在做這些資源定義時是遵循K8s 本身的聲明式定義的。 那這些的理想狀態由誰來實現呢? ——由自定義控制器。 自定義控制器會把所有的需求和K8s 集群裡的實際狀態做一個對比,對比之後就能發現兩者的不同,就需要把實際狀態向期望狀態轉移。 比如說我們把剛剛的TiDB 集群對象和TiDB 監控對象提交到K8s ,那麼TiDB Operator 的控制器就會幫助我們創建很多的容器以及監控。

當然,僅僅只有創建是不夠的,TiDB Operator 中還集成了TiDB 運維專家的所有的領域知識,下面我分享幾個運維知識。

🔺 運維知識:部署

  1. TiDB Operator 會為每個組件選擇最佳的K8s 原生對象;
  2. 會自動地引導PD 做Peer Discovery,無需手工配置;
  3. 最重要的,還會打散TiKV 容器並自動添加store-label ,輔助PD 實現Region 高可用拓撲。

🔺 運維知識:升級

滾動升級TiKV 的時候,給每個TiKV 實例發個SIGTEM,這時TiKV 其實只會做一些基本的Graceful Shutdown 操作。 那就有一個問題,TiKV 退出時並不會主動的把所有的Raft Leader 都遷移出去。 假設我們有比較大的流量,滾動升級時讓沒有受影響的Raft Group 被動地去做一個leader 超時重新選舉,那很可能會導致我們的數據庫延遲會有一定的抖動。

那麼TiDB Operator 怎麼做升級呢? 在每次升級一個TiKV 的容器之前,Operator 會先調用PD 接口,把TiKV 上邊的leader 全部遷移完,不接收讀寫請求後才會去重建TiKV 的容器。 依次往復,比如把TiKV2 遷完了,就要把TiKV2 重建, TiKV2 重建後,又可以把leader 遷上去,接收請求,然後下一個就是把TiKV1 的leader 遷完,再往下。 實現一個優雅的滾動升級。

🔺 運維知識:故障轉移

TiDB on Kubernetes 最佳實踐 1

比如,現在TiKV1 運行的不正常,那麼Operator 的控制器就可以結合PD 裡的TiKV1 對應的store 狀態信息和K8s 裡它所在容器的狀態信息,來判斷這一個TiKV 的store 是否異常。 判斷邏輯大致是store 處於異常狀態,並且持續超過一定時間。 檢測到異常後隔多久再做故障恢復以及怎麼樣判斷是否發生異常,本身也是一種運維知識。

TiDB on Kubernetes 最佳實踐 2

那Operator 有了這些知識並且把它代碼化之後,就可以在檢測到異常後,過一段合理的時間後再補充新的store ,把副本數補齊。 這樣即使我們接下來TiKV2 再掛,那集群就不會受影響,這就是Operator 幫助我們做的故障轉移。

TiDB on Kubernetes 最佳實踐 3

Operator 在最新版裡還提供了on to scaling 的功能,我們去查看集群當中的所有的組件的監控信息,並且根據這些監控信息,做自動的擴縮容,可想而知就需要更多的支持了。

大家可能會想,儘管Operator 帶來了這麼多好處,但我還是擔心假如用Operator 上了K8s 之後會有一些問題。 比如,上K8s 會帶來多少性能損耗? 會影響我的穩定性嗎? 假如K8s 掛了,我的數據庫會不會受影響呢? 一個TiDB 和K8s 的領域專家是可以解答這些問題的,因此,TiDB Operator 當然也可以。

🔺 運維知識:性能

  1. TiDB Operator 支持獨享節點與混部,可以按照優先級權衡性能與成本;
  2. 自動化運維知識考慮了本地盤,使用本地盤就可以消除遠程存儲的損耗;
  3. 支持K8s 的HostNetwork 部署集群,消除二層網絡開銷,所以說在一定的配置下,用TiDB Operator 部署TiDB 其實是可以做到零overhead 的。

🔺 運維知識:穩定性

  1. K8s Master 故障不會影響集群,因為只是控制節點故障,跑TiDB 的節點並沒有故障;
  2. K8s Node 故障會幫我們做自動故障轉移;
  3. 假如K8s 的整個集群所有節點都故障了怎麼辦? Operator 本身有一個默認配置是在這種情況下會保留所有的存儲,首先先保證數據不丟;
  4. 假設真的是發生了災難性的故障,整個機房比如說被水淹了怎麼辦? Operator 本身也會幫你做週期的備份,至少可以找回最近一次的備份,把你的數據先恢復到某個近期的時間點上。

Operator 開箱即用給我們很多穩定性上的增強,也就是說在穩定性方面, Operator 給了我們一個很好的基石,我們可以繼續在基石上再做一些增強,這可以省很多的工夫,並且獲得更好的穩定性。

最佳實踐案例:PayPay&馬上消費金融

最後再來看兩個案例,第一個案例是 日本領先的在線支付公司 PayPay。 PayPay 在日本就可以理解為中國的AliPay 加微信支付。 PayPay 現在是用Operator 部署了100 多個數據庫節點,生產環境有30 多個由Operator 管理的節點。 PayPay 當時在做PoC 時,做了相當詳盡的故障演練,包括各種進程故障、節點故障、以及AWS 整個可用區故障和還有災難恢復。 比如模擬AWS 整個全掛了,還能不能通過週期性備份把集群恢復出來,當時也是這些所有的故障演練都很好的通過了PayPay 的審核,PayPay 才得以放心把整套集群放到到TiDB Operator 和K8s 上來。

第二案例是我們國內的 馬上消費金融。上线的是系统归档和跑批业务,整个线上集群是有 60 多个物理节点,他们最显著的一点就是在用了 TiDB Kuberentes 之后,整个混部的硬件成本下降到原来物理机部署的 30% 左右。因此在整体的性价比上是一个巨大的提升。

最後總結一下,什麼是TiDB 在K8s 上的最佳實踐? 其實只有一句話,Keep Calm and Use TiDB Operator。 當然,用TiDB Operator 本身還是需要一定的上手成本的,這點我們也在不斷的做改進,大家可以參考我們的官網,看一下TiDB Operator 的一系列文檔,讓這個運維專家來為你的TiDB Kuberentes 之旅保駕護航。

作者介紹

吳葉磊, PingCAP Cloud 工程師。

本文轉載自公眾號PingCAP(ID:pingcap2015)。

原文鏈接

TiDB on Kubernetes 最佳實踐