京東的商品評(píng)論目前已達(dá)到數(shù)十億條,每天提供的服務(wù)調(diào)用也有數(shù)十億次,而這些數(shù)據(jù)每年還在成倍增長(zhǎng),而數(shù)據(jù)存儲(chǔ)是其中最重要的部分之一,接下來(lái)就介紹下京東評(píng)論系統(tǒng)的數(shù)據(jù)存儲(chǔ)是如何設(shè)計(jì)的。
整體數(shù)據(jù)存儲(chǔ)包括基礎(chǔ)數(shù)據(jù)存儲(chǔ)、文本存儲(chǔ)、數(shù)據(jù)索引、數(shù)據(jù)緩存幾個(gè)部分。
基礎(chǔ)數(shù)據(jù)存儲(chǔ)
基礎(chǔ)數(shù)據(jù)存儲(chǔ)使用mysql,因用戶(hù)評(píng)論為文本信息,通常包含文字、字符等,占用的存儲(chǔ)空間比較大,為此mysql作為基礎(chǔ)數(shù)據(jù)庫(kù)只存儲(chǔ)非文本的評(píng)論基礎(chǔ)信息,包括評(píng)論狀態(tài)、用戶(hù)、時(shí)間等基礎(chǔ)數(shù)據(jù),以及圖片、標(biāo)簽、點(diǎn)贊等附加數(shù)據(jù)。而不同的數(shù)據(jù)又可選擇不同的庫(kù)表拆分方案,參考如下:
評(píng)論基礎(chǔ)數(shù)據(jù)按用戶(hù)ID進(jìn)行拆庫(kù)并拆表;
圖片及標(biāo)簽處于同一數(shù)據(jù)庫(kù)下,根據(jù)商品編號(hào)分別進(jìn)行拆表;
其它的擴(kuò)展信息數(shù)據(jù),因數(shù)據(jù)量不大、訪問(wèn)量不高,處理于同一庫(kù)下且不做分表即可。
因人而異、因系統(tǒng)而異,根據(jù)不同的數(shù)據(jù)場(chǎng)景選擇不同存儲(chǔ)方案,有效利用資源的同時(shí)還能解決數(shù)據(jù)存儲(chǔ)問(wèn)題,為高性能、高可用服務(wù)打下堅(jiān)實(shí)基礎(chǔ)。
文本存儲(chǔ)
文本存儲(chǔ)使用了mongodb、hbase,選擇nosql而非mysql,一是減輕了mysql存儲(chǔ)壓力,釋放msyql,龐大的存儲(chǔ)也有了可靠的保障;二是nosql的高性能讀寫(xiě)大大提升了系統(tǒng)的吞吐量并降低了延遲。存儲(chǔ)的升級(jí)過(guò)程嘗試了cassandra、mongodb等分布式的nosql存儲(chǔ),cassandra適用于寫(xiě)多讀少的情況,而 mongodb也是基于分布式文件存儲(chǔ)的數(shù)據(jù)庫(kù),介于關(guān)系型數(shù)據(jù)庫(kù)與非關(guān)系型數(shù)據(jù)庫(kù)之間,同時(shí)也是內(nèi)存級(jí)數(shù)據(jù)庫(kù),mongo寫(xiě)性能不及 cassandra,但讀寫(xiě)分離情況下讀性能相當(dāng)不錯(cuò),因此從應(yīng)用場(chǎng)景上我們選擇了mongodb。mongodb確實(shí)不錯(cuò),也支持了系統(tǒng)穩(wěn)定運(yùn)行了好幾年。
但從今后的數(shù)據(jù)增長(zhǎng)、業(yè)務(wù)擴(kuò)增、應(yīng)用擴(kuò)展等多方面考慮,hbase才是最好的選擇,它的存儲(chǔ)能力、可靠性、可擴(kuò)展性都是毋庸置疑的。選擇了 hbase,只需要根據(jù)評(píng)論ID構(gòu)建Rowkey,然后將評(píng)論文本信息進(jìn)行存儲(chǔ),查詢(xún)時(shí)只需要根據(jù)ID便能快速讀取評(píng)論的文本內(nèi)容,當(dāng)然也可將評(píng)論的其它字段信息進(jìn)行冗余存儲(chǔ),這樣根據(jù)評(píng)論ID讀取評(píng)論信息后不用再?gòu)膍ysql進(jìn)行讀取,減少數(shù)據(jù)操作,提升查詢(xún)性能。
數(shù)據(jù)索引
京東的評(píng)論是以用戶(hù)和商品兩個(gè)維度進(jìn)行劃分的。對(duì)于用戶(hù)而言,用戶(hù)需要發(fā)表評(píng)論、上傳曬圖、查看自己的評(píng)論等,因此mysql數(shù)據(jù)庫(kù)中只要根據(jù)用戶(hù)ID對(duì)評(píng)論數(shù)據(jù)進(jìn)行拆庫(kù)拆表進(jìn)行存儲(chǔ),便能解決用戶(hù)數(shù)據(jù)讀寫(xiě)問(wèn)題。而對(duì)于商品而言,前臺(tái)需要將統(tǒng)計(jì)商品的評(píng)論數(shù)并將所有評(píng)論展示出來(lái),后臺(tái)需根據(jù)評(píng)論的全字段進(jìn)行檢索同時(shí)還帶模糊查詢(xún),而評(píng)論數(shù)據(jù)是按userId進(jìn)行庫(kù)表拆分的,現(xiàn)在要按商品去獲取評(píng)論,顯然當(dāng)前的拆分庫(kù)是無(wú)法實(shí)現(xiàn)的。起初考慮過(guò)根據(jù)商品編號(hào)再進(jìn)行拆庫(kù)拆表,但經(jīng)過(guò)多層分析后發(fā)現(xiàn)行不通,因?yàn)樵侔瓷唐肪幪?hào)進(jìn)行拆分,得再多加一倍機(jī)器,硬件成本非常高,同時(shí)要保持用戶(hù)及商品兩維度的分庫(kù)數(shù)據(jù)高度一致,不僅增加了系統(tǒng)維護(hù)成本及業(yè)務(wù)復(fù)雜度,同時(shí)也無(wú)法解決評(píng)論的數(shù)據(jù)統(tǒng)計(jì)、列表篩選、模糊查詢(xún)等問(wèn)題,為此引入了全文檢索框架solr(前臺(tái))/elasticsearch(后臺(tái))進(jìn)行數(shù)據(jù)索引。
數(shù)據(jù)索引其實(shí)就是將評(píng)論數(shù)據(jù)構(gòu)建成索引存儲(chǔ)于索引服務(wù)中,便于進(jìn)行評(píng)論數(shù)據(jù)的模糊查詢(xún)、條件篩選及切面統(tǒng)計(jì)等,以彌補(bǔ)以上數(shù)據(jù)存儲(chǔ)無(wú)法完成的功能。京東評(píng)論系統(tǒng)為此使用了solr/elasticsearch搜索服務(wù),它們都是基于Lucene的全文檢索框架,也是分布式的搜索框架(solr4.0后增加了solr cloud以支持分布式),支持?jǐn)?shù)據(jù)分片、切面統(tǒng)計(jì)、高亮顯示、分詞檢索等功能,利用搜索框架能有效解決前臺(tái)評(píng)論數(shù)據(jù)統(tǒng)計(jì)、列表篩選問(wèn)題,也能支持后臺(tái)系統(tǒng)中的關(guān)鍵詞顯示、多字段檢索及模糊查詢(xún),可謂是一舉多得。
搜索在構(gòu)建索引時(shí),屬性字段可分為存儲(chǔ)字段與索引字段,存儲(chǔ)字段在創(chuàng)建索引后會(huì)將內(nèi)容存儲(chǔ)于索引文檔中,同時(shí)也會(huì)占用相應(yīng)的索引空間,查詢(xún)后可返回原始內(nèi)容,而索引字段創(chuàng)建索引后不占用索引空間也無(wú)法返回原始內(nèi)容,只能用于查詢(xún),因此對(duì)于較長(zhǎng)的內(nèi)容建議不進(jìn)行存儲(chǔ)索引。
評(píng)論搜索在構(gòu)建索引時(shí),主鍵評(píng)論ID的索引方式設(shè)置為存儲(chǔ),其它字段設(shè)置為索引,這樣不僅減少索引文件的存儲(chǔ)空間,也大大提升了索引的構(gòu)建效率與查詢(xún)性能。當(dāng)然,在使用搜索框架時(shí),業(yè)務(wù)數(shù)據(jù)量比較小的也可選擇將所有字段進(jìn)行存儲(chǔ),這樣在搜索中查詢(xún)出結(jié)果后將不需要從數(shù)據(jù)庫(kù)上查詢(xún)其它信息,也減輕了數(shù)據(jù)庫(kù)的壓力。
為了更好地應(yīng)對(duì)前后臺(tái)不同的業(yè)務(wù)場(chǎng)景,搜索集群被劃分為前臺(tái)搜索集群和后臺(tái)搜索集群。
前臺(tái)搜索集群根據(jù)商品編號(hào)進(jìn)行索引數(shù)據(jù)分片,用于解決評(píng)論前臺(tái)的評(píng)論數(shù)統(tǒng)計(jì)、評(píng)論列表篩選功能。評(píng)論數(shù)統(tǒng)計(jì),如果使用常規(guī)數(shù)據(jù)庫(kù)進(jìn)行統(tǒng)計(jì)時(shí),需要進(jìn)行sql上的group分組統(tǒng)計(jì),如果只有單個(gè)分組統(tǒng)計(jì)性能上還能接受,但京東的評(píng)論數(shù)統(tǒng)計(jì)則需要對(duì)1到5分的評(píng)論分別進(jìn)行統(tǒng)計(jì),分組增加的同時(shí)隨著統(tǒng)計(jì)量的增加數(shù)據(jù)庫(kù)的壓力也會(huì)增加,因此在mysql上通過(guò)group方式進(jìn)行統(tǒng)計(jì)是行不通的。而使用solr的切面統(tǒng)計(jì),只需要一次查詢(xún)便能輕松地統(tǒng)計(jì)出商品每個(gè)分級(jí)的評(píng)論數(shù),而且查詢(xún)性能也是毫秒級(jí)的。切面統(tǒng)計(jì)用法如下:
評(píng)論列表,只需根據(jù)條件從搜索中查詢(xún)出評(píng)論ID集合,再根據(jù)評(píng)論ID到mysql、Hbase中查詢(xún)出評(píng)論的其它字段信息,經(jīng)過(guò)數(shù)據(jù)組裝后便可返回前臺(tái)進(jìn)行展示。
后臺(tái)搜索集群,評(píng)論后臺(tái)系統(tǒng)需要對(duì)評(píng)論進(jìn)行查詢(xún),其中包括關(guān)鍵詞高亮顯示、全字段檢索、模糊查詢(xún)等,為此solr/elasticsearch都是個(gè)很好的選擇,目前使用elasticsearch。
未來(lái)也計(jì)劃將前臺(tái)搜索集群切換為elasticsearch。
數(shù)據(jù)緩存
面對(duì)數(shù)十億的數(shù)據(jù)請(qǐng)求,直接擊穿到mysql、搜索服務(wù)上都是無(wú)法承受的,所以需要對(duì)評(píng)論數(shù)據(jù)進(jìn)行緩存,在此選擇了高性能緩存redis,根據(jù)不同的業(yè)務(wù)數(shù)據(jù)進(jìn)行集群劃分,同時(shí)采用多機(jī)房主從方式部署解決單點(diǎn)問(wèn)題,這樣只需要對(duì)不同的緩存集群進(jìn)行相應(yīng)的水平擴(kuò)展便能快速提升數(shù)據(jù)吞吐能力,也有效地保證了服務(wù)的高性能、高可用。
當(dāng)然,緩存設(shè)計(jì)時(shí)還有很多細(xì)節(jié)可以進(jìn)行巧妙處理的,如:
當(dāng)用戶(hù)新發(fā)表一條評(píng)論,要實(shí)現(xiàn)前臺(tái)實(shí)時(shí)展示,可以將新增的評(píng)論數(shù)向首屏列表緩存中追加最新的評(píng)論信息;
評(píng)論數(shù)是讀多寫(xiě)少,這樣就可以將評(píng)論數(shù)持久化到redis當(dāng)中,只有當(dāng)數(shù)據(jù)進(jìn)行更新時(shí)通過(guò)異步的方式去將緩存刷新即可;評(píng)論數(shù)展示可通過(guò)nginx+lua的方式提供服務(wù),服務(wù)請(qǐng)求無(wú)需回源到應(yīng)用上,不僅提升服務(wù)性能,也能減輕應(yīng)用系統(tǒng)的壓力;
對(duì)于評(píng)論列表,通常訪問(wèn)的都是第一屏的數(shù)據(jù),也就是第一頁(yè)的數(shù)據(jù),可以將第一頁(yè)的數(shù)據(jù)緩存到redis當(dāng)中,有數(shù)據(jù)更新時(shí)再通過(guò)異步程序去更新;
對(duì)于秒殺類(lèi)的商品,評(píng)論數(shù)據(jù)可以結(jié)合本地緩存提前進(jìn)行預(yù)熱,這樣當(dāng)秒殺流量瞬間涌入的時(shí)候也不會(huì)對(duì)緩存集群造成壓力;通過(guò)減短key長(zhǎng)度、去掉多余屬性、壓縮文本等方式節(jié)省內(nèi)存空間,提高內(nèi)存使用率。
數(shù)據(jù)容災(zāi)與高可用
引入了這么多的存儲(chǔ)方案就是為了解決大數(shù)據(jù)量存儲(chǔ)問(wèn)題及實(shí)現(xiàn)數(shù)據(jù)服務(wù)的高可用,同時(shí)合理的部署設(shè)計(jì)與相應(yīng)的容災(zāi)處理也必須要有的。以上數(shù)據(jù)存儲(chǔ)基本都使用多機(jī)房主從方式部署,各機(jī)房?jī)?nèi)部實(shí)現(xiàn)主從結(jié)構(gòu)進(jìn)行數(shù)據(jù)同步。如圖:
mysql集群數(shù)據(jù)庫(kù)拆庫(kù)后需要對(duì)各分庫(kù)進(jìn)行多機(jī)房主從部署,系統(tǒng)應(yīng)用進(jìn)行讀寫(xiě)分離并根據(jù)機(jī)房進(jìn)行就近調(diào)用,當(dāng)主機(jī)房數(shù)據(jù)庫(kù)出現(xiàn)故障后將故障機(jī)房的數(shù)據(jù)操作都切換到其它機(jī)房,待故障排除后再進(jìn)行數(shù)據(jù)同步與流量切換。
使用主從機(jī)房部署的方式所有數(shù)據(jù)更新操作都要在主庫(kù)上進(jìn)行,而當(dāng)主機(jī)房故障是需要通過(guò)數(shù)據(jù)庫(kù)主從關(guān)系的重建、應(yīng)用重新配置與發(fā)布等一系列操作后才能解決流量切換,過(guò)程較為復(fù)雜且影響面較大,所以這是個(gè)單點(diǎn)問(wèn)題,為此實(shí)現(xiàn)數(shù)據(jù)服務(wù)多中心將是我們下一個(gè)目標(biāo)。
多中心根據(jù)特定規(guī)則將用戶(hù)分別路由到不同機(jī)房進(jìn)行數(shù)據(jù)讀寫(xiě),各機(jī)房間通過(guò)數(shù)據(jù)總線進(jìn)行數(shù)據(jù)同步,當(dāng)某一機(jī)房出現(xiàn)故障,只需要一鍵操作便能快速地將故障機(jī)房的用戶(hù)流量全部路由到其它機(jī)房,實(shí)現(xiàn)了數(shù)據(jù)的多寫(xiě)多活,也進(jìn)一步實(shí)現(xiàn)了服務(wù)的高可用。數(shù)據(jù)多中心如下:

hbase集群目前使用的是京東的公有集群,實(shí)現(xiàn)了雙機(jī)房主備部署,主集群出現(xiàn)故障后自動(dòng)將流量切換到備用集群,而當(dāng)hbase整個(gè)集群故障時(shí)還可對(duì)其進(jìn)行降級(jí),同步只寫(xiě)入緩存及備用存儲(chǔ)mongo,待集群恢復(fù)后再由后臺(tái)異步任務(wù)將數(shù)據(jù)回寫(xiě)到hbase當(dāng)中。
搜索集群根據(jù)商品編號(hào)進(jìn)行索引數(shù)據(jù)分片多機(jī)房主從部署,并保證至少3個(gè)從節(jié)點(diǎn)并部署于多個(gè)機(jī)房當(dāng)中,當(dāng)主節(jié)點(diǎn)出現(xiàn)故障后從這些從節(jié)點(diǎn)選取其中一個(gè)作為新的主提供服務(wù)。集群主節(jié)點(diǎn)只提供異步任務(wù)進(jìn)行索引更新操作,從節(jié)點(diǎn)根據(jù)應(yīng)用機(jī)房部署情況提供索引查詢(xún)服務(wù)。
Redis緩存集群主從部署仍是標(biāo)配,主節(jié)點(diǎn)只提供數(shù)據(jù)的更新操作,從節(jié)點(diǎn)提供前臺(tái)緩存讀服務(wù),實(shí)現(xiàn)緩存數(shù)據(jù)的讀寫(xiě)分離,提升了緩存服務(wù)的處理能力。當(dāng)主節(jié)點(diǎn)出現(xiàn)故障,選取就近機(jī)房的一個(gè)從節(jié)點(diǎn)作為新主節(jié)點(diǎn)提供寫(xiě)服務(wù),并將主從關(guān)系進(jìn)行重新構(gòu)建。任何一從節(jié)點(diǎn)出現(xiàn)故障都可通過(guò)內(nèi)部的配置中心進(jìn)行一鍵切換,將故障節(jié)點(diǎn)的流量切換到其它的從節(jié)點(diǎn)上。
總結(jié)
整體數(shù)據(jù)架構(gòu)并沒(méi)有什么高大上的設(shè)計(jì),而且整體數(shù)據(jù)架構(gòu)方案也是為了解決實(shí)際痛點(diǎn)和業(yè)務(wù)問(wèn)題而演進(jìn)過(guò)來(lái)的。數(shù)據(jù)存儲(chǔ)方案上沒(méi)有最好的,只有最適合的,因此得根據(jù)不同的時(shí)期、不同的業(yè)務(wù)場(chǎng)景去選擇合適的設(shè)計(jì)才是最關(guān)鍵的,大家有什么好的方案和建議可以相互討論與借鑒,系統(tǒng)的穩(wěn)定、高性能、高可用才是王道。
核心關(guān)注:拓步ERP系統(tǒng)平臺(tái)是覆蓋了眾多的業(yè)務(wù)領(lǐng)域、行業(yè)應(yīng)用,蘊(yùn)涵了豐富的ERP管理思想,集成了ERP軟件業(yè)務(wù)管理理念,功能涉及供應(yīng)鏈、成本、制造、CRM、HR等眾多業(yè)務(wù)領(lǐng)域的管理,全面涵蓋了企業(yè)關(guān)注ERP管理系統(tǒng)的核心領(lǐng)域,是眾多中小企業(yè)信息化建設(shè)首選的ERP管理軟件信賴(lài)品牌。
轉(zhuǎn)載請(qǐng)注明出處:拓步ERP資訊網(wǎng)http://www.oesoe.com/
本文標(biāo)題:京東評(píng)價(jià)系統(tǒng)海量數(shù)據(jù)存儲(chǔ)設(shè)計(jì)
本文網(wǎng)址:http://www.oesoe.com/html/solutions/14019319954.html