互聯(lián)網(wǎng)技術(shù)的發(fā)展讓大多數(shù)企業(yè)能夠積累大量的數(shù)據(jù)区端,而企業(yè)需要靈活快速地從這些數(shù)據(jù)中提取出有價(jià)值的信息來(lái)服務(wù)用戶或幫助企業(yè)自身決策。然而處理器的主頻和散熱遇到了瓶頸澳腹,CPU難以通過(guò)縱向優(yōu)化來(lái)提升性能织盼,所以多核這種橫向擴(kuò)展成為了主流。也因此酱塔,開(kāi)發(fā)者需要利用多核甚至分布式架構(gòu)技術(shù)來(lái)提高企業(yè)的大數(shù)據(jù)處理能力沥邻。這些技術(shù)隨著開(kāi)源軟件的成功而在業(yè)界得到廣泛應(yīng)用。
下面我稍微介紹一些大數(shù)據(jù)應(yīng)用中通常出現(xiàn)的一些原理或者說(shuō)是特征羊娃。
基本原理
分布式:將數(shù)據(jù)分布到不同的節(jié)點(diǎn)(機(jī)器)唐全,從而存儲(chǔ)大量的數(shù)據(jù)。而分布式同時(shí)為并行讀寫(xiě)和計(jì)算提供了基礎(chǔ)蕊玷,這樣就能提高數(shù)據(jù)的處理能力邮利。
為什么不直接使用分布式的關(guān)系型數(shù)據(jù)庫(kù),比如主從模式的mysql垃帅?這主要是效率的問(wèn)題延届。分布式關(guān)系型數(shù)據(jù)庫(kù)為了實(shí)現(xiàn)分布式事務(wù)、線性一致性贸诚、維護(hù)自身索引結(jié)構(gòu)等功能會(huì)對(duì)性能造成影響方庭。而正如剛剛背景所提到,大數(shù)據(jù)需求重點(diǎn)是快速處理大量數(shù)據(jù)赦颇,幫助用戶和企業(yè)的決策二鳄。這個(gè)決策就包括推薦赴涵、監(jiān)控媒怯、數(shù)據(jù)分析等。這些場(chǎng)景并不一定需要數(shù)據(jù)庫(kù)這種嚴(yán)格的約束髓窜,是OLAP而非OLTP扇苞。所以大數(shù)據(jù)技術(shù)會(huì)通過(guò)解除這些限制而提升性能。
除了分布式外寄纵,還可以利用
可靠性相關(guān)
由于這個(gè)分享會(huì)的標(biāo)題起得有點(diǎn)大晌姚,包括存儲(chǔ)、搜索歇竟、計(jì)算三大塊挥唠,而且篇幅有限,所以我就只根據(jù)這三塊中我了解且比較流行的開(kāi)源組件來(lái)分享焕议,而且只講解大概的原理宝磨。畢竟下面的每個(gè)組件的原理和實(shí)戰(zhàn)都可以各自出一本五六百頁(yè)的書(shū)了,而且還沒(méi)涉及源碼細(xì)節(jié)的盅安。下面首先來(lái)介紹分布式文件系統(tǒng)唤锉,就是把我們單臺(tái)計(jì)算機(jī)的文件系統(tǒng)擴(kuò)展到多臺(tái)。
HDFS(Hadoop Distributed File System)
架構(gòu)原理
圖中有8臺(tái)機(jī)器或者容器别瞭,兩個(gè)client窿祥、5個(gè)DataNode、1個(gè)NameNode蝙寨。一個(gè)分布式文本系統(tǒng)晒衩,組成:NameNode、DataNode和secondary namenode
讀寫(xiě)流程
寫(xiě)入:client端調(diào)用filesystem的create方法嬉探,后者通過(guò)RPC調(diào)用NN的create方法擦耀,在其namespace中創(chuàng)建新的文件。NN會(huì)檢查該文件是否存在涩堤、client的權(quán)限等眷蜓。成功時(shí)返回FSDataOutputStream對(duì)象。client對(duì)該對(duì)象調(diào)用write方法胎围,這個(gè)對(duì)象會(huì)選出合適存儲(chǔ)數(shù)據(jù)副本的一組datanode吁系,并以此請(qǐng)求DN分配新的block。這組DN會(huì)建立一個(gè)管線白魂,例如從client node到最近的DN_1汽纤,DN_1傳遞自己接收的數(shù)據(jù)包給DN_2。DFSOutputStream自己還有一個(gè)確認(rèn)隊(duì)列福荸。當(dāng)所有的DN確認(rèn)寫(xiě)入完成后蕴坪,client關(guān)閉輸出流,然后告訴NN寫(xiě)入完成逞姿。
讀却俏恕:client端通過(guò)DistributedFileSystem對(duì)象調(diào)用open方法,同樣通過(guò)RPC調(diào)用遠(yuǎn)程的NN方法獲取所要查詢的文件所涉及的blocks所存儲(chǔ)的DN位置滞造,而且這些位置是按照距離排序的。返回的結(jié)果是一個(gè)FSDataInputStream對(duì)象栋烤,對(duì)輸入流對(duì)象調(diào)用read方法谒养。輸入流會(huì)從距離最近的DN中讀取數(shù)據(jù),將數(shù)據(jù)傳遞到client,讀取結(jié)束后關(guān)閉流买窟。
這個(gè)機(jī)制看上去是很笨重的丰泊,有了這個(gè)分布式文件系統(tǒng)的基礎(chǔ),其他組件就能利用這個(gè)系統(tǒng)提供的 API 來(lái)對(duì)數(shù)據(jù)的存儲(chǔ)進(jìn)行優(yōu)化始绍。在介紹下一個(gè)組件前瞳购,先對(duì)主要的主鍵索引作簡(jiǎn)單的介紹。
索引
類型
哈希SSTables/LSM樹(shù)BTree/B+Tree大致原理數(shù)據(jù)結(jié)構(gòu):哈希表亏推。內(nèi)存:有序集合学赛,例如紅黑樹(shù)、平衡二叉樹(shù)吞杭、跳躍表盏浇。
磁盤(pán):一個(gè)個(gè)獨(dú)立文件,里面包含一個(gè)個(gè)數(shù)據(jù)塊芽狗。
寫(xiě)入:內(nèi)存維護(hù)一個(gè)有序集合绢掰,數(shù)據(jù)大小達(dá)到一定閾值寫(xiě)入磁盤(pán)。后臺(tái)會(huì)按照特定策略合并segment童擎。讀鹊尉ⅰ:先查詢內(nèi)存,然后磁盤(pán)中的最新segment顾复,然后第二新哑芹,以此類推。數(shù)據(jù)結(jié)構(gòu):平衡多叉樹(shù)捕透。寫(xiě)入:通過(guò)二分查找找到相應(yīng)的葉子結(jié)點(diǎn)進(jìn)行修改聪姿。讀取:同上乙嘀。優(yōu)勢(shì)適合數(shù)據(jù)經(jīng)常更新寫(xiě)入快末购,順序讀取快,容易壓縮讀取快虎谢,更時(shí)間可控劣勢(shì)必須存儲(chǔ)在內(nèi)存盟榴;范圍查詢效率低隨機(jī)讀取,讀取舊數(shù)據(jù)較慢寫(xiě)入較慢涉及數(shù)據(jù)庫(kù)Mysql婴噩、RedisMongoDB擎场、Elasticsearch、HBaseMysql几莽、MongoDB
主要的主鍵索引有哈希迅办、LSM、BTree章蚣。下面主要涉及到LSM樹(shù)站欺,所以哈希和BTree這里就不多說(shuō)了。LSM樹(shù)有內(nèi)存和磁盤(pán)兩個(gè)部分....,以跳躍表為例矾策,大致的模型如下圖
內(nèi)存的 MemStore 是一個(gè)有序集合磷账,數(shù)據(jù)寫(xiě)入會(huì)先寫(xiě)入這里,當(dāng)大小達(dá)到閾值就會(huì) flush 到磁盤(pán)贾虽。而后臺(tái)會(huì)有程序按一定策略對(duì)這些文件進(jìn)行合并逃糟。合并的原因有:減少小文件,進(jìn)而減少讀取時(shí)IO來(lái)提升讀性能蓬豁。數(shù)據(jù)合并绰咽,比如圖中第二個(gè)file有數(shù)據(jù)a,但現(xiàn)在客戶端發(fā)送請(qǐng)求要把它刪掉或進(jìn)行修改庆尘,如果每次刪改都要把數(shù)據(jù)找到再調(diào)整剃诅,就會(huì)有大量的磁盤(pán)IO,所以這些操作一般只做標(biāo)記驶忌,等到后續(xù)文件合并時(shí)才真正對(duì)數(shù)據(jù)進(jìn)行修改矛辕。還有一個(gè)原因是調(diào)整排序,因?yàn)閒lush后數(shù)據(jù)只在file內(nèi)部有序付魔,合并能夠調(diào)整整體排序聊品。正因?yàn)檫@種結(jié)構(gòu),所以LSM的寫(xiě)入是很快的几苍,范圍讀取也快翻屈,因?yàn)閿?shù)據(jù)已經(jīng)有序。而為了保證不讀取到舊版本的數(shù)據(jù)妻坝,所以讀取需要從最新的開(kāi)始遍歷伸眶,這也導(dǎo)致讀取舊數(shù)據(jù)的效率較低。當(dāng)然刽宪,這里面還能優(yōu)化厘贼,但細(xì)節(jié)就不說(shuō)了。
HBase
簡(jiǎn)介
HBase 就是基于 HDFS API 構(gòu)建的一個(gè)可以在線低延遲訪問(wèn)大數(shù)據(jù)的NoSQL數(shù)據(jù)庫(kù)圣拄。本質(zhì)上就是給 HDFS 加上一個(gè) LSM Tree 索引嘴秸,從而提高讀寫(xiě)性能。當(dāng)然庇谆,即便優(yōu)化了岳掐,這個(gè)高性能也是相對(duì)大數(shù)據(jù)量而言。實(shí)際上“HBase并不快饭耳,只是當(dāng)數(shù)據(jù)量很大的時(shí)候它慢的不明顯”串述。由于是 NoSQL 數(shù)據(jù)庫(kù),所以它有文檔型數(shù)據(jù)庫(kù)的弱項(xiàng)哥攘,即基本不支持表關(guān)聯(lián)剖煌。
特點(diǎn)
- 數(shù)據(jù)量大材鹦,單表至少超千萬(wàn)逝淹。對(duì)稀疏數(shù)據(jù)尤其適用耕姊,因?yàn)槲臋n型數(shù)據(jù)庫(kù)的 null 就相當(dāng)于整個(gè)字段沒(méi)有,是不需要占用空間的栅葡。
- 高并發(fā)寫(xiě)入茉兰,正如上面 LSM 樹(shù)所說(shuō)。
- 讀取近期小范圍數(shù)據(jù)欣簇,效率較高规脸,大范圍需要計(jì)算引擎支持。
- 數(shù)據(jù)多版本
- 小數(shù)據(jù)
- 復(fù)雜數(shù)據(jù)分析熊咽,比如關(guān)聯(lián)莫鸭、聚合等,僅支持過(guò)濾
- 不支持全局跨行事務(wù)横殴,僅支持單行事務(wù)
場(chǎng)景
更多適用場(chǎng)景可以根據(jù)HBase的特點(diǎn)判斷
架構(gòu)原理
這里大概有10臺(tái)機(jī)器或節(jié)點(diǎn)呻粹,5個(gè)DataNode、兩個(gè)RegionServer苏研、一個(gè)Client等浊、Master、ZooKeeper
- 實(shí)現(xiàn)Master的高可用:當(dāng)active master宕機(jī)纹蝴,會(huì)通過(guò)選舉機(jī)制選取出新master庄萎。
- 管理系統(tǒng)元數(shù)據(jù):比如正常工作的RegionServer列表。
- 輔助RS的宕處理:發(fā)現(xiàn)宕機(jī)塘安,通知master處理糠涛。
- 分布式鎖:方式多個(gè)client對(duì)同一張表進(jìn)行表結(jié)構(gòu)修改而產(chǎn)生沖突。
- 處理 client 的 DDL 請(qǐng)求
- RegionServer 數(shù)據(jù)的負(fù)載均衡兼犯、宕機(jī)恢復(fù)等
- 清理過(guò)期日志
- Store:一個(gè)Store存儲(chǔ)一個(gè)列簇砸脊,即一組列具篇。
- MemStore和HFile:寫(xiě)緩存,閾值為128M凌埂,達(dá)到閾值會(huì)flush成HFile文件驱显。后臺(tái)有程序?qū)@些HFile進(jìn)行合并。
- HLog(WAL):提高數(shù)據(jù)可靠性瞳抓。寫(xiě)入數(shù)據(jù)時(shí)先按順序?qū)懭際Log埃疫,然后異步刷新落盤(pán)。這樣即便 MemoStore 的數(shù)據(jù)丟失孩哑,也能通過(guò)HLog恢復(fù)栓霜。而HBase數(shù)據(jù)的主從復(fù)制也是通過(guò)HLog回放實(shí)現(xiàn)的。
- BlockCache
- Region:數(shù)據(jù)表的一個(gè)分片横蜒,當(dāng)數(shù)據(jù)表大小達(dá)到一定閾值后會(huì)“水平切分”成多個(gè)Region胳蛮,通常同一張表的Region會(huì)分不到不同的機(jī)器上。
讀寫(xiě)過(guò)程
寫(xiě)入和讀取的流程類似瓶竭。
ElasticSearch
簡(jiǎn)介
Elastic Stack 是以 Elasticsearch 為中心開(kāi)發(fā)的一組組件督勺,其中Kibana、Logstash斤贰、Beats使用較多智哀。
Beats 是用 GO 實(shí)現(xiàn)的一個(gè)開(kāi)源的用來(lái)構(gòu)建輕量級(jí)數(shù)據(jù)匯集組件,可用于將各種類型的數(shù)據(jù)發(fā)送至 Elasticsearch 與 Logstash荧恍。
Logstash:流入瓷叫、流出 Elasticsearch 的傳送帶。其他MQ或計(jì)算引擎也可以導(dǎo)入ES送巡。
利用 Logstash 同步 Mysql 數(shù)據(jù)時(shí)并非使用 binlog摹菠,而且不支持同步刪除操作。
Kibana 是 ES 大數(shù)據(jù)的圖形化展示工具骗爆。集成了 DSL 命令行查看次氨、數(shù)據(jù)處理插件、繼承了 x-pack(收費(fèi))安全管理插件等摘投。
Elasticsearch 搜索引擎煮寡,它并不是基于 HDFS 建立的虹蓄,而是自己實(shí)現(xiàn)了分布式存儲(chǔ),并通過(guò)各種索引和壓縮技術(shù)來(lái)提高搜索的性能幸撕。當(dāng)然薇组,它作為文檔型數(shù)據(jù)庫(kù),其在內(nèi)存組織數(shù)據(jù)的方式也是類似LSM樹(shù)的杈帐。
特點(diǎn)
- 全文檢索体箕,like "%word%"
- 一定寫(xiě)入延遲的高效查詢
- 多維度數(shù)據(jù)分析
- 關(guān)聯(lián)
- 數(shù)據(jù)頻繁更新
- 不支持全局跨行事務(wù)专钉,僅支持單行事務(wù)
場(chǎng)景
框架原理
Cluster
Node:JVM進(jìn)程
Index:一組形成邏輯數(shù)據(jù)存儲(chǔ)的分片的集合跃须,數(shù)據(jù)庫(kù)
Shard:Lucene 索引站叼,用于存儲(chǔ)和處理 Elasticsearch 索引的一部分。
Segment:Lucene 段菇民,存儲(chǔ)了 Lucene 索引的一部分且不可變尽楔。結(jié)構(gòu)為倒排索引。
Document:條記錄第练,用以寫(xiě)入 Elasticsearch 索引并從中檢索數(shù)據(jù)阔馋。
增刪改查原理
Update = Delete + (Index - Ingest Pipeline)
細(xì)節(jié)補(bǔ)充
倒排索引
一般正向的就是通過(guò)文檔id找相應(yīng)的值,而倒排索引則是通過(guò)值找文檔id娇掏。通過(guò)倒排這種結(jié)構(gòu)呕寝,判斷哪些文檔包含某個(gè)關(guān)鍵詞時(shí),就不需要掃描所有文檔里面的值婴梧,而是從這個(gè)關(guān)鍵詞列表中去搜索即可下梢。而頻率主要是用來(lái)計(jì)算匹配程度的,默認(rèn)使用TF-IDF算法塞蹭。
為什么全文檢索中 ES 比 Mysql 快孽江?
Mysql 的輔助索引對(duì)于只有一個(gè)單詞的字段,查詢效率就跟 ES 差距不大番电。
select field1, field2
from tbl1
where field2 = a
and field3 in (1,2,3,4)
這里如果 field2 和 field3 都建立了索引岗屏,理論上速度跟 es 差不多。es最多把 field2 和 field3 concat 起來(lái)漱办,做到查詢時(shí)只走一次索引來(lái)提高查詢效率这刷。
但如果該字段是有多個(gè)單詞,那么缺乏分詞的 Mysql 就無(wú)法建立有效的索引洼冻,且查詢局限于右模糊崭歧,對(duì)于“%word%”的搜索效率是極低的。而 ES 通過(guò)分詞撞牢,仍然可以構(gòu)建出 term dictionary率碾。
然而 Term Dictionary 和 Position 加起來(lái)是很大的叔营,難以完全存儲(chǔ)在內(nèi)存。因此所宰,在查找 Term Dictionary 的過(guò)程會(huì)涉及磁盤(pán)IO绒尊,效率就會(huì)降低。為此仔粥,Luence 增加了 term index婴谱。這一層通過(guò) Lucene 壓縮算法,使得整個(gè) Term Index 存儲(chǔ)在內(nèi)存成為可能躯泰。搜索時(shí)在內(nèi)存找到相應(yīng)的節(jié)點(diǎn)谭羔,然后再到 Term Dictionary 找即可,省去大量磁盤(pán)IO麦向。
內(nèi)存消耗大
ES 之所以快瘟裸,很大程度是依賴 Lucene 的緩存以及緩存中的索引結(jié)構(gòu)。而這些緩存只有被預(yù)先加載到內(nèi)存才能做到快速的響應(yīng)诵竭,查詢沒(méi)有被加載的數(shù)據(jù)通常都是比較慢的话告,這是 ES 需要大量?jī)?nèi)存的原因之一。所以有人建議 ES 僅作為內(nèi)存索引庫(kù)卵慰,即與where沙郭、group by、in裳朋、sort等過(guò)濾病线、聚合相關(guān)的才存儲(chǔ)到 ES,而且其他字段并不能幫助查詢再扭,只會(huì)浪費(fèi)內(nèi)存空間氧苍。而查詢得出的id將返回通過(guò) Mysql 或者 Hbase 進(jìn)行第二次的查詢。由于是主鍵的搜索泛范,所以不會(huì)耗費(fèi)太多時(shí)間让虐。
而 ES 由于給了大部分內(nèi)存到 Lucene 緩存,那自己聚合計(jì)算時(shí)用的內(nèi)存空間就很有限了罢荡,這也是 ES 需要大量?jī)?nèi)存的原因赡突。
目前觸漫 ES 情況
剛剛起步,僅僅作為優(yōu)化部分慢sql查詢的解決方案区赵。而 ES 更強(qiáng)大的準(zhǔn)實(shí)時(shí)數(shù)據(jù)分析惭缰、文本搜索功能并沒(méi)有開(kāi)發(fā)。這其中有涉及到搜索優(yōu)化(排序規(guī)則笼才、分詞等)漱受、Kibana可視化、數(shù)據(jù)冷熱分離骡送、各種配置等昂羡,所以是需要一定的人力去學(xué)習(xí)和調(diào)試才能發(fā)揮它的潛能絮记。
從上面的介紹我們可以知道,ES 是不支持關(guān)聯(lián)的虐先,而且聚合計(jì)算的資源很有限怨愤。那這時(shí)就用到計(jì)算引擎了。
計(jì)算引擎
計(jì)算引擎目前主流的兩個(gè)開(kāi)源組件分別是 Spark 和 Flink蛹批。從兩個(gè)引擎的處理模型來(lái)看撰洗,Spark 的批處理更為高效,F(xiàn)link 則善于流處理腐芍,盡管兩者都向著流批一體化的方向發(fā)展差导。當(dāng)然,只要對(duì)弱項(xiàng)做優(yōu)化還是可以跟另一方未做太多優(yōu)化的強(qiáng)項(xiàng)比的甸赃,只是實(shí)現(xiàn)難度大些和效果上限可能略低柿汛。比如 Blink,阿里內(nèi)部的 Flink埠对,其 ML 模塊經(jīng)過(guò)優(yōu)化,在大部分常用模型的計(jì)算效率都能高于開(kāi)源的 Spark 的裁替。如果開(kāi)源 Spark 也經(jīng)過(guò)阿里那樣深度的優(yōu)化项玛,兩者的差距就難說(shuō)了。
簡(jiǎn)單提一下他們的特點(diǎn)
Spark
下面首先介紹 Spark遭商,它是一個(gè)用于大規(guī)模數(shù)據(jù)處理的統(tǒng)一分析引擎固灵,其內(nèi)部主要由 Scala 實(shí)現(xiàn)。Spark 當(dāng)初引起關(guān)注主要是它與 Hadoop 的三大件之一的 MapReduce 之間的比較劫流。Hadoop 的三大組件包括 HDFS巫玻、Yarn 和 MapReduce。他們?nèi)齻€(gè)都是可以拆分開(kāi)來(lái)單獨(dú)使用的祠汇。比如 Yarn 作為資源調(diào)度系統(tǒng)仍秤,傳統(tǒng) Spark 和 Flink 都會(huì)借助它的功能實(shí)現(xiàn)任務(wù)的調(diào)度。而 MapReduce 作為計(jì)算引擎可很,其計(jì)算速度當(dāng)時(shí)是弱于 Spark 的诗力,主要是 Spark 減少了不必要的磁盤(pán)IO;增加迭代計(jì)算功能我抠,從而更好支持機(jī)器學(xué)習(xí)苇本;引入了一些自動(dòng)優(yōu)化功能导坟。另外,Spark 廣泛的語(yǔ)言支持圈澈、API 更強(qiáng)的表達(dá)能力等優(yōu)點(diǎn)都讓 Spark 在當(dāng)時(shí)的離線計(jì)算領(lǐng)域中超越 MapReduce惫周。
功能豐富
4大場(chǎng)景:Spark 的高層組件包括Spark SQL、Spark Streaming康栈、Spark ML递递、GraphX。他們都是通過(guò)底層組件為 Spark Core 實(shí)現(xiàn)具體功能的啥么。但是在使用 Spark 的時(shí)候登舞,盡量是不要使用 Spark Core,因?yàn)楦邔咏M件的產(chǎn)生的 Spark Core一般會(huì)更高效悬荣,因?yàn)镾park做了不少優(yōu)化菠秒,具體后面再說(shuō)。
多種語(yǔ)言:支持 Java氯迂、Python践叠、R 和 Scala 來(lái)編寫(xiě)應(yīng)用代碼。
多種部署模式:本地嚼蚀、獨(dú)立部署禁灼、Mesos、Yarn轿曙、K8S
多種數(shù)據(jù)源:HDFS弄捕、HBase、Hive导帝、Cassandra守谓、Kafka等
架構(gòu)原理
Driver 是啟動(dòng) Spark 作業(yè)的JVM進(jìn)程,它會(huì)運(yùn)行作業(yè)(Application)里的main函數(shù)您单,并創(chuàng)建 SparkContext 對(duì)象斋荞。這個(gè) SparkContext 里面包含這次 Spark 計(jì)算的各種配置信息。Spark 通過(guò)它實(shí)現(xiàn)與 Cluster Manager 通信來(lái)申請(qǐng)計(jì)算資源睹限。這里的 Cluster Manager譬猫,在生產(chǎn)環(huán)境一般是 Mesos、Yarn 或者 K8s羡疗。這些 Manager 根據(jù)其管理的集群情況染服,給這個(gè) Spark 任務(wù)分配相應(yīng)的容器container扑庞,在容器中啟動(dòng) executor 進(jìn)程壳坪。這些啟動(dòng)后的 executor 會(huì)向 Driver 注冊(cè),之后 Driver 就可以把它根據(jù)用戶計(jì)算代碼生成出的計(jì)算任務(wù)task發(fā)送給這些 executor 執(zhí)行咳秉。計(jì)算結(jié)束后,結(jié)果可能輸出到 Driver秉颗,也可能輸出到當(dāng)前 executor 的磁盤(pán)痢毒,或者其他存儲(chǔ)。
作業(yè)例子
object SparkSQLExample {
def main(args: Array[String]): Unit = {
// 創(chuàng)建 SparkSession蚕甥,里面包含 sparkcontext
val spark = SparkSession
.builder()
.appName("Spark SQL basic example")
.getOrCreate()
import spark.implicits._
// 讀取數(shù)據(jù)
val df1 = spark.read.load("path1...")
val df2 = spark.read.load("path2...")
// 注冊(cè)表
df1.createOrReplaceTempView("tb1")
df2.createOrReplaceTempView("tb2")
// sql
val joinedDF = sql(
"""
|select tb1.id, tb2.field
|from tb1 inner join tb2
|on tb1.id = tb2.id
""".stripMargin)
// driver 終端顯示結(jié)果
joinedDF.show()
// 退出 spark
spark.stop()
}
}
SQL會(huì)經(jīng)過(guò)一層層的解析然后生成對(duì)應(yīng)的 Java 代碼來(lái)執(zhí)行哪替。
計(jì)算引擎的優(yōu)勢(shì)
與 HBase、 es 和傳統(tǒng)數(shù)據(jù)庫(kù)查詢比較菇怀,計(jì)算引擎的優(yōu)勢(shì):1)數(shù)據(jù)量大時(shí)速度快凭舶,2)計(jì)算更加靈活。
以大數(shù)據(jù)關(guān)聯(lián)為例:
- 基于內(nèi)存:計(jì)算引擎留有大量?jī)?nèi)存空間專門(mén)用于計(jì)算碴裙,盡量減少磁盤(pán) IO。
- 計(jì)算并行化
- 算法優(yōu)化
具體而言,Spark 提供了三種 Join 執(zhí)行策略:
從上面的例子可以看出計(jì)算引擎相比于其他組件在計(jì)算方面的優(yōu)勢(shì)。
數(shù)據(jù)流動(dòng)
下面通過(guò)一張圖小作,從另一個(gè)角度了解 Spark 的運(yùn)作亭姥。
這是一張簡(jiǎn)單的數(shù)據(jù)流程圖。描述了一個(gè) WorkCount 的數(shù)據(jù)流向顾稀。其主要代碼如下:
// 假設(shè)每個(gè) block 里的數(shù)據(jù)如下
// a
// b
// a
val textFile = sc.textFile("hdfs://...")
val counts = textFile.map(word => (word, 1)) // a -> <a,1>
.reduceByKey(_ + _) // <a,<1,1>> -> <a,2>
counts.saveAsTextFile("hdfs://...")
圖中同一階段有多個(gè)數(shù)據(jù)流體現(xiàn)的是并行达罗。中間的 shuffle 是在聚合、關(guān)聯(lián)静秆、全局排序等操作時(shí)會(huì)出現(xiàn)的粮揉。比如這里的 reduceByKey 就是將相同 key 的數(shù)據(jù)移動(dòng)到相同的 partition。這樣就能對(duì)所有的 a 進(jìn)行加總抚笔,從而得出 a 的總數(shù)扶认。
上圖的任務(wù)是一次性的,或者是周期性的塔沃,數(shù)據(jù)的驅(qū)動(dòng)是拉取型的蝠引。如果將數(shù)據(jù)塊換成數(shù)據(jù)流阳谍,map 和 reduce 在啟動(dòng)后就一直存在,并接受數(shù)據(jù)源不斷發(fā)送過(guò)來(lái)的信息螃概,那就變成了流計(jì)算矫夯。即由周期性變?yōu)橐恢碧幚恚瑥亩優(yōu)閷?shí)時(shí)處理吊洼,由主動(dòng)拉取變?yōu)楸粍?dòng)接收的形式训貌。下面就來(lái)介紹 Flink 計(jì)算引擎。
Flink
Flink 同樣是分布式的計(jì)算引擎冒窍,主要基于Java實(shí)現(xiàn)递沪,但它的特色主要體現(xiàn)在流式計(jì)算。這個(gè)引擎流行的主要推手是阿里综液。阿里在19年初開(kāi)源了它修改過(guò)的 Flink款慨,收購(gòu)了 Flink 的母公司,并在各種線下技術(shù)論壇上推廣 Flink谬莹,讓 Flink 在 19 年的關(guān)注度極速上升檩奠。
除了在實(shí)時(shí)計(jì)算領(lǐng)域,F(xiàn)link 在其他領(lǐng)域或許稍微落后于 Spark附帽,畢竟 Spark 發(fā)展比較早埠戳,其生態(tài)比 Flink 要成熟更多。Flink 目前支持 Scala蕉扮、Java 和 Python 來(lái)寫(xiě)任務(wù)代碼整胃。功能上同樣支持批計(jì)算、ML喳钟、Graph屁使。部署工具、支持的數(shù)據(jù)源也 Spark 類似奔则。
場(chǎng)景
架構(gòu)原理
細(xì)節(jié)補(bǔ)充
和 Spark 一樣,F(xiàn)link 也會(huì)根據(jù) SQL 或者業(yè)務(wù)代碼生成 DAG 圖祠丝,然后將任務(wù)劃分并發(fā)送給不同的節(jié)點(diǎn)執(zhí)行疾呻。最大的不同正如之前所說(shuō),數(shù)據(jù)是實(shí)時(shí)地写半、一條條或一小批一小批地不斷流進(jìn)這些節(jié)點(diǎn)岸蜗,然后節(jié)點(diǎn)輸出響應(yīng)的結(jié)果。而在這種場(chǎng)景下叠蝇,F(xiàn)link 在一定程度上解決了實(shí)時(shí)處理中的不少難點(diǎn)璃岳。
與 Spark 比較
Spark:
Flink:
小紅書(shū)實(shí)時(shí)技術(shù)
小紅書(shū)舊的離線框架和我們現(xiàn)在的大數(shù)據(jù)體系有點(diǎn)類似,都是把埋點(diǎn)數(shù)據(jù)上報(bào)到日志服務(wù)内狗,然后進(jìn)入離線數(shù)倉(cāng)怪嫌,只是小紅書(shū)用 Hive,我們用 DataWorks柳沙。然后我們同樣也有 T+1 的用戶畫(huà)像岩灭、BI報(bào)表和推薦的訓(xùn)練數(shù)據(jù)。
而后續(xù)的實(shí)時(shí)框架是這樣的
日志服務(wù)的埋點(diǎn)數(shù)據(jù)先進(jìn)入 Kafka 這一消息隊(duì)列里面赂鲤。不太清楚為什么要加上 Kafka 這一中間件噪径,或許當(dāng)時(shí)并沒(méi)有開(kāi)源的 日志服務(wù)到Flink 的 connecter 吧。但總之数初,引入 Flink 之后就可以實(shí)時(shí)累計(jì)埋點(diǎn)中的數(shù)據(jù)找爱,進(jìn)而產(chǎn)生實(shí)時(shí)的畫(huà)像、BI指標(biāo)和訓(xùn)練數(shù)據(jù)了泡孩。下面介紹一下這個(gè)實(shí)時(shí)歸因
如上圖所以车摄,用戶app屏幕展示了4個(gè)筆記,然后就會(huì)有4條曝光埋點(diǎn)仑鸥,而如果點(diǎn)擊筆記吮播、點(diǎn)贊筆記以及從筆記中退出都會(huì)有相應(yīng)的埋點(diǎn)。通過(guò)這些埋點(diǎn)就可以得出右面兩份簡(jiǎn)單的訓(xùn)練或分析數(shù)據(jù)眼俊。這些數(shù)據(jù)跟原來(lái)已經(jīng)積累的筆記/用戶畫(huà)像進(jìn)行關(guān)聯(lián)就能得出一份維度更多的數(shù)據(jù)意狠,用于實(shí)時(shí)的分析或模型預(yù)測(cè)。實(shí)時(shí)模型訓(xùn)練這一塊至少小紅書(shū)在19年8月都還沒(méi)有實(shí)現(xiàn)疮胖。下圖是小紅書(shū)推薦預(yù)測(cè)模型的演進(jìn)
那么如何進(jìn)行實(shí)時(shí)訓(xùn)練深度學(xué)習(xí)模型呢环戈?以下是我的一些想法闷板。借助一個(gè)阿里的開(kāi)源框架flink-ai-extended。
如上圖所示院塞,這是 flink 的數(shù)據(jù)流結(jié)構(gòu)圖遮晚,左邊 source 為數(shù)據(jù)源,然后進(jìn)過(guò)join迫悠、udf等算子進(jìn)行訓(xùn)練樣本數(shù)據(jù)的生成鹏漆,然后傳遞給一個(gè) UDTF/FlatMap 算子,這實(shí)際上也是一個(gè) Flink 節(jié)點(diǎn)创泄,但它里面包含的是 Tensorflow 的訓(xùn)練 worker艺玲,而上下也是 Flink 的節(jié)點(diǎn),都是包含了 Tensorflow 訓(xùn)練所需的一些角色鞠抑,這樣數(shù)據(jù)源源不斷地實(shí)時(shí)進(jìn)入 TF 模型來(lái)完成實(shí)時(shí)訓(xùn)練饭聚。TF 也可以因此借助 Flink 的分布式框架來(lái)完成分布式的學(xué)習(xí)。多臺(tái)GPU或者CPU或許應(yīng)該會(huì)比一臺(tái)GPU的訓(xùn)練效率更高搁拙。
這個(gè)框架同時(shí)適用于模型預(yù)測(cè)秒梳,只要把里面的訓(xùn)練角色換成訓(xùn)練完成的 model,也就可以進(jìn)行實(shí)時(shí)的預(yù)測(cè)箕速,而且這里借助 Flink 內(nèi)部的通信機(jī)制酪碘,效率應(yīng)該會(huì)比普通的 http 調(diào)用要快不少。
總結(jié)
本次分享由于時(shí)間有限盐茎,講的都是比較淺層的東西兴垦,實(shí)際上剛剛所說(shuō)的每一個(gè)組件里面包含的內(nèi)容都不少,都可以作為一個(gè)長(zhǎng)遠(yuǎn)的目標(biāo)去研究和改造字柠。說(shuō)回分享的主題之一探越,使用場(chǎng)景。
首先是存儲(chǔ)窑业,上述介紹的 HDFS钦幔、HBase、ES(ES雖然是搜索引擎常柄,但它也可以在某些方面替代傳統(tǒng)關(guān)系型數(shù)據(jù)的功能) 都是適用于 OLAP 場(chǎng)景鲤氢,即分析推薦而非事務(wù)。從公司目前的情況來(lái)看西潘,HDFS 基本可以忽略铜异,因?yàn)橐呀?jīng)有 DataWork,數(shù)據(jù)的存儲(chǔ)暫時(shí)不是問(wèn)題秸架。更多的問(wèn)題在于數(shù)據(jù)使用時(shí)的性能。HBase 和 ES 作為文檔型數(shù)據(jù)庫(kù)咆蒿,適合一對(duì)多的數(shù)據(jù)模型东抹,比如將帖子和其評(píng)論作為一個(gè)整體來(lái)存儲(chǔ)蚂子。對(duì)于多對(duì)一、多對(duì)多的模型缭黔,文檔型數(shù)據(jù)庫(kù)實(shí)際上并不合適食茎,但可以通過(guò)合并寬表、應(yīng)用層關(guān)聯(lián)等方式在一定程度上進(jìn)行彌補(bǔ)馏谨。而如果多對(duì)多關(guān)系確實(shí)復(fù)雜别渔、量大、文檔型數(shù)據(jù)庫(kù)性能無(wú)法滿足惧互,比如一些大型社交網(wǎng)絡(luò)哎媚,那么可以考慮圖數(shù)據(jù)庫(kù)。
當(dāng)決定嘗試文檔型數(shù)據(jù)庫(kù)時(shí)喊儡,HBase 的特點(diǎn)在于較為快速地查詢小范圍的新數(shù)據(jù)拨与,而且這條數(shù)據(jù)可以很大。ES 的特點(diǎn)則在于快速的全文檢索艾猜、準(zhǔn)實(shí)時(shí)的數(shù)據(jù)分析买喧。當(dāng)然,分析的復(fù)雜度是不能跟計(jì)算引擎比的匆赃,比如關(guān)聯(lián)淤毛、機(jī)器學(xué)習(xí)等。但通過(guò)合并寬表算柳、各種where低淡、group by操作,還是能滿足不少需求的埠居,尤其是應(yīng)用的搜索功能查牌,ES 實(shí)現(xiàn)起來(lái)是比較簡(jiǎn)單的。目前公司并沒(méi)有應(yīng)用它的強(qiáng)項(xiàng)滥壕,最好由專人負(fù)責(zé)它的調(diào)試纸颜,尤其是搜索排序方面。
然后是計(jì)算引擎绎橘,目前公司用的 MaxCompute 已經(jīng)能夠滿足離線計(jì)算的各種需求胁孙,或者就欠缺實(shí)時(shí)計(jì)算了。但公司目前實(shí)時(shí)性需求不多而且也不緊急称鳞,所以開(kāi)發(fā)一直都沒(méi)有啟動(dòng)涮较。目前就看明年推薦是否有這樣的需求,而且有相應(yīng)的prd出來(lái)了冈止。而考慮到成本和靈活性狂票,自建或許是更好的選擇,比如剛剛提到的 Flink + Tensorflow熙暴。
以上便是這次分享會(huì)的全部?jī)?nèi)容闺属,謝謝大家的參與慌盯。
參考:
書(shū)籍:
文章:
文檔:
分享: