|
2011年7月3日
淘寶招聘hadoop工程師若干, 面向在校生(2014年畢業(yè)),工作地點(diǎn):杭州或北京 Hadoop研發(fā)工程師 職位描述 您將負(fù)責(zé): 1.預(yù)研、開發(fā)、測(cè)試hdfs/mapreduce/hive/hbase的功能、性能和擴(kuò)展; 2.對(duì)有助于提升集群處理能力/高可用性/高擴(kuò)展性的各種解決方案進(jìn)行跟蹤和落地; 3.解決海量數(shù)據(jù)不斷增長(zhǎng)面臨的挑戰(zhàn),解決業(yè)務(wù)需求。 您需要具備: 1、熟練運(yùn)用java語(yǔ)言; 2、熟悉jvm運(yùn)行機(jī)制、熟悉linux; 3、至少熟悉hadoop、hbase、hive等軟件之一;
有意者請(qǐng)發(fā)送郵件到 yuling.sh@taobao.com
mapreduce中,一個(gè)job的map個(gè)數(shù), 每個(gè)map處理的數(shù)據(jù)量是如何決定的呢? 另外每個(gè)map又是如何讀取輸入文件的內(nèi)容呢? 用戶是否可以自己決定輸入方式, 決定map個(gè)數(shù)呢? 這篇文章將詳細(xì)講述hadoop中各種InputFormat的功能和如何編寫自定義的InputFormat. 簡(jiǎn)介: mapreduce作業(yè)會(huì)根據(jù)輸入目錄產(chǎn)生多個(gè)map任務(wù), 通過(guò)多個(gè)map任務(wù)并行執(zhí)行來(lái)提高作業(yè)運(yùn)行速度, 但如果map數(shù)量過(guò)少, 并行量低, 作業(yè)執(zhí)行慢, 如果map數(shù)過(guò)多, 資源有限, 也會(huì)增加調(diào)度開銷. 因此, 根據(jù)輸入產(chǎn)生合理的map數(shù), 為每個(gè)map分配合適的數(shù)據(jù)量, 能有效的提升資源利用率, 并使作業(yè)運(yùn)行速度加快. 在mapreduce中, 每個(gè)作業(yè)都會(huì)通過(guò) InputFormat來(lái)決定map數(shù)量. InputFormat是一個(gè)接口, 提供兩個(gè)方法: InputSplit[] getSplits(JobConf job, int numSplits) throws IOException; RecordReader<K, V> getRecordReader(InputSplit split, JobConf job, Reporter reporter) throws IOException; 其中getSplits方法會(huì)根據(jù)輸入目錄產(chǎn)生InputSplit數(shù)組, 每個(gè)InputSplit會(huì)相應(yīng)產(chǎn)生一個(gè)map任務(wù), map的輸入定義在InputSplit中. getRecordReader方法返回一個(gè)RecordReader對(duì)象, RecordReader決定了map任務(wù)如何讀取輸入數(shù)據(jù), 例如一行一行的讀取還是一個(gè)字節(jié)一個(gè)字節(jié)的讀取, 等等. 下圖是InputFormat的實(shí)現(xiàn)類: (暫時(shí)無(wú)法上傳) 這理詳細(xì)介紹FileInputFormat和CombineFileInputFormat, 其它不常用,有興趣的可以自己查看hadoop源碼.
FileInputFormat(舊接口org.apache.hadoop.mapred) mapreduce默認(rèn)使用TextInputFormat,TextInputFormat沒(méi)有實(shí)現(xiàn)自己的getSplits方法,它繼承于FileInputFormat, 因此使用了FileInputFormat的. org.apache.hadoop.mapred.FileInputFormat的getSplits流程: 兩個(gè)配置 mapred.min.split.size (一個(gè)map最小輸入長(zhǎng)度), mapred.map.tasks (推薦map數(shù)量) 如何決定每個(gè)map輸入長(zhǎng)度呢? 首先獲取輸入目錄下所有文件的長(zhǎng)度和, 除以mapred.map.tasks得到一個(gè)推薦長(zhǎng)度goalSize, 然后通過(guò)式子: Math.max(minSize, Math.min(goalSize, blockSize))決定map輸入長(zhǎng)度. 這里的minSize為mapred.min.split.size, blockSize為相應(yīng)文件的block長(zhǎng)度. 這式子能保證一個(gè)map的輸入至少大于mapred.min.split.size, 對(duì)于推薦的map長(zhǎng)度,只有它的長(zhǎng)度小于blockSize且大于mapred.min.split.size才會(huì)有效果. 由于mapred.min.split.size默認(rèn)長(zhǎng)度為1, 因此通常情況下只要小于blockSize就有效果,否則使用blockSize做為map輸入長(zhǎng)度. 因此, 如果想增加map數(shù), 可以把mapred.min.split.size調(diào)小(其實(shí)默認(rèn)值即可), 另外還需要把mapred.map.tasks設(shè)置大. 如果需要減少map數(shù),可以把mapred.min.split.size調(diào)大, 另外把mapred.map.tasks調(diào)小. 這里要特別指出的是FileInputFormat會(huì)讓每個(gè)輸入文件至少產(chǎn)生一個(gè)map任務(wù), 因此如果你的輸入目錄下有許多文件, 而每個(gè)文件都很小, 例如幾十kb, 那么每個(gè)文件都產(chǎn)生一個(gè)map會(huì)增加調(diào)度開銷. 作業(yè)變慢. 那么如何防止這種問(wèn)題呢? CombineFileInputFormat能有效的減少map數(shù)量.
FileInputFormat(新接口org.apache.hadoop.mapreduce.lib.input) Hadoop 0.20開始定義了一套新的mapreduce編程接口, 使用新的FileInputFormat, 它與舊接口下的FileInputFormat主要區(qū)別在于, 它不再使用mapred.map.tasks, 而使用mapred.max.split.size參數(shù)代替goalSize, 通過(guò)Math.max(minSize, Math.min(maxSize, blockSize))決定map輸入長(zhǎng)度, 一個(gè)map的輸入要大于minSize,小于 Math.min(maxSize, blockSize). 若需增加map數(shù),可以把mapred.min.split.size調(diào)小,把mapred.max.split.size調(diào)大. 若需減少map數(shù), 可以把mapred.min.split.size調(diào)大, 并把mapred.max.split.size調(diào)小. CombineFileInputFormat 顧名思義, CombineFileInputFormat的作用是把許多文件合并作為一個(gè)map的輸入. 在它之前,可以使用MultiFileInputFormat,不過(guò)其功能太簡(jiǎn)單, 它以文件為單位,一個(gè)文件至多分給一個(gè)map處理, 如果某個(gè)目錄下有許多小文件, 另外還有一個(gè)超大文件, 處理大文件的map會(huì)嚴(yán)重偏慢. CombineFileInputFormat是一個(gè)被推薦使用的InputFormat. 它有三個(gè)配置: mapred.min.split.size.per.node, 一個(gè)節(jié)點(diǎn)上split的至少的大小 mapred.min.split.size.per.rack 一個(gè)交換機(jī)下split至少的大小 mapred.max.split.size 一個(gè)split最大的大小 它的主要思路是把輸入目錄下的大文件分成多個(gè)map的輸入, 并合并小文件, 做為一個(gè)map的輸入. 具體的原理是下述三步: 1.根據(jù)輸入目錄下的每個(gè)文件,如果其長(zhǎng)度超過(guò)mapred.max.split.size,以block為單位分成多個(gè)split(一個(gè)split是一個(gè)map的輸入),每個(gè)split的長(zhǎng)度都大于mapred.max.split.size, 因?yàn)橐?/span>block為單位, 因此也會(huì)大于blockSize, 此文件剩下的長(zhǎng)度如果大于mapred.min.split.size.per.node, 則生成一個(gè)split, 否則先暫時(shí)保留. 2. 現(xiàn)在剩下的都是一些長(zhǎng)度效短的碎片,把每個(gè)rack下碎片合并, 只要長(zhǎng)度超過(guò)mapred.max.split.size就合并成一個(gè)split, 最后如果剩下的碎片比mapred.min.split.size.per.rack大, 就合并成一個(gè)split, 否則暫時(shí)保留. 3. 把不同rack下的碎片合并, 只要長(zhǎng)度超過(guò)mapred.max.split.size就合并成一個(gè)split, 剩下的碎片無(wú)論長(zhǎng)度, 合并成一個(gè)split. 舉例: mapred.max.split.size=1000 mapred.min.split.size.per.node=300 mapred.min.split.size.per.rack=100 輸入目錄下五個(gè)文件,rack1下三個(gè)文件,長(zhǎng)度為2050,1499,10, rack2下兩個(gè)文件,長(zhǎng)度為1010,80. 另外blockSize為500. 經(jīng)過(guò)第一步, 生成五個(gè)split: 1000,1000,1000,499,1000. 剩下的碎片為rack1下:50,10; rack2下10:80 由于兩個(gè)rack下的碎片和都不超過(guò)100, 所以經(jīng)過(guò)第二步, split和碎片都沒(méi)有變化. 第三步,合并四個(gè)碎片成一個(gè)split, 長(zhǎng)度為150. 如果要減少map數(shù)量, 可以調(diào)大mapred.max.split.size, 否則調(diào)小即可. 其特點(diǎn)是: 一個(gè)塊至多作為一個(gè)map的輸入,一個(gè)文件可能有多個(gè)塊,一個(gè)文件可能因?yàn)閴K多分給做為不同map的輸入, 一個(gè)map可能處理多個(gè)塊,可能處理多個(gè)文件。
Yarn做為hadoop下一代集群資源管理和調(diào)度平臺(tái), 其上能支持多種計(jì)算框架, 本文就簡(jiǎn)要介紹一下這些計(jì)算框架.
1. MapReduce 首先是大家熟悉的mapreduce, 在MR2之前, hadoop包括HDFS和mapreduce, 做為hadoop上唯一的分布式計(jì)算框架, 其優(yōu)點(diǎn)是用戶可以很方便的編寫分布式計(jì)算程序, 并支持許多的應(yīng)用, 如hive, mahout, pig等. 但是其缺點(diǎn)是無(wú)法充分利用集群資源, 不支持DAG, 迭代式計(jì)算等. 為了解決這些問(wèn)題, yahoo提出了Yarn (next generation mapreduce), 一個(gè)分布式集群集群資源管理和調(diào)度平臺(tái). 這樣除了mapreduce外, 還可以支持各種計(jì)算框架. 2. Spark Spark是一種與mapreduce相似的開源計(jì)算框架, 不同之處在于Spark在某些工作負(fù)載方面表現(xiàn)更優(yōu), 因?yàn)樗褂昧藘?nèi)存分布式數(shù)據(jù)集, 另外除了提供交互式查詢外, 它還可以優(yōu)化迭代工作負(fù)載. 3. Apache HAMA Apache Hama 是一個(gè)運(yùn)行在HDFS上的BSP(Bulk Synchronous Parallel大容量同步并行) 計(jì)算框架, 主要針對(duì)大規(guī)模科學(xué)計(jì)算,如矩陣, 圖像, 網(wǎng)絡(luò)算法等.當(dāng)前它有一下功能: - 作業(yè)提交和管理接口
- 單節(jié)點(diǎn)上運(yùn)行多個(gè)任務(wù)
- 輸入/輸出格式化
- 備份恢復(fù)
- 支持通過(guò)Apache Whirr運(yùn)行在云端
- 支持與Yarn一起運(yùn)行
4. Apache Giraph 圖像處理平臺(tái)上運(yùn)行這大型算法(如page rank, shared connections, personalization-based popularity 等)已經(jīng)很流行, Giraph采用BSP模型(bulk-synchronous parallel model),可用于等迭代類算法。 5. Open MPI 這是一個(gè)高性能計(jì)算函數(shù)庫(kù),通常在HPC(High Performance Computing)中采用,與MapReduce相比,其性能更高,用戶可控性更強(qiáng),但編程復(fù)雜,容錯(cuò)性差,可以說(shuō),各有所長(zhǎng),在實(shí)際應(yīng)用中,針對(duì)不同 該應(yīng)用會(huì)采用MPI或者MapReduce。 6. Apache HBase HBase是一個(gè)hadoop數(shù)據(jù)庫(kù), 其特點(diǎn)是分布式,可擴(kuò)展的,存儲(chǔ)大數(shù)據(jù)。當(dāng)有需要隨機(jī),實(shí)時(shí)讀寫的大數(shù)據(jù)時(shí), 使用HBase很適合.
本文參考: http://wiki.apache.org/hadoop/PoweredByYarn http://www.oschina.net/p/open+mpi
http://incubator.apache.org/hama/ http://incubator.apache.org/giraph/ http://hbase.apache.org/
轉(zhuǎn)載 http://fujun.sinaapp.com/2011/11/02/68.html 第一步,打開終端,看看你的顯卡Ubuntu能認(rèn)出多少顯示分辨率設(shè)置,輸入命令 wufujun@wufujun-VirtualBox:~$ xrandr
系統(tǒng)給出的結(jié)果 Screen 0: minimum 64 x 64, current 1024 x 768, maximum 32000 x 32000 VBOX0 connected 1024×768+0+0 0mm x 0mm 1024×768 60.0 + 60.0 1600×1200 60.0 1440×1050 60.0 1280×960 60.0 800×600 60.0 640×480 60.0 這里可以看到,沒(méi)有16:9的的分辨率設(shè)置 第二步,用cvt命令測(cè)試1368×768是否可用 wufujun@wufujun-VirtualBox:~$ cvt 1368 768
顯示結(jié)果如下 # 1368×768 59.88 Hz (CVT) hsync: 47.79 kHz; pclk: 85.86 MHz Modeline “1368x768_60.00″ 85.25 1368 1440 1576 1784 768 771 781 798 -hsync +vsync 從這個(gè)結(jié)果里可以到,16:9的分辨率是可以用的 第三步 輸入 wufujun@wufujun-VirtualBox:~$ sudo xrandr --newmode "1368x768" 85.86 1368 1440 1576 1784 768 771 781 798 -hsync +vsync
建立新的分辨率模式1368×768,把剛才cvt得到的數(shù)據(jù)寫進(jìn)參數(shù) 第四步 繼續(xù)輸入 sudo xrandr --addmode VBOX0 "1368x768"
給當(dāng)前顯示器VBOX0增加1368×768分辨率設(shè)置 做完以上操作后,可以在”顯示“設(shè)置里面看到顯示的分辨率列表中多了一個(gè) 1368×768(16:9)的選項(xiàng)。選中這個(gè)選項(xiàng),點(diǎn)擊應(yīng)用,完美的寬屏顯示回來(lái)了! 經(jīng)過(guò)測(cè)試,上面的方法做完以后,每次注銷后就又變回了4:3的比例,而且會(huì)有的報(bào)錯(cuò),沒(méi)辦法,按上面的修改完畢后,還要再修改一下/etc/X11/xorg.conf這個(gè)文件,這個(gè)配置文件在現(xiàn)在的版里已經(jīng)取消了,所以需要我們新建一個(gè) $ sudo gedit /etc/X11/xorg.conf
編輯內(nèi)容為: Section "Device" Identifier "Configured Video Device" EndSection
Section "Monitor" Identifier "Configured Monitor" Modeline "1368x768_60.00" 85.86 1368 1440 1584 1800 768 769 772 795 -HSync +Vsync EndSection Section "Screen" Identifier "Default Screen" Monitor "Configured Monitor" Device "Configured Video Device" SubSection "Display" Modes "1368x768@60" EndSubSection EndSection 其中 Modeline “1368x768_60.00″ 85.86 1368 1440 1584 1800 768 769 772 795 -HSync +Vsync 就是用$ cvt 1368 768得到的值。也可以用$ gtf 1368 768 60命令來(lái)得到這個(gè)Modeline的值,這個(gè)命令中,1368 768是分辨率 60為刷新率,用這個(gè)命令得到的值可能會(huì)更為準(zhǔn)確一些。 SubSection "Display" Modes "1368x768@60" EndSubSection
這段是設(shè)置默認(rèn)顯示最佳分辨率。 注意這段文件中的一些規(guī)則 Section “Device”區(qū)塊中,Identifier指定了顯卡的唯一名稱,這個(gè)名稱可以隨便取,但一定要與Section “Screen”區(qū)塊中的device選項(xiàng)中的名稱相同。在Section “Monitor”區(qū)塊中,Identifier指定了顯示器的唯一名稱,這個(gè)名稱可以隨便取,但一定要與Section “Screen”區(qū)塊中的Monitor選項(xiàng)中所指定的名稱相同。Section “Screen”區(qū)塊中的Identifier選項(xiàng),指定了這個(gè)顯卡與顯示器相結(jié)合的唯一名稱。這個(gè)名稱也可以隨便取的。這個(gè)名稱需要與Section “ServerLayout” 區(qū)塊中的名稱相同。這個(gè)Section “ServerLayout” 區(qū)塊我們一般不必編寫
摘要: 最近這些天學(xué)習(xí)了classLoader的原理, 原因是因?yàn)榉?wù)器上的一個(gè)java進(jìn)程啟動(dòng)時(shí)加載兩個(gè)不同版本的jar包, 含有相同名字的類, 而且服務(wù)端的jar包排在前面, 我上傳的jar包排在后面, 于是每次都使用服務(wù)端的jar包, 我的jar包便無(wú)法生效, 因此希望修改classLader, 讓它按相反的順序加載jar包. ... 閱讀全文
摘要: High Availability for the HDFS Namenode Sanjay Radia, Suresh Srinivas Yahoo! Inc (本文為namdnoe HA的設(shè)計(jì)文檔翻譯) 1. 問(wèn)題闡述 有許多方法可以改善HDFS Namednoe(NN)的可用性,包括減少啟動(dòng)時(shí)間,更... 閱讀全文
本文轉(zhuǎn)自:http://blog.csdn.net/zhouysh/article/details/304767 JAVA代碼編寫的30條建議 (1) 類名首字母應(yīng)該大寫。字段、方法以及對(duì)象(句柄)的首字母應(yīng)小寫。對(duì)于所有標(biāo)識(shí)符,其中包含的所有單詞都應(yīng)緊靠在一起,而且大寫中間單詞的首字母。例如: ThisIsAClassName thisIsMethodOrFieldName 若在定義中出現(xiàn)了常數(shù)初始化字符,則大寫static final基本類型標(biāo)識(shí)符中的所有字母。這樣便可標(biāo)志出它們屬于編譯期的常數(shù)。 Java包(Package)屬于一種特殊情況:它們?nèi)际切懽帜福幢阒虚g的單詞亦是如此。對(duì)于域名擴(kuò)展名稱,如com,org,net或者edu等,全部都應(yīng)小寫(這也是Java 1.1和Java 1.2的區(qū)別之一)。
(2) 為了常規(guī)用途而創(chuàng)建一個(gè)類時(shí),請(qǐng)采取"經(jīng)典形式",并包含對(duì)下述元素的定義:
equals() hashCode() toString() clone()(implement Cloneable) implement Serializable
(3) 對(duì)于自己創(chuàng)建的每一個(gè)類,都考慮置入一個(gè)main(),其中包含了用于測(cè)試那個(gè)類的代碼。為使用一個(gè)項(xiàng)目中的類,我們沒(méi)必要?jiǎng)h除測(cè)試代碼。若進(jìn)行了任何形式的改動(dòng),可方便地返回測(cè)試。這些代碼也可作為如何使用類的一個(gè)示例使用。
(4) 應(yīng)將方法設(shè)計(jì)成簡(jiǎn)要的、功能性單元,用它描述和實(shí)現(xiàn)一個(gè)不連續(xù)的類接口部分。理想情況下,方法應(yīng)簡(jiǎn)明扼要。若長(zhǎng)度很大,可考慮通過(guò)某種方式將其分割成較短的幾個(gè)方法。這樣做也便于類內(nèi)代碼的重復(fù)使用(有些時(shí)候,方法必須非常大,但它們?nèi)詰?yīng)只做同樣的一件事情)。
(5) 設(shè)計(jì)一個(gè)類時(shí),請(qǐng)?jiān)O(shè)身處地為客戶程序員考慮一下(類的使用方法應(yīng)該是非常明確的)。然后,再設(shè)身處地為管理代碼的人考慮一下(預(yù)計(jì)有可能進(jìn)行哪些形式的修改,想想用什么方法可把它們變得更簡(jiǎn)單)。 (6) 使類盡可能短小精悍,而且只解決一個(gè)特定的問(wèn)題。下面是對(duì)類設(shè)計(jì)的一些建議: ■一個(gè)復(fù)雜的開關(guān)語(yǔ)句:考慮采用"多形"機(jī)制 ■數(shù)量眾多的方法涉及到類型差別極大的操作:考慮用幾個(gè)類來(lái)分別實(shí)現(xiàn) ■許多成員變量在特征上有很大的差別:考慮使用幾個(gè)類
(7) 讓一切東西都盡可能地"私有"--private。可使庫(kù)的某一部分"公共化"(一個(gè)方法、類或者一個(gè)字段等等),就永遠(yuǎn)不能把它拿出。若強(qiáng)行拿出,就可 能破壞其他人現(xiàn)有的代碼,使他們不得不重新編寫和設(shè)計(jì)。若只公布自己必須公布的,就可放心大膽地改變其他任何東西。在多線程環(huán)境中,隱私是特別重要的一個(gè) 因素--只有private字段才能在非同步使用的情況下受到保護(hù)。
(8) 謹(jǐn)惕"巨大對(duì)象綜合癥"。對(duì)一些習(xí)慣于順序編程思維、且初涉OOP領(lǐng)域的新手,往往喜歡先寫一個(gè)順序執(zhí)行的程序,再把它嵌入一個(gè)或兩個(gè)巨大的對(duì)象里。根據(jù)編程原理,對(duì)象表達(dá)的應(yīng)該是應(yīng)用程序的概念,而非應(yīng)用程序本身。
(9) 若不得已進(jìn)行一些不太雅觀的編程,至少應(yīng)該把那些代碼置于一個(gè)類的內(nèi)部。
(10) 任何時(shí)候只要發(fā)現(xiàn)類與類之間結(jié)合得非常緊密,就需要考慮是否采用內(nèi)部類,從而改善編碼及維護(hù)工作(參見(jiàn)第14章14.1.2小節(jié)的"用內(nèi)部類改進(jìn)代碼")。
(11) 盡可能細(xì)致地加上注釋,并用javadoc注釋文檔語(yǔ)法生成自己的程序文檔。
(12) 避免使用"魔術(shù)數(shù)字",這些數(shù)字很難與代碼很好地配合。如以后需要修改它,無(wú)疑會(huì)成為一場(chǎng)噩夢(mèng),因?yàn)楦静恢?100"到底是指"數(shù)組大小"還是"其他 全然不同的東西"。所以,我們應(yīng)創(chuàng)建一個(gè)常數(shù),并為其使用具有說(shuō)服力的描述性名稱,并在整個(gè)程序中都采用常數(shù)標(biāo)識(shí)符。這樣可使程序更易理解以及更易維護(hù)。
(13) 涉及構(gòu)建器和異常的時(shí)候,通常希望重新丟棄在構(gòu)建器中捕獲的任何異常--如果它造成了那個(gè)對(duì)象的創(chuàng)建失敗。這樣一來(lái),調(diào)用者就不會(huì)以為那個(gè)對(duì)象已正確地創(chuàng)建,從而盲目地繼續(xù)。
(14) 當(dāng)客戶程序員用完對(duì)象以后,若你的類要求進(jìn)行任何清除工作,可考慮將清除代碼置于一個(gè)良好定義的方法里,采用類似于cleanup()這樣的名字,明確表 明自己的用途。除此以外,可在類內(nèi)放置一個(gè)boolean(布爾)標(biāo)記,指出對(duì)象是否已被清除。在類的finalize()方法里,請(qǐng)確定對(duì)象已被清除, 并已丟棄了從RuntimeException繼承的一個(gè)類(如果還沒(méi)有的話),從而指出一個(gè)編程錯(cuò)誤。在采取象這樣的方案之前,請(qǐng)確定 finalize()能夠在自己的系統(tǒng)中工作(可能需要調(diào)用System.runFinalizersOnExit(true),從而確保這一行為)。
(15) 在一個(gè)特定的作用域內(nèi),若一個(gè)對(duì)象必須清除(非由垃圾收集機(jī)制處理),請(qǐng)采用下述方法:初始化對(duì)象;若成功,則立即進(jìn)入一個(gè)含有finally從句的try塊,開始清除工作。
(16) 若在初始化過(guò)程中需要覆蓋(取消)finalize(),請(qǐng)記住調(diào)用super.finalize()(若Object屬于我們的直接超類,則無(wú)此必 要)。在對(duì)finalize()進(jìn)行覆蓋的過(guò)程中,對(duì)super.finalize()的調(diào)用應(yīng)屬于最后一個(gè)行動(dòng),而不應(yīng)是第一個(gè)行動(dòng),這樣可確保在需要 基礎(chǔ)類組件的時(shí)候它們依然有效。
(17) 創(chuàng)建大小固定的對(duì)象集合時(shí),請(qǐng)將它們傳輸至一個(gè)數(shù)組(若準(zhǔn)備從一個(gè)方法里返回這個(gè)集合,更應(yīng)如此操作)。這樣一來(lái),我們就可享受到數(shù)組在編譯期進(jìn)行類型檢查的好處。此外,為使用它們,數(shù)組的接收者也許并不需要將對(duì)象"造型"到數(shù)組里。
(18) 盡量使用interfaces,不要使用abstract類。若已知某樣?xùn)|西準(zhǔn)備成為一個(gè)基礎(chǔ)類,那么第一個(gè)選擇應(yīng)是將其變成一個(gè)interface(接 口)。只有在不得不使用方法定義或者成員變量的時(shí)候,才需要將其變成一個(gè)abstract(抽象)類。接口主要描述了客戶希望做什么事情,而一個(gè)類則致力 于(或允許)具體的實(shí)施細(xì)節(jié)。
(19) 在構(gòu)建器內(nèi)部,只進(jìn)行那些將對(duì)象設(shè)為正確狀態(tài)所需的工作。盡可能地避免調(diào)用其他方法,因?yàn)槟切┓椒赡鼙黄渌烁采w或取消,從而在構(gòu)建過(guò)程中產(chǎn)生不可預(yù)知的結(jié)果(參見(jiàn)第7章的詳細(xì)說(shuō)明)。
(20) 對(duì)象不應(yīng)只是簡(jiǎn)單地容納一些數(shù)據(jù);它們的行為也應(yīng)得到良好的定義。
(21) 在現(xiàn)成類的基礎(chǔ)上創(chuàng)建新類時(shí),請(qǐng)首先選擇"新建"或"創(chuàng)作"。只有自己的設(shè)計(jì)要求必須繼承時(shí),才應(yīng)考慮這方面的問(wèn)題。若在本來(lái)允許新建的場(chǎng)合使用了繼承,則整個(gè)設(shè)計(jì)會(huì)變得沒(méi)有必要地復(fù)雜。
(22) 用繼承及方法覆蓋來(lái)表示行為間的差異,而用字段表示狀態(tài)間的區(qū)別。一個(gè)非常極端的例子是通過(guò)對(duì)不同類的繼承來(lái)表示顏色,這是絕對(duì)應(yīng)該避免的:應(yīng)直接使用一個(gè)"顏色"字段。
(23) 為避免編程時(shí)遇到麻煩,請(qǐng)保證在自己類路徑指到的任何地方,每個(gè)名字都僅對(duì)應(yīng)一個(gè)類。否則,編譯器可能先找到同名的另一個(gè)類,并報(bào)告出錯(cuò)消息。若懷疑自己碰到了類路徑問(wèn)題,請(qǐng)?jiān)囋囋陬惵窂降拿恳粋€(gè)起點(diǎn),搜索一下同名的.class文件。
(24) 在Java 1.1 AWT中使用事件"適配器"時(shí),特別容易碰到一個(gè)陷阱。若覆蓋了某個(gè)適配器方法,同時(shí)拼寫方法沒(méi)有特別講究,最后的結(jié)果就是新添加一個(gè)方法,而不是覆蓋現(xiàn) 成方法。然而,由于這樣做是完全合法的,所以不會(huì)從編譯器或運(yùn)行期系統(tǒng)獲得任何出錯(cuò)提示--只不過(guò)代碼的工作就變得不正常了。
(25) 用合理的設(shè)計(jì)方案消除"偽功能"。也就是說(shuō),假若只需要?jiǎng)?chuàng)建類的一個(gè)對(duì)象,就不要提前限制自己使用應(yīng)用程序,并加上一條"只生成其中一個(gè)"注釋。請(qǐng)考慮將 其封裝成一個(gè)"獨(dú)生子"的形式。若在主程序里有大量散亂的代碼,用于創(chuàng)建自己的對(duì)象,請(qǐng)考慮采納一種創(chuàng)造性的方案,將些代碼封裝起來(lái)。
(26) 警惕"分析癱瘓"。請(qǐng)記住,無(wú)論如何都要提前了解整個(gè)項(xiàng)目的狀況,再去考察其中的細(xì)節(jié)。由于把握了全局,可快速認(rèn)識(shí)自己未知的一些因素,防止在考察細(xì)節(jié)的時(shí)候陷入"死邏輯"中。
(27) 警惕"過(guò)早優(yōu)化"。首先讓它運(yùn)行起來(lái),再考慮變得更快--但只有在自己必須這樣做、而且經(jīng)證實(shí)在某部分代碼中的確存在一個(gè)性能瓶頸的時(shí)候,才應(yīng)進(jìn)行優(yōu)化。 除非用專門的工具分析瓶頸,否則很有可能是在浪費(fèi)自己的時(shí)間。性能提升的隱含代價(jià)是自己的代碼變得難于理解,而且難于維護(hù)。
(28) 請(qǐng)記住,閱讀代碼的時(shí)間比寫代碼的時(shí)間多得多。思路清晰的設(shè)計(jì)可獲得易于理解的程序,但注釋、細(xì)致的解釋以及一些示例往往具有不可估量的價(jià)值。無(wú)論對(duì)你自 己,還是對(duì)后來(lái)的人,它們都是相當(dāng)重要的。如對(duì)此仍有懷疑,那么請(qǐng)?jiān)囅胱约涸噲D從聯(lián)機(jī)Java文檔里找出有用信息時(shí)碰到的挫折,這樣或許能將你說(shuō)服。
(29) 如認(rèn)為自己已進(jìn)行了良好的分析、設(shè)計(jì)或者實(shí)施,那么請(qǐng)稍微更換一下思維角度。試試邀請(qǐng)一些外來(lái)人士--并不一定是專家,但可以是來(lái)自本公司其他部門的人。 請(qǐng)他們用完全新鮮的眼光考察你的工作,看看是否能找出你一度熟視無(wú)睹的問(wèn)題。采取這種方式,往往能在最適合修改的階段找出一些關(guān)鍵性的問(wèn)題,避免產(chǎn)品發(fā)行 后再解決問(wèn)題而造成的金錢及精力方面的損失。
(30) 良好的設(shè)計(jì)能帶來(lái)最大的回報(bào)。簡(jiǎn)言之,對(duì)于一個(gè)特定的問(wèn)題,通常會(huì)花較長(zhǎng)的時(shí)間才能找到一種最恰當(dāng)?shù)慕鉀Q方案。但一旦找到了正確的方法,以后的工作就輕松 多了,再也不用經(jīng)歷數(shù)小時(shí)、數(shù)天或者數(shù)月的痛苦掙扎。我們的努力工作會(huì)帶來(lái)最大的回報(bào)(甚至無(wú)可估量)。而且由于自己傾注了大量心血,最終獲得一個(gè)出色的 設(shè)計(jì)方案,成功的快感也是令人心動(dòng)的。堅(jiān)持抵制草草完工的誘惑--那樣做往往得不償失
在互聯(lián)網(wǎng)這個(gè)領(lǐng)域一直有這樣的說(shuō)法:“如果老二無(wú)法戰(zhàn)勝老大,那么就把老大賴以生存的東西開源吧”。當(dāng)年Yahoo!與Google還是處在 強(qiáng)烈競(jìng)爭(zhēng)關(guān)系時(shí)候,招聘了Doug(Hadoop創(chuàng)始人),把Google老大賴以生存的DFS與Map-Reduce開源了,開始了Hadoop的童年 時(shí)期。差不多在2008年的時(shí)候,Hadoop才算逐漸成熟。 從初創(chuàng)到現(xiàn)在,Hadoop經(jīng)過(guò)了至少7年的積累,現(xiàn)在的Hadoop不僅是當(dāng)年的老二Yahoo的專用產(chǎn)品了,從Hadoop長(zhǎng)長(zhǎng)的用戶名單中, 可以看到Facebook、Linkedin、Amazon,可以看到EMC、eBay、Twitter、IBM、Microsoft,、Apple、 HP…國(guó)內(nèi)的公司有淘寶、百度等等。  本文將對(duì)Hadoop七年(2004-2011)的發(fā)展歷程進(jìn) 行梳理。讀完本文后,將不難看出,Hadoop的發(fā)展基本上經(jīng)歷了這樣一個(gè)過(guò)程:從一個(gè)開源的Apache基金會(huì)項(xiàng)目,隨著越來(lái)越多的用戶的加入,不斷地 使用、貢獻(xiàn)和完善,形成一個(gè)強(qiáng)大的生態(tài)系統(tǒng),從2009年開始,隨著云計(jì)算和大數(shù)據(jù)的發(fā)展,Hadoop作為海量數(shù)據(jù)分析的最佳解決方案,開始受到許多 IT廠商的關(guān)注,從而出現(xiàn)了許多Hadoop的商業(yè)版以及支持Hadoop的產(chǎn)品,包括軟件和硬件。 - 2004年,Google發(fā)表論文,向全世界介紹了MapReduce。
- 2005年初,為了支持Nutch搜索引擎項(xiàng)目,Nutch的開發(fā)者基于Google發(fā)布的MapReduce報(bào)告,在Nutch上開發(fā)了一個(gè)可工作的MapReduce應(yīng)用。
- 2005年年中,所有主要的Nutch算法被移植到使用MapReduce和NDFS(Nutch Distributed File System )來(lái)運(yùn)行。
- 2006年1月,Doug Cutting加入雅虎,Yahoo!提供一個(gè)專門的團(tuán)隊(duì)和資源將Hadoop發(fā)展成一個(gè)可在網(wǎng)絡(luò)上運(yùn)行的系統(tǒng)。
- 2006年2月,Apache Hadoop項(xiàng)目正式啟動(dòng)以支持MapReduce和HDFS的獨(dú)立發(fā)展。
- 2007年,百度開始使用Hadoop做離線處理,目前差不多80%的Hadoop集群用作日志處理。
- 2007年,中國(guó)移動(dòng)開始在“大云”研究中使用Hadoop技術(shù),規(guī)模超過(guò)1000臺(tái)。
- 2008年,淘寶開始投入研究基于Hadoop的系統(tǒng)——云梯,并將其用于處理電子商務(wù)相關(guān)數(shù)據(jù)。云梯1的總?cè)萘看蟾艦?.3PB,包含了1100臺(tái)機(jī)器,每天處理約18000道作業(yè),掃描500TB數(shù)據(jù)。
- 2008年1月,Hadoop成為Apache頂級(jí)項(xiàng)目。
- 2008年2月,Yahoo!宣布其搜索引擎產(chǎn)品部署在一個(gè)擁有1萬(wàn)個(gè)內(nèi)核的Hadoop集群上。
- 2008年7月,Hadoop打破1TB數(shù)據(jù)排序基準(zhǔn)測(cè)試記錄。Yahoo!的一個(gè)Hadoop集群用209秒完成1TB數(shù)據(jù)的排序 ,比上一年的紀(jì)錄保持者保持的297秒快了將近90秒。
- 2009 年 3 月,Cloudera推出CDH(Cloudera’s Distribution including Apache Hadoop)平臺(tái),完全由開放源碼軟件組成,目前已經(jīng)進(jìn)入第3版。
- 2009年5月,Yahoo的團(tuán)隊(duì)使用Hadoop對(duì)1 TB的數(shù)據(jù)進(jìn)行排序只花了62秒時(shí)間。
- 2009年7月 ,Hadoop Core項(xiàng)目更名為Hadoop Common;
- 2009年7月 ,MapReduce 和 Hadoop Distributed File System (HDFS) 成為Hadoop項(xiàng)目的獨(dú)立子項(xiàng)目。
- 2009年7月 ,Avro 和 Chukwa 成為Hadoop新的子項(xiàng)目。
- 2010年5月 ,Avro脫離Hadoop項(xiàng)目,成為Apache頂級(jí)項(xiàng)目。
- 2010年5月 ,HBase脫離Hadoop項(xiàng)目,成為Apache頂級(jí)項(xiàng)目。
- 2010年5月,IBM提供了基于Hadoop 的大數(shù)據(jù)分析軟件——InfoSphere BigInsights,包括基礎(chǔ)版和企業(yè)版。
- 2010年9月,Hive( Facebook) 脫離Hadoop,成為Apache頂級(jí)項(xiàng)目。
- 2010年9月,Pig脫離Hadoop,成為Apache頂級(jí)項(xiàng)目。
- 2011年1月,ZooKeeper 脫離Hadoop,成為Apache頂級(jí)項(xiàng)目。
- 2011年3月,Apache Hadoop獲得Media Guardian Innovation Awards 。
- 2011年3月, Platform Computing 宣布在它的Symphony軟件中支持Hadoop MapReduce API。
- 2011年5月,Mapr Technologies公司推出分布式文件系統(tǒng)和MapReduce引擎——MapR Distribution for Apache Hadoop。
- 2011年5月,HCatalog 1.0發(fā)布。該項(xiàng)目由Hortonworks 在2010年3月份提出,HCatalog主要用于解決數(shù)據(jù)存儲(chǔ)、元數(shù)據(jù)的問(wèn)題,主要解決HDFS的瓶頸,它提供了一個(gè)地方來(lái)存儲(chǔ)數(shù)據(jù)的狀態(tài)信息,這使得 數(shù)據(jù)清理和歸檔工具可以很容易的進(jìn)行處理。
- 2011年4月,SGI( Silicon Graphics International )基于SGI Rackable和CloudRack服務(wù)器產(chǎn)品線提供Hadoop優(yōu)化的解決方案。
- 2011年5月,EMC為客戶推出一種新的基于開源Hadoop解決方案的數(shù)據(jù)中心設(shè)備——GreenPlum HD,以助其滿足客戶日益增長(zhǎng)的數(shù)據(jù)分析需求并加快利用開源數(shù)據(jù)分析軟件。Greenplum是EMC在2010年7月收購(gòu)的一家開源數(shù)據(jù)倉(cāng)庫(kù)公司。
- 2011年5月,在收購(gòu)了Engenio之后, NetApp推出與Hadoop應(yīng)用結(jié)合的產(chǎn)品E5400存儲(chǔ)系統(tǒng)。
- 2011年6月,Calxeda公司(之前公司的名字是Smooth-Stone)發(fā)起了“開拓者行動(dòng)”,一個(gè)由10家軟件公司組成的團(tuán)隊(duì)將為基于Calxeda即將推出的ARM系統(tǒng)上芯片設(shè)計(jì)的服務(wù)器提供支持。并為Hadoop提供低功耗服務(wù)器技術(shù)。
- 2011年6月,數(shù)據(jù)集成供應(yīng)商Informatica發(fā)布了其旗艦產(chǎn)品,產(chǎn)品設(shè)計(jì)初衷是處理當(dāng)今事務(wù)和社會(huì)媒體所產(chǎn)生的海量數(shù)據(jù),同時(shí)支持Hadoop。
- 2011年7月,Yahoo!和硅谷風(fēng)險(xiǎn)投資公司 Benchmark Capital創(chuàng)建了Hortonworks 公司,旨在讓Hadoop更加魯棒(可靠),并讓企業(yè)用戶更容易安裝、管理和使用Hadoop。
- 2011年8月,Cloudera公布了一項(xiàng)有益于合作伙伴生態(tài)系統(tǒng)的計(jì)劃——創(chuàng)建一個(gè)生態(tài)系統(tǒng),以便硬件供應(yīng)商、軟件供應(yīng)商以及系統(tǒng)集成商可以一起探索如何使用Hadoop更好的洞察數(shù)據(jù)。
- 2011年8月,Dell與Cloudera聯(lián)合推出Hadoop解決方案——Cloudera Enterprise。Cloudera Enterprise基于Dell PowerEdge C2100機(jī)架服務(wù)器以及Dell PowerConnect 6248以太網(wǎng)交換機(jī) 。
 在梳理的過(guò)程中,筆者發(fā)現(xiàn)了上圖,它很好地展現(xiàn)了Hadoop生態(tài)系統(tǒng)是如何在使用中一步一步成長(zhǎng)起來(lái)的。
本文轉(zhuǎn)自:http://linuxtoy.org/archives/bash-shortcuts.html
生活在 Bash shell 中,熟記以下快捷鍵,將極大的提高你的命令行操作效率。 編輯命令 - Ctrl + a :移到命令行首
- Ctrl + e :移到命令行尾
- Ctrl + f :按字符前移(右向)
- Ctrl + b :按字符后移(左向)
- Alt + f :按單詞前移(右向)
- Alt + b :按單詞后移(左向)
- Ctrl + xx:在命令行首和光標(biāo)之間移動(dòng)
- Ctrl + u :從光標(biāo)處刪除至命令行首
- Ctrl + k :從光標(biāo)處刪除至命令行尾
- Ctrl + w :從光標(biāo)處刪除至字首
- Alt + d :從光標(biāo)處刪除至字尾
- Ctrl + d :刪除光標(biāo)處的字符
- Ctrl + h :刪除光標(biāo)前的字符
- Ctrl + y :粘貼至光標(biāo)后
- Alt + c :從光標(biāo)處更改為首字母大寫的單詞
- Alt + u :從光標(biāo)處更改為全部大寫的單詞
- Alt + l :從光標(biāo)處更改為全部小寫的單詞
- Ctrl + t :交換光標(biāo)處和之前的字符
- Alt + t :交換光標(biāo)處和之前的單詞
- Alt + Backspace:與 Ctrl + w 相同類似,分隔符有些差別 [感謝 rezilla 指正]
重新執(zhí)行命令 - Ctrl + r:逆向搜索命令歷史
- Ctrl + g:從歷史搜索模式退出
- Ctrl + p:歷史中的上一條命令
- Ctrl + n:歷史中的下一條命令
- Alt + .:使用上一條命令的最后一個(gè)參數(shù)
控制命令 - Ctrl + l:清屏
- Ctrl + o:執(zhí)行當(dāng)前命令,并選擇上一條命令
- Ctrl + s:阻止屏幕輸出
- Ctrl + q:允許屏幕輸出
- Ctrl + c:終止命令
- Ctrl + z:掛起命令
Bang (!) 命令 - !!:執(zhí)行上一條命令
- !blah:執(zhí)行最近的以 blah 開頭的命令,如 !ls
- !blah:p:僅打印輸出,而不執(zhí)行
- !$:上一條命令的最后一個(gè)參數(shù),與 Alt + . 相同
- !$:p:打印輸出 !$ 的內(nèi)容
- !*:上一條命令的所有參數(shù)
- !*:p:打印輸出 !* 的內(nèi)容
- ^blah:刪除上一條命令中的 blah
- ^blah^foo:將上一條命令中的 blah 替換為 foo
- ^blah^foo^:將上一條命令中所有的 blah 都替換為 foo
友情提示: - 以上介紹的大多數(shù) Bash 快捷鍵僅當(dāng)在 emacs 編輯模式時(shí)有效,若你將 Bash 配置為 vi 編輯模式,那將遵循 vi 的按鍵綁定。Bash 默認(rèn)為 emacs 編輯模式。如果你的 Bash 不在 emacs 編輯模式,可通過(guò)
set -o emacs 設(shè)置。 - ^S、^Q、^C、^Z 是由終端設(shè)備處理的,可用
stty 命令設(shè)置。
本文轉(zhuǎn)自 http://trinea.iteye.com/blog/1196400
1、jps的作用 jps類似linux的ps命令,不同的是ps是用來(lái)顯示進(jìn)程,而jps只顯示java進(jìn)程,準(zhǔn)確的說(shuō)是當(dāng)前用戶已啟動(dòng)的部分java進(jìn)程信息,信息包括進(jìn)程號(hào)和簡(jiǎn)短的進(jìn)程command。 2、某個(gè)java進(jìn)程已經(jīng)啟動(dòng),用jps卻顯示不了該進(jìn)程進(jìn)程號(hào) 這個(gè)問(wèn)題已經(jīng)碰到過(guò)兩次了,所以在這里總結(jié)下。 現(xiàn)象: 用ps -ef|grep java能看到啟動(dòng)的java進(jìn)程,但是用jps查看卻不存在該進(jìn)程的id。待會(huì)兒解釋過(guò)之后就能知道在該情況下,jconsole、jvisualvm可能無(wú)法監(jiān)控該進(jìn)程,其他java自帶工具也可能無(wú)法使用 分析: java程序啟動(dòng)后,默認(rèn)(請(qǐng)注意是默認(rèn))會(huì)在/tmp/hsperfdata_userName目錄下以該進(jìn)程的id為文件名新建文件,并在該文件中存儲(chǔ)jvm運(yùn)行的相關(guān)信息,其中的userName為當(dāng)前的用戶名,/tmp/hsperfdata_userName目錄會(huì)存放該用戶所有已經(jīng)啟動(dòng)的java進(jìn)程信息。對(duì)于windows機(jī)器/tmp用Windows存放臨時(shí)文件目錄代替。 而jps、jconsole、jvisualvm等工具的數(shù)據(jù)來(lái)源就是這個(gè)文件(/tmp/hsperfdata_userName/pid)。所以當(dāng)該文件不存在或是無(wú)法讀取時(shí)就會(huì)出現(xiàn)jps無(wú)法查看該進(jìn)程號(hào),jconsole無(wú)法監(jiān)控等問(wèn)題 原因: (1)、磁盤讀寫、目錄權(quán)限問(wèn)題 若該用戶沒(méi)有權(quán)限寫/tmp目錄或是磁盤已滿,則無(wú)法創(chuàng)建/tmp/hsperfdata_userName/pid文件。或該文件已經(jīng)生成,但用戶沒(méi)有讀權(quán)限 (2)、臨時(shí)文件丟失,被刪除或是定期清理 對(duì)于linux機(jī)器,一般都會(huì)存在定時(shí)任務(wù)對(duì)臨時(shí)文件夾進(jìn)行清理,導(dǎo)致/tmp目錄被清空。這也是我第一次碰到該現(xiàn)象的原因 這個(gè)導(dǎo)致的現(xiàn)象可能會(huì)是這樣,用jconsole監(jiān)控進(jìn)程,發(fā)現(xiàn)在某一時(shí)段后進(jìn)程仍然存在,但是卻沒(méi)有監(jiān)控信息了。 (3)、java進(jìn)程信息文件存儲(chǔ)地址被設(shè)置,不在/tmp目錄下 上面我們?cè)诮榻B時(shí)說(shuō)默認(rèn)會(huì)在/tmp/hsperfdata_userName目錄保存進(jìn)程信息,但由于以上1、2所述原因,可能導(dǎo)致該文件無(wú)法生成或是丟失,所以java啟動(dòng)時(shí)提供了參數(shù),可以對(duì)這個(gè)文件的位置進(jìn)行設(shè)置,而jps、jconsole都只會(huì)從/tmp目錄讀取,而無(wú)法從設(shè)置后的目錄讀物信息, 這個(gè)問(wèn)題只會(huì)在jdk 6u23和6u24上出現(xiàn),在6u23和6u24上,進(jìn)程信息會(huì)保存在-Djava.io.tmpdir下, 因此如果它被設(shè)置為非/tmp目錄則會(huì)導(dǎo)致 jps,jconsole等無(wú)法讀取的現(xiàn)象, 但在其他版本的jdk上,即使設(shè)置-Djava.io.tmpdir為非/tmp, 也會(huì)在/tmp/hsperfdata_userName下保存java進(jìn)程信息.因此可以說(shuō)這是6u23和6u24的bug, 以下是jdk對(duì)該bug的描述地址:
bug描述: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7021676 bug的修復(fù)描述: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7009828 bug修改代碼: http://hg.openjdk.java.net/jdk7/hotspot/hotspot/rev/34d64ad817f4
關(guān)于設(shè)置該文件位置的參數(shù)為-Djava.io.tmpdir
1. 根據(jù)上一章配好的集群,現(xiàn)為Myhost1配置backupNode和SecondaryNamenode, 由于機(jī)器有限,這里就不為Myhost2配置backupNode和SecondaryNamenode,但是方法相同. 2. 我們選定Myhost4為SecondaryNamenode, Myhost5為backupNode. 配置并啟動(dòng)SecondaryNamenode: 1. 配置:為Myhost1的 hdfs-site.xml 加入如下配置,指定SecondaryNamenode. <property> <name>dfs.namenode.secondary.http-address</name> <value> Myhost4:9001</value> </property> 2. Myhost4的hdfs-site.xml 加入如下配置,指定nn的url和本地的checkpoint.dir. <property> <name>dfs.federation.nameservice.id</name> <value> Myhost1:50070</value> </property> <property> <name>dfs.namenode.checkpoint.dir</name> <value>/home/yuling.sh/checkpoint-data</value> </property> 3. 啟動(dòng)SecondaryNamenode. 在Myhost1上運(yùn)行命令:sbin/star-dfs.sh或者在Myhost4上運(yùn)行sbin/hadoop-daemo.sh start SecondaryNamenode 即可以啟動(dòng)SecondaryNamenode. 可以通過(guò)log或者網(wǎng)頁(yè)Myhost4:50090查看其狀態(tài). 另外在checkpoint.dir下會(huì)有元數(shù)據(jù)信息. 配置并啟動(dòng)backupNode: 1. 配置Myhost5的hdfs-site.xml, 加入如下配置信息: <property> <name>dfs.namenode.backup.address</name> <value> Myhost5:9002</value> </property> <property> <name>dfs.namenode.backup.http-address</name> <value> Myhost5:9003</value> </property> <property> <name>dfs.namenode.http-address</name> <value> Myhost1:50070</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/home/yuling.sh/ backup-data</value> </property> 2. 啟動(dòng)backupNode, 在Myhost5上運(yùn)行bin/hdfs namenode –backup & 3. 在dfs.namenode.name.dir下查看元數(shù)據(jù)信息.
下一篇博客將講述如何搭建hadoop 0.23 的mapreduce
使用hadoop-0.23 搭建hdfs, namenode + datanode 1. HDFS-1052引入了多namenode, HDFS架構(gòu)變化較大, 可以參考hortonworks的文章: http://hortonworks.com/an-introduction-to-hdfs-federation/. 我將在接下來(lái)的博客里把此文章翻譯一下(另外還有: http://developer.yahoo.com/blogs/hadoop/posts/2011/03/mapreduce-nextgen-scheduler/). 所有namenode共享datanode, 各個(gè)namenode相互獨(dú)立, 互不影響, 每個(gè)namenode都有一個(gè)backupNode和SecondaryNamenode,提供主備切換功能和備份元數(shù)據(jù)的功能. 下文的配置信息主要參考HDFS-2471. 2. 環(huán)境: a) 五臺(tái)機(jī)器 ,linux系統(tǒng), b) 互相添加ssh-key,后應(yīng)該可以不用密碼互連 c) 編譯好的0.23版本的包: hadoop-0.23.0-SNAPSHOT.tar.gz d) 每臺(tái)機(jī)器需要安裝java1.6或以上版本.并把JAVA_HOME加到$PATH中. e) 最好加上pssh和pscp工具. 這里把五臺(tái)機(jī)器命名為: Myhost1 Myhost2 Myhost3 Myhost4 Myhost5 假設(shè)我們需要搭建如下集群: Myhost1和Myhost2開啟 namenode, 另外三臺(tái)機(jī)器啟動(dòng)datanode服務(wù). 3. 首先把分配到五臺(tái)機(jī)器上,然后解壓.(推薦使用pscp, pssh命令) 4. 然后在五臺(tái)機(jī)器上安裝java,并把JAVA_HOME加到$PATH中 5. 進(jìn)入解壓后的hadoop目錄, 編輯 etc/hadoop/hdfs-site.xml a) Myhost1的配置如下(其中hadoop存放在/home/yuling.sh/目錄下): <property> <name>fs.defaultFS</name> <value>hdfs:// Myhost1:9000</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/home/yuling.sh/cluster-data</value> </property> b) Myhost2的配置如下(其中hadoop存放在/home/yuling.sh/目錄下): <property> <name>fs.defaultFS</name> <value>hdfs:// Myhost2:9000</value> </property> <property> <name>dfs.namenode.name.dir</name> <value>/home/yuling.sh/cluster-data</value> </property> c) 這里把Myhost1集群起名ns1, Myhost1集群起名ns2, 三臺(tái)slava的etc/hadoop/hdfs-site.xml配置如下: <property> <name>dfs.federation.nameservices</name> <value>ns1,ns2</value> </property> <property> <name>dfs.namenode.rpc-address.ns1</name> <value>hdfs:// Myhost1:9000</value> </property> <property> <name>dfs.namenode.http-address.ns1</name> <value> Myhost1:50070</value> </property> <property> <name>dfs.namenode.rpc-address.ns2</name> <value>hdfs:// Myhost2:9000</value> </property> <property> <name>dfs.namenode.http-address.ns1</name> <value> Myhost2:50070</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/home/yuling.sh/datanode</value> </property> d) 解釋:namenode需要指定兩個(gè)參數(shù), 用于存放元數(shù)據(jù)和文件系統(tǒng)的URL. Datanode需指定要連接的namenode 的rpc-address和http-address. 以及數(shù)據(jù)存放位置dfs.datanode.data.dir. 6. 然后編輯兩臺(tái)namenode的hadoop目錄下 etc/hadoop/slaves文件. 加入三臺(tái)slave機(jī)器名: Myhost3 Myhost4 Myhost5 7. 現(xiàn)在需要格式化namenode, 由于namenode共享datanode, 因此它們的clusterid需要有相同的名字.這里我們把名字設(shè)為 yuling .命令如下: bin/hdfs namenode –format –clusterid yuling 兩臺(tái)機(jī)器格式話之后會(huì)在/home/yuling.sh/cluster-data下生成元數(shù)據(jù)目錄. 8. 啟動(dòng)Myhost1和Myhost2上的namenode和slave上datanode服務(wù). 命令如下: sbin/start-hdfs.sh 分別在Myhost1和Myhost2下運(yùn)行. 9. 啟動(dòng)之后打開瀏覽器, 分別查看兩namenode啟動(dòng)后狀態(tài). URL為: Myhost1:50070和Myhost2:50070 10. 這期間可能會(huì)遇到許多問(wèn)題, 但是可以根據(jù)拋出的異常自己解決, 我這里就不多說(shuō)了. 下一篇博客將講述如何啟動(dòng)backupNode和SecondaryNamenode
編譯(環(huán)境linux, 需要聯(lián)網(wǎng)) 1. 首先下載hadoop 0.23版本 svn checkout http://svn.apache.org/repos/asf/hadoop/common/tags/release-0.23.0-rc0/ 2. 進(jìn)入release-0.23.0-rc0目錄下能看到INSTALL.TXT文件, 這里有編譯hadoop 0.23的教程. 編譯前的準(zhǔn)備:. a) * Unix System b) * JDK 1.6 c) * Maven 3.0 d) * Forrest 0.8 (if generating docs) e) * Findbugs 1.3.9 (if running findbugs) f) * ProtocolBuffer 2.4.1+ (for MapReduce) g) * Autotools (if compiling native code) h) * Internet connection for first build (to fetch all Maven and Hadoop dependencies) 可以根據(jù)需要安裝全部或部分的工具,然后把它們加入到$PATH中. 這里介紹一下ProtocolBuffer的安裝方法:下載2.4.1版本后解壓,進(jìn)入目錄,運(yùn)行如下命令即可. $ ./configure --prefile=/usr/local $ make $ sudo make install 3. 經(jīng)過(guò)第二步準(zhǔn)備之后,由于從hadoop0.23開始使用Maven編譯,因此必需聯(lián)網(wǎng),命令如下: mvn package [-Pdist][-Pdocs][-Psrc][-Pnative][-Dtar] 建議先運(yùn)行命令: mvn package -Pdist -DskipTests –Dtar (前提Maven 3.0和ProtocolBuffer2.4.1以上), 此命令成功之后會(huì)在release-0.23.0-rc0/下生成 hadoop-dist/target/hadoop-0.23.0-SNAPSHOT.tar.gz. 可以使用這個(gè)包搭建集群. 使用-Pdocs選項(xiàng)可以生成文檔,當(dāng)然前提是安裝了Forrest 0.8和Findbugs 1.3.9. 可以參考如下命令手動(dòng)指定:FORREST_HOME和FINDBUGS_HOME. mvn package -Pdocs -DskipTests -Dtar -Dmaven.test.skip -Denv.FORREST_HOME=/usr/local/apache-forrest-0.9 -Denv.FINDBUGS_HOME=/usr/local/findbugs-1.3.9 生成的文檔在各自的target/site目錄下.
經(jīng)過(guò)以上步驟,我們已經(jīng)編譯好了hadoop-0.23,現(xiàn)在可以使用hadoop-0.23.0-SNAPSHOT.tar.gz來(lái)搭建集群了. 下一篇博客將講述如何使用hadoop-0.23 搭建hdfs集群
本周末學(xué)習(xí)zookeeper,原理和安裝配置 本文參考: http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/ http://zookeeper.apache.org/ Zookeeper 作為一個(gè)分布式的服務(wù)框架,主要用來(lái)解決分布式集群中應(yīng)用系統(tǒng)的一致性問(wèn)題,它能提供基于類似于文件系統(tǒng)的目錄節(jié)點(diǎn)樹方式的數(shù)據(jù)存儲(chǔ),但是 Zookeeper 并不是用來(lái)專門存儲(chǔ)數(shù)據(jù)的,它的作用主要是用來(lái)維護(hù)和監(jiān)控你存儲(chǔ)的數(shù)據(jù)的狀態(tài)變化。通過(guò)監(jiān)控這些數(shù)據(jù)狀態(tài)的變化,從而可以達(dá)到基于數(shù)據(jù)的集群管理。 Zookeeper安裝和配置比較簡(jiǎn)單,可以參考官網(wǎng). 數(shù)據(jù)模型 Zookeeper 會(huì)維護(hù)一個(gè)具有層次關(guān)系的數(shù)據(jù)結(jié)構(gòu),它非常類似于一個(gè)標(biāo)準(zhǔn)的文件系統(tǒng),如圖 1 所示: 圖 1 Zookeeper 數(shù)據(jù)結(jié)構(gòu)
據(jù)結(jié)構(gòu).jpg)
Zookeeper 這種數(shù)據(jù)結(jié)構(gòu)有如下這些特點(diǎn): - 每個(gè)子目錄項(xiàng)如 NameService 都被稱作為 znode,這個(gè) znode 是被它所在的路徑唯一標(biāo)識(shí),如 Server1 這個(gè) znode 的標(biāo)識(shí)為 /NameService/Server1
- znode 可以有子節(jié)點(diǎn)目錄,并且每個(gè) znode 可以存儲(chǔ)數(shù)據(jù),注意 EPHEMERAL 類型的目錄節(jié)點(diǎn)不能有子節(jié)點(diǎn)目錄
- znode 是有版本的,每個(gè) znode 中存儲(chǔ)的數(shù)據(jù)可以有多個(gè)版本,也就是一個(gè)訪問(wèn)路徑中可以存儲(chǔ)多份數(shù)據(jù)
- znode 可以是臨時(shí)節(jié)點(diǎn),一旦創(chuàng)建這個(gè) znode 的客戶端與服務(wù)器失去聯(lián)系,這個(gè) znode 也將自動(dòng)刪除,Zookeeper 的客戶端和服務(wù)器通信采用長(zhǎng)連接方式,每個(gè)客戶端和服務(wù)器通過(guò)心跳來(lái)保持連接,這個(gè)連接狀態(tài)稱為 session,如果 znode 是臨時(shí)節(jié)點(diǎn),這個(gè) session 失效,znode 也就刪除了
- znode 的目錄名可以自動(dòng)編號(hào),如 App1 已經(jīng)存在,再創(chuàng)建的話,將會(huì)自動(dòng)命名為 App2
- znode 可以被監(jiān)控,包括這個(gè)目錄節(jié)點(diǎn)中存儲(chǔ)的數(shù)據(jù)的修改,子節(jié)點(diǎn)目錄的變化等,一旦變化可以通知設(shè)置監(jiān)控的客戶端,這個(gè)是 Zookeeper 的核心特性,Zookeeper 的很多功能都是基于這個(gè)特性實(shí)現(xiàn)的,后面在典型的應(yīng)用場(chǎng)景中會(huì)有實(shí)例介紹
ZooKeeper 典型的應(yīng)用場(chǎng)景 Zookeeper 從設(shè)計(jì)模式角度來(lái)看,是一個(gè)基于觀察者模式設(shè)計(jì)的分布式服務(wù)管理框架,它負(fù)責(zé)存儲(chǔ)和管理大家都關(guān)心的數(shù)據(jù),然后接受觀察者的注冊(cè),一旦這些數(shù)據(jù)的狀態(tài)發(fā)生 變化,Zookeeper 就將負(fù)責(zé)通知已經(jīng)在 Zookeeper 上注冊(cè)的那些觀察者做出相應(yīng)的反應(yīng),從而實(shí)現(xiàn)集群中類似 Master/Slave 管理模式,關(guān)于 Zookeeper 的詳細(xì)架構(gòu)等內(nèi)部細(xì)節(jié)可以閱讀 Zookeeper 的源碼 下面詳細(xì)介紹這些典型的應(yīng)用場(chǎng)景,也就是 Zookeeper 到底能幫我們解決那些問(wèn)題?下面將給出答案。 統(tǒng)一命名服務(wù)(Name Service) 分布式應(yīng)用中,通常需要有一套完整的命名規(guī)則,既能夠產(chǎn)生唯一的名稱又便于人識(shí)別和記住,通常情況下用樹形的名稱結(jié)構(gòu)是一個(gè)理想的選擇,樹形 的名稱結(jié)構(gòu)是一個(gè)有層次的目錄結(jié)構(gòu),既對(duì)人友好又不會(huì)重復(fù)。說(shuō)到這里你可能想到了 JNDI(Java Naming and Directory Interface,Java命名和目錄接口,是一組在Java應(yīng)用中訪問(wèn)命名和目錄服務(wù)的API),沒(méi)錯(cuò) Zookeeper 的 Name Service 與 JNDI 能夠完成的功能是差不多的,它們都是將有層次的目錄結(jié)構(gòu)關(guān)聯(lián)到一定資源上,但是 Zookeeper 的 Name Service 更加是廣泛意義上的關(guān)聯(lián),也許你并不需要將名稱關(guān)聯(lián)到特定資源上,你可能只需要一個(gè)不會(huì)重復(fù)名稱,就像數(shù)據(jù)庫(kù)中產(chǎn)生一個(gè)唯一的數(shù)字主鍵一樣。 Name Service 已經(jīng)是 Zookeeper 內(nèi)置的功能,你只要調(diào)用 Zookeeper 的 API 就能實(shí)現(xiàn)。如調(diào)用 create 接口就可以很容易創(chuàng)建一個(gè)目錄節(jié)點(diǎn)。 配置管理(Configuration Management) 配置的管理在分布式應(yīng)用環(huán)境中很常見(jiàn),例如同一個(gè)應(yīng)用系統(tǒng)需要多臺(tái) PC Server 運(yùn)行,但是它們運(yùn)行的應(yīng)用系統(tǒng)的某些配置項(xiàng)是相同的,如果要修改這些相同的配置項(xiàng),那么就必須同時(shí)修改每臺(tái)運(yùn)行這個(gè)應(yīng)用系統(tǒng)的 PC Server,這樣非常麻煩而且容易出錯(cuò)。 像這樣的配置信息完全可以交給 Zookeeper 來(lái)管理,將配置信息保存在 Zookeeper 的某個(gè)目錄節(jié)點(diǎn)中,然后將所有需要修改的應(yīng)用機(jī)器監(jiān)控配置信息的狀態(tài),一旦配置信息發(fā)生變化,每臺(tái)應(yīng)用機(jī)器就會(huì)收到 Zookeeper 的通知,然后從 Zookeeper 獲取新的配置信息應(yīng)用到系統(tǒng)中。 圖 2. 配置管理結(jié)構(gòu)圖
集群管理(Group Membership) Zookeeper 能夠很容易的實(shí)現(xiàn)集群管理的功能,如有多臺(tái) Server 組成一個(gè)服務(wù)集群,那么必須要一個(gè)“總管”知道當(dāng)前集群中每臺(tái)機(jī)器的服務(wù)狀態(tài),一旦有機(jī)器不能提供服務(wù),集群中其它集群必須知道,從而做出調(diào)整重新分配服 務(wù)策略。同樣當(dāng)增加集群的服務(wù)能力時(shí),就會(huì)增加一臺(tái)或多臺(tái) Server,同樣也必須讓“總管”知道。 Zookeeper 不僅能夠幫你維護(hù)當(dāng)前的集群中機(jī)器的服務(wù)狀態(tài),而且能夠幫你選出一個(gè)“總管”,讓這個(gè)總管來(lái)管理集群,這就是 Zookeeper 的另一個(gè)功能 Leader Election。 它們的實(shí)現(xiàn)方式都是在 Zookeeper 上創(chuàng)建一個(gè) EPHEMERAL 類型的目錄節(jié)點(diǎn),然后每個(gè) Server 在它們創(chuàng)建目錄節(jié)點(diǎn)的父目錄節(jié)點(diǎn)上調(diào)用 getChildren(String path, boolean watch) 方法并設(shè)置 watch 為 true,由于是 EPHEMERAL 目錄節(jié)點(diǎn),當(dāng)創(chuàng)建它的 Server 死去,這個(gè)目錄節(jié)點(diǎn)也隨之被刪除,所以 Children 將會(huì)變化,這時(shí) getChildren上的 Watch 將會(huì)被調(diào)用,所以其它 Server 就知道已經(jīng)有某臺(tái) Server 死去了。新增 Server 也是同樣的原理。 Zookeeper 如何實(shí)現(xiàn) Leader Election,也就是選出一個(gè) Master Server。和前面的一樣每臺(tái) Server 創(chuàng)建一個(gè) EPHEMERAL 目錄節(jié)點(diǎn),不同的是它還是一個(gè) SEQUENTIAL 目錄節(jié)點(diǎn),所以它是個(gè) EPHEMERAL_SEQUENTIAL 目錄節(jié)點(diǎn)。之所以它是 EPHEMERAL_SEQUENTIAL 目錄節(jié)點(diǎn),是因?yàn)槲覀兛梢越o每臺(tái) Server 編號(hào),我們可以選擇當(dāng)前是最小編號(hào)的 Server 為 Master,假如這個(gè)最小編號(hào)的 Server 死去,由于是 EPHEMERAL 節(jié)點(diǎn),死去的 Server 對(duì)應(yīng)的節(jié)點(diǎn)也被刪除,所以當(dāng)前的節(jié)點(diǎn)列表中又出現(xiàn)一個(gè)最小編號(hào)的節(jié)點(diǎn),我們就選擇這個(gè)節(jié)點(diǎn)為當(dāng)前 Master。這樣就實(shí)現(xiàn)了動(dòng)態(tài)選擇 Master,避免了傳統(tǒng)意義上單 Master 容易出現(xiàn)單點(diǎn)故障的問(wèn)題。 圖 3. 集群管理結(jié)構(gòu)圖
這部分的示例代碼如下,完整的代碼請(qǐng)看源代碼: 清單 3. Leader Election 關(guān)鍵代碼 void findLeader() throws InterruptedException { byte[] leader = null; try { leader = zk.getData(root + "/leader", true, null); } catch (Exception e) { logger.error(e); } if (leader != null) { following(); } else { String newLeader = null; try { byte[] localhost = InetAddress.getLocalHost().getAddress(); newLeader = zk.create(root + "/leader", localhost, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); } catch (Exception e) { logger.error(e); } if (newLeader != null) { leading(); } else { mutex.wait(); } } } | 共享鎖(Locks) 共享鎖在同一個(gè)進(jìn)程中很容易實(shí)現(xiàn),但是在跨進(jìn)程或者在不同 Server 之間就不好實(shí)現(xiàn)了。Zookeeper 卻很容易實(shí)現(xiàn)這個(gè)功能,實(shí)現(xiàn)方式也是需要獲得鎖的 Server 創(chuàng)建一個(gè) EPHEMERAL_SEQUENTIAL 目錄節(jié)點(diǎn),然后調(diào)用 getChildren方法獲取當(dāng)前的目錄節(jié)點(diǎn)列表中最小的目錄節(jié)點(diǎn)是不是就是自己創(chuàng)建的目錄節(jié)點(diǎn),如果正是自己創(chuàng)建的,那么它就獲得了這個(gè)鎖,如果不是那么它就調(diào)用 exists(String path, boolean watch) 方法并監(jiān)控 Zookeeper 上目錄節(jié)點(diǎn)列表的變化,一直到自己創(chuàng)建的節(jié)點(diǎn)是列表中最小編號(hào)的目錄節(jié)點(diǎn),從而獲得鎖,釋放鎖很簡(jiǎn)單,只要?jiǎng)h除前面它自己所創(chuàng)建的目錄節(jié)點(diǎn)就行了。 圖 4. Zookeeper 實(shí)現(xiàn) Locks 的流程圖
同步鎖的實(shí)現(xiàn)代碼如下,完整的代碼請(qǐng)看源代碼: 清單 4. 同步鎖的關(guān)鍵代碼 void getLock() throws KeeperException, InterruptedException{ List<String> list = zk.getChildren(root, false); String[] nodes = list.toArray(new String[list.size()]); Arrays.sort(nodes); if(myZnode.equals(root+"/"+nodes[0])){ doAction(); } else{ waitForLock(nodes[0]); } } void waitForLock(String lower) throws InterruptedException, KeeperException { Stat stat = zk.exists(root + "/" + lower,true); if(stat != null){ mutex.wait(); } else{ getLock(); } } | 隊(duì)列管理 Zookeeper 可以處理兩種類型的隊(duì)列: - 當(dāng)一個(gè)隊(duì)列的成員都聚齊時(shí),這個(gè)隊(duì)列才可用,否則一直等待所有成員到達(dá),這種是同步隊(duì)列。
- 隊(duì)列按照 FIFO 方式進(jìn)行入隊(duì)和出隊(duì)操作,例如實(shí)現(xiàn)生產(chǎn)者和消費(fèi)者模型。
同步隊(duì)列用 Zookeeper 實(shí)現(xiàn)的實(shí)現(xiàn)思路如下: 創(chuàng)建一個(gè)父目錄 /synchronizing,每個(gè)成員都監(jiān)控標(biāo)志(Set Watch)位目錄 /synchronizing/start 是否存在,然后每個(gè)成員都加入這個(gè)隊(duì)列,加入隊(duì)列的方式就是創(chuàng)建 /synchronizing/member_i 的臨時(shí)目錄節(jié)點(diǎn),然后每個(gè)成員獲取 / synchronizing 目錄的所有目錄節(jié)點(diǎn),也就是 member_i。判斷 i 的值是否已經(jīng)是成員的個(gè)數(shù),如果小于成員個(gè)數(shù)等待 /synchronizing/start 的出現(xiàn),如果已經(jīng)相等就創(chuàng)建 /synchronizing/start。 用下面的流程圖更容易理解: 圖 5. 同步隊(duì)列流程圖
同步隊(duì)列的關(guān)鍵代碼如下,完整的代碼請(qǐng)看附件: 清單 5. 同步隊(duì)列 void addQueue() throws KeeperException, InterruptedException{ zk.exists(root + "/start",true); zk.create(root + "/" + name, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); synchronized (mutex) { List<String> list = zk.getChildren(root, false); if (list.size() < size) { mutex.wait(); } else { zk.create(root + "/start", new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } } } | 當(dāng)隊(duì)列沒(méi)滿是進(jìn)入 wait(),然后會(huì)一直等待 Watch 的通知,Watch 的代碼如下: public void process(WatchedEvent event) { if(event.getPath().equals(root + "/start") && event.getType() == Event.EventType.NodeCreated){ System.out.println("得到通知"); super.process(event); doAction(); } } | FIFO 隊(duì)列用 Zookeeper 實(shí)現(xiàn)思路如下: 實(shí)現(xiàn)的思路也非常簡(jiǎn)單,就是在特定的目錄下創(chuàng)建 SEQUENTIAL 類型的子目錄 /queue_i,這樣就能保證所有成員加入隊(duì)列時(shí)都是有編號(hào)的,出隊(duì)列時(shí)通過(guò) getChildren( ) 方法可以返回當(dāng)前所有的隊(duì)列中的元素,然后消費(fèi)其中最小的一個(gè),這樣就能保證 FIFO。 下面是生產(chǎn)者和消費(fèi)者這種隊(duì)列形式的示例代碼,完整的代碼請(qǐng)看附件: 清單 6. 生產(chǎn)者代碼 boolean produce(int i) throws KeeperException, InterruptedException{ ByteBuffer b = ByteBuffer.allocate(4); byte[] value; b.putInt(i); value = b.array(); zk.create(root + "/element", value, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT_SEQUENTIAL); return true; } | 清單 7. 消費(fèi)者代碼 int consume() throws KeeperException, InterruptedException{ int retvalue = -1; Stat stat = null; while (true) { synchronized (mutex) { List<String> list = zk.getChildren(root, true); if (list.size() == 0) { mutex.wait(); } else { Integer min = new Integer(list.get(0).substring(7)); for(String s : list){ Integer tempValue = new Integer(s.substring(7)); if(tempValue < min) min = tempValue; } byte[] b = zk.getData(root + "/element" + min,false, stat); zk.delete(root + "/element" + min, 0); ByteBuffer buffer = ByteBuffer.wrap(b); retvalue = buffer.getInt(); return retvalue; } } } } | 總結(jié) Zookeeper 作為 Hadoop 項(xiàng)目中的一個(gè)子項(xiàng)目,是 Hadoop 集群管理的一個(gè)必不可少的模塊,它主要用來(lái)控制集群中的數(shù)據(jù),如它管理 Hadoop 集群中的 NameNode,還有 Hbase 中 Master Election、Server 之間狀態(tài)同步等。 本文介紹的 Zookeeper 的基本知識(shí),以及介紹了幾個(gè)典型的應(yīng)用場(chǎng)景。這些都是 Zookeeper 的基本功能,最重要的是 Zoopkeeper 提供了一套很好的分布式集群管理的機(jī)制,就是它這種基于層次型的目錄樹的數(shù)據(jù)結(jié)構(gòu),并對(duì)樹中的節(jié)點(diǎn)進(jìn)行有效管理,從而可以設(shè)計(jì)出多種多樣的分布式的數(shù)據(jù)管 理模型,而不僅僅局限于上面提到的幾個(gè)常用應(yīng)用場(chǎng)景。
使用 Linux 系統(tǒng)總是免不了要接觸包管理工具。比如,Debian/Ubuntu 的 apt、openSUSE 的 zypp、Fedora 的 yum、Mandriva 的 urpmi、Slackware 的 slackpkg、Archlinux 的 pacman、Gentoo 的 emerge、Foresight 的 conary、Pardus 的 pisi,等等。DistroWatch 針對(duì)上述包管理器的主要用法進(jìn)行了總結(jié),對(duì)各位 Linux 用戶來(lái)說(shuō)具有很好的參考作用。這個(gè)總結(jié)還是有一點(diǎn)不足,有空給大家整理一個(gè)更全面的版本。 任務(wù) | apt Debian, Ubuntu | zypp openSUSE | yum Fedora, CentOS | 安裝包 | apt-get install <pkg> | zypper install <pkg> | yum install <pkg> | 移除包 | apt-get remove <pkg> | zypper remove <pkg> | yum erase <pkg> | 更新包列表 | apt-get update | zypper refresh | yum check-update | 更新系統(tǒng) | apt-get upgrade | zypper update | yum update | 列出源 | cat /etc/apt/sources.list | zypper repos | yum repolist | 添加源 | (edit /etc/apt/sources.list) | zypper addrepo <path> <name> | (add <repo> to /etc/yum.repos.d/) | 移除源 | (edit /etc/apt/sources.list) | zypper removerepo <name> | (remove <repo> from /etc/yum.repos.d/) | 搜索包 | apt-cache search <pkg> | zypper search <pkg> | yum search <pkg> | 列出已安裝的包 | dpkg -l | rpm -qa | rpm -qa | 任務(wù) | urpmi Mandriva | slackpkg Slackware | pacman Arch | 安裝包 | urpmi <pkg> | slackpkg install <pkg> | pacman -S <pkg> | 移除包 | urpme <pkg> | slackpkg remove <pkg> | pacman -R <pkg> | 更新包列表 | urpmi.update -a | slackpkg update | pacman -Sy | 更新系統(tǒng) | urpmi --auto-select | slackpkg upgrade-all | pacman -Su | 列出源 | urpmq --list-media | cat /etc/slackpkg/mirrors | cat /etc/pacman.conf | 添加源 | urpmi.addmedia <name> <path> | (edit /etc/slackpkg/mirrors) | (edit /etc/pacman.conf) | 移除源 | urpmi.removemedia <media> | (edit /etc/slackpkg/mirrors) | (edit /etc/pacman.conf) | 搜索包 | urpmf <pkg> | -- | pacman -Qs <pkg> | 列出已安裝的包 | rpm -qa | ls /var/log/packages/ | pacman -Qii | 任務(wù) | conary rPath, Foresight | pisi Pardus | emerge Gentoo | 安裝包 | conary update <pkg> | pisi install <pkg> | emerge <pkg> | 移除包 | conary erase <pkg> | pisi remove <pkg> | emerge -C <pkg> | 更新包列表 | | pisi update-repo | emerge --sync | layman -S [for added repositories] | 更新系統(tǒng) | conary updateall | pisi upgrade | emerge -NuDa world | 列出源 | | pisi list-repo | layman -L | 添加源 | | pisi add-repo <name> <path> | layman -a | 移除源 | | pisi remove-repo <name> | layman -d | 搜索包 | conary query <pkg> | pisi search <pkg> | emerge --search | 列出已安裝的包 | conary query | pisi list-installed | cat /var/lib/portage | more |
本文轉(zhuǎn)自 http://linuxtoy.org/archives/linux-package-management-cheatsheet.html
-Xms256m -Xmx512m -Xmn128m -XX:PermSize=96m -XX:MaxPermSize=96m -Xverify:none -Xnoclassgc -XX:UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=85 加入以上參數(shù)能使eclipse啟動(dòng)速度得到加快.至于各個(gè)參數(shù)的意義可以在網(wǎng)上查找到,這里不詳細(xì)贅述.
Eclipse插件開發(fā) 1. 下載并安裝jdk和eclipse 這里強(qiáng)調(diào)一下: 需要下載Eclipse for RCP and RAP Developers, 否則無(wú)法新建Plug-in Development 項(xiàng)目. 2. 新建項(xiàng)目 安裝好之后打開eclipse, 點(diǎn)擊 File->NewProject。選擇Plug-in Project,點(diǎn)擊Next。新建一個(gè)名為com.developer.showtime的項(xiàng)目,所有參數(shù)采用默認(rèn)值. 3. 在com.developer.showtime項(xiàng)目的src下新建一個(gè)類: ShowTime,代碼如下:
package com.developer.showtime;
import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IStartup;
public class ShowTime implements IStartup { public void earlyStartup() { Display.getDefault().syncExec(new Runnable() { public void run(){ long eclipseStartTime = Long.parseLong(System.getProperty("eclipse.startTime")); long costTime = System.currentTimeMillis() - eclipseStartTime; Shell shell = Display.getDefault().getActiveShell(); String message = "Eclipse start in " + costTime + "ms"; MessageDialog.openInformation(shell, "Information", message); } }); } }
4. 修改plugin.xml文件如下: <?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?>
<plugin> <extension
point="org.eclipse.ui.startup">
<startup class="com.developer.showtime.ShowTime"/>
</extension>
</plugin> 5. 試運(yùn)行 右鍵點(diǎn)擊Run as -> Eclipse Application. 此時(shí)會(huì)運(yùn)行一個(gè)eclipse, 啟動(dòng)之后就能顯示啟動(dòng)所需時(shí)間. 6. 導(dǎo)出插件. 右鍵Export -> Deployable plug-ins and fragments. 在Directory中輸入需要導(dǎo)出的路徑, 點(diǎn)擊finish后會(huì)在該目錄下產(chǎn)生一個(gè)plugins的目錄, 里面就是插件包: com.developer.showTime_1.0.0.201110161216.jar. 把這個(gè)包復(fù)制到eclipse目錄下的plugin目錄下. 然后再啟動(dòng)eclipse 便可以看到eclipse啟動(dòng)所花的時(shí)間.
本周學(xué)習(xí)了mapreduce-64,對(duì)map端的spill有了較為深入的了解. 附件描述了修改前后sort的原理.mapreduce-64前spill原理較為簡(jiǎn)單,打上mapreduce-64后主要流程也不難,需要了解各個(gè)參數(shù)的意義.
下文翻譯自yahoo博客:http://developer.yahoo.com/blogs/hadoop/posts/2011/02/mapreduce-nextgen/
Hadoop的下一代mapreduce 概述 在大數(shù)據(jù)商業(yè)領(lǐng)域中,運(yùn)行個(gè)數(shù)少但較大的集群比運(yùn)行多個(gè)小集群更劃算,大集群還可以處理更大的數(shù)據(jù)集并支持更多的作業(yè)和用戶. Apache Hadoop 的MapReduce框架已經(jīng)達(dá)到4000臺(tái)機(jī)器的擴(kuò)展極限,我們正在發(fā)展下一代MapReduce,使其成為一個(gè)通用資源管理,單作業(yè),用戶自定義組件,管理著應(yīng)用程序執(zhí)行的框架. 由于停機(jī)成本更大,高可用必需從一開始就得建立,就如安全性和多用戶組,用以支持更多用戶使用更大的集群,新的構(gòu)架在許多地方進(jìn)行了創(chuàng)新,增加了敏捷性和機(jī)器利用率. 背景 當(dāng)前Apache Hadoop 的MapReduce的接口會(huì)顯示其年齡. 由于集群大小和工作負(fù)載的變化趨勢(shì), MapReduce的JobTracker需要徹底的改革以解決其可擴(kuò)展性,內(nèi)存消耗,線程模型,可靠性和性能上的不足. 過(guò)去五年,我們做了一些小的修復(fù),然而最近,修改框架的的成本越來(lái)越高. 結(jié)構(gòu)的缺陷和糾正措施都很好理解,甚至早在2007年,當(dāng)我們記錄下修復(fù)建議: https://issues.apache.org/jira/browse/MAPREDUCE-278. 從運(yùn)營(yíng)的角度看,目前的Hadoop MapReduce框架面臨系統(tǒng)級(jí)別的升級(jí),以解決例如bug修復(fù),性能改善和功能的需求. 更糟糕的是,它迫使每個(gè)用戶也需要同時(shí)升級(jí),不顧其利益;這使用戶使用新版本的周期變長(zhǎng). 需求 我們考慮改善Hadoop MapReduce框架的方法,重要的是記住最迫切的需求,下一代Hadoop MapReduce框架最迫切的需求是: - 可靠性
- 可用性
- 可擴(kuò)展性 - 10000臺(tái)機(jī)器,200000核,或者更多
- 向后兼容性 - 確保用戶的MapReduce應(yīng)用程序在下一代框架下不需要改變
- 進(jìn)展 – 客戶端可以控制hadoop軟件堆棧的升級(jí).
- 可預(yù)測(cè)的延遲 – 用戶很關(guān)注的一點(diǎn).
- 集群利用率
第二層次需求: - 使MapReduce支持備用編程范式
- 支持短時(shí)間的服務(wù)
鑒于以上需求,顯然我們需要重新考慮使用hadoop成為數(shù)據(jù)處理的基礎(chǔ)設(shè)施. 事實(shí)上,當(dāng)前MapReduce結(jié)構(gòu)無(wú)法滿足我們的需求,因此需要新的創(chuàng)新,這在hadoop社區(qū)這已成為共識(shí),查看2008年一月的一個(gè)提議,在jira: https://issues.apache.org/jira/browse/MAPREDUCE-279. 下一代MapReduce 重構(gòu)的基本思想是把jobtracker的兩大功能分開,使資源管理和作業(yè)分配/監(jiān)控成為兩個(gè)部件.新的資源管理器管理提供給應(yīng)用(一個(gè)或多個(gè))的計(jì)算資源,應(yīng)用管理中心管理應(yīng)用程序的調(diào)度和協(xié)調(diào),應(yīng)用程序既是一個(gè)經(jīng)典MapReduce作業(yè)也是這類作業(yè)的DAG. 資源管理器和每臺(tái)機(jī)器的NodeManager服務(wù),管理該機(jī)上的用戶進(jìn)程,形成計(jì)算結(jié)構(gòu). 每個(gè)應(yīng)用程序的ApplicationMaster是一個(gè)具體庫(kù)的架構(gòu),負(fù)責(zé)從資源管理器請(qǐng)求資源,并和NodeManager協(xié)同執(zhí)行和監(jiān)控任務(wù). 資源管理器支持應(yīng)用程序的分組,這些組保證使用一定比例集群資源. 它是純粹的調(diào)度,也就是,它運(yùn)行時(shí)并不監(jiān)控和追蹤應(yīng)用的狀態(tài). 此外,它不保證重新啟動(dòng)失敗的任務(wù),無(wú)論是應(yīng)用程序或硬件導(dǎo)致的失敗. 資源管理器執(zhí)行調(diào)度功能是基于應(yīng)用的資源需求,每個(gè)應(yīng)用需要多種資源需求,代表對(duì)對(duì)容器所需的資源,資源需求包括內(nèi)存,cpu,硬盤,網(wǎng)絡(luò)等,注意這與當(dāng)前使用slot模型的MapReduce有很大的不同,slot模型導(dǎo)致集群利用率不高,資源管理器有一個(gè)調(diào)度策略插件,負(fù)責(zé)分把集群資源分給各個(gè)組,應(yīng)用等.有基礎(chǔ)的調(diào)度插件,例如:當(dāng)前的CapacityScheduler 和FairScheduler. NodeManager是每臺(tái)機(jī)器的框架代理,負(fù)責(zé)提交應(yīng)用程序的容器,監(jiān)控他們的資源利用率(cpu,內(nèi)存,硬盤,網(wǎng)絡(luò)),并且報(bào)告給調(diào)度器. 每個(gè)應(yīng)用程序的ApplicationMaster負(fù)責(zé)與調(diào)度器請(qǐng)求適當(dāng)?shù)馁Y源容器,提交作業(yè),追蹤其狀態(tài),監(jiān)控進(jìn)度和處理失敗任務(wù). 結(jié)構(gòu) 改進(jìn)當(dāng)前實(shí)現(xiàn)面對(duì)面的Hadoop MapReduce 可擴(kuò)展性 在集群中把資源管理從集群管理器的整個(gè)生命周期和他們的部件中分離出來(lái)后形成的架構(gòu):擴(kuò)展性更好并且更優(yōu)雅, Hadoop MapReduce的JobTracker花費(fèi)很大一部分時(shí)間和精力管理應(yīng)用程序的生命周期,這是導(dǎo)致軟件災(zāi)難的原因.把它移到應(yīng)用指定的實(shí)體是一個(gè)重大的勝利. 可擴(kuò)展性在當(dāng)前硬件趨勢(shì)下更加重要,當(dāng)前hadoop的MapReduce已經(jīng)發(fā)展到4000臺(tái)機(jī)器,然而4000臺(tái)機(jī)器在2009年(例:8core,16G RAM,4TB硬盤)只有2011年400臺(tái)機(jī)器的一半(16core,48G RAM, 24TB硬盤). 并且,運(yùn)營(yíng)成本的因素有助于迫使和鞏固我們使用更大的集群:6000臺(tái)機(jī)器或者更多. 可用性 - 資源管理器 – 使用 Apache ZooKeeper 用于故障轉(zhuǎn)移. 當(dāng)資源管理器發(fā)生故障,另外一個(gè)可以迅速恢復(fù),這是由于集群狀態(tài)保存在ZooKeeper中. 資源管理器失敗后,重啟所有組和正在運(yùn)行的應(yīng)用程序.
- 應(yīng)用中心 - 下一代MapReduce支持應(yīng)用特殊點(diǎn)的檢查功能 ,依靠其把自身狀態(tài)存儲(chǔ)在hdfs上的功能,MapReduce 應(yīng)用中心可以從失敗中恢復(fù),
兼容性 下一代MapReduce使用線兼容協(xié)議以允許不同版本的服務(wù)端和客戶端相互通信,在將來(lái)的releases版本,這將使集群滾動(dòng)升級(jí),一個(gè)重要的可操作性便成功了. 創(chuàng)新和敏捷性 提出的構(gòu)架一個(gè)主要優(yōu)點(diǎn)是MapReduce將更有效,成為user-land library. 計(jì)算框架(資源管理器和節(jié)點(diǎn)管理器)完全通用并在MapReduce看來(lái)是透明的. 這使最終客戶在同一個(gè)集群使用可用不同版本的MapReduce, 這是微不足道的支持,因?yàn)?/span>MapReduce的應(yīng)用中心和運(yùn)行時(shí)的多版本可用于不同的應(yīng)用. 這為應(yīng)用提供顯著的靈活性,因?yàn)檎麄€(gè)集群沒(méi)必要升級(jí),如修復(fù)bug,改進(jìn)和新功能的應(yīng)用. 它也允許終端用戶根據(jù)他們自己的安排升級(jí)其應(yīng)用到MapReduce版本,這大大提高了集群的可操作性. 允許用戶自定義的Map-Reduce版本的創(chuàng)新不會(huì)影響軟件的穩(wěn)定性. 這是微不足道的,就像hadoop在線原型進(jìn)入用戶MapReduce版本而不影響其他用戶.( It will be trivial to incorporate features such as the Hadoop Online Prototype into the user’s version of MapReduce without affecting other users.) 集群利用率 下一代MapReduce資源管理器使用通用概念,用于調(diào)度和分配給單獨(dú)的個(gè)體. 集群中的每個(gè)機(jī)器資源是概念性的,例如內(nèi)存,cpu,I/O帶寬等. 每個(gè)機(jī)器都是可替代的,分配給應(yīng)用程序就像基于應(yīng)用指定需求資源的容器.每個(gè)容器包括一些處理器,并和其他容器邏輯隔離,提供強(qiáng)有利的多租戶支持. 它刪除了當(dāng)前hadoop MapReduce中map和reduce slots概念. Slot會(huì)影響集群的利用率,因?yàn)樵谌魏螘r(shí)候,無(wú)論map和reduce都是稀缺的. 支持MapReduce編程范式 下一代MapReduce提供一個(gè)完全通用的計(jì)算框架以支持MapReduce和其他的范例. 架構(gòu)允許終端用戶實(shí)現(xiàn)應(yīng)用指定的框架,通過(guò)實(shí)現(xiàn)用戶的ApplicationMaster,可以向資源管理器請(qǐng)求資源并利用他們,因?yàn)樗麄兺ㄟ^(guò)隔離并保證資源的情況下看起來(lái)是適合的. 因此,在同一個(gè)hadoop集群下支持多種編程范式,例如MapReduce, MPI, Master-Worker和迭代模型,并允許為每個(gè)應(yīng)用使用適當(dāng)?shù)目蚣?/span>.這對(duì)自定義框架順序執(zhí)行一定數(shù)目的MapReduc應(yīng)用程序(例: K-Means, Page-Rank)很重要. 結(jié)論 Apache Hadoop和特定的Hadoop MapReduce,是一個(gè)用于處理大數(shù)據(jù)集的成功開源項(xiàng)目. 我們建議Hadoop的 MapReduce重構(gòu)以提供高可用性,增加集群利用率,提供編程范例的支持以加快發(fā)展. 我們認(rèn)為,在已存在的選項(xiàng)中如Torque, Condor, Mesos 等,沒(méi)有一個(gè)用于設(shè)計(jì)解決MapReduce集群規(guī)模的問(wèn)題, 某些功能很新且不成熟, 另外一些沒(méi)有解決關(guān)鍵問(wèn)題,如調(diào)度在上十萬(wàn)個(gè)task,規(guī)模的性能,安全和多用戶等. 我們將與Apache Hadoop社區(qū)合作,為實(shí)現(xiàn)這以提升Apache Hadoop以適應(yīng)下一代大數(shù)據(jù)空間.
0.23的調(diào)度方法: http://developer.yahoo.com/blogs/hadoop/posts/2011/03/mapreduce-nextgen-scheduler/
周末無(wú)事,故翻譯sheepdog design. 原文地址: https://github.com/collie/sheepdog/wiki/Sheepdog-Design Sheepdog 設(shè)計(jì) Sheeepdog采用完全對(duì)稱的結(jié)構(gòu),沒(méi)有類似元數(shù)據(jù)服務(wù)的中心節(jié)點(diǎn). 這種設(shè)計(jì)有以下的特點(diǎn). 1) 性能于容量的線性的可擴(kuò)展性. 當(dāng)需要提升性能或容量時(shí),只需向集群中增加新的機(jī)器便能使Sheeepdog線性成長(zhǎng). 2) 沒(méi)有單點(diǎn)故障 即使某臺(tái)機(jī)器發(fā)生故障,依然可以通過(guò)其他機(jī)器訪問(wèn)數(shù)據(jù). 3) 容易管理 不需要配置機(jī)器角色,當(dāng)管理員在新增的機(jī)器開啟Sheepdog守護(hù)進(jìn)程時(shí), Sheepdog會(huì)自動(dòng)檢測(cè)新加入的機(jī)器并配置它成為存儲(chǔ)系統(tǒng)中的一員. 結(jié)構(gòu)概述  Sheepdog是一個(gè)分布式存儲(chǔ)系統(tǒng).為Sheepdog客戶端(QEMU的塊驅(qū)動(dòng)程序)提供對(duì)象存儲(chǔ)(類似于簡(jiǎn)單的鍵值對(duì)). 接下來(lái)幾章將更加詳細(xì)的闡述Sheepdog各個(gè)部分. 1) 對(duì)象存儲(chǔ)(Object對(duì)象存儲(chǔ)(Object Storage) 2) ) Sheepdog不同于一般的文件系統(tǒng), Sheepdog進(jìn)程為QEMU(Sheepdog進(jìn)程名)創(chuàng)建一個(gè)分布式對(duì)象存儲(chǔ)系統(tǒng),它可以存儲(chǔ)”對(duì)象”.這里的”對(duì)象”數(shù)據(jù)大小可變,并有唯一的標(biāo)識(shí),通過(guò)標(biāo)識(shí)可以進(jìn)行讀/寫/創(chuàng)建/刪除操作.對(duì)象存儲(chǔ)組成”網(wǎng)關(guān)”和”對(duì)象管理器”. 3) 網(wǎng)關(guān)(getway) Getway接收QEMU塊驅(qū)動(dòng)的I/O請(qǐng)求(對(duì)象id,偏移,長(zhǎng)度和操作類型),通過(guò)一直散列算法獲得目標(biāo)節(jié)點(diǎn),然后轉(zhuǎn)發(fā)I/O請(qǐng)求至該節(jié)點(diǎn). 4) 對(duì)象管理器(Object manager) 對(duì)象管理器接收getway轉(zhuǎn)發(fā)過(guò)來(lái)的I/O請(qǐng)求,然后對(duì)磁盤執(zhí)行讀/寫操作. 5) 集群管理器(Cluster manager) 集群管理器管理管理節(jié)點(diǎn)成員(探測(cè)失敗/新增節(jié)點(diǎn)并報(bào)告節(jié)點(diǎn)成員的變化),以及一些需要節(jié)點(diǎn)一致的操作(vdi 創(chuàng)建, 快照 vdi等).當(dāng)前集群管理器使用corosync集群引擎. 6) QEMU 塊驅(qū)動(dòng) QEMU塊驅(qū)動(dòng)把VM image分為固定大小(默認(rèn)4M),并通過(guò)其getway存儲(chǔ)到對(duì)象存儲(chǔ)中 對(duì)象存儲(chǔ)(Object Storage) 每個(gè)對(duì)象使用一個(gè)64bit的整數(shù)作為全局標(biāo)識(shí),并在多臺(tái)機(jī)器存有備份,QEMU塊驅(qū)動(dòng)并不關(guān)心存儲(chǔ)的位置,對(duì)象存儲(chǔ)系統(tǒng)負(fù)責(zé)管理存儲(chǔ)的位置. 對(duì)象類型(object types) Sheepdog的對(duì)象分為以下四種: 1) 數(shù)據(jù)類型(data object) 它包括虛擬磁盤映射的真實(shí)數(shù)據(jù),虛擬磁盤映射分為固定大小的數(shù)據(jù)對(duì)象, Sheepdog客戶端訪問(wèn)這個(gè)對(duì)象. 2) vdi object 它包括虛擬磁盤映射的元數(shù)據(jù)(例:映射名,磁盤大小,創(chuàng)建時(shí)間,vdi的數(shù)據(jù)對(duì)象ID等). 3) vmstate object 它存儲(chǔ)運(yùn)行中的VM狀態(tài)映射.管理員通過(guò)它獲取實(shí)時(shí)快照信息. 4) vdi attr object 使用它存儲(chǔ)各個(gè)vdi的屬性,屬性為鍵值對(duì)類型,類似于普通文件的擴(kuò)展信息. 對(duì)象ID規(guī)則(object ID rules) 1) 0 - 31 (32 bits): 對(duì)象類型詳細(xì)信息 2) 32 - 55 (24 bits): vdi id 3) 56 - 59 ( 4 bits): 預(yù)留 4) 60 - 63 ( 4 bits): 對(duì)象類型標(biāo)識(shí)符 每個(gè)VDI有一個(gè)全局唯一的ID(vdi id), 通過(guò)VDI名求得的散列值,低三十二位使用如下: 對(duì)象類型 | 低32位的作用 | 數(shù)據(jù)類型 | 虛擬磁盤映射的索引號(hào) | Vdi對(duì)象 | 未使用(填0) | Vm狀態(tài)對(duì)象 | Vm狀態(tài)映射索引 | Vdi屬性對(duì)象 | 鍵名的散列值 | 對(duì)象格式(object format) 1) 數(shù)據(jù)對(duì)象 虛擬磁盤映射的塊 2) Vdi對(duì)象 1 struct sheepdog_inode { 2 char name[SD_MAX_VDI_LEN]; /* the name of this VDI*/ 3 char tag[SD_MAX_VDI_TAG_LEN]; /* the snapshot tag name */ 4 uint64_t ctime; /* creation time of this VDI */ 5 uint64_t snap_ctime; /* the time snapshot is taken */ 6 uint64_t vm_clock_nsec; /* vm clock (used for live snapshot) */ 7 uint64_t vdi_size; /* the size of VDI */ 8 uint64_t vm_state_size; /* the size of vm state (used for live snapshot) */ 9 uint16_t copy_policy; /* reserved */ 10 uint8_t nr_copies; /* the number of object redundancy */ 11 uint8_t block_size_shift; /* info about the size of the data object */ 12 uint32_t snap_id; /* the snapshot id */ 13 uint32_t vdi_id; /* the vdi id */ 14 uint32_t parent_vdi_id; /* the parent snapshot vdi id of this VDI */ 15 uint32_t child_vdi_id[MAX_CHILDREN]; /* the children VDIs of this VDI */ 16 uint32_t data_vdi_id[MAX_DATA_OBJS]; /* the data object IDs this VDI contains*/ 17 }; 3) Vm狀態(tài)對(duì)象 Vm狀態(tài)映射塊 4) Vdi屬性對(duì)象 前SD_MAX_VDI_ATTR_KEY_LEN位(256位)為屬性的鍵名,余下的是屬性指. 只讀/可寫對(duì)象(read-only/writable objects) 從如何訪問(wèn)對(duì)象的角度,我們還可以把Sheepdog對(duì)象分為以下兩類. 1) 只讀對(duì)象(例:VDI快照數(shù)據(jù)對(duì)象) 只允許一個(gè)VM對(duì)其讀寫,其他vm無(wú)法訪問(wèn) 2) 可寫對(duì)象 不允許任何VM對(duì)其寫,所有VM都可讀 其他功能(other features) Sheepdog對(duì)象存儲(chǔ)可接收正在寫時(shí)復(fù)制(copy-on-write)的請(qǐng)求.當(dāng)一個(gè)客戶端發(fā)送一個(gè)創(chuàng)建和寫的請(qǐng)求時(shí),同時(shí)可以指定基本對(duì)象(CoW操作的來(lái)源),這用于快照和克隆操作. 網(wǎng)關(guān)(Gateway) 對(duì)象存在哪(where to store objects) Sheepdog使用一致性哈希算法決定存放對(duì)象的位置,一致性哈希算法提供哈希表,而且增加或介紹節(jié)點(diǎn)不回顯著的改變對(duì)象映射,通過(guò)哈希表能使I/O負(fù)載均衡. 副本(replication) Sheepdog的數(shù)據(jù)副本很簡(jiǎn)單,我們假設(shè)只有一個(gè)寫,所以寫沖突不會(huì)發(fā)生,客戶端可以并行發(fā)生請(qǐng)求到目標(biāo)節(jié)點(diǎn),發(fā)生讀請(qǐng)求到一個(gè)目標(biāo)節(jié)點(diǎn)如果客戶端自己處理I/O請(qǐng)求順序. 寫I/O流(write I/O flow) Getway使用一致性哈希算法計(jì)算目標(biāo)節(jié)點(diǎn)并發(fā)送寫請(qǐng)求到所有目標(biāo)節(jié)點(diǎn),只有所有副本均更新成功寫請(qǐng)求才會(huì)成功,這是因?yàn)槿绻粋€(gè)副本未更新,getway有可能從未更新的節(jié)點(diǎn)讀取舊數(shù)據(jù). 讀I/O流(read I/O flow) Getway使用一致性哈希算法計(jì)算目標(biāo)節(jié)點(diǎn),并發(fā)送讀請(qǐng)求到一個(gè)目標(biāo)節(jié)點(diǎn). 1) 修復(fù)對(duì)象一致性 當(dāng)某節(jié)點(diǎn)在轉(zhuǎn)發(fā)I/O請(qǐng)求時(shí)crash,有可能破壞副本的一致性,所以當(dāng)getway第一次讀取對(duì)象時(shí)會(huì)試圖修復(fù)其一致性,從一節(jié)點(diǎn)讀取整個(gè)對(duì)象并用它覆蓋所有副本. 重試I/O請(qǐng)求(retrying I/O requests) Sheepdog存儲(chǔ)所有成員節(jié)點(diǎn)的歷史信息,我們把歷史版本號(hào)叫做”epoch”(詳見(jiàn)章節(jié)’對(duì)象恢復(fù)’). 如果getway轉(zhuǎn)發(fā)I/O請(qǐng)求至目標(biāo)節(jié)點(diǎn)并且getway與目標(biāo)節(jié)點(diǎn)epoch號(hào)不相符,I/O請(qǐng)求失敗且getway重試請(qǐng)求直到epcho號(hào)相符,這就需要保持副本強(qiáng)一致性. I/O重試也可能發(fā)生在目標(biāo)節(jié)點(diǎn)掛了導(dǎo)致無(wú)法完成I/O操作. 對(duì)象管理器(Object Manager) 對(duì)象管理器把對(duì)象存儲(chǔ)到本地磁盤,當(dāng)前把每個(gè)對(duì)象存儲(chǔ)為一個(gè)文件,這中方法簡(jiǎn)單.我們也可以使用DBMS(例: BerkeleyDB, Tokyo Cabinet等) 作為對(duì)象存儲(chǔ)器,但還不支持. 路徑命名規(guī)則(path name rule) 對(duì)象存儲(chǔ)成如下路徑: /store_dir/obj/[epoch number]/[object ID] 所有對(duì)象文件有一個(gè)擴(kuò)展屬性: 副本數(shù)(sheepdog.copies), 寫日志(write journaling) 當(dāng)sheep進(jìn)程在寫操作過(guò)程中失敗,對(duì)象有可能至少部分更新,一般情況這不會(huì)有問(wèn)題,因?yàn)槿绻?/span>VM未接收成功消息,不保證所寫部分的內(nèi)容.然而對(duì)于vdi對(duì)象,我們必須整體更新或整體未更新,因?yàn)槿绻?/span>vdi對(duì)象只是部分更新,VDI的元數(shù)據(jù)有可能被破壞. 為例防止這個(gè)問(wèn)題,我們使用日志記錄對(duì)vdi對(duì)象的寫操作. 日志過(guò)程很簡(jiǎn)單: 1) 創(chuàng)建日志文件"/store_dir/journal/[epoch]/[vdi object id]" 2) 首先寫數(shù)據(jù)到日志文件 3) 寫一個(gè)數(shù)據(jù)到vdi對(duì)象 4) 刪除日志文件 集群管理器(Cluster Manager) 大多情況, Sheepdo客戶端單獨(dú)訪問(wèn)它們的映射因?yàn)槲覀儾辉试S兩個(gè)客戶端同時(shí)訪問(wèn)一個(gè)映射,但是某些VDI操作(例:克隆VDI,創(chuàng)建VDI)必須做,因?yàn)檫@些操作更新全局信息,我們使用Corosync集群引擎完成而不是中心服務(wù)器. 我們將擴(kuò)展Sheepdog以支持其他集群管理系統(tǒng). 本章正在編輯 QEMU 塊驅(qū)動(dòng)(QEMU Block Driver)  Sheepdog卷被分為4M的數(shù)據(jù)對(duì)象,剛創(chuàng)建的對(duì)象未分配,也就是說(shuō),只有寫對(duì)象被分配. Open 首先QEMU塊驅(qū)動(dòng)通過(guò)getway的bdrv_open()從對(duì)象存儲(chǔ)讀取vdi 讀/寫(read/write) 塊驅(qū)動(dòng)通過(guò)請(qǐng)求的部分偏移量和大小計(jì)算數(shù)據(jù)對(duì)象id, 并向getway發(fā)送請(qǐng)求. 當(dāng)塊驅(qū)動(dòng)發(fā)送寫請(qǐng)求到那些不屬于其當(dāng)前vdi的數(shù)據(jù)對(duì)象是,塊驅(qū)動(dòng)發(fā)送CoW請(qǐng)求分配一個(gè)新的數(shù)據(jù)對(duì)象. 寫入快照vdi(write to snapshot vdi) 我們可以把快照VDI附加到QEMU, 當(dāng)塊驅(qū)動(dòng)第一次發(fā)送寫請(qǐng)求到快照VDI, 塊驅(qū)動(dòng)創(chuàng)建一個(gè)新的可寫VDI作為子快照,并發(fā)送請(qǐng)求到新的VDI. VDI操作(VDI Operations) 查找(lookup) 當(dāng)查找VDI對(duì)象時(shí): 1) 通過(guò)求vdi名的哈希值得到vdi id 2) 通過(guò)vdi id計(jì)算di對(duì)象 3) 發(fā)送讀請(qǐng)求到vdi對(duì)象 4) 如果此vdi不是請(qǐng)求的那個(gè),增加vdi id并重試發(fā)送讀請(qǐng)求 快照,克隆(snapshot, cloning) 快照可克隆操作很簡(jiǎn)單, 1) 讀目標(biāo)VDI 2) 創(chuàng)建一個(gè)與目標(biāo)一樣的新VDI 3) 把新vdi的‘'parent_vdi_id''設(shè)為目標(biāo)VDI的id 4) 設(shè)置目標(biāo)vdi的''child_vdi_id''為新vdi的id. 5) 設(shè)置目標(biāo)vdi的''snap_ctime''為當(dāng)前時(shí)間, 新vdi變?yōu)楫?dāng)前vdi對(duì)象 刪除(delete) TODO:當(dāng)前,回收未使用的數(shù)據(jù)對(duì)象是不會(huì)被執(zhí)行,直到所有相關(guān)VDI對(duì)象(相關(guān)的快照VDI和克隆VDI)被刪除. 所有相關(guān)VDI被刪除后, Sheepdog刪除所有此VDI的數(shù)據(jù)對(duì)象,設(shè)置此VDI對(duì)象名為空字符串. 對(duì)象恢復(fù)(Object Recovery) epoch Sheepdog把成員節(jié)點(diǎn)歷史存儲(chǔ)在存儲(chǔ)路徑, 路徑名如下: /store_dir/epoch/[epoch number] 每個(gè)文件包括節(jié)點(diǎn)在epoch的列表信息(IP地址,端口,虛擬節(jié)點(diǎn)個(gè)數(shù)). 恢復(fù)過(guò)程(recovery process) 1) 從所有節(jié)點(diǎn)接收存儲(chǔ)對(duì)象ID 2) 計(jì)算選擇那個(gè)對(duì)象 3) 創(chuàng)建對(duì)象ID list文件"/store_dir/obj/[the current epoch]/list" 4) 發(fā)送一個(gè)讀請(qǐng)求以獲取id存在于list文件的對(duì)象. 這個(gè)請(qǐng)求被發(fā)送到包含前一次epoch的對(duì)象的節(jié)點(diǎn).( The requests are sent to the node which had the object at the previous epoch.) 5) 把對(duì)象存到當(dāng)前epoch路徑. 沖突的I/O(conflicts I/Os) 如果QEMU發(fā)送I/O請(qǐng)求到某些未恢復(fù)的對(duì)象, Sheepdog阻塞此請(qǐng)求并優(yōu)先恢復(fù)對(duì)象. 協(xié)議(Protocol) Sheepdog的所有請(qǐng)求包含固定大小的頭部(48位)和固定大小的數(shù)據(jù)部分,頭部包括協(xié)議版本,操作碼,epoch號(hào),數(shù)據(jù)長(zhǎng)度等. between sheep and QEMU 操作碼 | 描述 | SD_OP_CREATE_AND_WRITE_OBJ | 發(fā)送請(qǐng)求以創(chuàng)建新對(duì)象并寫入數(shù)據(jù),如果對(duì)象存在,操作失敗 | SD_OP_READ_OBJ | 讀取對(duì)象中的數(shù)據(jù) | SD_OP_WRITE_OBJ | 向?qū)ο髮懭霐?shù)據(jù),如果對(duì)象不存在,失敗 | SD_OP_NEW_VDI | 發(fā)送vdi名到對(duì)象存儲(chǔ)并創(chuàng)建新vdi對(duì)象, 返回應(yīng)答vdi的唯一的vdi id | SD_OP_LOCK_VDI | 與SD_OP_GET_VDI_INFO相同 | SD_OP_RELEASE_VDI | 未使用 | SD_OP_GET_VDI_INFO | 獲取vdi信息(例:vdi id) | SD_OP_READ_VDIS | 獲取已經(jīng)使用的vdi id | between sheep and collie 操作碼 | 描述 | SD_OP_DEL_VDI | 刪除VDI | SD_OP_GET_NODE_LIST | 獲取sheepdog的節(jié)點(diǎn)列表 | SD_OP_GET_VM_LIST | 未使用 | SD_OP_MAKE_FS | 創(chuàng)建sheepdog集群 | SD_OP_SHUTDOWN | 停止sheepdog集群 | SD_OP_STAT_SHEEP | 獲取本地磁盤使用量 | SD_OP_STAT_CLUSTER | 獲取sheepdog集群信息 | SD_OP_KILL_NODE | 退出sheep守護(hù)進(jìn)程 | SD_OP_GET_VDI_ATTR | 獲取vdi屬性對(duì)象id | between sheeps 操作碼 | 描述 | SD_OP_REMOVE_OBJ | 刪除對(duì)象 | SD_OP_GET_OBJ_LIST | 獲取對(duì)象id列表,并存儲(chǔ)到目標(biāo)節(jié)點(diǎn) |
Ant是什么? Ant是一種基于 Java和XML的build工具. 1 編寫build.xml Ant的buildfile是用XML寫的.每個(gè)buildfile含有一個(gè)project. buildfile中每個(gè)task元素可以有一個(gè)id屬性,可以用這個(gè)id值引用指定的任務(wù).這個(gè)值  是唯一的.(詳情請(qǐng)參考下面的Task小節(jié)) 1.1 Projects project有下面的屬性: Attribute | Description | Required | name | 項(xiàng)目名稱. | No | default | 當(dāng)沒(méi)有指定target時(shí)使用的缺省target | Yes | basedir | 用于計(jì)算所有其他路徑的基路徑.該屬性可以被basedir property覆蓋.當(dāng)覆蓋時(shí),該屬性被忽略.如果屬性和basedir property都沒(méi)有設(shè)定,就使用buildfile文件的父目錄. | No | 項(xiàng)目的描述以一個(gè)頂級(jí)的<description>元素的形式出現(xiàn)(參看description小節(jié)).
一個(gè)項(xiàng)目可以定義一個(gè)或多個(gè)target.一個(gè)target是一系列你想要執(zhí)行的.執(zhí)行Ant時(shí),你可以選擇執(zhí)行那個(gè)target.當(dāng)沒(méi)有給定target時(shí),使用project的default屬性所確定的target.
1.2 Targets
一個(gè)target可以依賴于其他的target.例如,你可能會(huì)有一個(gè)target用于編譯程序,一個(gè)target用于生成可執(zhí)行文件.你在生成可執(zhí)行文件之前 先編譯通過(guò), 生成可執(zhí)行文件的target依賴于編譯target.Ant會(huì)處理這種依賴關(guān)系.
然而,應(yīng)當(dāng)注意到,Ant的depends屬性只指定了target應(yīng)該被執(zhí)行的順序-如果被依賴的target無(wú)法運(yùn)行,這種depends對(duì)于指定了依賴關(guān)系的target就沒(méi)有影響.
Ant會(huì)依照depends屬性中target出現(xiàn)的順序(從左到右)依次執(zhí)行每個(gè)target.然而,要記住的是只要某個(gè)target依賴于一個(gè)target,后者就會(huì)被先執(zhí)行. <target name="A"/> <target name="B" depends="A"/> <target name="C" depends="B"/> <target name="D" depends="C,B,A"/> 假定我們要執(zhí)行target D.從它的依賴屬性來(lái)看,你可能認(rèn)為先執(zhí)行C,然后B, A被執(zhí)行.錯(cuò)了,C依賴于B,B依賴于A, 先執(zhí)行A,然后B,然后C, D被執(zhí)行.
一個(gè)target只能被執(zhí)行一次,即時(shí)有多個(gè)target依賴于它(看上面的例子).
如 果(或如果不)某些屬性被設(shè)定,才執(zhí)行某個(gè)target.這樣,允許根據(jù)系統(tǒng)的狀態(tài)(java version, OS, 命令行屬性定義等等)來(lái)更好地控制build的過(guò)程.要想讓一個(gè)target這樣做,你就應(yīng)該在target元素中,加入if(或unless)屬性,帶 上target因該有所判斷的屬性.例如: <target name="build-module-A" if="module-A-present"/> <target name="build-own-fake-module-A" unless="module-A-present"/> 如果沒(méi)有if或unless屬性,target總會(huì)被執(zhí)行.
可選的description屬性可用來(lái)提供關(guān)于target的一行描述,這些描述可由-projecthelp命令行選項(xiàng)輸出. 將你的tstamp task在一個(gè)所謂的初始化target是很好的做法,其他的target依賴這個(gè)初始化target.要確保初始化target是出現(xiàn)在其他target依賴表中的第一個(gè)target.在本手冊(cè)中大多數(shù)的初始化target的名字是"init". target有下面的屬性: Attribute | Description | Required | name | target的名字 | Yes | depends | 用逗號(hào)分隔的target的名字列表,也就是依賴表. | No | if | 執(zhí)行target所需要設(shè)定的屬性名. | No | unless | 執(zhí)行target需要清除設(shè)定的屬性名. | No | description | 關(guān)于target功能的簡(jiǎn)短描述. | No | 1.3 Tasks
一個(gè)task是一段可執(zhí)行的代碼.
一個(gè)task可以有多個(gè)屬性(如果你愿意的話,可以將其稱之為變量).屬性只可能包含對(duì)property的引用.這些引用會(huì)在task執(zhí)行前被解析.
下面是Task的一般構(gòu)造形式: <name attribute1="value1" attribute2="value2" ... /> 這里name是task的名字,attributeN是屬性名,valueN是屬性值.
有一套內(nèi)置的(built-in)task,以及一些可選task,但你也可以編寫自己的task.
所有的task都有一個(gè)task名字屬性.Ant用屬性值來(lái)產(chǎn)生日志信息.
可以給task賦一個(gè)id屬性: <taskname id="taskID" ... /> 這里taskname是task的名字,而taskID是這個(gè)task的唯一標(biāo)識(shí)符.通過(guò)這個(gè)標(biāo)識(shí)符,你可以在腳本中引用相應(yīng)的task.例如,在腳本中你可以這樣: <script ... > task1.setFoo("bar"); </script> 設(shè)定某個(gè)task實(shí)例的foo屬性.在另一個(gè)task中(用java編寫),你可以利用下面的語(yǔ)句存取相應(yīng)的實(shí)例. project.getReference("task1"). 注意1:如果task1還沒(méi)有運(yùn)行,就不會(huì)被生效(例如:不設(shè)定屬性),如果你在隨后配置它,你所作的一切都會(huì)被覆蓋.
注意2:未來(lái)的Ant版本可能不會(huì)兼容這里所提的屬性, 很有可能根本沒(méi)有task實(shí)例,只有proxies.
1.4 Properties
一個(gè)project可以有很多的properties.可以在buildfile中用 property task來(lái)設(shè)定,或在Ant之外設(shè)定.一個(gè)property有一個(gè)名字和一個(gè)值.property可用于task的屬性值.這是通過(guò)將屬性名放在"${" 和"}"之間并放在屬性值的位置來(lái)實(shí)現(xiàn)的.例如如果有一個(gè)property builddir的值是"build",這個(gè)property就可用于屬性值:${builddir}/classes.這個(gè)值就可被解析為build /classes. 內(nèi)置屬性 如果你使用了<property> task 定義了所有的系統(tǒng)屬性,Ant允許你使用這些屬性.例如,${os.name}對(duì)應(yīng)操作系統(tǒng)的名字. 要想得到系統(tǒng)屬性的列表可參考the Javadoc of System.getProperties. 除了Java的系統(tǒng)屬性,Ant還定義了一些自己的內(nèi)置屬性: basedir project基目錄的絕對(duì)路徑 (與<project>的basedir屬性一樣). ant.file buildfile的絕對(duì)路徑. ant.version Ant的版本. ant.project.name 當(dāng)前執(zhí)行的project的名字;由<project>的name屬性設(shè)定. ant.java.version Ant檢測(cè)到的JVM的版本; 目前的值有"1.1", "1.2", "1.3" and "1.4". 例子 <project name="MyProject" default="dist" basedir="."> <!-- set global properties for this build --> <property name="src" value="."/> <property name="build" value="build"/> <property name="dist" value="dist"/> <target name="init"> <!-- Create the time stamp --> <tstamp/> <!-- Create the build directory structure used by compile --> <mkdir dir="${build}"/> </target> <target name="compile" depends="init"> <!-- Compile the java code from ${src} into ${build} --> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile"> <!-- Create the distribution directory --> <mkdir dir="${dist}/lib"/> <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file --> <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/> </target> <target name="clean"> <!-- Delete the ${build} and ${dist} directory trees --> <delete dir="${build}"/> <delete dir="${dist}"/> </target> </project> 1.5 Path-like Structures 你可以用":"和";"作為分隔符,指定類似PATH和CLASSPATH的引用.Ant會(huì)把分隔符轉(zhuǎn)換為當(dāng)前系統(tǒng)所用的分隔符. 當(dāng)需要指定類似路徑的值時(shí),可以使用嵌套元素.一般的形式是 <classpath> <pathelement path="${classpath}"/> <pathelement location="lib/helper.jar"/> </classpath> location屬性指定了相對(duì)于project基目錄的一個(gè)文件和目錄,而path屬性接受逗號(hào)或分號(hào)分隔的一個(gè)位置列表.path屬性一般用作預(yù)定義的路徑--其他情況下,應(yīng)該用多個(gè)location屬性. 為簡(jiǎn)潔起見(jiàn),classpath標(biāo)簽支持自己的path和location屬性.  : <classpath> <pathelement path="${classpath}"/> </classpath> 可以被簡(jiǎn)寫作: <classpath path="${classpath}"/> 也可通過(guò)<fileset>元素指定路徑.構(gòu)成一個(gè)fileset的多個(gè)文件加入path-like structure的順序是未定的. <classpath> <pathelement path="${classpath}"/> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> <pathelement location="classes"/> </classpath> 上面的例子構(gòu)造了一個(gè)路徑值包括:${classpath}的路徑,跟著lib目錄下的所有jar文件,接著是classes目錄. 如果你想在多個(gè)task中使用相同的path-like structure,你可以用<path>元素定義他們(與target同級(jí)),然后通過(guò)id屬性引用--參考Referencs例子.
path-like structure可能包括對(duì)另一個(gè)path-like structurede的引用(通過(guò)嵌套<path>元素): <path id="base.path"> <pathelement path="${classpath}"/> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> <pathelement location="classes"/> </path> <path id="tests.path"> <path refid="base.path"/> <pathelement location="testclasses"/> </path> 前面所提的關(guān)于<classpath>的簡(jiǎn)潔寫法對(duì)于<path>也是有效的,如: <path id="tests.path"> <path refid="base.path"/> <pathelement location="testclasses"/> </path> 可寫成: <path id="base.path" path="${classpath}"/> 命令行變量
有些task可接受參數(shù),并將其傳遞給另一個(gè)進(jìn)程.為了能在變量中包含空格字符,可使用嵌套的arg元素. Attribute Description Required value 一個(gè)命令行變量;可包含空格字符. 只能用一個(gè) line 空格分隔的命令行變量列表. file 作為命令行變量的文件名;會(huì)被文件的絕對(duì)名替代. path 一個(gè)作為單個(gè)命令行變量的path-like的字符串;或作為分隔符,Ant會(huì)將其轉(zhuǎn)變?yōu)樘囟ㄆ脚_(tái)的分隔符.
例子 <arg value="-l -a"/> 是一個(gè)含有空格的單個(gè)的命令行變量. <arg line="-l -a"/> 是兩個(gè)空格分隔的命令行變量. <arg path="/dir;/dir2:dir3"/> 是一個(gè)命令行變量,其值在DOS系統(tǒng)上為dir;dir2;dir3;在Unix系統(tǒng)上為/dir:/dir2:/dir3 .
References
buildfile元素的id屬性可用來(lái)引用這些元素.如果你需要一遍遍的復(fù)制相同的XML代碼塊,這一屬性就很有用--如多次使用<classpath>結(jié)構(gòu).
下面的例子: <project ... > <target ... > <rmic ...> <classpath> <pathelement location="lib/"/> <pathelement path="${java.class.path}/"/> <pathelement path="${additional.path}"/> </classpath> </rmic> </target> <target ... > <javac ...> <classpath> <pathelement location="lib/"/> <pathelement path="${java.class.path}/"/> <pathelement path="${additional.path}"/> </classpath> </javac> </target> </project> 可以寫成如下形式: <project ... > <path id="project.class.path"> <pathelement location="lib/"/> <pathelement path="${java.class.path}/"/> <pathelement path="${additional.path}"/> </path> <target ... > <rmic ...> <classpath refid="project.class.path"/> </rmic> </target> <target ... > <javac ...> <classpath refid="project.class.path"/> </javac> </target> </project> 所有使用PatternSets, FileSets 或 path-like structures嵌套元素的task也接受這種類型的引用. 轉(zhuǎn)自: http://www.linux521.com/2009/java/200904/1760.html
最近看了hadoop進(jìn)度顯示部分代碼,做了個(gè)ppt算是一個(gè)總結(jié)吧. /Files/shenh062326/hadoop進(jìn)度計(jì)算.ppt
|