美團(tuán)數(shù)據(jù)庫(kù)運(yùn)維自動(dòng)化系統(tǒng)構(gòu)建之路
2016-09-23 09:22:00 來(lái)源:來(lái)源:美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì) 評(píng)論:0 點(diǎn)擊:
美團(tuán)點(diǎn)評(píng)技術(shù)沙龍由美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì)主辦,每月一期。每期沙龍邀請(qǐng)美團(tuán)點(diǎn)評(píng)及其它互聯(lián)網(wǎng)公司的技術(shù)專(zhuān)家分享來(lái)自一線(xiàn)的實(shí)踐經(jīng)驗(yàn),覆蓋各主要技術(shù)領(lǐng)域。
目前沙龍會(huì)分別在北京、上海和廈門(mén)等地舉行,要參加下一次最新沙龍活動(dòng)?趕快關(guān)注微信公眾號(hào)“美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì)”。
本次沙龍主要圍繞數(shù)據(jù)庫(kù)相關(guān)的主題,內(nèi)容包括美團(tuán)數(shù)據(jù)庫(kù)自動(dòng)化運(yùn)維系統(tǒng)構(gòu)建、點(diǎn)評(píng)側(cè)MySQL自動(dòng)化服務(wù)平臺(tái)RDS、美團(tuán)數(shù)據(jù)庫(kù)中間件、和小米高級(jí)DBA帶來(lái)的Redis Cluster的大規(guī)模運(yùn)維實(shí)踐。
講師簡(jiǎn)介
寧龍,美團(tuán)網(wǎng)高級(jí)DBA,現(xiàn)負(fù)責(zé)美團(tuán)數(shù)據(jù)庫(kù)自動(dòng)化運(yùn)維系統(tǒng)的架構(gòu)和開(kāi)發(fā)工作。
目錄
今天我主要分這幾個(gè)部分講:
- 第一部分是美團(tuán)在數(shù)據(jù)庫(kù)自動(dòng)化運(yùn)維系統(tǒng)構(gòu)建前的煩惱,DBA手動(dòng)運(yùn)維DB的時(shí)候遇到的各種問(wèn)題;
- 第二個(gè)是我們?cè)跇?gòu)數(shù)據(jù)庫(kù)運(yùn)維自動(dòng)化系統(tǒng)過(guò)程中的一些坎坷和思考,這里我會(huì)說(shuō)我們的1.0版系統(tǒng),還有1.0版的系統(tǒng)為什么要到2.0版的,以及現(xiàn)在2.0版系統(tǒng)在線(xiàn)上的使用情況,在2.0版系統(tǒng)的基礎(chǔ)上,我會(huì)給大家介紹三個(gè)典型的案例,可能大家平時(shí)會(huì)用到的;
- 最后說(shuō)一下我們2.0版系統(tǒng)構(gòu)建之后線(xiàn)上跑的效果,以及我們做的后期改進(jìn)的計(jì)劃,也可以說(shuō)是3.0;
- Q&A環(huán)節(jié)。
構(gòu)建前的苦惱——一線(xiàn)運(yùn)維DBA
首先說(shuō)一下數(shù)據(jù)庫(kù)運(yùn)維自動(dòng)化系統(tǒng)構(gòu)建前,運(yùn)維DBA都有哪些煩惱?
這是我們的一線(xiàn)運(yùn)維DBA的小團(tuán),它每天需要對(duì)接很多的RD(Research&Development 研發(fā))的需求。從我們現(xiàn)在的系統(tǒng)統(tǒng)計(jì)來(lái)看,使用我們平臺(tái)系統(tǒng)的RD大概是一千五六百人,我們的人數(shù)是RD人數(shù)的十分之一不到。我們每個(gè)DBA對(duì)接的RD需求還是非常多的。新業(yè)務(wù)的上線(xiàn),RD需要申請(qǐng)新的數(shù)據(jù)庫(kù)集群。隨著業(yè)務(wù)的發(fā)展,比如:數(shù)據(jù)庫(kù)的流量大了,需要拆分了,都需要DBA手動(dòng)去做。第三個(gè)是SQL的審核和上線(xiàn),SQL會(huì)不會(huì)有什么問(wèn)題,可能他測(cè)試環(huán)境OK,但是到了線(xiàn)上會(huì)有各種各樣的問(wèn)題。第四個(gè)是變更、升級(jí)。第五個(gè)是備份,不然的話(huà),RD把數(shù)據(jù)寫(xiě)壞了,你就沒(méi)地方找了,再就是帳號(hào)和安全,虛IP的維護(hù),DNS、MySQL本身的維護(hù),還有數(shù)據(jù)一致性,包括RD提的一些問(wèn)題的排查,自身報(bào)警的處理。這就是我們一線(xiàn)運(yùn)維的DBA,小團(tuán)每天需要干很多的事情,這些事情都很重復(fù),相信大家在座的有DBA的話(huà),肯定是每天都會(huì)遇到我列的這些事情中的一個(gè)或多個(gè)。
構(gòu)建前的苦惱——手動(dòng)運(yùn)維的煩惱
接下來(lái),我們先看一下美團(tuán)點(diǎn)評(píng)初期數(shù)據(jù)庫(kù)系統(tǒng)的架構(gòu):一開(kāi)始是兩層的架構(gòu),在主從庫(kù)的基礎(chǔ)上配置讀寫(xiě)DNS,后來(lái)引入LVS。這個(gè)兩層或者三層的數(shù)據(jù)庫(kù)架有什么問(wèn)題呢?
比如底層的數(shù)據(jù)庫(kù)做切換了,上層的DNS配置也要變更,生效到各個(gè)機(jī)房,幾分鐘過(guò)去了……
RD說(shuō):“這個(gè)不行,你不能這么搞,忍不了”。
所以說(shuō),這樣的數(shù)據(jù)庫(kù)架構(gòu)在切換或者從庫(kù)上下線(xiàn)流量的時(shí)候,都會(huì)導(dǎo)致業(yè)務(wù)的報(bào)錯(cuò),業(yè)務(wù)接受不了。
第二個(gè)是多:重復(fù)沒(méi)有成長(zhǎng),你讓一個(gè)DBA一開(kāi)始做搭建、擴(kuò)容、拆分、切換,他們可能覺(jué)得很有新鮮感和成就感,但是你讓他做了上百次甚至上千次之后他們覺(jué)得這個(gè)沒(méi)有成長(zhǎng)。
第三個(gè)是雜:經(jīng)常被打斷,有報(bào)警處理的時(shí)候需要立馬處理,RD找到你說(shuō)這個(gè)問(wèn)題必須馬上、立刻處理,所以經(jīng)常在做一些事情的時(shí)候被打斷,總感覺(jué)自己在做雜事。
最后一個(gè)煩:RD經(jīng)常不按照規(guī)范做事,包括上線(xiàn)一些大SQL、慢查詢(xún)。程序不加重試,在網(wǎng)絡(luò)抖動(dòng)的時(shí)候,發(fā)現(xiàn)數(shù)據(jù)庫(kù)怎么連接斷了?他就會(huì)找到你。還有一些誤操作,前幾天有一個(gè)RD半夜打電話(huà)跟我說(shuō),線(xiàn)上數(shù)據(jù)誤刪除了需要恢復(fù),通過(guò)我們平臺(tái)去Delete數(shù)據(jù)的話(huà),是很好恢復(fù)的,但是他說(shuō)不好意思,我通過(guò)帳號(hào)直連線(xiàn)上刪了數(shù)據(jù)。有些明白的RD會(huì)不好意思,知道數(shù)據(jù)不好恢復(fù);但是,有些RD會(huì)說(shuō):“你DBA就是干這個(gè)事兒的,你就是得幫我恢復(fù)數(shù)據(jù)。”
大家很郁悶,在沒(méi)有自動(dòng)化運(yùn)維系統(tǒng)之前的DBA還是非常苦惱的。
構(gòu)建中的坎坷和思考——1.0版系統(tǒng)設(shè)計(jì)之初的考慮
以上講完了數(shù)據(jù)庫(kù)運(yùn)維自動(dòng)化系統(tǒng)構(gòu)建前DBA的苦惱,接下來(lái)說(shuō)一說(shuō)我們?nèi)绻肴?gòu)建一套數(shù)據(jù)庫(kù)自動(dòng)化運(yùn)維系統(tǒng)應(yīng)該從哪里開(kāi)始著手,我這里列的都是非常重要的。
第一個(gè)就是CMDB,如果你做的自動(dòng)化系統(tǒng)中沒(méi)有CMDB,那么,我覺(jué)得你做的自動(dòng)化系統(tǒng)就不叫自動(dòng)化系統(tǒng)。做自動(dòng)化其實(shí)就是做標(biāo)準(zhǔn)化,這樣的話(huà),你在做自動(dòng)化運(yùn)維的時(shí)候,CMDB可以很方便的讓你查詢(xún)到信息,對(duì)業(yè)務(wù)進(jìn)行合理的描述,這樣的話(huà)有一個(gè)基本的地方,其實(shí)就是數(shù)據(jù)標(biāo)準(zhǔn),我后面會(huì)說(shuō)。
第二個(gè)就是你想一想在你做自動(dòng)化運(yùn)維系統(tǒng)之前,你整個(gè)公司或者RD的需求、DBA的需求,你需要做哪些自動(dòng)化。美團(tuán)初期只做了三個(gè),在線(xiàn)DDL,數(shù)據(jù)庫(kù)帳號(hào)申請(qǐng)和慢查詢(xún)。有些RD或者DBA經(jīng)常出去聽(tīng)一些會(huì),比如騰訊講藍(lán)鯨,阿里講魯班,我們回去搞一套這么大的,其實(shí)沒(méi)有必要,你們公司需要什么,你迫切需要的應(yīng)該最先做,先把系統(tǒng)搭起來(lái),再迭代。這里我給大家說(shuō)個(gè)經(jīng)驗(yàn)就是,可以先從DBA內(nèi)部入手,再推廣到RD。
第三個(gè)就是開(kāi)發(fā)人員和成本,當(dāng)時(shí)2015年初期的時(shí)候,美團(tuán)App的DBA只有4個(gè)人,那時(shí)候既沒(méi)有FE,也沒(méi)有后臺(tái)做開(kāi)發(fā)的,這個(gè)時(shí)候就需要考慮到開(kāi)發(fā)會(huì)有一些人員和成本的問(wèn)題。會(huì)想,我是不是招一個(gè)人或者招兩個(gè)人?其實(shí)沒(méi)有必要,你可以放眼整個(gè)公司看一看,有沒(méi)有共用的平臺(tái)或者資源給你使用,這樣更快,更便利的讓你搭建平臺(tái)。
最后就是開(kāi)發(fā)形式,我們整個(gè)大的運(yùn)維部是有開(kāi)發(fā)人員相關(guān)資源的,我們找到他們?nèi)臀覀冏鲆恍╉?yè)面,這樣的話(huà),你就會(huì)迅速的搭建你的1.0版本。
以上就是我要說(shuō)的四點(diǎn)。
構(gòu)建中的坎坷和思考——1.0版系統(tǒng)架構(gòu)設(shè)計(jì)&使用情況
大家可以看一下我們1.0版系統(tǒng)的整體框圖,用戶(hù)就不說(shuō)了,前端模塊主要是Django+MVC的方式,前端開(kāi)發(fā)是不懂DBA業(yè)務(wù)的,他們需要做什么事情呢?他們把用戶(hù)提交的任務(wù)寫(xiě)到數(shù)據(jù)庫(kù)的task表中,我們后臺(tái)的DBA去寫(xiě)一些腳本,去把前端提交的任務(wù)拉出來(lái),拉出來(lái)之后如果有日志,會(huì)反寫(xiě)到task表里,這就是我們1.0版的架構(gòu),非常的簡(jiǎn)單,但是也是非常的實(shí)用,右邊這個(gè)圖是我們1.0版的效果,其實(shí)我后來(lái)加了DML,一開(kāi)始只有DDL,業(yè)務(wù)他只需要選擇他所需要變更的SQL類(lèi)型之后,提交到后端DB的task表。后臺(tái)會(huì)有一個(gè)常駐內(nèi)存的進(jìn)程,掃描這個(gè)DB,去發(fā)現(xiàn)當(dāng)前有沒(méi)有需要我去執(zhí)行的任務(wù),如果有就拉出去執(zhí)行,執(zhí)行的過(guò)程中會(huì)有一些日志,會(huì)回填到這個(gè)DB中,前端從DB拉去日志信息,就可以展示了。當(dāng)時(shí)的效果,日均的訂單是1840,2015年初,公司正是快速增長(zhǎng)期的時(shí)候,現(xiàn)在應(yīng)該比這個(gè)稍微少一點(diǎn),當(dāng)時(shí)使用人數(shù)大概600人,雖然是很簡(jiǎn)單的一套架構(gòu),但是使用的人數(shù)還是非常多。
構(gòu)建中的坎坷和思考——1.0版的反思
1.0版的系統(tǒng)做完了之后為什么做2.0版的系統(tǒng)呢?
不是說(shuō)1.0版的系統(tǒng)不好,或者使用的人少,隨著美團(tuán)的發(fā)展你的標(biāo)準(zhǔn)化程度就慢慢得滿(mǎn)足不了要求,所以我們會(huì)反思1.0版的一些問(wèn)題,開(kāi)始去做2.0版的系統(tǒng)。
1.0版有什么問(wèn)題呢?
首先是前瞻模塊重,開(kāi)發(fā)人員很多,因?yàn)槲覀儺?dāng)時(shí)都是公用開(kāi)發(fā)人員,開(kāi)發(fā)人員很多,依賴(lài)也非常多,其實(shí)我開(kāi)發(fā)習(xí)慣不太喜歡依賴(lài)什么太多的框架、組建,這樣的話(huà)感覺(jué)很重,可能導(dǎo)致你代碼的遷移、擴(kuò)展性差。
第二個(gè)是沒(méi)有接口化,RD不方便接入,很深刻的一個(gè)例子就是,有一個(gè)業(yè)務(wù),他可能到某天的凌晨需要建跟時(shí)間相關(guān)的表,需要?jiǎng)h表、建表,他每次都等到凌晨的時(shí)候去平臺(tái)提交去做,他覺(jué)得很辛苦,于是就問(wèn)我:“你們有沒(méi)有接口讓我去調(diào),我寫(xiě)個(gè)腳本到那個(gè)時(shí)間就把我的表建上,因?yàn)槊總€(gè)時(shí)間表結(jié)構(gòu)都是一樣的”。如果你的平臺(tái)沒(méi)有接口化很不方便,特別有一些需要定期跑的業(yè)務(wù)。
第三個(gè)就是開(kāi)發(fā)周期長(zhǎng)、成本高,得跟他們溝通,需求調(diào)整復(fù)雜。當(dāng)然它主要在高并發(fā)、高性能上很差,原因是什么?因?yàn)楹笈_(tái)是一個(gè)常駐內(nèi)存的進(jìn)程,我當(dāng)時(shí)只起了大概可能是6個(gè)線(xiàn)程就跑了,并發(fā)的話(huà)只能跑6個(gè),我們2.0版的系統(tǒng)你想跑多少個(gè)就跑多少個(gè),我一會(huì)兒給大家介紹一下怎么做的,不易擴(kuò)展,這個(gè)也不方便擴(kuò)展,后臺(tái)的任務(wù)就一個(gè),掛了就掛了,圖象化做的也不好,畢竟是找人家?guī)臀覀冏龅模Ч膊皇翘谩_@個(gè)是我們?yōu)槭裁醋?.0下定決心的一個(gè)原因吧!
最后就是任務(wù)的不可干預(yù)性,有一個(gè)改表操作,改到一半不想改了,這時(shí)候需要DBA上去手動(dòng)操作,且不能暫停、回滾,2.0版的支持。
構(gòu)建中的坎坷和思考——2.0版架構(gòu)設(shè)計(jì)
隨著業(yè)務(wù)的發(fā)展,1.0版系統(tǒng)已經(jīng)不能滿(mǎn)足我們現(xiàn)在的需求,我們就做了2.0版。
2.0版需要遵循三個(gè)方面:標(biāo)準(zhǔn)化、自助化、自動(dòng)化。
第一個(gè)標(biāo)準(zhǔn)化,指的是:接口標(biāo)準(zhǔn)、數(shù)據(jù)標(biāo)準(zhǔn)、流程標(biāo)準(zhǔn)。接口標(biāo)準(zhǔn)。你不能說(shuō),我的平臺(tái)(WEB前端)提交的是一種方式,API接口提交是另一種方式,這是不行的。數(shù)據(jù)標(biāo)準(zhǔn),就是CMDB,一定要準(zhǔn),一定要實(shí)時(shí)得更新,不然整個(gè)上層,它是基石,整個(gè)上面的框架搭起來(lái)都是白費(fèi)的。流程標(biāo)準(zhǔn),你需要制定ABCD各種各樣的流程,很多DBA,他有自己的方式、方法。比如說(shuō)對(duì)于拆分來(lái)說(shuō),A有它的方法,B有它的方法,可能都能達(dá)到目的,但是標(biāo)準(zhǔn)化,只能用一種方式。
第二個(gè)自助化,操作自助,只要能放給RD自主操作的就自主操作。問(wèn)題定位的自助,RD碰到了數(shù)據(jù)庫(kù)相關(guān)的問(wèn)題,不是第一時(shí)間找DBA,而是第一時(shí)間在你平臺(tái)上可以看到現(xiàn)在數(shù)據(jù)庫(kù)的狀況,定位到現(xiàn)在數(shù)據(jù)庫(kù)的問(wèn)題,去操作相關(guān)業(yè)務(wù)邏輯解決問(wèn)題。
第三個(gè)自動(dòng)化,高可用和報(bào)警自動(dòng)處理。高可用,從庫(kù)宕機(jī)你可以把它剔掉;報(bào)警自動(dòng)處理,對(duì)于收到報(bào)警看一眼,后臺(tái)有報(bào)警自動(dòng)處理的程序就給它處掉了。
這是我們需要遵循的三個(gè)化,標(biāo)準(zhǔn)化、自助化和自動(dòng)化。
構(gòu)建中的坎坷和思考——2.0版架構(gòu)設(shè)計(jì)
介紹2.0版系統(tǒng)整體的架構(gòu)之前,我先給大家介紹一下兩個(gè)開(kāi)源的組件,第一個(gè)是RabbitMQ,這是一種應(yīng)用程序?qū)?yīng)用程序的通訊方法,這個(gè)端對(duì)于另一個(gè)端的通訊,它是通過(guò)這個(gè)端來(lái)發(fā)消息,另一個(gè)端接消息,從而連接了兩個(gè)端,很簡(jiǎn)單,其實(shí)他的作用就是連接消息的橋梁,美團(tuán)點(diǎn)評(píng)現(xiàn)在做的O2O,就是連接人和服務(wù),你不需要自己找,你只需要在APP上操作就行了。對(duì)于消息隊(duì)列,你只需要提交到對(duì)應(yīng)的隊(duì)列中去就行了。
構(gòu)建中的坎坷和思考——2.0版架構(gòu)設(shè)計(jì)
第二個(gè)就是Celery,這個(gè)Rabbit的中文翻譯是兔子,Celery翻譯成中文就是芹菜,兔子和芹菜構(gòu)建了我們2.0版系統(tǒng)。大家可以這么理解,Celery其實(shí)就是封裝在消息隊(duì)列上面一個(gè)非常好用的任務(wù)調(diào)度者,是基于Python開(kāi)發(fā)的,他可以幫你干什么呢?可以幫你發(fā)任務(wù),可以幫接任務(wù),可以幫你定時(shí)的起任務(wù),我今天凌晨2點(diǎn)拆分,可以白天提交,凌晨Celery幫你調(diào)度。它是對(duì)于消息中間件上面很好用的封裝。
構(gòu)建中的坎坷和思考——2.0版架構(gòu)設(shè)計(jì)
說(shuō)完了以上兩個(gè)開(kāi)源的組建,我們接下來(lái)說(shuō)整個(gè)2.0版系統(tǒng)的架構(gòu),一點(diǎn)點(diǎn)的放出來(lái),首先是用戶(hù),通過(guò)前端的Web,他的所有的操作全部打到我們的API層,業(yè)務(wù)模塊:腳本也好,系統(tǒng)也好,也是打到我們的API層,這樣做到了接口的統(tǒng)一,后端的處理都是一樣的,不管是任何人,對(duì)于我來(lái)說(shuō)都是我的一個(gè)端。
API層它可以做兩個(gè)事情,比如我想查詢(xún)當(dāng)前數(shù)據(jù)庫(kù)的主從架構(gòu)情況,當(dāng)前服務(wù)里的數(shù)據(jù)庫(kù)列表,那么API層直接跟CMDB交互獲取數(shù)據(jù)并返回。第二種是需要后臺(tái)做任務(wù)的,比如搭建,擴(kuò)容,拆分這些都是任務(wù),它們需要到后臺(tái)的任務(wù)管理模塊去做。任務(wù)管理模塊會(huì)把任務(wù)分發(fā)下去。這中間會(huì)有CMDB。任務(wù)管理模塊可以詳細(xì)講一下,這個(gè)就是剛才我所說(shuō)的MQ的消息管道,這里是Celery,這里有兩個(gè)Celery,你可以理解為它是MQ的封裝,你只需要給Celery通信就可以了。TaskControl是掛載到整個(gè)消息中間件上面的一個(gè)任務(wù)處理者。它會(huì)生成父子進(jìn)程去處理任務(wù)。
構(gòu)建中的坎坷和思考——2.0版架構(gòu)設(shè)計(jì)
我剛才說(shuō)的為什么任務(wù)是可以無(wú)限地增加,前提是在機(jī)器可以承載的情況下無(wú)限增加。第一步,TaskControl先f(wàn)ork出一個(gè)子進(jìn)程,第二步,子進(jìn)程1再fork出一個(gè)子進(jìn)程,這個(gè)子進(jìn)程2,是真正得做任務(wù)的進(jìn)程,這個(gè)進(jìn)程再調(diào)用任務(wù)執(zhí)行腳本或者模塊去進(jìn)行任務(wù)操作。子進(jìn)程1,它會(huì)把子進(jìn)程2的一些信息,比如進(jìn)程PID,回填到數(shù)據(jù)庫(kù)里,子進(jìn)程一1就退出了,子進(jìn)程1退出之后,它跟子進(jìn)程2的關(guān)系就斷開(kāi)了,這里要說(shuō)一點(diǎn),子進(jìn)程1得忽略回收子進(jìn)程,這時(shí)候子進(jìn)程2就托管給了init進(jìn)程,這樣的話(huà)就生成了這么一個(gè)任務(wù)執(zhí)行單元。任務(wù)執(zhí)行單元只是需要自己去做任務(wù),比如說(shuō)它去做DDL,這個(gè)子進(jìn)程2是父進(jìn)程,會(huì)去做子進(jìn)程的回收操作,任務(wù)日志的回填工作等。
構(gòu)建中的坎坷和思考——2.0版架構(gòu)設(shè)計(jì)
最后的效果大家可以看到,就是右下角這樣的,這個(gè)TaskControl,每次生成父子進(jìn)程完成之后,它就回去從消息隊(duì)列去拿新的任務(wù),一臺(tái)機(jī)器上,好多個(gè)父子進(jìn)程,并發(fā)高的時(shí)候,這些任務(wù)會(huì)有一百多個(gè),這樣的話(huà),大大提升了整個(gè)系統(tǒng)的并發(fā)性,正常的話(huà),這里起6個(gè)子進(jìn)程就夠了,用來(lái)監(jiān)聽(tīng)任務(wù),生成任務(wù)執(zhí)行單元。我看有些公司會(huì)起很多很多模塊去處理,用這種技巧的話(huà),就可以讓任務(wù)的執(zhí)行脫離整個(gè)任務(wù)系統(tǒng)。
這么做還有什么好處呢?在做升級(jí)或者整個(gè)系統(tǒng)掛了的時(shí)候:我們直接升級(jí)好了,系統(tǒng)掛了也沒(méi)事,任務(wù)還是不受影響。機(jī)器掛了怎么辦?這個(gè)就沒(méi)辦法了,機(jī)器掛了確實(shí)就掛掉了,上面的任務(wù)需要重新發(fā)起,可能需要人工的干預(yù)。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
說(shuō)完了上面的整體架構(gòu)之后我會(huì)給大家講三個(gè)案例:
第一個(gè)案例是我們現(xiàn)有的集群的搭建過(guò)程,我先說(shuō)一下我們線(xiàn)上跑的整體數(shù)據(jù)庫(kù)的四層架構(gòu):第一層是業(yè)務(wù)層,業(yè)務(wù)層,訪問(wèn)我們都是通過(guò)DNS,DNS下面掛的是虛IP層,虛IP層下面會(huì)掛我們的中間件,atlas,每個(gè)機(jī)房會(huì)有并行得部署多個(gè),最下面掛的是數(shù)據(jù)庫(kù)主從架構(gòu),這個(gè)是現(xiàn)在美團(tuán)用的線(xiàn)上數(shù)據(jù)庫(kù)主流架構(gòu)。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
現(xiàn)在開(kāi)始說(shuō)搭建流程,我說(shuō)了這么多,大家沒(méi)看到我們系統(tǒng)的廬山真面目,這個(gè)是我們2.0版本系統(tǒng)的頁(yè)面。對(duì)于搭建,DBA需要先點(diǎn)擊一下服務(wù)組初始化,首先需要去創(chuàng)建一個(gè)服務(wù),我們每一個(gè)DB集群在數(shù)據(jù)庫(kù)里面都是有一個(gè)標(biāo)識(shí)的,被稱(chēng)做服務(wù)組。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
接著,需要選擇你要搭建的類(lèi)型,我剛才說(shuō)的四層的架構(gòu)是這里的A套餐,但是如果說(shuō)是一些統(tǒng)計(jì)、運(yùn)營(yíng)類(lèi)的庫(kù),我們可能會(huì)用到BCD套餐,后面三個(gè)套餐用的比較少。當(dāng)然因?yàn)檫@里有四個(gè),可能涉及到的情況非常多:有沒(méi)有atlas、有沒(méi)有MGW、有無(wú)DNS……可能至少得有八種情況。有時(shí)候大家做自動(dòng)化的時(shí)候,就會(huì)遇到矛盾,這種情況怎么辦?現(xiàn)在給DBA的四個(gè)套餐其實(shí)就是制定標(biāo)準(zhǔn),就是你搭建的數(shù)據(jù)庫(kù)集群,都是按照我的標(biāo)準(zhǔn)來(lái)的,只有這四種,DBA就說(shuō)了:你有時(shí)候不滿(mǎn)足我的情況,DBA就要手動(dòng)去做,怎么辦?
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
你的系統(tǒng)不能夠兼容DBA的需求的時(shí)候怎么辦呢?這個(gè)時(shí)候確實(shí)很麻煩,它手動(dòng)運(yùn)維在后面搞一搞,很有可能造成你的CMDB信息缺失等問(wèn)題,這個(gè)就很麻煩。
遇到這種情況,我就告訴他們:“OK,我整個(gè)平臺(tái)兼容你所有的操作”。
很簡(jiǎn)單,他說(shuō)了:“我想mysql上面不掛中間件,我想直接掛MGW。”
可以。但是你得分兩步做:第一步你是在平臺(tái),你先把D套餐給它搭起來(lái),你到我們MGW和DNS里面去申請(qǐng)。你在這個(gè)管理功能就可以做。也就是說(shuō),做流程化或者是標(biāo)準(zhǔn)化的時(shí)候,你把流程制定出來(lái)的時(shí)候,也要考慮到靈活性,你要兼容它可能存在的所有情況,我們把線(xiàn)上相關(guān)的所有組件都做了管理,MGW有管理,DNS有管理,包括其他的日志都有管理,細(xì)分的管理都有,你正常情況下按我的標(biāo)準(zhǔn)、按我的流程去走,你萬(wàn)一涉及到特殊情況的話(huà),你也可以在各個(gè)分組件的管理里把你想做的事情做完。這樣的話(huà),就把整個(gè)DBA或者整個(gè)ID用戶(hù)都圈到你的整個(gè)平臺(tái)里面來(lái)了,而不是我的平臺(tái)今天只兼容一部分。這樣的話(huà),大家做自動(dòng)化起來(lái)會(huì)很費(fèi)勁。 因?yàn)樵瓉?lái)也是,原來(lái)我線(xiàn)上會(huì)有報(bào)警校驗(yàn)線(xiàn)上CMDB的準(zhǔn)確性,如果線(xiàn)上CMDB的錯(cuò)的話(huà),可能非常麻煩。所以說(shuō),DBA在應(yīng)對(duì)RD的時(shí)候很苦惱,我們做自動(dòng)化運(yùn)維開(kāi)發(fā)在應(yīng)對(duì)DBA的時(shí)候,也很苦惱,用這種方式就可以滿(mǎn)足他們了。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
在大家選完套餐之后就可以到這個(gè)界面了,做數(shù)據(jù)庫(kù)運(yùn)維自動(dòng)化系統(tǒng)有很多流程性的東西,你接下來(lái)需要走哪一步,選完套餐之后讓他選機(jī)器,你的監(jiān)控是什么,buffer pool多大,下面會(huì)給他展示一個(gè)實(shí)時(shí)的拓?fù)?你要把你的用戶(hù)當(dāng)小白鼠,你得告訴他現(xiàn)在長(zhǎng)什么樣子了,不然的話(huà)他提交出錯(cuò)了,又回來(lái)找你。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
第二個(gè)我們?nèi)ミx擇atlas,根據(jù)分組選擇atlas,就是數(shù)據(jù)庫(kù)中間件,選擇完之后就可以形成這樣的圖。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
第三步就是你去申請(qǐng)這個(gè)虛IP和域名了,這個(gè)虛IP層正常一個(gè)機(jī)房會(huì)有一個(gè)。一個(gè)虛IP上會(huì)掛多個(gè)atlas。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
到最后一步可能就是你需要新搭建集群的時(shí)候,需要給RD申請(qǐng)一個(gè)DB,申請(qǐng)一個(gè)帳號(hào),讓他可以訪問(wèn)。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例一:集群搭建
這樣形成最后一個(gè)大的JSON,讓DBA去做確認(rèn),你申請(qǐng)的服務(wù)名稱(chēng)、你當(dāng)前數(shù)據(jù)庫(kù)的機(jī)器、中間件的機(jī)器、你的虛IP層和域名,包括你的DB,會(huì)有一個(gè)整體的拓?fù)鋱D,這樣的話(huà)。然后把整個(gè)的參數(shù),所有的需要你完成這個(gè)數(shù)據(jù)庫(kù)集群搭建的參數(shù)合成一個(gè)大的JSON。發(fā)到API層,API層會(huì)做參數(shù)校驗(yàn),你當(dāng)前搭建的參數(shù)是否滿(mǎn)足系統(tǒng)的要求,如果滿(mǎn)足要求,就會(huì)發(fā)到后臺(tái)的流程引擎中,就是后臺(tái)系統(tǒng)去做任務(wù)。做任務(wù)的時(shí)候,大家可能說(shuō),我需不需要有什么高深的語(yǔ)言,這個(gè)無(wú)所謂了,你可以是腳本,也可以是程序。我們現(xiàn)在線(xiàn)上,搭建的話(huà)用的還是DBA他們一開(kāi)始寫(xiě)的搭建腳本,只需要把腳本改造一下,輸入,輸出標(biāo)準(zhǔn)化一下,你能夠識(shí)別腳本的輸出輸入就行了。
大家說(shuō)自動(dòng)化很艱辛,很艱難。其實(shí)身邊有很多的資源就是DBA手中平時(shí)做的一些腳本,有一些腳本可能DBA自己用,寫(xiě)的不太好。但是他本身,他是有非常大的價(jià)值的,因?yàn)樗情L(zhǎng)年累月改過(guò)的,可能第一版不行改第二版、第二版不行改第三版,他可能改了一年,他的整個(gè)腳本跑起來(lái)還是非常流利的,我們腳本搭建很穩(wěn)定得跑了10個(gè)月的時(shí)間,主要的原因是因?yàn)槲覀僁BA很靠譜,積累的很多實(shí)用的腳本。有些純開(kāi)發(fā)的人去做DBA的自動(dòng)化系統(tǒng),他很難理解DBA的需求,有時(shí)候DBA也講不清楚,所以通過(guò)你做系統(tǒng),他做腳本的方式去合作,真的很靠譜。因?yàn)樽龀鰜?lái)的系統(tǒng)是非常穩(wěn)定的。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例二:在線(xiàn)表變更
說(shuō)完了數(shù)據(jù)庫(kù)集群搭建這個(gè)案例,我們說(shuō)第二個(gè)案例:在線(xiàn)表變更是怎么做的。首先批量的DDL或者DML打造我們的API層,我們API層會(huì)做兩個(gè)事情,第一個(gè)是語(yǔ)法檢測(cè),語(yǔ)法檢測(cè)有兩種方式,一種是測(cè)試庫(kù),一種是sqlparser;比如,對(duì)于autoddl的create操作,你可以在測(cè)試庫(kù)上建一下這個(gè)表,你就知道語(yǔ)法對(duì)不。或者是說(shuō)alter操作,你可能先從線(xiàn)上把表結(jié)構(gòu)拉到測(cè)試環(huán)境,在測(cè)試庫(kù)上先建上,再把a(bǔ)lter語(yǔ)句用到這個(gè)表上,你看alter能不能通過(guò),這樣很方便就繞過(guò)了sqlparser。
但是,在這個(gè)時(shí)候,因?yàn)樵谧鲈诰€(xiàn)的DML的時(shí)候,你是需要給用戶(hù)備份的,方便用戶(hù),萬(wàn)一我誤操作了,可以去恢復(fù),就必須進(jìn)行sqlparser。第一步:你必須把update或者delete語(yǔ)句改寫(xiě)成select,然后會(huì)去線(xiàn)上做查詢(xún)計(jì)劃,看一下explain的結(jié)果是否滿(mǎn)足我的要求,如果不滿(mǎn)足的話(huà),就提示選擇,不是直接拒絕掉,沒(méi)有那么暴力,這個(gè)后面會(huì)說(shuō)。所以說(shuō)這個(gè)sqlparser,應(yīng)該也是一個(gè)比較基礎(chǔ)的難題,大家可以嘗試一下在源碼把這個(gè)sqlparser抽離出來(lái),或者大家可以考慮去找一些已經(jīng)開(kāi)源的sqlparser。第二個(gè)就是語(yǔ)義的檢測(cè),是什么呢?也是標(biāo)準(zhǔn)化,就是RD提交的SQL是否滿(mǎn)足你的要求,比如命名的要求、必須要有主鍵索引,而且不能有重復(fù)的索引,對(duì)于DML來(lái)說(shuō),因?yàn)閷?duì)于互聯(lián)網(wǎng)應(yīng)用來(lái)說(shuō)會(huì)有很多的比如說(shuō)客服給我們運(yùn)營(yíng)人員說(shuō),我的什么什么錯(cuò)了,這個(gè)時(shí)候運(yùn)營(yíng)的人都會(huì)改這個(gè)數(shù)據(jù)庫(kù),改動(dòng)一般都是一兩行這種,所以我們?cè)O(shè)定一千行基本上能夠滿(mǎn)足大部分人的需求。然后在語(yǔ)法、語(yǔ)義提交通過(guò)之會(huì)到后臺(tái)的提交任務(wù),剛才所說(shuō)的2.0的系統(tǒng),由后臺(tái)的任務(wù)執(zhí)行者去執(zhí)行,然后做在線(xiàn)的DDL。我們選擇的是開(kāi)源的pt-online-schema-change,這個(gè)是一個(gè)開(kāi)源工具,它做操作的時(shí)候,可以做到在線(xiàn)改表的時(shí)候不鎖表,當(dāng)然還會(huì)有一些其他的問(wèn)題,這里不是我們今天所說(shuō)的重點(diǎn),大家如果以后有遇到這個(gè)工具有什么相關(guān)的問(wèn)題都可以找我們,美團(tuán)還是踩了非常多的坑,有比較多的經(jīng)驗(yàn)。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例二:在線(xiàn)表變更
大家可以看看這是我們現(xiàn)在的在線(xiàn)表變更的提交頁(yè)面。這里也是先選業(yè)務(wù),選完相關(guān)的業(yè)務(wù),你選庫(kù),選操作類(lèi)型,我們這里會(huì)有一個(gè)業(yè)務(wù)高峰的描述,比如對(duì)于pt-online-schema-change在做表變更的時(shí)候,他會(huì)有一個(gè)數(shù)據(jù)拷貝的過(guò)程,所以說(shuō)我們會(huì)有一個(gè)業(yè)務(wù)高峰,在業(yè)務(wù)高峰的時(shí)候RD發(fā)起的任務(wù)是不能被執(zhí)行的。還有任務(wù)操作時(shí)間區(qū)間,RD也可以選,比如我選今天晚上凌晨變更或者什么時(shí)候變更都是OK的,RD把他的SQL批量粘到這里。對(duì)于在線(xiàn)的分表,粘一個(gè)母表就行了,下面我們自動(dòng)生成帶數(shù)字的語(yǔ)句會(huì)給他操作。這樣也方便我們后臺(tái)的處理,對(duì)于512的分表,我們只校驗(yàn)第一個(gè)語(yǔ)法語(yǔ)義就行了,不然的話(huà),會(huì)產(chǎn)生很多性能問(wèn)題。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例二:在線(xiàn)表變更
講到這里大家肯定會(huì)有疑問(wèn),如果你在語(yǔ)法檢測(cè)或者語(yǔ)義檢測(cè)出問(wèn)題的時(shí)候應(yīng)該怎么辦?我們不是非常暴力的把RD的請(qǐng)求直接拒絕掉。而是在這里,給了RD一個(gè)選擇:也就是說(shuō)我們現(xiàn)在,大部分在線(xiàn)的表變更都是自動(dòng)的,當(dāng)然有一些不滿(mǎn)足語(yǔ)法語(yǔ)義的單子,語(yǔ)法當(dāng)然不用說(shuō)了,直接報(bào)錯(cuò)給RD讓修改,對(duì)于語(yǔ)義來(lái)說(shuō),有些RD說(shuō),你幫我刪或者幫我改,我們可以接受延遲,這個(gè)時(shí)候我們讓RD選擇,你可以點(diǎn)繼續(xù),把這個(gè)單子發(fā)給DBA,如果DBA說(shuō)能執(zhí)行就可以執(zhí)行了,我們的在線(xiàn)表變更是手自一體的。我們要把RD所有的操作,都得圈到我們的平臺(tái)里去做,而不是說(shuō)我語(yǔ)義不支持了,就找DBA手動(dòng)去做。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例二:在線(xiàn)表變更
這里可以看到,遇到了語(yǔ)法或者語(yǔ)義檢測(cè)失敗之后,我們的平臺(tái)會(huì)給他報(bào)錯(cuò),并會(huì)給他一個(gè)詳細(xì)原因的解釋?zhuān)悴荒苷f(shuō)錯(cuò)了,而且你要直白得告訴RD為什么錯(cuò)了;這樣的話(huà)可以提升RD的DBA能力。比如說(shuō)這里長(zhǎng)度,SQL語(yǔ)法問(wèn)題,都會(huì)告訴他;這樣的話(huà),他可能用問(wèn)一次兩次,后面如果用多了,他就不會(huì)問(wèn)了。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例二:在線(xiàn)表變更
這個(gè)就是我們整個(gè)任務(wù)執(zhí)行的一個(gè)詳情的單子,就是RD在提交完任務(wù)之后在這個(gè)頁(yè)面看到他任務(wù)執(zhí)行的詳細(xì)的信息,這上面是一些元信息,包括他提交的時(shí)間,他服務(wù)的信息,下面會(huì)有一個(gè)詳細(xì)的執(zhí)行日志發(fā)給他,你在做任務(wù)操作的時(shí)候,你把你的任務(wù)相關(guān)的數(shù)據(jù)實(shí)時(shí)回填到任務(wù)表里,前端只需要讀這個(gè)任務(wù)表就行了。
構(gòu)建中的坎坷和思考——2.0版功能實(shí)現(xiàn)案例三:高可用解決方案(MHA)
第三個(gè)案例是什么呢?就是我們的高可用的解決方案,上面已經(jīng)列了,美團(tuán)現(xiàn)在用的是開(kāi)源的MHA,一個(gè)很牛的日本人寫(xiě)的。我這里大概介紹一下切換的過(guò)程,原理大家可以回去自己看,左邊是我們四層的架構(gòu),我們現(xiàn)在整個(gè)MHA只運(yùn)用于這四層的架構(gòu),如果你不是這四層的架構(gòu)切換過(guò)程是不滿(mǎn)足的。對(duì)于主從的結(jié)構(gòu)這里會(huì)有監(jiān)控的哨兵,比如這個(gè)哨兵他發(fā)現(xiàn)現(xiàn)在主庫(kù)連不上了,這個(gè)時(shí)候,他不是說(shuō)我就切換了,他是先聯(lián)系其他哨兵,不能相信謠言嘛,也要先打聽(tīng)打聽(tīng)我自己的判斷是不是對(duì)的,他會(huì)去聯(lián)系其他幾個(gè)哨兵,你們幫我看看當(dāng)前主庫(kù)是不是掛了,其他幾個(gè)哨兵跑回來(lái)跟他說(shuō)主庫(kù)確實(shí)掛了,他便開(kāi)始切換。
到了第2步,調(diào)MHA去做主從切換。切換完之后呢,他會(huì)通過(guò)API去改CMDB的信息,CMDB里面會(huì)描述數(shù)據(jù)庫(kù)的主從的架構(gòu),描述完之后,他會(huì)去調(diào)接口,通知中間件變更主從信息,那么到3.2為止服務(wù)就恢復(fù)了。我們現(xiàn)在自動(dòng)和手動(dòng)做切換,時(shí)間都在10秒左右,如果RD程序有數(shù)據(jù)庫(kù)重試的話(huà)應(yīng)該是沒(méi)有影響的。切換完之后會(huì)到第4步,其實(shí)這里很簡(jiǎn)單,就是告訴哨兵主從結(jié)構(gòu)變了,告訴他重新監(jiān)聽(tīng)新的主從結(jié)構(gòu)就OK,這是我們現(xiàn)在平臺(tái)去做切換的過(guò)程,大家可以借鑒一下。
構(gòu)建之后的效果和后期計(jì)劃——構(gòu)建之后的效果
說(shuō)完我們整體的1.0版的數(shù)據(jù)庫(kù)自動(dòng)化運(yùn)維系統(tǒng)、2.0版的系統(tǒng),以及三個(gè)案例之后我們來(lái)看一下現(xiàn)在整個(gè)線(xiàn)上構(gòu)建之后的效果,以及我們后期的計(jì)劃。這個(gè)統(tǒng)計(jì)圖是一個(gè)開(kāi)源組件統(tǒng)計(jì)的,他可以分析每天我們的一個(gè)用戶(hù)量,我們每天在這個(gè)平臺(tái)上跑的RD的用戶(hù)量大概是在三百多。每天會(huì)有三百多RD在我們的平臺(tái)上做操作,累計(jì)的RD數(shù)目大概是1461個(gè),這些是需要跟DB打交道的RD數(shù)量。這個(gè)是我們整體平臺(tái)跑的效果,你的自動(dòng)化運(yùn)維系統(tǒng)做出來(lái)之后做的怎么樣?不是嘴說(shuō)的,還是要有質(zhì)量運(yùn)營(yíng)的數(shù)據(jù)。我們做質(zhì)量運(yùn)營(yíng),包括用戶(hù)數(shù),任務(wù)的成功率,平臺(tái)的接入率,功能的覆蓋率去衡量整個(gè)平臺(tái)的指標(biāo)。
構(gòu)建之后的效果和后期計(jì)劃——后期計(jì)劃
這個(gè)圖,也是我們,我剛才前面已經(jīng)講過(guò)了,這個(gè)架構(gòu)。我們?cè)谑褂眠@個(gè)架構(gòu)的過(guò)程中,很好用,非常好。但是也會(huì)存在一些問(wèn)題,存在什么問(wèn)題呢?首先這個(gè)API層,隨著前端的功能越來(lái)越多,我們API會(huì)有200多個(gè),很多很多,維護(hù)起來(lái)比較麻煩。第二個(gè)是CMDB,誰(shuí)都可以去寫(xiě)。
第三個(gè)這個(gè)任務(wù)執(zhí)行者現(xiàn)在用不著重,因?yàn)樗F(xiàn)在需要處理后端的各種各樣的任務(wù),他會(huì)越來(lái)越重,DBA可能想要加一個(gè)功能,也只能找我加或者我們組內(nèi)的人去加這個(gè)功能,這里能不能讓DBA也參與進(jìn)來(lái)
構(gòu)建之后的效果和后期計(jì)劃——wew后期計(jì)劃
在這個(gè)做完之后我們會(huì)有一個(gè)后期的計(jì)劃,我們需要把整個(gè)的架構(gòu)改造成這樣的,加入兩個(gè)東西,一個(gè)是核心功能庫(kù)和核心組件庫(kù),這兩個(gè)東西包含了API基礎(chǔ)的核心功能,包括日志,包括統(tǒng)計(jì),包括權(quán)限校驗(yàn)都放在核心功能里,核心組件包括一些DNS組件,Atlas組件、監(jiān)控都放在這里操作,API層只需要負(fù)責(zé)他的邏輯就行了。
任務(wù)執(zhí)行者也是只做通用,我只幫你分發(fā)任務(wù),幫你做任務(wù)的子進(jìn)程生成,具體誰(shuí)去做,去調(diào)任務(wù)執(zhí)行平臺(tái)去做,這樣的話(huà),我只要任務(wù)平臺(tái)做的足夠好,DBA或者RD只需要把你的腳本放在這個(gè)平臺(tái)的下面的目錄里,就能調(diào)用整個(gè)系統(tǒng),這樣的話(huà)非常方便,讓更多的人參與你整個(gè)平臺(tái)的建設(shè)、開(kāi)發(fā)和改造的過(guò)程中來(lái)。

【編輯推薦】
相關(guān)熱詞搜索:數(shù)據(jù)庫(kù) 運(yùn)維 自動(dòng)化
上一篇:Nginx/Apache下如何禁止指定目錄運(yùn)行PHP腳本
下一篇:運(yùn)維架構(gòu)師是你并不遙遠(yuǎn)的彼岸

頻道總排行
- Cisco NetFlow v9為何無(wú)人問(wèn)津?
- 技術(shù)專(zhuān)題:智能化運(yùn)維
- 開(kāi)源代碼管理:如何安全地使用開(kāi)源庫(kù)?
- Facebook架構(gòu)解讀
- IT運(yùn)維分析與海量日志搜索需要注意什么(1)
- 金山運(yùn)維肖力:如何將業(yè)務(wù)遷移到虛擬化環(huán)境并穩(wěn)定運(yùn)行(1)
- Apache Ignite(四):基于Ignite的分布式ID生成器
- SDN時(shí)代的網(wǎng)絡(luò)管理系統(tǒng)會(huì)走向何方
- CrazyEye,一款國(guó)人開(kāi)源的堡壘機(jī)軟件(1)
- WOT2016吳兆松:Zabbix監(jiān)控自動(dòng)化的未來(lái)如何發(fā)展
頻道本月排行
- 8你消費(fèi)我買(mǎi)單——"漏洞"天使OneRASP...
- 7有了Jenkins,為什么還需要一個(gè)獨(dú)立...
- 6IT運(yùn)維分析與海量日志搜索需要注意什么(1)
- 5新浪微博王傳鵬:微博推薦架構(gòu)的演進(jìn)(1)
- 4云運(yùn)維如何選擇部署適合自身的IDC和...
- 4雅虎開(kāi)源可以提升流操作速度的DataSketches
- 4大眾點(diǎn)評(píng)高可用性系統(tǒng)運(yùn)維經(jīng)驗(yàn)分享
- 4開(kāi)源還是商用?十大云運(yùn)維監(jiān)控工具測(cè)...
- 4論開(kāi)發(fā)與運(yùn)維沖突的根源、表現(xiàn)形式及...
- 4史上最大機(jī)器學(xué)習(xí)數(shù)據(jù)集,雅虎對(duì)外開(kāi)...