最近的一個(gè)項(xiàng)目中使用了spark技術(shù)過(guò)程遇到的一些問(wèn)題叮喳,下面就以問(wèn)題來(lái)分析原因及解決過(guò)程钥庇。
問(wèn)題
1烤送、創(chuàng)建sparkView沒(méi)有加限制條件,導(dǎo)致創(chuàng)建幾十上百萬(wàn)大數(shù)據(jù)量的view時(shí)卖丸,多庫(kù)的情況下在driver創(chuàng)建了 大量的view,就把driver端的內(nèi)存撐爆了纺且,之前線上沒(méi)有暴露出來(lái)的這個(gè)問(wèn)題原因主要是每一個(gè)小時(shí)都會(huì)處理一次,每次數(shù)據(jù)量都不大,后面任務(wù)有停了幾天坯苹,數(shù)據(jù)量突增了很多隆檀,這時(shí)就出現(xiàn)很多問(wèn)題
-
如代碼:
2粹湃、使用spark過(guò)程中只用于查詢大數(shù)據(jù)量的源數(shù)據(jù)恐仑,其中數(shù)據(jù)運(yùn)算過(guò)程都是在使用JAVA方式滿1000條處理,運(yùn)算過(guò)程是逐條進(jìn)行運(yùn)算为鳄,代碼中產(chǎn)生過(guò)程多的對(duì)象裳仆,沒(méi)有處理完數(shù)據(jù)一直駐留在內(nèi)存,造成嚴(yán)重的FULL-GC孤钦,sparkUI上面也發(fā)現(xiàn)大量任務(wù)處于DEAD狀態(tài)歧斟。
-
如代碼:
3、運(yùn)算過(guò)程使用大量的JDBC的方式查詢關(guān)聯(lián)的它表數(shù)據(jù)偏形,每條數(shù)據(jù)每次查詢它表幾毫秒静袖,一旦數(shù)據(jù)量放大時(shí),消耗時(shí)間也是非常大的俊扭,而且運(yùn)算過(guò)程中會(huì)按多個(gè)步驟順序查詢關(guān)聯(lián)表數(shù)據(jù)(每個(gè)步驟都會(huì)做队橙,并沒(méi)有做緩存機(jī)制)。
-
如代碼:8053749-c08ec8489fcb02c0.png
4萨惑、每條數(shù)據(jù)進(jìn)行運(yùn)算時(shí)捐康,都打印出大量日志信息,有些日志信息可以不用輸出的庸蔼,打印日志也是導(dǎo)致性能問(wèn)題之一解总。
-
如部分代碼:
針對(duì)上述這些懷情況已經(jīng)嚴(yán)重影響到處理速度問(wèn)題,進(jìn)行結(jié)構(gòu)上改造姐仅,充分利用起spark的技術(shù)優(yōu)勢(shì)花枫,如下:
-
1刻盐、 重新創(chuàng)建源數(shù)據(jù)view,對(duì)數(shù)據(jù)按一定條件進(jìn)行切分及分批并行拉取出來(lái),即加快了拉取速度乌昔,也控制了一次加載數(shù)據(jù)量隙疚。如代碼:
-
2壤追、 舍棄每條源數(shù)據(jù)都去數(shù)據(jù)庫(kù)查詢相關(guān)活動(dòng)的數(shù)據(jù)及它表的數(shù)據(jù)來(lái)進(jìn)行運(yùn)算磕道,創(chuàng)建相關(guān)的view,通過(guò)大sql來(lái)關(guān)聯(lián)數(shù)據(jù)行冰。如:
-
3溺蕉、 由逐條數(shù)據(jù)進(jìn)行運(yùn)算的方式,改進(jìn)成通過(guò)大SQL中自定義函數(shù)來(lái)實(shí)現(xiàn)匹配運(yùn)算過(guò)程悼做,減少java查詢方式運(yùn)算時(shí)導(dǎo)致大量數(shù)據(jù)對(duì)象駐留內(nèi)存沒(méi)有釋放疯特,也改善并行運(yùn)算的速度。
如代碼:
-
4肛走、 減少?zèng)]有必要的日志輸出漓雅,將日志輸出信息級(jí)別調(diào)整為debug來(lái)減少IO輸出。如代碼:
-
5朽色、 解決上述問(wèn)題后性能提高了幾倍邻吞,但是也發(fā)現(xiàn)存在其它問(wèn)題,后面發(fā)現(xiàn)有各別活動(dòng)數(shù)據(jù)量超過(guò)一百萬(wàn)葫男,創(chuàng)建view應(yīng)該按源數(shù)據(jù)的條件先過(guò)濾出來(lái)有效數(shù)據(jù)來(lái)進(jìn)行關(guān)聯(lián)抱冷。如代碼:
-
6、 自定義累計(jì)器的問(wèn)題梢褐,實(shí)現(xiàn)累加計(jì)的方法旺遮,必須實(shí)現(xiàn)幾個(gè)方法,當(dāng)時(shí)我只用到其中一個(gè)add方法,就只正確實(shí)現(xiàn)這個(gè)方法盈咳,其它的方法就隨意寫了下耿眉,如代碼:
結(jié)果在運(yùn)算中調(diào)用累加器的時(shí)候就報(bào)出異常信息,說(shuō)必須實(shí)現(xiàn)copy及reset方法鱼响,后面才知道調(diào)用累加器時(shí)候鸣剪,它的實(shí)現(xiàn)方法中會(huì)逐個(gè)會(huì)被調(diào)用到,調(diào)用foreachPartition 的時(shí)候热押,會(huì)為每個(gè)Partition執(zhí)行一次自定義累加器的copy-》reset-》isZero方法西傀。
-
7、 使用累加器來(lái)收集數(shù)據(jù)還有一個(gè)問(wèn)題桶癣,它存儲(chǔ)的數(shù)據(jù)對(duì)象字段非常多是一個(gè)很大的對(duì)象集拥褂,它又是一個(gè)共享的數(shù)據(jù)變量,分發(fā)到各個(gè)機(jī)器上進(jìn)行操作牙寞,它達(dá)到一定的數(shù)據(jù)量才會(huì)入庫(kù)及清空數(shù)據(jù)饺鹃,這樣導(dǎo)致driver端上經(jīng)常FULL-GC莫秆,分片數(shù)據(jù)入庫(kù)依賴于它。如代碼:
8归苍、 在不斷的優(yōu)化過(guò)程中用狱,發(fā)現(xiàn)自己的代碼存在很多問(wèn)題,每次review代碼時(shí)拼弃,都會(huì)發(fā)現(xiàn)可以優(yōu)化之處夏伊,如方法及變量命名不清晰,方法體的代碼過(guò)長(zhǎng)吻氧,存在冗余的代碼溺忧,結(jié)構(gòu)不夠清晰,注釋太少且不清晰等等盯孙。
9鲁森、 SparkUI的重要性,有什么問(wèn)題都可以在上面看到镀梭,從中也可以發(fā)現(xiàn)出潛在的問(wèn)題刀森,也能在上面實(shí)時(shí)觀察出任務(wù)的運(yùn)行情況;SparkUI上面雖然只有六個(gè)菜單报账,如何在其中找到我想要數(shù)據(jù)分析及技術(shù)分析的信息研底,還是值得我學(xué)習(xí)及研究的。
總結(jié)
經(jīng)過(guò)一系列的改造后透罢,從之前的每小時(shí)處理200百萬(wàn)數(shù)據(jù)提升到每小時(shí)處理上千萬(wàn)的數(shù)據(jù)量;在該過(guò)程中遇到很多的問(wèn)題及困難榜晦,主要是自己對(duì)spark方面的知識(shí)了解不夠深入,在代碼結(jié)構(gòu)及細(xì)節(jié)上處理上面還不夠細(xì)致羽圃。通過(guò)同事們幫助下乾胶,順利地解決了spark性能上的問(wèn)題
作者:唯品會(huì)-蔣先輝
日期:2018.1.22