最近幾年一直參與大數(shù)據(jù)產(chǎn)品的研發(fā),同時大數(shù)據(jù)產(chǎn)品在海量數(shù)據(jù)場景下其處理性能又是其主要賣點和突破,所以個人在這幾年經(jīng)常忙于如何對大數(shù)據(jù)產(chǎn)品進行性能上面的優(yōu)化,并且想通過本文和大家聊聊具體的幾種比較常見大數(shù)據(jù)性能優(yōu)化技術(shù)。
常見的大數(shù)據(jù)性能優(yōu)化技術(shù)一般分為兩部分,其一是硬件和系統(tǒng)層面的觀測,從而來發(fā)現(xiàn)具體的瓶頸,并進行硬件或者系統(tǒng)級的調(diào)整;其二是主要通過對軟件具體使用方法的調(diào)整來實現(xiàn)優(yōu)化。
硬件方面的監(jiān)測
圖1. Windows7性能指數(shù)
關(guān)于硬件性能本身,個人覺得最好對性能的詮釋就像圖1大家比較熟悉的Windows7操作系統(tǒng)性能指數(shù)所展示的一樣,性能本身并在于其所長,而是在于其所短,就像圖1里面那個5.4分主硬盤托了整體的后腿一樣,只要有短板存在,其他地方再強也可能收效甚微,所以需要硬件的性能檢測就是找出短板在那里,并且盡可能地找到應(yīng)對的方法。
在硬件觀測角度方面,主要通過以下四個維度來判斷到底哪里是瓶頸,它們分別是CPU、內(nèi)存、硬盤還有網(wǎng)絡(luò)。
CPU利用率
首先,在講檢測CPU性能之前,我們可以通過這個“cat /proc/cpuinfo |grep “processor”|wc -l”命令來獲取本機的核數(shù)(如果開了超線程,一個核可以被看作兩個核),這樣可以知道CPU利用率的上限是多少。
最常用CPU監(jiān)測工具是TOP,當然TOP輸出是一個瞬間值,如果想獲取精確的數(shù)據(jù),需要持續(xù)關(guān)注一段時間。
圖2 TOP示例
TOP的使用主要看兩個值,其一是總體使用值,其最大值是100%,就是圖2第三行Cpu(s),前面兩個0.2%分別是用戶態(tài)和內(nèi)核態(tài)的利用率 而99.7%是CPU空閑率,從這個可以看出,本機的CPU部分基本是空閑的;其二可以看相關(guān)進程,看它的“%CPU”使用率,比如,Xorg這個GUI進程的占用率是0.3%,但是這里面的100%不是本機所有CPU的100%,而是單個核的100%。所以它的上限會是本機核數(shù)*100%。
圖3 uptime示例
因為TOP主要關(guān)注的是瞬時的值,如果要看一段時間的均值,這個時候可以用uptime這個命令,見圖3,它除了可以顯示當前總運行時,當前在線用戶,更重要的是可以顯示1分鐘、5分鐘、15分鐘的整機CPU的平均負載情況。
假設(shè)在平時監(jiān)測的時候,如果經(jīng)常碰到用滿80%以上CPU資源的話,可以理解為CPU利用率高,在這種場景下大多數(shù)只能靠優(yōu)化執(zhí)行邏輯,才能提升效率。
內(nèi)存的監(jiān)測
圖4 free -m的示例
關(guān)于內(nèi)存的監(jiān)測,常用的命令是free -m,通過這個命令可以查看系統(tǒng)內(nèi)存的具體使用情況。其中total,used和free都很好理解,通過這三列可以看出此時系統(tǒng)總內(nèi)存,已經(jīng)使用內(nèi)存和沒有被使用的內(nèi)存,而cached這列則表示有多少內(nèi)存已經(jīng)被Page Cache占用,但當系統(tǒng)內(nèi)存吃緊的時候,Page Cache會立即被回收并分配給請求內(nèi)存的應(yīng)用程序,所以Page Cache也可以被視為處于free狀態(tài)的內(nèi)存。
還有下面的Swap分區(qū),如果used數(shù)值比較高,說明內(nèi)存非常緊張,系統(tǒng)已經(jīng)動用交換區(qū),同時IO開銷也會增長非常明顯。當發(fā)現(xiàn)內(nèi)存不夠用的情況,可以考慮重啟或者關(guān)閉那些占用很多內(nèi)存的進程。
在這里稍微擴展一下Page Cache這個內(nèi)存機制,因為這個機制對大數(shù)據(jù)挺重要的。一般在Linux系統(tǒng)上,利用默認系統(tǒng)I/O接口寫入的文件塊,會先在Page Cache上面有一個緩存,之后再寫入到I/O設(shè)備上面,那么假設(shè)系統(tǒng)內(nèi)存沒有被占有滿的話,在這種情況下,這個緩存會長時間保留,并不會被洗出內(nèi)存,這樣等下次程序訪問到這些文件塊的時候,肯定會訪問Page Cache上面的那個版本,也就是直接訪問內(nèi)存,所以性能方面是內(nèi)存級別的。
I/O性能的監(jiān)測
圖5 iostat –xz 1示例
關(guān)于I/O性能,可以通過iostat這個命令來觀察I/O的性能,具體見圖5(sda是主硬盤),雖然參數(shù)比較多,但可以主要關(guān)注這兩個參數(shù):
其一是await,它代表了IO操作的平均等待時間,單位是毫秒,這也是應(yīng)用和磁盤之間操作所要消耗的時間,包括等待和實際的操作,如果這個數(shù)值大,說明I/O資源非常忙或者有故障;
其二是%util,也就是設(shè)備利用率,數(shù)值如果超過60,所以利用率很高,并會影響I/O平均等待時間,如果到100,那就說明設(shè)備已飽和了,只能添加更多I/O資源。
網(wǎng)絡(luò)方面的監(jiān)測
圖6 sar –n DEV 1示例
在網(wǎng)絡(luò)方面,使用的比較多的sar(System Activity Reporter)命令,如圖6。這個命令可以查看網(wǎng)絡(luò)設(shè)備的吞吐率,并在這個基礎(chǔ)上,將吞吐量和硬件上限做對比,來判斷網(wǎng)絡(luò)設(shè)備是否已經(jīng)飽和,假設(shè)以單張千兆網(wǎng)卡為例,如果“rxkB/s”和“txkB/s”兩種相加超過100MB的話,說明網(wǎng)絡(luò)已經(jīng)接近飽和了。還有除了這個通過命令行來獲取網(wǎng)絡(luò)數(shù)據(jù)之外,還可以通過開源的nload的工具來進行監(jiān)測,具體見下圖:
圖7:nload示例
VMSTAT
圖8 vmstat 1示例
其實除了上面這些工具外,還有一個vmstat這個全能的命令,能監(jiān)控硬件的方方面面,比如,如圖8所示,Procs的“r”列,這個列顯示正在等待CPU資源的進程數(shù),這個數(shù)據(jù)比之前看的top和uptime更加能夠體現(xiàn)CPU負載情況,并且這個數(shù)據(jù)不包含等待IO的進程。如果這個數(shù)值大于機器CPU核數(shù),那么機器的CPU資源已經(jīng)飽和。
Memory部分的“free”,“buff”和“cache”列的作用和上面free作用類似,而“si”和“so”說明使用Swap的次數(shù),如果這個數(shù)據(jù)不為0,說明Swap交換區(qū)已經(jīng)在使用,也意味著物理內(nèi)存已經(jīng)不足。
Cpu部分也大體和TOP上面顯示類似,但可以關(guān)注“wa”這列,其代表的是IO等待時間,如果數(shù)值大于0的話,可以判斷I/O資源有爭搶。
如果通過上面硬件方面的監(jiān)測,發(fā)現(xiàn)了瓶頸,或者發(fā)現(xiàn)了有很多余量,可以通過下半部分的軟件方面的優(yōu)化來進行調(diào)整,如果軟件方面也無能為力的話,那么只能通過購買和安裝更多的硬件。
軟件方面的優(yōu)化
這個方面因為各個大數(shù)據(jù)產(chǎn)品的實現(xiàn)方式不同,并且需要優(yōu)化點也不同,操作方式更是不同,所以在這里,主要提供一些方針供大家參考。
寫入優(yōu)化
因為常見大數(shù)據(jù)產(chǎn)品的寫入和傳統(tǒng)關(guān)系型數(shù)據(jù)庫是不同,傳統(tǒng)關(guān)系數(shù)據(jù)庫的寫入是一行一行的寫入,而常見大數(shù)據(jù)產(chǎn)品的寫入是批量的寫入,并且每次批量寫入之后,都會生成新的數(shù)據(jù)文件,并且這個數(shù)據(jù)文件是不會被修改的。所以導(dǎo)入數(shù)據(jù)粒度小的話會導(dǎo)致很多細小文件產(chǎn)生,這樣會導(dǎo)致更多的I/O操作,所以在使用大數(shù)據(jù)產(chǎn)品的時候,導(dǎo)入數(shù)據(jù)規(guī)模是越大越好,常見的規(guī)模在100MB以上為佳。
盡可能地并行
假設(shè)通過前面的硬件方面的測試方面,發(fā)現(xiàn)無論是CPU,內(nèi)存,I/O還是網(wǎng)絡(luò),都沒有遇到瓶頸,并且至少有20%潛力可挖,這個時候可以考慮盡可能地通過并行來提升性能,主要有兩個方式:其一是每臺機器上面部署更多的進程來壓榨硬件資源;其二是提升單個進程的多線程數(shù),這種方式比第一種更簡單,風險也更低。總體而言,盡量使每臺機器所使用到的線程數(shù)可以達到系統(tǒng)自身線程數(shù)的80%。
盡可能使用壓縮和列存
對于一些新入門的工程師,也包括那些有很多傳統(tǒng)關(guān)系數(shù)據(jù)庫使用經(jīng)驗的專業(yè)DBA數(shù)據(jù)管理員而言,大家都對列存比較一知半解,從而不敢使用。
列存和傳統(tǒng)行存相比,主要有兩個比較大的區(qū)別:
其一是數(shù)據(jù)不是按照行來存儲,而且是將很多行的數(shù)據(jù)按列歸屬在一起,并存儲 ,具體可以看圖9;
其二是一般行存的寫入是一行行,而且列存是比較批量的,所以寫入的數(shù)據(jù)庫塊會比較大,一般大于行存常見的8KB。基于我個人這幾年的經(jīng)驗,列存在極大多數(shù)分析場景下,都能提升3倍以上的性能,除了 些需要遍歷一個表半數(shù)以上列的場景。因為通過列存不僅能夠通過避免那些不要列的導(dǎo)入,這樣能減少硬盤的I/O總量。并且由于列存本身數(shù)據(jù)是一個大塊一個大塊的存在,所以是硬盤I/O讀取操作的次數(shù)也會減傷,這個對于硬盤I/O非常有利,因為本身硬盤I/O單次隨機讀取操作的成本非常高,和SSD相比。但是批量連續(xù)成本卻非常優(yōu)秀,當然如果使用SSD的話,性能會更優(yōu)。
在這個基礎(chǔ)上,由于連續(xù)數(shù)據(jù)都歸屬于一列都比較類似,比如,性別,所以對其壓縮的效果非常不錯,一般在1比5左右,并且通過壓縮節(jié)省的I/O遠大于壓縮和解壓縮所帶來CPU的損耗。這也導(dǎo)致就算所有數(shù)據(jù)全都在硬盤上,其性能的損失和所有數(shù)據(jù)在內(nèi)存上面緩存相比,一般慢4到5倍左右,其他也不會特別虧。
圖9 列存和行存的對比
善加利用Page Cache
在上半部分已經(jīng)提到了, 利用好Page Cache可以達到最基礎(chǔ)級別的內(nèi)存計算的效果,當然和真正意義上的內(nèi)存計算還是很大的距離。在性能測試的時候,這個優(yōu)化是比較常見的。一般作法是,先通過命令“sync; echo 3 > /proc/sys/vm/drop_caches”來清空page cache,之后跑一下比較簡單,但又能加載所有相關(guān)數(shù)據(jù)的語句,比如,對每一列進行求總,這種做法的壞處是沒有機會應(yīng)對真實可能存在性能瓶頸,這對今后的實際運行會產(chǎn)生很多不可控的因素,因為真實業(yè)務(wù)場景肯定會比所預(yù)想到的場景更復(fù)雜。
利用好分區(qū)特性
眾所周知,最快SQL就是什么都不做的SQL,比如,“select 1”;當然在實際的操作過程中,肯定不會有類似“select 1”這樣沒有意義的操作。所以對于傳統(tǒng)關(guān)系數(shù)據(jù)庫而言,為了減少讀取不必要的數(shù)據(jù),一般會使用索引。但是對于大數(shù)據(jù)這樣分析操作而言,索引這種機制太昂貴,而且收效甚微。
分析大數(shù)據(jù)應(yīng)用常用的過濾數(shù)據(jù)的方式是分區(qū),特別是按照時間來分區(qū),因為一般時間是最合適分割大數(shù)據(jù)的維度,比如,數(shù)據(jù)按照月分區(qū),這樣如果查詢只需要涉及到某月數(shù)據(jù),那么其余十一個月數(shù)據(jù)可以立刻忽略,當然如果按日來分區(qū)的,效果可能會更好,但盡量避免因為粒度太小,導(dǎo)致寫入文件過于碎片化的情況。
Join的優(yōu)化
對于大數(shù)據(jù)的分析應(yīng)用而言,Join操作是非常常見的,并且Join操作本身對硬件的短板也更敏感,特別是網(wǎng)絡(luò),因為大多數(shù)的分布式操作,每個數(shù)據(jù)節(jié)點可以獨立地完成,但 Join經(jīng)常需要來自其他節(jié)點數(shù)據(jù)才能完成本節(jié)點的執(zhí)行,并且這個量可能很大,有的時候,一個節(jié)點執(zhí)行所需要的數(shù)據(jù)遠超本節(jié)點自帶的數(shù)據(jù),類似場景還有unique這樣的去重操作,所以在調(diào)優(yōu)方面消耗的功夫也最多。
常見Join方式,主要有三種:
其一是Broadcast廣播,常用于大小表之間的Join,Join發(fā)起方會將小表的相關(guān)數(shù)據(jù)完整地分發(fā)到每個數(shù)據(jù)節(jié)點,之后當每個數(shù)據(jù)節(jié)點收到小表之后,會找其本地的大表數(shù)據(jù)來完成Join的,如圖10,pages是小表,visits是大表,發(fā)起方將Pages這張小表分發(fā)到每個數(shù)據(jù)節(jié)點;
其二是對小表Local化,這個機制本質(zhì)上非常類似Broadcast,只是分發(fā)小表這個操作是做導(dǎo)入數(shù)據(jù)的時候自動完成,性能肯定比Broadcast更好,因為減少傳輸小表的網(wǎng)絡(luò)消耗和等待時間,但是需要在創(chuàng)建表的時候,做一些額外的設(shè)置,這個機制在MPP數(shù)據(jù)是非常常見的,但是在Hadoop平臺上面還是比較少見,因為其底層的HDFS分布式文件系統(tǒng)比較強調(diào)硬件無關(guān),地址透明,這個和數(shù)據(jù)盡可能Local化的思路是違背的;
其三是Shuffle或者Partitioned Join機制,其常用于兩張大表之間的Join。因為將大表都分發(fā)給每個節(jié)點肯定成本太高了,而且數(shù)據(jù)節(jié)點的內(nèi)存不一定能放的下這么多數(shù)據(jù),所以通過Shuffle洗牌機制,也就是將所有參與的Join表的相關(guān)部分按照某種機制均勻分發(fā)到各個節(jié)點,并且每個節(jié)點數(shù)據(jù)都是獨立的,如圖11所示,pages和visits都是大表,它們按照Join列Hash的值來進行再次分布,節(jié)點1有Join列為A-E的數(shù)據(jù),之后依次類推,雖然成本很高,但是對于大表之間的Join是最合理和最可行的方法。
圖10 Broadcast Join
圖11 Shuffle Join
介紹完Join機制之后,再深入一下Join的優(yōu)化,也主要有三個方面:
其一是在大表和小表擺放順序要符合技術(shù)規(guī)范,這樣能避免優(yōu)化器將大表作為Broadcast表來進行分發(fā);
其二是開啟或者執(zhí)行預(yù)統(tǒng)計,也就是在查詢之前,開啟表的預(yù)統(tǒng)計,雖然預(yù)統(tǒng)計會耗費一點時間,但這樣能夠讓優(yōu)化器知道表的具體情況,從而做出合理的方案,即使之前表的順序?qū)戝e了,還有由于預(yù)統(tǒng)計會遍歷數(shù)據(jù),這樣可以將數(shù)據(jù)預(yù)先加載到Page Cache上面;
其三是選擇合理的Join機制,也就是做好Broadcast和Shuffle之間的抉擇,兩個大表之間選擇Shuffle,如果不是選擇Broadcast,當然假如優(yōu)化器能判斷出是更好不過了,但當優(yōu)化器出現(xiàn)問題的時候,可以通過人工輸入一些提示符來幫助優(yōu)化器來判斷;
多看Profile
介紹很多優(yōu)化技術(shù),但是這樣技術(shù)都比較籠統(tǒng),為了更好做優(yōu)化,做某個產(chǎn)品優(yōu)化,還是最好能多看看每次執(zhí)行后的Profile,這樣能對產(chǎn)品更深的理解。
因為大數(shù)據(jù)產(chǎn)品和技術(shù)比較多,并且每個產(chǎn)品和特色和設(shè)計都不同,所以在細節(jié)方面沒有特別深入,但是的確有非常多的共性,所以通過硬件的監(jiān)測,以及軟件方面的優(yōu)化,應(yīng)該能把常見的大數(shù)據(jù)產(chǎn)品發(fā)揮到八成的功力。
參考資料:
1.用十條命令在一分鐘內(nèi)檢查Linux服務(wù)器性能http://www.infoq.com/cn/news/2015/12/linux-performance
2.在 Linux/UNIX 終端下使用 nload 實時監(jiān)控網(wǎng)絡(luò)流量和帶寬使用http://linux.cn/article-2871-1.html
作者介紹
吳朱華:國內(nèi)資深云計算和大數(shù)據(jù)專家,之前曾在IBM中國研究院和上海云人信息科技有限公司參與過多款云計算產(chǎn)和大數(shù)據(jù)產(chǎn)品的開發(fā)工作,同濟本科,并曾在北京大學(xué)讀過碩士。2011年中,發(fā)表業(yè)界最好的兩本云計算書之一《云計算核心技術(shù)剖析》。2016年和上海華東理工大學(xué)的阮彤教授等合著了《大數(shù)據(jù)技術(shù)前沿》一書。