本文轉載自公衆號 51CTO技術棧。做者介紹:賀磊,360 數據庫運維資深工程師,《MongoDB 運維實戰做者》,知名論壇 MySQL 版主,51CTO 博客之星,閒暇之餘,喜歡將部分案例寫成博客,累計訪問量過百萬。mysql
我先說幾個最讓你興奮和開心的點吧:sql
60 雲平臺對 360 集團各大業務線均有提供服務支持,涉及的數據庫支持方案有:MySQL、Redis、MongoDB、ES、GP、PiKA。數據庫
其中 MySQL 至今已有過萬的實例,目前,對於一些寫入量大的業務,已經出現瓶頸。架構
例如磁盤空間,雖然咱們能夠經過分庫分表的方式,拆分出來,但這對業務和 DBA 來講都是不小的工做量,最痛苦的無異於這些大表的改表。併發
不管是單表上 T,仍是分庫分表,對一張大表執行 DDL 的代價是很是大的。app
針對業務爆發式增加的數據量,咱們開始調研選型是否有其餘數據庫能夠代替傳統的 MySQL。負載均衡
經過調研咱們瞭解到 TiDB,遷移平滑,基本上無需業務變更代碼,徹底的事務 ACID 支持,分佈式的架構,自帶高可用、Online DDL。運維
截止目前,360 雲平臺這邊有三套 TiDB 集羣,總節點數在 50+。有 9 個業務線接入使用,有過百億級表 Online 加索引的案例,總數據量目前在 80T。dom
版本上,咱們從 3.0.1 一路跟隨到 3.0.5,DM 版本從內測到 1.0.2 GA 版本,共計提出 9 個 Bug 或改進項反饋。分佈式
後續咱們計劃將 TiDB 上到 360 HULK 雲平臺上,並定製化開發一些功能爲業務提供可視化的服務,以便讓 360 集團更多的業務線接觸到 TiDB、使用 TiDB。
版本的選擇咱們之因此從大版本 3 開始,也是看到了一些 2.X 版本的社區反饋,尤爲是索引執行計劃這塊,3.X 版本較以前的版本會好不少。DM 版本咱們是直接選取的最新版,後一路跟隨新版本升級。
總體架構上,咱們除了 TiDB 集羣外,還用到了 DM 和 Pump、Drainer 套件。
這塊主要是因爲咱們使用 TiDB 的業務有兩種:
老得 MySQL 業務因單機磁盤受限,致使單實例磁盤沒法支撐爆炸式增加的數據量,數據比較重要,須要備份和支持 7*24 小時的恢復。
這類業務咱們用到 DM 套件來實現無障礙遷移,1TB 的導入時間在 16 小時,這裏若是是比較大的數據源,且 TiDB 是全新集羣,可使用 TiDB Lightning,速度能夠更快。
Lightning 的實測導入速度,37 分鐘,導完 2 張大表共計 54G 的數據,符合 100G/H 預估,是 loader 的 3 倍速度,loader 用時 2 小時 4 分鐘。
提及 DM 使用這塊文章後面會單獨分享下這塊須要注意的問題,以下圖所示:
全新的業務,或者由業務自行導入到 TiDB 集羣中,這種業務數據量通常都會比較大,也是看中了 TiDB 支持 ACID 和分佈式的特色。
目前網盾業務有多張表都過 10 億級別,其中有張表到達了 100 億+,建索引花了近 10 天(這塊其實咱們應當注意,不是分佈式就一張表就完事兒了,由於表量級過大,清理老舊數據都是個問題)。
TiDB 如今支持分區表,但咱們在使用過程當中發現性能上和普通表有差距,期待後續版本可以讓分區表功能和性能更加的完善。
對於這一全新的數據庫,咱們本着大膽用,不拘泥於傳統的態度進行使用。
咱們的 MySQL 如今也正在適配 8.0 版本,MongoDB、ES 也都是時刻關注着新版本狀況來評估是否適合雲平臺。
所以 TiDB 的上線也是從離線業務→邊緣業務→核心業務來過渡的。
通過大量的測試、也參考了其餘公司的使用狀況,咱們計劃將 TiDB 歸入 360 HULK 雲平臺,並計劃後期對其不斷完善在雲平臺中的功能,對全公司業務線開放使用。
定製化開發一些 MySQL 已經具有的,例如 SQL 審覈、慢查統計、冗餘索引檢測、自增索引閾值等各項基礎功能等等。
雖然在使用過程當中遇到了一些小問題,例如索引的選取、參數的調優,由於一些配置致使的性能抖動,但都獲得了 PingCAP 同窗快速的響應和回覆,這對咱們推動 TiDB 有重大的幫助。
DM 使用經驗以下:
官網手冊上只說明須要以下權限:
TiDB Lightning 須要如下權限:
存儲斷點的數據庫額外須要如下權限:
但實測過程當中發現還須要以下權限:
PD 監控中 -Statistics-balance 中,有 Store-region-score 監控項,這裏記錄的是各個節點的 Score 得分,正常狀況下,咱們指望的結果是得分接近的,這說明無需進行 Region 大規模遷移。
Region 負載均衡調度主要依賴 balance-leader 和 balance-region 兩個調度器。
兩者的調度目標是將 Region 均勻地分散在集羣中的全部 Store 上,但它們各有側重:
咱們這裏重點關注的是 balance-region,當它出現不均衡的時候,咱們能夠直接在監控中看到相似下圖所示:
調度期間,不可避免的會出現 IO 爭用、磁盤的 lantency,都會出現不一樣程度的上漲,從業務上的反饋看,就會出現積壓,響應不及時等等。而當 Region Balance 完成後, Duration 等都會恢復正常水平。
所以,咱們要關注的地方有兩點:
對於第一點,咱們遷移的時候是有參數能夠控制的。這裏不管是磁盤空間閾值,仍是 Region Balance 調度速度,或者 Drop 大量表後調整空 Region Merge 的速度,其實都是能夠經過 pd-ctl 的 config set 命令來實時調節。
例如:
TIPS:理解了做用和原理,上述參數均可以根據需求自行控制。
例如當咱們在 Drop 大量的表後,會產生不少的空 Region。在 Region 數量較多的狀況下,Raftstore 須要花費一些時間去處理大量 Region 的心跳,從而帶來一些延遲,致使某些讀寫請求得不到及時處理。
若是讀寫壓力較大,Raftstore 線程的 CPU 使用率容易達到瓶頸,致使延遲進一步增長,進而影響性能表現。
所以咱們會但願儘快的進行 Region Merge,來避免過多的 Region 對集羣形成性能損耗時,咱們能夠同時調小 max-merge-region-keys、max-merge-region-size,來讓其更快的觸發 Merge 操做,同時調大 merge-schedule-limit 提升併發度。
例如當咱們發現某臺 KV 磁盤空間剩餘 40% 開始大量調度時,咱們能夠將 high-space-ratio 調整到 0.7,以臨時避免調度對業務產生的影響。
咱們也能夠控制調度的併發度,來減小對業務產生的影響,實測這都是立竿見影的參數,你們若是遇到這些問題可供參考。
對於第二點,尤爲是使用 DM 期間,將 DM-worker 和 TiKV 混合部署的狀況下,要注意清理全量備份留下的文件和 Relaylog。
默認調度策略是當磁盤剩餘的有效空間不足 40%,處於中間態時則同時考慮數據量和剩餘空間兩個因素作加權和看成得分,當得分出現比較大的差別時,就會開始調度。
因此 DM 導入完成後,要記得刪除全量備份。就是 dumped_data.task_xxx 文件夾,這個全量備份通常都會比較大,若是 dm-worker 和 TiKV 混部,就會出現某個 TiKV 節點磁盤已使用率高於其餘。
這時 PD 的 store region score 就會相比其餘節點出現異常,引發性能抖動和 Duration 升高。
一直等待其追上後,纔會像下圖這樣:
此時,balancer 已達平衡狀態:
Duration 恢復正常水平,以下圖 16:54 分時的狀況:
QPS 也再也不積壓,恢復正常水準:
關於 relay-log,默認是不清理的,就和 MySQL 的 expire_logs_days 同樣,這塊能夠經過 dm-worker 的配置文件來進行配置。
例如將 Expires 配置爲 7,表明 7 天后刪除:
[purge] interval = 3600 expires = 7 remain-space = 15
Expires 來控制保留天數。默認 expires=0,即沒有過時時間,而 remain-space=15 意思是當磁盤只剩於 15G 的時候開始嘗試清理,這種狀況咱們極少會碰到,所以這個清理方式其實基本上是用不到的。
因此建議有須要刪除過時 relay-log 的小夥伴,直接配置 Expires 保留天數就能夠了。
DM 導入完成後,應該提供是否在完成後自動刪除全備文件的選項,能夠默認不刪,由使用者決定是否刪除。
從使用者角度來講,全量備份目錄不管是全量一次性導入仍是 all 增量同步,後續都不會再使用到。
若是 dm-worker 和 TiKV 混部,會致使全備文件佔據大量磁盤空間,引發 TiKV Region 評分出現異常,致使性能降低,已轉化爲 PRM 產品需求。
在早期尚未 dm-portal 自動化生成 task 時,咱們都是自行編寫 DM 的 task 同步文件。後來有了 dm-portal 自動化生成工具,只要圖形頁面點點點就能夠了。
但該工具目前有一個問題是,沒有全庫正則匹配,即使你只勾選一個庫,他底層是默認把每張表都給你配置一遍。
這就會出現當上層 MySQL 新建立某張表的時候,下游會被忽略掉,例如當你使用改表工具 gh-ost 或者 pt-online-schema-change,你的臨時表都會被當作爲不在白名單內而被忽略,這個問題使用者須要注意。
咱們也已經反饋給了官方。將來不久的版本估計就能夠修復。
["skip event"] [task=task_20357] [unit="binlog replication"] [event=query] [statement="ALTER TABLE `360`.`_data_201910_gho` ADD COLUMN `raw_url_md5` CHAR(32) NOT NULL DEFAULT '' COMMENT 'raw_url md5'"] ["skip event"] [task=task_20357] [unit="binlog replication"] [event=query] [statement="ALTER TABLE `360`.`_data_201910_gho` ADD INDEX `idx_rawurl_md5`(`raw_url_md5`)"] [schema=flow] ["skip event"] [task=task_20357] [unit="binlog replication"] [event=query] [statement="ALTER TABLE `360`.`_data_201910_gho` DROP INDEX `idx_raw_url`"] [schema=flow]
這裏日誌能夠看到 event 被 skip 了。
query-error task 能看到具體的報錯信息,下游看都沒有該值:
mysql> select * from client where clientid='82b51e6f6eb64955487f978dd94a2c81e492f6170xxxxxxxxxxxxxxxxxxxxxxxxx'; Empty set (0.00 sec)
再去上游看,結果發現也沒有值,業務邏輯應該是後來 delete 了:
mysql> select * from client where clientid='82b51e6f6eb64955487f978dd94a2c81e492f6170xxxxxxxxxxxxxxxxxxxxxxxxx'; Empty set (0.00 sec)
由於上游也沒有值,去上游看 Binlog 後分析以下:
是先寫入,再刪除,因此上游沒值是能夠預期的,可是下游尚未同步到這塊,此時也是沒有值的,不該該存在 1062 的問題。
當集羣有大規模 kv:1062 報錯時,或者集羣寫入壓力大時,DM 從結果看沒法保證 Binlog 的有序落盤,需確認 DM能不能保證 LVS 下的多個 TiDB Binlog 的每個 Event 是有序執行的。
只從現象看,只要集羣沒有大量的 1062 報錯,PD 相關的監控值都比較低,DM 也不會出現任何同步報錯,反之就出現。
從 Binlog 看就像是第一條 Insert了,還沒來得及 Delete,直接 Insert 產生的報錯,但報錯後那個 Delete 的也完成了,因此這時候我再怎麼快也快不到毫秒級,下游看不到全部記錄。
解決的辦法是將 1062 大量衝突的業務拆分出集羣,或 DM 直接寫 TiDB 的真實 IP 而不是 LVS。
有業務反饋 Drop 分區和 Drop 列時出現同步異常。補充下分區表相關的測試的結果,DM 更多的沒法拆分的狀況仍是在 Drop 這塊,普通的 add,modify 沒問題的。
一次刪除多個分區的操做則會報錯:
alter table dsp_group_media_report drop partition p202006 ,p202007 ;
Drop 含有索引的列操做會報錯:
Alter table dsp_group drop column test_column;
40 億表添加 DDL 添加索引致使的 Duration 升高:
定位到是:
mysql> show global variables like 'tidb_ddl_reorg_worker_cnt'; +---------------------------+-------+ | Variable_name | Value | +---------------------------+-------+ | tidb_ddl_reorg_worker_cnt | 16 | +---------------------------+-------+ 1 row in set (0.11 sec) mysql> show global variables like 'tidb_ddl_reorg_batch_size'; +---------------------------+-------+ | Variable_name | Value | +---------------------------+-------+ | tidb_ddl_reorg_batch_size | 1024 | +---------------------------+-------+
上述兩個參數對已有非 pcie 集羣壓力比較大致使。經過 set global 調節(3.0.3 後,默認從 256 漲到了 1000 和 16):
tidb_ddl_reorg_batch_size 1000-256 tidb_ddl_reorg_worker_cnt 16-4
同時,提升 Compaction 相關:
max-background-jobs: 8-10-12 max-sub-compactions: 1-2-4 defaultcf.compression-per-level: ["lz4", "lz4", "lz4", "lz4", "lz4", "zstd", "zstd"] writecf.compression-per-level: ["lz4", "lz4", "lz4", "lz4", "lz4", "zstd", "zstd"]
最終的優化結果是,QPS 穩定在 3K 左右:
在實際狀況中,讀寫請求並不會均勻分佈到每一個 Region 上,而是集中在少數的 Region 上。
那麼能夠儘可能減小暫時空閒的 Region 的消息數量,這也就是 Hibernate Region 的功能。
無必要時可不進行 raft-base-tick,即不驅動空閒 Region 的 Raft 狀態機,那麼就不會觸發這些 Region 的 Raft 產生心跳信息,極大地減少了 Raftstore 的工做負擔。
截至 TiDB v3.0.5,Hibernate Region 還是一個實驗功能,在 TiKV master 分支上已經默認開啓。可根據實際狀況和需求來開啓該功能。
參數以下:
raftstore.hibernate-regions: true
在 DM 導入集羣期間,確實會由於寫熱點的問題致使集羣總體 Duration 更高,由於 IO 爭用會更明顯。這裏其實也是能夠經過一些參數來讓集羣運行的更快的。
以下參數從原值調到-新值:
raftstore: apply-pool-size: 3-4 store-pool-size: 3-4 storage: scheduler-worker-pool-size: 4-6 server: grpc-concurrency: 4-6 rocksdb: max-background-jobs: 8-10 max-sub-compactions: 1-2
能夠看到效果以下:QPS 再也不抖動,Duration 也恢復到正常的水平。
DM 還有個注意點就是 dm-worker.toml 配置文件裏的配置 log-level=「debug」 是不生效的,啓動的時候默認有個 -L=info 選項,會覆蓋掉配置文件裏的,默認 -L 優先級高於配置文件,人工排查時自行啓動。
也就是說當須要對 dm-worker 開啓 debug 模式,要人工拉起進程並指定 -L 選項=debug。
TiDB 目前 load data 的導入速度不及 MySQL,若是依賴 load data 的話,這塊能夠調優一下參數。
咱們的場景是 TiKV 上沒有明顯的瓶頸,主要慢在了 scheduler latch wait duration,能夠調下參數看看:
storage: scheduler-concurrency: 204800000 raftstore: raft-max-inflight-msgs: 4096
調優完成後是有提高,但提高不大,咱們得知新版本的 TiDB 在 Load data 這塊又有速度提高,比較期待新版本。
MySQL 是 1024,TiDB 目前限制是 512 列。若是你的表有很是多的列,那麼這塊要提早注意下是否是能夠拆分出去。
GC 的數據包括兩部分,一部分是 DML 和 DDL ,DDL 的 GC 的對象信息包含在 mysql.gc_delete_range 和 mysql.gc_delete_range_done ,分別記錄的是待 GC 的對象以及已經 GC 的對象。mysql.gc_delete_range_done表裏面沒有數據不表明 GC 異常。
官方建議更換規則:
sum(increase(tikv_gcworker_gc_tasks_vec{task="gc"}[1d]))
在 TiDB 中,以下查詢是不能用到索引的:
select * from manual_domain where host_md5 = '55fbea39965484a61xxxxxxxxxx' or domain_md5 = '55fbea39965484a61xxxxxxxxxx';
MySQL 中用到了 index_merge,TiDB 計劃 4.0 支持,能夠先用 union all 來處理這種 a or b。
業務反饋查詢變慢,發現是另一個業務全表掃 insert into select 導數據致使的。
去 CPU 佔用率高的這臺機器上搜索對應的 log,關鍵字 slow,發現以下狀況:
[2019/09/18 10:04:37.339 +08:00] [INFO] [tracker.rs:150] [slow-query] [internal_key_skipped_count=46649] [internal_delete_skipped_count=0] [block_cache_hit_count=1596] [block_read_count=9] [block_read_byte=31933] [scan_first_range="Some(start: 7480000000000002285F72800000000021E9BD end: 7480000000000002285F72800000000024199A)"] [scan_ranges=1] [scan_iter_processed=46650] [scan_iter_ops=46652] [scan_is_desc=false] [tag=select] [table_id=552] [txn_start_ts=411244239493267464] [wait_time=2ms] [total_process_time=1.41s] [peer_id=ipv4:192.168.1.248:45686] [region_id=835437]
根據 table_id 去經過 information_schema.tables 表查一下,能夠經過上述方式來定位到是哪張表致使的問題。
TiDB enum 致使的性能問題:
enum 在 TiDB 3.0.2 進行 where 條件查找時,發現不能下推到 TiKV。官方說4.0GA 修復。臨時辦法是修改到其餘類型。
enum modify 爲 tinyint 發現內容出現變化,本來的’'變成了 default 值,‘1’ 變成了 2,經測試 varchar 正常,所以不要嘗試去變動 DM 備份出來的 Schema 文件來實現表結構變動,應該從上游 MySQL 解決。
沒有視圖能夠查詢當前已建分區信息。在 TiDB 中目前沒有視圖支持查詢分區表已建分區信息,那麼用戶那邊沒有辦法直觀的判斷當前已建的分區,以及當前是否須要及時的添加新分區。目前已轉化爲 PRM 產品需求,相信新版本不久會實現。
分區表 - 部分分區 - limit 未下推:分區表出現 limit 未下推的現象,表 content_info_p 其中只有分區 p201911 有數據。該問題已在 3.0.6 版本修復。
mysql.tidb 表權限異常:使用 use db_name 或者 mysql 客戶端指定 DB name 後,能夠對該表進行查詢或更新操做。計劃 3.1 版本修復。
事物的限制:單個事物的 SQL statement 不超過 5000(stmt-count-limit 參數可調);每一個鍵值對不超過 6M;鍵值對的總數不超過 300000;鍵值對的總大小不超過 100M。
注:鍵值對是指一張表裏有 2 個索引,那麼一共就是數值 +2 個索引,總共 3 個鍵值對,那麼每一個鍵值對的老是不能超過 30 萬/3=10 萬。
一行數據會映射爲一個 KV entry,每多一個索引,也會增長一個 KV entry,因此這個限制反映在 SQL 層面是:總的行數*(1+索引個數)<30w。
官方提供內部 batch 的方法,來繞過大事務的限制,分別由三個參數來控制:
寫熱點的處理:若是能夠去掉 MySQL 自增主鍵,就能夠經過建表時指定 SHARD_ROW_ID_BITS、PRE_SPLIT_REGION 來實現預切分,避免單調自增引起的只往某個 KV 上寫數據引發的熱點問題。
詳情可參考官網 TiDB 專用系統變量和語法中 SHARD_ROW_ID_BITS 的介紹。
這塊能夠經過將 TiDB 和 DM 監控部署到不一樣的機器上來繞過解決,不然就會出現經過 Ansible 安裝後,ansible-playbook rolling_update_monitor.yml --tags=prometheus 時,二者只有一個是正常的。
磁盤已使用不建議超過 50%:數據量太多 LSM 過大, compaction 成本會很高,而且內存命中率降低,同時單機恢復時間很長,50% 左右最好,使用率過高,若是忽然寫入爆增,region 來不及調度會寫滿磁盤,有風險。
所以建議 SSD 不要使用超過 2T 的,採用更多的機器會有更好的性能。
在使用 Mydumper 備份大時,會打滿 TiDB 網卡,同時會消耗 TiDB、TiKV 更多的內存。
TiDB ERR】[emergency]TiDB_schema_error:192.168.1.1:10080,[add_dba_mysql]【360】 【TiDB ERR】[critical]NODE_memory_used_more_than_80%:192.168.1.2:9100,[add_dba_mysql]【360】
去抓取慢日誌會看到以下內容:
grep Query_time tidb_slow_query-2019-12-24T04-53-14.111.log|awk -F : '$2>10' # Time: 2019-12-24T03:18:49.685904971+08:00 # Txn_start_ts: 413433784152621060 # User: backup@192.168.1.3 # Conn_ID: 4803611 # Query_time: 4002.295099802 SELECT /*!40001 SQL_NO_CACHE */ * FROM `360`.`t_d` ;
期待後續的版本物理備份,邏輯備份看起來目前是能夠備份,但會比較消耗資源,同時恢復時間也會更久。
從 TiDB 2.x 開始咱們就已經開始進行測試了,最終選擇的版本是 3.0.2,後續升級到 3.0.5。
上述文章總結和一些案例但願可以幫助到已使用或打算使用 TiDB 的朋友。
360 雲平臺 DBA 團隊也計劃將 TiDB 推上 360 HULK 雲平臺,爲 360 集團更多的業務線提供豐富多彩和穩定可靠的數據庫服務。
在這裏首先要感謝 PingCAP 同窗及時的技術支持,幫助咱們儘快的解決了一些技術問題。
同時,我本身也通讀了 TiDB 的官方手冊。從 Ansible 部署、二進制部署、升級、DM、Lighting、Pump、Drainer、調優、排障、遷移、備份,這一路打怪下來,切身感覺到了 TiDB 愈來愈好的過程。
我相信將來隨着 3.1 和 4.0 版本的推出,有更多人加入使用 TiDB 的這個隊伍中來。
從業務給咱們的反饋也是對 TiDB 的使用狀況表示滿意,咱們相信,TiDB 會在你們共同的努力下,愈來愈好。