<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 28, comments - 37, trackbacks - 0, articles - 0

    周末無事,故翻譯sheepdog design.

    原文地址: https://github.com/collie/sheepdog/wiki/Sheepdog-Design

    Sheepdog 設(shè)計

    Sheeepdog采用完全對稱的結(jié)構(gòu),沒有類似元數(shù)據(jù)服務(wù)的中心節(jié)點. 這種設(shè)計有以下的特點.

    1)       性能于容量的線性的可擴展性.

    當(dāng)需要提升性能或容量時,只需向集群中增加新的機器便能使Sheeepdog線性成長.

    2)       沒有單點故障

    即使某臺機器發(fā)生故障,依然可以通過其他機器訪問數(shù)據(jù).

    3)       容易管理

    不需要配置機器角色,當(dāng)管理員在新增的機器開啟Sheepdog守護進(jìn)程時, Sheepdog會自動檢測新加入的機器并配置它成為存儲系統(tǒng)中的一員.

    結(jié)構(gòu)概述



    Sheepdog是一個分布式存儲系統(tǒng).Sheepdog客戶端(QEMU的塊驅(qū)動程序)提供對象存儲(類似于簡單的鍵值對). 接下來幾章將更加詳細(xì)的闡述Sheepdog各個部分.

    1)       對象存儲(Object對象存儲(Object Storage)

    2)       )

    Sheepdog不同于一般的文件系統(tǒng), Sheepdog進(jìn)程為QEMU(Sheepdog進(jìn)程名)創(chuàng)建一個分布式對象存儲系統(tǒng),它可以存儲對象”.這里的對象數(shù)據(jù)大小可變,并有唯一的標(biāo)識,通過標(biāo)識可以進(jìn)行讀//創(chuàng)建/刪除操作.對象存儲組成網(wǎng)關(guān)對象管理器”.

    3)       網(wǎng)關(guān)(getway)

    Getway接收QEMU塊驅(qū)動的I/O請求(對象id,偏移,長度和操作類型),通過一直散列算法獲得目標(biāo)節(jié)點,然后轉(zhuǎn)發(fā)I/O請求至該節(jié)點.

    4)       對象管理器(Object manager)

    對象管理器接收getway轉(zhuǎn)發(fā)過來的I/O請求,然后對磁盤執(zhí)行讀/寫操作.

    5)       集群管理器(Cluster manager)

    集群管理器管理管理節(jié)點成員(探測失敗/新增節(jié)點并報告節(jié)點成員的變化),以及一些需要節(jié)點一致的操作(vdi 創(chuàng)建, 快照 vdi).當(dāng)前集群管理器使用corosync集群引擎.

    6)       QEMU 塊驅(qū)動

    QEMU塊驅(qū)動把VM image分為固定大小(默認(rèn)4M),并通過其getway存儲到對象存儲中

    對象存儲(Object Storage)

    每個對象使用一個64bit的整數(shù)作為全局標(biāo)識,并在多臺機器存有備份,QEMU塊驅(qū)動并不關(guān)心存儲的位置,對象存儲系統(tǒng)負(fù)責(zé)管理存儲的位置.

    對象類型(object types)

    Sheepdog的對象分為以下四種:

    1)       數(shù)據(jù)類型(data object)

    它包括虛擬磁盤映射的真實數(shù)據(jù),虛擬磁盤映射分為固定大小的數(shù)據(jù)對象, Sheepdog客戶端訪問這個對象.

    2)       vdi object

    它包括虛擬磁盤映射的元數(shù)據(jù)(:映射名,磁盤大小,創(chuàng)建時間,vdi的數(shù)據(jù)對象ID).

    3)       vmstate object

    它存儲運行中的VM狀態(tài)映射.管理員通過它獲取實時快照信息.

    4)       vdi attr object

    使用它存儲各個vdi的屬性,屬性為鍵值對類型,類似于普通文件的擴展信息.

    對象ID規(guī)則(object ID rules)

    1) 0 - 31 (32 bits): 對象類型詳細(xì)信息

    2) 32 - 55 (24 bits): vdi id

    3) 56 - 59 ( 4 bits): 預(yù)留

    4) 60 - 63 ( 4 bits): 對象類型標(biāo)識符

    每個VDI有一個全局唯一的ID(vdi id), 通過VDI名求得的散列值,低三十二位使用如下:

    對象類型

    32位的作用

    數(shù)據(jù)類型

    虛擬磁盤映射的索引號

    Vdi對象

    未使用(0)

    Vm狀態(tài)對象

    Vm狀態(tài)映射索引

    Vdi屬性對象

    鍵名的散列值

     

    對象格式(object format)

    1)       數(shù)據(jù)對象

    虛擬磁盤映射的塊

    2)       Vdi對象

     

     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)對象

    Vm狀態(tài)映射塊

    4)       Vdi屬性對象

    SD_MAX_VDI_ATTR_KEY_LEN(256)為屬性的鍵名,余下的是屬性指.

    只讀/可寫對象(read-only/writable objects)

    從如何訪問對象的角度,我們還可以把Sheepdog對象分為以下兩類.

    1)       只讀對象(:VDI快照數(shù)據(jù)對象)

    只允許一個VM對其讀寫,其他vm無法訪問

    2)       可寫對象

    不允許任何VM對其寫,所有VM都可讀

    其他功能(other features)

    Sheepdog對象存儲可接收正在寫時復(fù)制(copy-on-write)的請求.當(dāng)一個客戶端發(fā)送一個創(chuàng)建和寫的請求時,同時可以指定基本對象(CoW操作的來源),這用于快照和克隆操作.

    網(wǎng)關(guān)(Gateway)

    對象存在哪(where to store objects)

    Sheepdog使用一致性哈希算法決定存放對象的位置,一致性哈希算法提供哈希表,而且增加或介紹節(jié)點不回顯著的改變對象映射,通過哈希表能使I/O負(fù)載均衡.

    副本(replication)

    Sheepdog的數(shù)據(jù)副本很簡單,我們假設(shè)只有一個寫,所以寫沖突不會發(fā)生,客戶端可以并行發(fā)生請求到目標(biāo)節(jié)點,發(fā)生讀請求到一個目標(biāo)節(jié)點如果客戶端自己處理I/O請求順序.

    I/O(write I/O flow)

    Getway使用一致性哈希算法計算目標(biāo)節(jié)點并發(fā)送寫請求到所有目標(biāo)節(jié)點,只有所有副本均更新成功寫請求才會成功,這是因為如果一個副本未更新,getway有可能從未更新的節(jié)點讀取舊數(shù)據(jù).

    I/O(read I/O flow)

    Getway使用一致性哈希算法計算目標(biāo)節(jié)點,并發(fā)送讀請求到一個目標(biāo)節(jié)點.

    1)       修復(fù)對象一致性

    當(dāng)某節(jié)點在轉(zhuǎn)發(fā)I/O請求時crash,有可能破壞副本的一致性,所以當(dāng)getway第一次讀取對象時會試圖修復(fù)其一致性,從一節(jié)點讀取整個對象并用它覆蓋所有副本.

    重試I/O請求(retrying I/O requests)

    Sheepdog存儲所有成員節(jié)點的歷史信息,我們把歷史版本號叫做”epoch”(詳見章節(jié)對象恢復(fù)’). 如果getway轉(zhuǎn)發(fā)I/O請求至目標(biāo)節(jié)點并且getway與目標(biāo)節(jié)點epoch號不相符,I/O請求失敗且getway重試請求直到epcho號相符,這就需要保持副本強一致性.

    I/O重試也可能發(fā)生在目標(biāo)節(jié)點掛了導(dǎo)致無法完成I/O操作.

    對象管理器(Object Manager)

    對象管理器把對象存儲到本地磁盤,當(dāng)前把每個對象存儲為一個文件,這中方法簡單.我們也可以使用DBMS(: BerkeleyDB, Tokyo Cabinet) 作為對象存儲器,但還不支持.

    路徑命名規(guī)則(path name rule)

    對象存儲成如下路徑:

            /store_dir/obj/[epoch number]/[object ID]

    所有對象文件有一個擴展屬性: 副本數(shù)(sheepdog.copies),

    寫日志(write journaling)

    當(dāng)sheep進(jìn)程在寫操作過程中失敗,對象有可能至少部分更新,一般情況這不會有問題,因為如果VM未接收成功消息,不保證所寫部分的內(nèi)容.然而對于vdi對象,我們必須整體更新或整體未更新,因為如果vdi對象只是部分更新,VDI的元數(shù)據(jù)有可能被破壞. 為例防止這個問題,我們使用日志記錄對vdi對象的寫操作. 日志過程很簡單:

    1)       創(chuàng)建日志文件"/store_dir/journal/[epoch]/[vdi object id]"

    2)       首先寫數(shù)據(jù)到日志文件

    3)       寫一個數(shù)據(jù)到vdi對象

    4)       刪除日志文件

    集群管理器(Cluster Manager)

    大多情況, Sheepdo客戶端單獨訪問它們的映射因為我們不允許兩個客戶端同時訪問一個映射,但是某些VDI操作(:克隆VDI,創(chuàng)建VDI)必須做,因為這些操作更新全局信息,我們使用Corosync集群引擎完成而不是中心服務(wù)器.

    我們將擴展Sheepdog以支持其他集群管理系統(tǒng).

    本章正在編輯

    QEMU 塊驅(qū)動(QEMU Block Driver)

    Sheepdog卷被分為4M的數(shù)據(jù)對象,剛創(chuàng)建的對象未分配,也就是說,只有寫對象被分配.

    Open

    首先QEMU塊驅(qū)動通過getwaybdrv_open()從對象存儲讀取vdi

    /(read/write)

    塊驅(qū)動通過請求的部分偏移量和大小計算數(shù)據(jù)對象id, 并向getway發(fā)送請求. 當(dāng)塊驅(qū)動發(fā)送寫請求到那些不屬于其當(dāng)前vdi的數(shù)據(jù)對象是,塊驅(qū)動發(fā)送CoW請求分配一個新的數(shù)據(jù)對象.

    寫入快照vdi(write to snapshot vdi)

    我們可以把快照VDI附加到QEMU, 當(dāng)塊驅(qū)動第一次發(fā)送寫請求到快照VDI, 塊驅(qū)動創(chuàng)建一個新的可寫VDI作為子快照,并發(fā)送請求到新的VDI.

    VDI操作(VDI Operations)

    查找(lookup)

    當(dāng)查找VDI對象時:

    1)       通過求vdi名的哈希值得到vdi id

    2)       通過vdi id計算di對象

    3)       發(fā)送讀請求到vdi對象

    4)       如果此vdi不是請求的那個,增加vdi id并重試發(fā)送讀請求

    快照,克隆(snapshot, cloning)

    快照可克隆操作很簡單,

    1)       讀目標(biāo)VDI

    2)       創(chuàng)建一個與目標(biāo)一樣的新VDI

    3)       把新vdi‘'parent_vdi_id''設(shè)為目標(biāo)VDIid

    4)       設(shè)置目標(biāo)vdi''child_vdi_id''為新vdiid.

    5)       設(shè)置目標(biāo)vdi''snap_ctime''為當(dāng)前時間, vdi變?yōu)楫?dāng)前vdi對象

    刪除(delete)

    TODO:當(dāng)前,回收未使用的數(shù)據(jù)對象是不會被執(zhí)行,直到所有相關(guān)VDI對象(相關(guān)的快照VDI和克隆VDI)被刪除.

    所有相關(guān)VDI被刪除后, Sheepdog刪除所有此VDI的數(shù)據(jù)對象,設(shè)置此VDI對象名為空字符串.

    對象恢復(fù)(Object Recovery)

    epoch

    Sheepdog把成員節(jié)點歷史存儲在存儲路徑, 路徑名如下:

            /store_dir/epoch/[epoch number]

    每個文件包括節(jié)點在epoch的列表信息(IP地址,端口,虛擬節(jié)點個數(shù)).

    恢復(fù)過程(recovery process)

    1)       從所有節(jié)點接收存儲對象ID

    2)       計算選擇那個對象

    3)       創(chuàng)建對象ID list文件"/store_dir/obj/[the current epoch]/list"

    4)       發(fā)送一個讀請求以獲取id存在于list文件的對象. 這個請求被發(fā)送到包含前一次epoch的對象的節(jié)點.( The requests are sent to the node which had the object at the previous epoch.)

    5)       把對象存到當(dāng)前epoch路徑.

    沖突的I/O(conflicts I/Os)

    如果QEMU發(fā)送I/O請求到某些未恢復(fù)的對象, Sheepdog阻塞此請求并優(yōu)先恢復(fù)對象.

    協(xié)議(Protocol)

    Sheepdog的所有請求包含固定大小的頭部(48)和固定大小的數(shù)據(jù)部分,頭部包括協(xié)議版本,操作碼,epoch,數(shù)據(jù)長度等.

    between sheep and QEMU

    操作碼

    描述

    SD_OP_CREATE_AND_WRITE_OBJ

    發(fā)送請求以創(chuàng)建新對象并寫入數(shù)據(jù),如果對象存在,操作失敗

    SD_OP_READ_OBJ

    讀取對象中的數(shù)據(jù)

    SD_OP_WRITE_OBJ

    向?qū)ο髮懭霐?shù)據(jù),如果對象不存在,失敗

    SD_OP_NEW_VDI

    發(fā)送vdi名到對象存儲并創(chuàng)建新vdi對象, 返回應(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é)點列表

    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守護進(jìn)程

    SD_OP_GET_VDI_ATTR

    獲取vdi屬性對象id

    between sheeps

    操作碼

    描述

    SD_OP_REMOVE_OBJ

    刪除對象

    SD_OP_GET_OBJ_LIST

    獲取對象id列表,并存儲到目標(biāo)節(jié)點

     

    posted @ 2011-08-28 17:02 俞靈 閱讀(3284) | 評論 (0)編輯 收藏

    Ant是什么?
    Ant是一種基于Java和XML的build工具.
    1 編寫build.xml

    Ant的buildfile是用XML寫的.每個buildfile含有一個project.

    buildfile中每個task元素可以有一個id屬性,可以用這個id值引用指定的任務(wù).這個值是唯一的.(詳情請參考下面的Task小節(jié))

    1.1 Projects

    project有下面的屬性:
    Attribute Description Required
    name 項目名稱. No
    default 當(dāng)沒有指定target時使用的缺省target Yes
    basedir 用于計算所有其他路徑的基路徑.該屬性可以被basedir property覆蓋.當(dāng)覆蓋時,該屬性被忽略.如果屬性和basedir property都沒有設(shè)定,就使用buildfile文件的父目錄. No


    項目的描述以一個頂級的<description>元素的形式出現(xiàn)(參看description小節(jié)).

    一個項目可以定義一個或多個target.一個target是一系列你想要執(zhí)行的.執(zhí)行Ant時,你可以選擇執(zhí)行那個target.當(dāng)沒有給定target時,使用project的default屬性所確定的target.

    1.2 Targets

    一個target可以依賴于其他的target.例如,你可能會有一個target用于編譯程序,一個target用于生成可執(zhí)行文件.你在生成可執(zhí)行文件之前先編譯通過,生成可執(zhí)行文件的target依賴于編譯target.Ant會處理這種依賴關(guān)系.

    然而,應(yīng)當(dāng)注意到,Ant的depends屬性只指定了target應(yīng)該被執(zhí)行的順序-如果被依賴的target無法運行,這種depends對于指定了依賴關(guān)系的target就沒有影響.

    Ant會依照depends屬性中target出現(xiàn)的順序(從左到右)依次執(zhí)行每個target.然而,要記住的是只要某個target依賴于一個target,后者就會被先執(zhí)行.
    <target name="A"/>
    <target name="B" depends="A"/>
    <target name="C" depends="B"/>
    <target name="D" depends="C,B,A"/>
    假定我們要執(zhí)行target D.從它的依賴屬性來看,你可能認(rèn)為先執(zhí)行C,然后B,A被執(zhí)行.錯了,C依賴于B,B依賴于A,先執(zhí)行A,然后B,然后C,D被執(zhí)行.

    一個target只能被執(zhí)行一次,即時有多個target依賴于它(看上面的例子).

    如 果(或如果不)某些屬性被設(shè)定,才執(zhí)行某個target.這樣,允許根據(jù)系統(tǒng)的狀態(tài)(java version, OS, 命令行屬性定義等等)來更好地控制build的過程.要想讓一個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"/>
    如果沒有if或unless屬性,target總會被執(zhí)行.

    可選的description屬性可用來提供關(guān)于target的一行描述,這些描述可由-projecthelp命令行選項輸出.

    將你的tstamp task在一個所謂的初始化target是很好的做法,其他的target依賴這個初始化target.要確保初始化target是出現(xiàn)在其他target依賴表中的第一個target.在本手冊中大多數(shù)的初始化target的名字是"init".

    target有下面的屬性:
    Attribute Description Required
    name target的名字 Yes
    depends 用逗號分隔的target的名字列表,也就是依賴表. No
    if 執(zhí)行target所需要設(shè)定的屬性名. No
    unless 執(zhí)行target需要清除設(shè)定的屬性名. No
    description 關(guān)于target功能的簡短描述. No


    1.3 Tasks

    一個task是一段可執(zhí)行的代碼.

    一個task可以有多個屬性(如果你愿意的話,可以將其稱之為變量).屬性只可能包含對property的引用.這些引用會在task執(zhí)行前被解析.

    下面是Task的一般構(gòu)造形式:
    <name attribute1="value1" attribute2="value2" ... />
    這里name是task的名字,attributeN是屬性名,valueN是屬性值.

    有一套內(nèi)置的(built-in)task,以及一些可選task,但你也可以編寫自己的task.

    所有的task都有一個task名字屬性.Ant用屬性值來產(chǎn)生日志信息.

    可以給task賦一個id屬性:
    <taskname id="taskID" ... />
    這里taskname是task的名字,而taskID是這個task的唯一標(biāo)識符.通過這個標(biāo)識符,你可以在腳本中引用相應(yīng)的task.例如,在腳本中你可以這樣:
    <script ... >
    task1.setFoo("bar");
    </script>
    設(shè)定某個task實例的foo屬性.在另一個task中(用java編寫),你可以利用下面的語句存取相應(yīng)的實例.
    project.getReference("task1").
    注意1:如果task1還沒有運行,就不會被生效(例如:不設(shè)定屬性),如果你在隨后配置它,你所作的一切都會被覆蓋.

    注意2:未來的Ant版本可能不會兼容這里所提的屬性,很有可能根本沒有task實例,只有proxies.

    1.4 Properties

    一個project可以有很多的properties.可以在buildfile中用 property task來設(shè)定,或在Ant之外設(shè)定.一個property有一個名字和一個值.property可用于task的屬性值.這是通過將屬性名放在"${" 和"}"之間并放在屬性值的位置來實現(xiàn)的.例如如果有一個property builddir的值是"build",這個property就可用于屬性值:${builddir}/classes.這個值就可被解析為build /classes.

    內(nèi)置屬性

    如果你使用了<property> task 定義了所有的系統(tǒng)屬性,Ant允許你使用這些屬性.例如,${os.name}對應(yīng)操作系統(tǒng)的名字.

    要想得到系統(tǒng)屬性的列表可參考the Javadoc of System.getProperties.

    除了Java的系統(tǒng)屬性,Ant還定義了一些自己的內(nèi)置屬性:
    basedir project基目錄的絕對路徑 (與<project>的basedir屬性一樣).
    ant.file buildfile的絕對路徑.
    ant.version Ant的版本.
    ant.project.name 當(dāng)前執(zhí)行的project的名字;由<project>的name屬性設(shè)定.
    ant.java.version Ant檢測到的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會把分隔符轉(zhuǎn)換為當(dāng)前系統(tǒng)所用的分隔符.

    當(dāng)需要指定類似路徑的值時,可以使用嵌套元素.一般的形式是
    <classpath>
    <pathelement path="${classpath}"/>
    <pathelement location="lib/helper.jar"/>
    </classpath>
    location屬性指定了相對于project基目錄的一個文件和目錄,而path屬性接受逗號或分號分隔的一個位置列表.path屬性一般用作預(yù)定義的路徑--其他情況下,應(yīng)該用多個location屬性.

    為簡潔起見,classpath標(biāo)簽支持自己的path和location屬性.
    <classpath>
    <pathelement path="${classpath}"/>
    </classpath>
    可以被簡寫作:
    <classpath path="${classpath}"/>
    也可通過<fileset>元素指定路徑.構(gòu)成一個fileset的多個文件加入path-like structure的順序是未定的.
    <classpath>
    <pathelement path="${classpath}"/>
    <fileset dir="lib">
    <include name="**/*.jar"/>
    </fileset>
    <pathelement location="classes"/>
    </classpath>
    上面的例子構(gòu)造了一個路徑值包括:${classpath}的路徑,跟著lib目錄下的所有jar文件,接著是classes目錄.

    如果你想在多個task中使用相同的path-like structure,你可以用<path>元素定義他們(與target同級),然后通過id屬性引用--參考Referencs例子.

    path-like structure可能包括對另一個path-like structurede的引用(通過嵌套<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>的簡潔寫法對于<path>也是有效的,如:
    <path id="tests.path">
    <path refid="base.path"/>
    <pathelement location="testclasses"/>
    </path>
    可寫成:
    <path id="base.path" path="${classpath}"/>
    命令行變量

    有些task可接受參數(shù),并將其傳遞給另一個進(jìn)程.為了能在變量中包含空格字符,可使用嵌套的arg元素.
    Attribute Description Required
    value 一個命令行變量;可包含空格字符. 只能用一個
    line 空格分隔的命令行變量列表.
    file 作為命令行變量的文件名;會被文件的絕對名替代.
    path 一個作為單個命令行變量的path-like的字符串;或作為分隔符,Ant會將其轉(zhuǎn)變?yōu)樘囟ㄆ脚_的分隔符.

    例子
    <arg value="-l -a"/>
    是一個含有空格的單個的命令行變量.
    <arg line="-l -a"/>
    是兩個空格分隔的命令行變量.
    <arg path="/dir;/dir2:dir3"/>
    是一個命令行變量,其值在DOS系統(tǒng)上為dir;dir2;dir3;在Unix系統(tǒng)上為/dir:/dir2:/dir3 .

    References

    buildfile元素的id屬性可用來引用這些元素.如果你需要一遍遍的復(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

    posted @ 2011-08-07 11:46 俞靈 閱讀(1146) | 評論 (0)編輯 收藏

    最近看了hadoop進(jìn)度顯示部分代碼,做了個ppt算是一個總結(jié)吧.
    /Files/shenh062326/hadoop進(jìn)度計算.ppt

    posted @ 2011-07-03 09:44 俞靈 閱讀(323) | 評論 (0)編輯 收藏

    本文轉(zhuǎn)自 http://coolshell.cn/articles/3463.html

    對于SQL的Join,在學(xué)習(xí)起來可能是比較亂的。我們知道,SQL的Join語法有很多inner的,有outer的,有l(wèi)eft的,有時候,對于Select出來的結(jié)果集是什么樣子有點不是很清楚。Coding Horror上有一篇文章(實在不清楚為什么Coding Horror也被墻)通過 文氏圖 Venn diagrams 解釋了SQL的Join。我覺得清楚易懂,轉(zhuǎn)過來。

    假設(shè)我們有兩張表。

    • Table A 是左邊的表。
    • Table B 是右邊的表。

    其各有四條記錄,其中有兩條記錄是相同的,如下所示:

    id name       id  name
    -- ----       --  ----
    1  Pirate     1   Rutabaga
    2  Monkey     2   Pirate
    3  Ninja      3   Darth Vader
    4  Spaghetti  4   Ninja

    下面讓我們來看看不同的Join會產(chǎn)生什么樣的結(jié)果。

    SELECT * FROM TableA
    INNER JOIN TableB
    ON TableA.name = TableB.name
    
    id  name       id   name
    --  ----       --   ----
    1   Pirate     2    Pirate
    3   Ninja      4    Ninja

    Inner join
    產(chǎn)生的結(jié)果集中,是A和B的交集。

    Venn diagram of SQL inner join
    SELECT * FROM TableA
    FULL OUTER JOIN TableB
    ON TableA.name = TableB.name
    
    id    name       id    name
    --    ----       --    ----
    1     Pirate     2     Pirate
    2     Monkey     null  null
    3     Ninja      4     Ninja
    4     Spaghetti  null  null
    null  null       1     Rutabaga
    null  null       3     Darth Vader

    Full outer join 產(chǎn)生A和B的并集。但是需要注意的是,對于沒有匹配的記錄,則會以null做為值。

    Venn diagram of SQL cartesian join
    SELECT * FROM TableA
    LEFT OUTER JOIN TableB
    ON TableA.name = TableB.name
    
    id  name       id    name
    --  ----       --    ----
    1   Pirate     2     Pirate
    2   Monkey     null  null
    3   Ninja      4     Ninja
    4   Spaghetti  null  null

    Left outer join 產(chǎn)生表A的完全集,而B表中匹配的則有值,沒有匹配的則以null值取代。

    Venn diagram of SQL left join
    SELECT * FROM TableA
    LEFT OUTER JOIN TableB
    ON TableA.name = TableB.name
    WHERE TableB.id IS null 
    
    id  name       id     name
    --  ----       --     ----
    2   Monkey     null   null
    4   Spaghetti  null   null

    產(chǎn)生在A表中有而在B表中沒有的集合。

    join-left-outer.png
    SELECT * FROM TableA
    FULL OUTER JOIN TableB
    ON TableA.name = TableB.name
    WHERE TableA.id IS null
    OR TableB.id IS null
    
    id    name       id    name
    --    ----       --    ----
    2     Monkey     null  null
    4     Spaghetti  null  null
    null  null       1     Rutabaga
    null  null       3     Darth Vader

    產(chǎn)生A表和B表都沒有出現(xiàn)的數(shù)據(jù)集。

    join-outer.png

    還需要注冊的是我們還有一個是“交差集” cross join, 這種Join沒有辦法用文式圖表示,因為其就是把表A和表B的數(shù)據(jù)進(jìn)行一個N*M的組合,即笛卡爾積。表達(dá)式如下:

    SELECT * FROM TableA
    CROSS JOIN TableB

    這個笛卡爾乘積會產(chǎn)生 4 x 4 = 16 條記錄,一般來說,我們很少用到這個語法。但是我們得小心,如果不是使用嵌套的select語句,一般系統(tǒng)都會產(chǎn)生笛卡爾乘積然再做過濾。這是對于性能來說是非常危險的,尤其是表很大的時候。

    posted @ 2011-07-01 15:06 俞靈 閱讀(301) | 評論 (0)編輯 收藏

    簡單的jar使用方法
    JAR files are packaged with the ZIP file format, so you can use them for "ZIP-like" tasks such as lossless data compression, archiving, decompression, and archive unpacking. These are among the most common uses of JAR files, and you can realize many JAR file benefits using only these basic features.

    Even if you want to take advantage of advanced functionality provided by the JAR file format such as electronic signing, you'll first need to become familiar with the fundamental operations.

    To perform basic tasks with JAR files, you use the Java Archive Tool provided as part of the Java Development Kit. Because the Java Archive tool is invoked by using the jar command, for convenience we'll call it the "Jar tool".

    As a synopsis and preview of some of the topics to be covered in this lesson, the following table summarizes common JAR-file operations:

    OperationCommand
    To create a JAR filejar cf jar-file input-file(s)
    To view the contents of a JAR filejar tf jar-file
    To extract the contents of a JAR filejar xf jar-file
    To extract specific files from a JAR filejar xf jar-file archived-file(s)
    To run an application packaged as a JAR file 
    (version 1.1)
    jre -cp app.jar MainClass
    To run an application packaged as a JAR file 
    (version 1.2 -- requires Main-Class
    manifest header)
    java -jar app.jar
    To invoke an applet packaged as a JAR file
    <applet code=AppletClassName.class
            archive="JarFileName.jar"
            width=width height=height>
    </applet>

    posted @ 2011-07-01 11:18 俞靈 閱讀(759) | 評論 (0)編輯 收藏

    SIEGE is an http load tester and benchmarking utility. It was designed to let web developers measure the performance of their code under duress, to see how it will stand up to load on the internet. It lets the user hit a web server with a configurable number of concurrent simulated users. Those users place the server "under siege." 

    posted @ 2011-03-23 11:15 俞靈 閱讀(169) | 評論 (0)編輯 收藏

    下載與安裝 
    去官網(wǎng)下載tar  或Google 找RPM 皆可,個人都習(xí)慣用tar  裝,安裝方法同一般的程式 
    $>./configure --prefix=/usr/local 
    $>make 
    $>make install 
    Complier 過程中會有幾個Warning,但是對整個環(huán)境并沒有影響.基本上安裝部份都不會有什么問題, rrdtool 的tarball 內(nèi)即可附了libgd,zlib 等自用的lib,不會像mrtg FAQ一樣裝好了試一下打rrdtool ,看會不會出現(xiàn)類似訊息 
    以下是rrdtool中一些參數(shù)的解釋:
    1. DS :DS 用于定義 Data Soure 。也就是用于存放腳本的結(jié)果的變量名(DSN)。
    2. DST :DST 就是 Data Source Type 的意思。有 COUNTER、GUAGE、DERIVE、ABSOLUTE、COMPUTE 5種。
    3. RRA :RRA 用于指定數(shù)據(jù)如何存放。我們可以把一個RRA 看成一個表,各保存不同 interval 的統(tǒng)計結(jié)果
    4. PDP :Primary Data Point 。正常情況下每個 interval RRDtool 都會收到一個值;RRDtool 在收到腳本給來的值后 會計算出另外一個值(例如平均值),這個 值就是 PDP,這個值代表的一般是“xxx/秒”的含義
    5. CF :CF 就是 Consolidation Function 的縮寫。也就是合并(統(tǒng)計)功能。有 AVERAGE、MAX、MIN、LAST 四種分別表示對多個PDP 進(jìn)行取平均、取最大值、取最小值、取當(dāng)前值四種類型
    6. CDP :Consolidation Data Point 。RRDtool 使用多個 PDP 合并為(計算出)一個 CDP。也就是執(zhí)行上面 的CF 操作后的結(jié)果。這個值就是存入 RRA的數(shù)據(jù),繪圖時使用的也是這些數(shù)據(jù)
    7. xff:是 xfile factor 的縮寫。定義:he xfiles factor defines what part of a consolidation interval may be made up from *UNKNOWN* data while the consolidated value is still regarded as known. It is given as the ratio of allowed *UNKNOWN* PDPs to。Xff 字段實際就是一個比例值。0.5 表示一個 CDP 中的所有 PDP 如果超過一半的值為 UNKNOWN ,則該 CDP 的值就被標(biāo)為 UNKNOWN。
    8. step :就是 RRDtool “期望” 每隔多長時間就收到一個值

    posted @ 2011-03-09 08:55 俞靈 閱讀(600) | 評論 (1)編輯 收藏

    最近看了hadoop的mapreduce部分代碼,看了之后總結(jié)了一下,算是成果吧。以下是程序執(zhí)行的主要流程,其中參考了網(wǎng)上的一些文章。


    概括

    Hadoop包括hdfsmapreduce兩部分,在試用期期間我主要看了mapreduce部分,即hadoop執(zhí)行作業(yè)的部分。

    1. mapreduce中幾個主要的概念

           mapreduce整體上可以分為這么幾條執(zhí)行的線索,jobclientJobTrackerTaskTracker

      1. JobClient

                   每一個job都會在客戶端通過JobClient類將應(yīng)用程序以及配置參數(shù)打包成jar文件存儲在HDFS,然后向JobTracker提交作業(yè),JobTracker創(chuàng)建Task(即MapTaskReduceTask)并將它們分發(fā)到各個TaskTracker服務(wù)中去執(zhí)行。


      1. JobTracker

                    JobTracker是一個master服務(wù),hadoop服務(wù)端啟動之后JobTracker接收job,負(fù)責(zé)調(diào)度job的每一個子任務(wù)task運行于TaskTracker上,并監(jiān)控它們,如果發(fā)現(xiàn)有失敗的task就重新運行它。一般情況應(yīng)該把JobTracker部署在單獨的機器上。


      1. TaskTracker

                   TaskTracker是運行于多個節(jié)點上的slaver服務(wù)。TaskTracker主動與JobTracker通信,接收作業(yè),并負(fù)責(zé)直接執(zhí)行每一個任務(wù)。

    下圖簡單的描述了三者之間的關(guān)系:(上傳不了圖片,抱歉!)


    1. 數(shù)據(jù)結(jié)構(gòu)

    2.1 JobInProgress

    JobClient提交job后,JobTracker會創(chuàng)建一個JobInProgress來跟蹤和調(diào)度這個job,并把它添加到job隊列里。JobInProgress會根據(jù)提交的job jar中定義的輸入數(shù)據(jù)集(已分解成FileSplit)創(chuàng)建對應(yīng)的一批TaskInProgress用于監(jiān)控和調(diào)度MapTask,同時在創(chuàng)建指定數(shù)目的TaskInProgress用于監(jiān)控和調(diào)度ReduceTask,缺省為1ReduceTask


    2.2 TaskInProgress

    JobTracker啟動任務(wù)時通過每一個TaskInProgress來launchTask,這時會把Task對象(即MapTaskReduceTask)序列化寫入相應(yīng)的TaskTracker服務(wù)中,TaskTracker收到后會創(chuàng)建對應(yīng)的TaskInProgress(此TaskInProgress實現(xiàn)非JobTracker中使用的TaskInProgress,作用類似)用于監(jiān)控和調(diào)度該Task。啟動具體的Task進(jìn)程是通過TaskInProgress管理的TaskRunner對象來運行的。TaskRunner會自動裝載job jar,并設(shè)置好環(huán)境變量后啟動一個獨立的java child進(jìn)程來執(zhí)行Task,即MapTask或者ReduceTask,但它們不一定運行在同一個TaskTracker中。


    2.3 MapTaskReduceTask

    一個完整的job會自動依次執(zhí)行MapperCombiner(在JobConf指定了Combiner時執(zhí)行)和Reducer,其中MapperCombiner是由MapTask調(diào)用執(zhí)行,Reducer則由ReduceTask調(diào)用,Combiner實際也是Reducer接口類的實現(xiàn)。Mapper會根據(jù)job jar中定義的輸入數(shù)據(jù)集按<key1,value1>對讀入,處理完成生成臨時的<key2,value2>對,如果定義了CombinerMapTask會在Mapper完成調(diào)用該Combiner將相同key的值做合并處理,以減少輸出結(jié)果集。MapTask的任務(wù)全完成即交給ReduceTask進(jìn)程調(diào)用Reducer處理,生成最終結(jié)果<key3,value3>對。

     

    1. 整體流程

    一道MapRedcue作業(yè)是通過JobClient.rubJob(job)master節(jié)點的JobTracker提交的, JobTracker接到JobClient的請求后把其加入作業(yè)隊列中。JobTracker一直在等待JobClient通過RPC提交作業(yè),TaskTracker一直通過RPCJobTracker發(fā)送心跳heartbeat詢問有沒有任務(wù)可做,如果有,讓其派發(fā)任務(wù)給它執(zhí)行。如果JobTracker的作業(yè)隊列不為空, TaskTracker發(fā)送的心跳將會獲得JobTracker給它派發(fā)的任務(wù)。這是一道pull過程。slave節(jié)點的TaskTracker接到任務(wù)后在其本地發(fā)起Task,執(zhí)行任務(wù)。以下是簡略示意圖:



    下圖比較詳細(xì)的解釋了程序的流程:



     

    1. Jobclient

    在編寫MapReduce程序時通常是上是這樣寫的:

    Configuration conf = new Configuration(); // 讀取hadoop配置

    Job job = new Job(conf, "作業(yè)名稱"); // 實例化一道作業(yè)

    job.setMapperClass(Mapper類型);

    job.setCombinerClass(Combiner類型);

    job.setReducerClass(Reducer類型);

    job.setOutputKeyClass(輸出Key的類型);

    job.setOutputValueClass(輸出Value的類型);

    FileInputFormat.addInputPath(job, new Path(輸入hdfs路徑));

    FileOutputFormat.setOutputPath(job, new Path(輸出hdfs路徑));

    // 其它初始化配置

    JobClient.runJob(job);

    4.1 配置Job

    JobConf是用戶描述一個job的接口。下面的信息是MapReduce過程中一些較關(guān)鍵的定制信息:


    4.2 JobClient.runJob():運行Job并分解輸入數(shù)據(jù)集


    runJob()提交作業(yè),如何等待返回的狀態(tài),根據(jù)狀態(tài)返回不同的結(jié)構(gòu)給客戶端。

    其中runJob()使用submitJob(job)方法向 master提交作業(yè)。

    submitJob(Job)方法的流程



     

    一個MapReduceJob會通過JobClient類根據(jù)用戶在JobConf類中定義的InputFormat實現(xiàn)類來將輸入的數(shù)據(jù)集分解成一批小的數(shù)據(jù)集,每一個小數(shù)據(jù)集會對應(yīng)創(chuàng)建一個MapTask來處理。JobClient會使用缺省的FileInputFormat類調(diào)用FileInputFormat.getSplits()方法生成小數(shù)據(jù)集,如果判斷數(shù)據(jù)文件是isSplitable()的話,會將大的文件分解成小的FileSplit,當(dāng)然只是記錄文件在HDFS里的路徑及偏移量和Split大小。這些信息會統(tǒng)一打包到jobFilejar中。


    hadoop分布系統(tǒng)文件系統(tǒng)hdfs依次上傳三個文件: job.jar, job.splitjob.xml。 

    job.xml: 作業(yè)配置,例如Mapper, Combiner, Reducer的類型,輸入輸出格式的類型等。 

    job.jar: jar,里面包含了執(zhí)行此任務(wù)需要的各種類,比如 Mapper,Reducer等實現(xiàn)。 

    job.split: 文件分塊的相關(guān)信息,比如有數(shù)據(jù)分多少個塊,塊的大小(默認(rèn)64m)等。 

    這三個文件在hdfs上的路徑由hadoop-default.xml文件中的mapreduce系統(tǒng)路徑mapred.system.dir屬性 + jobid決定。mapred.system.dir屬性默認(rèn)是/tmp/hadoop-user_name/mapred/system。寫完這三個文 件之后, 此方法會通過RPC調(diào)用master節(jié)點上的JobTracker.submitJob(job)方法,等待返回狀態(tài),此時作業(yè)已經(jīng)提交完成。

    接下來轉(zhuǎn)到JobTracker上執(zhí)行。

    (事實上這里還涉及到一些相關(guān)的類與方法)

    4.3 提交Job

    jobFile的提交過程是通過RPC(遠(yuǎn)程進(jìn)程調(diào)用)模塊來實現(xiàn)的。大致過程是,JobClient類中通過RPC實現(xiàn)的Proxy接口調(diào)用JobTrackersubmitJob()方法,而JobTracker必須實現(xiàn)JobSubmissionProtocol接口。

    JobTracker創(chuàng)建job成功后會給JobClient傳回一個JobStatus對象用于記錄job的狀態(tài)信息,如執(zhí)行時間、MapReduce任務(wù)完成的比例等。JobClient會根據(jù)這個JobStatus對象創(chuàng)建一個NetworkedJobRunningJob對象,用于定時從JobTracker獲得執(zhí)行過程的統(tǒng)計數(shù)據(jù)來監(jiān)控并打印到用戶的控制臺。

    與創(chuàng)建Job過程相關(guān)的類和方法如下圖所示


     

    1. JobTracker

    5.1 JobTracker啟動

    JobTracker類中有一個main()函數(shù),在軟件啟動的時候執(zhí)行此main()函數(shù)啟動JobTracker進(jìn)程,main()中生成一個JobTracker的對象,然后通過tracker.offerService()語句啟動服務(wù),即啟動一些線程,下面是幾個主要的線程:

    taskScheduler:一個抽象類,被JobTracker用于安排執(zhí)行在TaskTrackers上的task任務(wù),它使用一個或多個JobInProgressListeners接收jobs的通知。另外一個任務(wù)是調(diào)用JobInProgress.initTask()job初始化tasks。啟動,提交作業(yè),設(shè)置配置參數(shù),終止等方法。


    completedJobsStoreThread對應(yīng)completedJobStatusStoreCompletedJobStatusStore類:把JobInProgress中的job信息存儲到DFS中;提供一些讀取狀態(tài)信息的方法;是一個守護進(jìn)程,用于刪除DFS中的保存時間超過規(guī)定時間的job status刪除,


    interTrackerServer,抽象類Server類型的實例。一個IPC (Inter-Process Communication,進(jìn)程間通信)服務(wù)器,IPC調(diào)用一個以一個參數(shù)的形式調(diào)用Writable,然后返回一個Writable作為返回值,在某個端口上運行。提供了call,listener,responder,connection,handle類。包括start(),stop(),join(),getListenerAddress(),call()等方法。

    這些線程啟動之后,便可開始工作了。



    job是統(tǒng)一由JobTracker來調(diào)度的,把具體的Task分發(fā)給各個TaskTracker節(jié)點來執(zhí)行。下面來詳細(xì)解析執(zhí)行過程,首先先從JobTracker收到JobClient的提交請求開始。

      1. JobTracker初始化Job

    5.2.1 JobTracker.submitJob() 收到請求

    當(dāng)JobTracker接收到新的job請求(即submitJob()函數(shù)被調(diào)用)后,會創(chuàng)建一個JobInProgress對象并通過它來管理和調(diào)度任務(wù)。JobInProgress在創(chuàng)建的時候會初始化一系列與任務(wù)有關(guān)的參數(shù),調(diào)用到FileSystem,把在JobClient端上傳的所有任務(wù)文件下載到本地的文件系統(tǒng)中的臨時目錄里。這其中包括上傳的*.jar文件包、記錄配置信息的xml、記錄分割信息的文件。

    5.2 JobTracker.JobInitThread 通知初始化線程

    JobTracker 中的監(jiān)聽器類EagerTaskInitializationListener負(fù)責(zé)任務(wù)Task的初始化。JobTracker使用jobAdded(job)加入jobEagerTaskInitializationListener中一個專門管理需要初始化的隊列里,即一個list成員變量jobInitQueue里。resortInitQueue方法根據(jù)作業(yè)的優(yōu)先級排序。然后調(diào)用notifyAll()函數(shù),會喚起一個用于初始化job的線程JobInitThread來處理???JobInitThread收到信號后即取出最靠前的job,即優(yōu)先級別最高的job,調(diào)用TaskTrackerManagerinitJob最終調(diào)用JobInProgress.initTasks()執(zhí)行真正的初始化工作。

    5.3 JobInProgress.initTasks() 初始化TaskInProgress

    任務(wù)Task分兩種: MapTask reduceTask,它們的管理對象都是TaskInProgress

    首先JobInProgress會創(chuàng)建Map的監(jiān)控對象。在initTasks()函數(shù)里通過調(diào)用JobClientreadSplitFile()獲得已分解的輸入數(shù)據(jù)的RawSplit列表,然后根據(jù)這個列表創(chuàng)建對應(yīng)數(shù)目的Map執(zhí)行管理對象TaskInProgress。在這個過程中,還會記錄該RawSplit塊對應(yīng)的所有在HDFS里的blocks所在的DataNode節(jié)點的host,這個會在RawSplit創(chuàng)建時通過FileSplitgetLocations()函數(shù)獲取,該函數(shù)會調(diào)用DistributedFileSystem的getFileCacheHints()獲得。當(dāng)然如果是存儲在本地文件系統(tǒng)中,即使用LocalFileSystem時當(dāng)然只有一個location即“localhost”了。

    創(chuàng)建這些TaskInProgress對象完畢后,initTasks()方法會通 過createCache()方法為這些TaskInProgress對象產(chǎn)生一個未執(zhí)行任務(wù)的Map緩存nonRunningMapCacheslave端的 TaskTrackermaster發(fā)送心跳時,就可以直接從這個cache中取任務(wù)去執(zhí)行。

    其次JobInProgress會創(chuàng)建Reduce的監(jiān)控對象,這個比較簡單,根據(jù)JobConf里指定的Reduce數(shù)目創(chuàng)建,缺省只創(chuàng)建1Reduce任務(wù)。監(jiān)控和調(diào)度Reduce任務(wù)的是TaskInProgress類,不過構(gòu)造方法有所不同,TaskInProgress會根據(jù)不同參數(shù)分別創(chuàng)建具體的MapTask或者ReduceTask。同樣地,initTasks()也會通過createCache()方法產(chǎn)生nonRunningReduces成員。

    JobInProgress創(chuàng)建完TaskInProgress后,最后構(gòu)造JobStatus并記錄job正在執(zhí)行中,然后再調(diào)用JobHistory.JobInfo.logStarted()記錄job的執(zhí)行日志。到這里JobTracker里初始化job的過程全部結(jié)束。


    5.3.2 JobTracker調(diào)度Job

    hadoop默認(rèn)的調(diào)度器是FIFO策略的JobQueueTaskScheduler,它有兩個成員變量 jobQueueJobInProgressListener與上面說的eagerTaskInitializationListener。JobQueueJobInProgressListener是JobTracker的另一個監(jiān)聽器類,它包含了一個映射,用來管理和調(diào)度所有的JobInProgress。jobAdded(job)同時會加入job到JobQueueJobInProgressListener中的映射。

    JobQueueTaskScheduler最重要的方法是assignTasks ,他實現(xiàn)了工作調(diào)度。具體實現(xiàn):JobTracker 接到TaskTracker heartbeat() 調(diào)用后,首先會檢查上一個心跳響應(yīng)是否完成,是沒要求啟動或重啟任務(wù),如果一切正常,則會處理心跳。首先它會檢查 TaskTracker 端還可以做多少個 map reduce 任務(wù),將要派發(fā)的任務(wù)數(shù)是否超出這個數(shù),是否超出集群的任務(wù)平均剩余可負(fù)載數(shù)。如果都沒超出,則為此 TaskTracker 分配一個 MapTask ReduceTask 。產(chǎn)生 Map 任務(wù)使用 JobInProgress obtainNewMapTask() 方法,實質(zhì)上最后調(diào)用了 JobInProgress findNewMapTask() 訪問 nonRunningMapCache

    上面講解任務(wù)初始化時說過,createCache()方法會在網(wǎng)絡(luò)拓?fù)浣Y(jié)構(gòu)上掛上需要執(zhí)行的TaskInProgressfindNewMapTask()從近到遠(yuǎn)一層一層地尋找,首先是同一節(jié)點,然后在尋找同一機柜上的節(jié)點,接著尋找相同數(shù)據(jù)中心下的節(jié)點,直到找了maxLevel層結(jié)束。這樣的話,在JobTrackerTaskTracker派發(fā)任務(wù)的時候,可以迅速找到最近的TaskTracker,讓它執(zhí)行任務(wù)。

    最終生成一個Task類對象,該對象被封裝在一個LanuchTaskAction 中,發(fā)回給TaskTracker,讓它去執(zhí)行任務(wù)。

    產(chǎn)生 Reduce 任務(wù)過程類似,使用 JobInProgress.obtainNewReduceTask() 方法,實質(zhì)上最后調(diào)用了 JobInProgress findNewReduceTask() 訪問 nonRunningReduces

    6. TaskTracker

    6.1 TaskTracker的啟動

    JobTracker一樣,里面包含一個main()方法,在hadoop啟動的時候啟動此進(jìn)程。

    Main()方法最主要的一句話

    TaskTracker(conf).run()

    TaskTracker(conf)獲取本機的一些配置信息,初始化服務(wù)器并啟動服務(wù)器(StatusHttpServer);然后調(diào)用initialize(),這個方法才是真正構(gòu)造TaskTracker的地方,把它作為一個單獨的方法便可以再次調(diào)用并可以在close()之后回收對象,就是初始化一些變量對象,最后啟動線程:

    taskMemoryManagerTaskMemoryManagerThread類的對象。管理本機上task運行時內(nèi)存的使用,殺死任何溢出和超出內(nèi)存限制的task-trees

    mapLauncherreduceLauncher都是TaskLauncher類的對象,其作用是啟動maptaskreducetask任務(wù)線程。根據(jù)tasksToLaunch判斷是否需要新建任務(wù),其中的調(diào)用的關(guān)系為:run()startNewTask()localizeJob()launchTaskForJoblaunchTask()localizeTask


    run()方法中啟動TaskTracker服務(wù)器然后一直循環(huán)。循環(huán)會嘗試連接到的JobTracker。主要調(diào)用了兩個方法startCleanupThreads(),offerService()

    startCleanupThreads()啟動為守護進(jìn)程,可以用來刪除一個獨立線程的路徑。

    offerService()類似于JobTracker中的offerService()方法,即服務(wù)器執(zhí)行的主循環(huán)。規(guī)定的時間內(nèi)給JobTracker發(fā)送心跳信息,并處理返回的命令。

    下面具體介紹流程中的每一步。

    6.2 TaskTracker加載Task到子進(jìn)程

    Task的執(zhí)行實際是由TaskTracker發(fā)起的,TaskTracker會定期與JobTracker進(jìn)行一次通信,報告自己Task的執(zhí)行狀態(tài),接收JobTracker的指令等。如果發(fā)現(xiàn)有自己需要執(zhí)行的新任務(wù)也會在這時啟動,即是在TaskTracker調(diào)用JobTrackerheartbeat()方法時進(jìn)行,此調(diào)用底層是通過IPC層調(diào)用Proxy接口實現(xiàn)。

    6.2.1 TaskTracker.run() 連接JobTracker

    TaskTracker的啟動過程會初始化一系列參數(shù)和服務(wù),然后嘗試連接JobTracker(即必須實現(xiàn)InterTrackerProtocol接口),如果連接斷開,則會循環(huán)嘗試連接JobTracker,并重新初始化所有成員和參數(shù)。

    6.2.2 TaskTracker.offerService() 主循環(huán)

    如果連接JobTracker服務(wù)成功,TaskTracker就會調(diào)用offerService()函數(shù)進(jìn)入主執(zhí)行循環(huán)中。這個循環(huán)會每隔10秒與JobTracker通訊一次,調(diào)用transmitHeartBeat(),獲得HeartbeatResponse信息。然后調(diào)用HeartbeatResponsegetActions()函數(shù)獲得JobTracker傳過來的所有指令即一個TaskTrackerAction數(shù)組。再遍歷這個數(shù)組,如果是一個新任務(wù)指令即LaunchTaskAction則調(diào)用調(diào)用addToTaskQueue加入到待執(zhí)行

    隊列,否則加入到tasksToCleanup隊列,交給一個taskCleanupThread線程來處理,如執(zhí)行KillJobAction或者KillTaskAction等。

    6.2.3 TaskTracker.transmitHeartBeat() 獲取JobTracker指令

    transmitHeartBeat()函數(shù)處理中,TaskTracker會創(chuàng)建一個新的TaskTrackerStatus對象記錄目前任務(wù)的執(zhí)行狀況,檢查目前執(zhí)行的Task數(shù)目以及本地磁盤的空間使用情況等,如果可以接收新的Task則設(shè)置heartbeat()askForNewTask參數(shù)為true。然后通過IPC接口調(diào)用JobTrackerheartbeat()方法發(fā)送過去,heartbeat()返回值TaskTrackerAction數(shù)組。

    6.2.4 TaskTracker.addToTaskQueue,交給TaskLauncher處理

    TaskLauncher是用來處理新任務(wù)的線程類,包含了一個待運行任務(wù)的隊列 tasksToLaunchTaskTracker.addToTaskQueue會調(diào)用TaskTrackerregisterTask,創(chuàng)建TaskInProgress對象來調(diào)度和監(jiān)控任務(wù),并把它加入到runningTasks隊列中。同時將這個TaskInProgress加到tasksToLaunch 中,并notifyAll()喚醒一個線程運行,該線程從隊列tasksToLaunch取出一個待運行任務(wù),調(diào)用TaskTrackerstartNewTask運行任務(wù)。

    6.2.5 TaskTracker.startNewTask() 啟動新任務(wù)

    調(diào)用localizeJob()真正初始化Task并開始執(zhí)行。

    6.2.6 TaskTracker.localizeJob() 初始化job目錄等

    此函數(shù)主要任務(wù)是初始化工作目錄workDir,再將job jar包從HDFS復(fù)制到本地文件系統(tǒng)中,調(diào)用RunJar.unJar()將包解壓到工作目錄。然后創(chuàng)建一個RunningJob并調(diào)用addTaskToJob()函數(shù)將它添加到runningJobs監(jiān)控隊列中。addTaskToJob方法把一個任務(wù)加入到該任務(wù)屬于的runningJobtasks列表中。如果該任務(wù)屬于的runningJob不存在,先新建,加到runningJobs中。完成后即調(diào)用launchTaskForJob()開始執(zhí)行Task

    6.2.7 TaskTracker.launchTaskForJob() 執(zhí)行任務(wù)

    啟動Task的工作實際是調(diào)用TaskTracker$TaskInProgresslaunchTask()函數(shù)來執(zhí)行的。

    6.2.8 TaskTracker$TaskInProgress.launchTask() 執(zhí)行任務(wù)

    執(zhí)行任務(wù)前先調(diào)用localizeTask()更新一下jobConf文件并寫入到本地目錄中。然后通過調(diào)用TaskcreateRunner()方法創(chuàng)建TaskRunner對象并調(diào)用其start()方法最后啟動Task獨立的java執(zhí)行子進(jìn)程。

    6.2.9 Task.createRunner() 創(chuàng)建啟動Runner對象

    Task有兩個實現(xiàn)版本,即MapTaskReduceTask,它們分別用于創(chuàng)建MapReduce任務(wù)。MapTask會創(chuàng)建MapTaskRunner來啟動Task子進(jìn)程,而ReduceTask則創(chuàng)建ReduceTaskRunner來啟動。

    6.2.10 TaskRunner.start() 啟動子進(jìn)程

    TaskRunner負(fù)責(zé)將一個任務(wù)放到一個進(jìn)程里面來執(zhí)行。它會調(diào)用run()函數(shù)來處理,主要的工作就是初始化啟動java子進(jìn)程的一系列環(huán)境變量,包括設(shè)定工作目錄workDir,設(shè)置CLASSPATH環(huán)境變量等。然后裝載job jar包。JvmManager用于管理該TaskTracker上所有運行的Task子進(jìn)程。每一個進(jìn)程都是由JvmRunner來管理的,它也是位于單獨線程中的。JvmManagerlaunchJvm方法,根據(jù)任務(wù)是map還是reduce,生成對應(yīng)的JvmRunner并放到對應(yīng)JvmManagerForType的進(jìn)程容器中進(jìn)行管理。JvmManagerForTypereapJvm()

    分配一個新的JVM進(jìn)程。如果JvmManagerForType槽滿,就尋找idle的進(jìn)程,如果是同Job的直接放進(jìn)去,否則殺死這個進(jìn)程,用一個新的進(jìn)程代替。如果槽沒有滿,那么就啟動新的子進(jìn)程。生成新的進(jìn)程使用spawnNewJvm方法。spawnNewJvm使用JvmRunner線程的run方法,run方法用于生成一個新的進(jìn)程并運行它,具體實現(xiàn)是調(diào)用runChild

    6.3 子進(jìn)程執(zhí)行MapTask

    真實的執(zhí)行載體,是Child,它包含一個 main函數(shù),進(jìn)程執(zhí)行,會將相關(guān)參數(shù)傳進(jìn)來,它會拆解這些參數(shù),通過getTask(jvmId)向父進(jìn)程索取任務(wù),并且構(gòu)造出相關(guān)的Task實例,然后使用Taskrun()啟動任務(wù)。

    6.3.1 run

    方法相當(dāng)簡單,配置完系統(tǒng)的TaskReporter后,就根據(jù)情況執(zhí)行runJobCleanupTaskrunJobSetupTaskrunTaskCleanupTask或執(zhí)行map

    6.3.2 mapper

    首先構(gòu)造Mapper的輸出,是通過MapOutputCollector進(jìn)行的,也分兩種情況,如果沒有Reducer,那么,用DirectMapOutputCollector,否則,用MapOutputBuffer。然后構(gòu)造Mapper處理的InputSplit,然后就開始創(chuàng)建MapperRecordReader,最終得到map的輸入。構(gòu)造完Mapper的輸入輸出,通過構(gòu)造配置文件中配置的MapRunnable,就可以執(zhí)行Mapper了。目前系統(tǒng)有兩個MapRunnableMapRunnerMultithreadedMapRunnerMapRunner是單線程執(zhí)行器,比較簡單,他會使用反射機制生成用戶定義的Mapper接口實現(xiàn)類,作為他的一個成員。

    6.3.3 MapRunnerrun方法

    會先創(chuàng)建對應(yīng)的keyvalue對象,然后,對InputSplit的每一對<keyvalue>,調(diào)用用戶實現(xiàn)的Mapper接口實現(xiàn)類的map方法,每處理一個數(shù)據(jù)對,就要使用OutputCollector收集每次處理kv對后得到的新的kv對,把他們spill到文件或者放到內(nèi)存,以做進(jìn)一步的處理,比如排序,combine等。

    6.3.4 OutputCollector

    OutputCollector的作用是收集每次調(diào)用map后得到的新的kv對,并把他們spill到文件或者放到內(nèi)存,以做進(jìn)一步的處理,比如排序,combine等。

    MapOutputCollector 有兩個子類:MapOutputBufferDirectMapOutputCollectorDirectMapOutputCollector用在不需要Reduce階段的時候。如果Mapper后續(xù)有reduce任務(wù),系統(tǒng)會使用MapOutputBuffer做為輸出, MapOutputBuffer使用了一個緩沖區(qū)對map的處理結(jié)果進(jìn)行緩存,放在內(nèi)存中,又使用幾個數(shù)組對這個緩沖區(qū)進(jìn)行管理。



    在適當(dāng)?shù)臅r機,緩沖區(qū)中的數(shù)據(jù)會被spill到硬盤中。



    向硬盤中寫數(shù)據(jù)的時機:

    1)當(dāng)內(nèi)存緩沖區(qū)不能容下一個太大的k v對時。spillSingleRecord方法。

    2)內(nèi)存緩沖區(qū)已滿時。SpillThread線程。

    3Mapper的結(jié)果都已經(jīng)collect了,需要對緩沖區(qū)做最后的清理。Flush方法。

    2.5 spillThread線程:將緩沖區(qū)中的數(shù)據(jù)spill到硬盤中。

    1)需要spill時調(diào)用函數(shù)sortAndSpill,按照partitionkey做排序。默認(rèn)使用的是快速排序QuickSort

    2)如果沒有combiner,則直接輸出記錄,否則,調(diào)用CombinerRunnercombine,先做combin然后輸出。

    6.4 子進(jìn)程執(zhí)行ReduceTask

    ReduceTask.run方法開始和MapTask類似,包括initialize()初始化 ,runJobCleanupTask()runJobSetupTask()runTaskCleanupTask()。之后進(jìn)入正式的工作,主要有這么三個步驟:CopySortReduce

    6.4.1 Copy

    就是從執(zhí)行各個Map任務(wù)的服務(wù)器那里,收羅到map的輸出文件。拷貝的任務(wù),是由ReduceTask.ReduceCopier 類來負(fù)責(zé)。

    6.4.1.1 類圖:



    6.4.1.2 流程: 使用ReduceCopier.fetchOutputs開始

    1)索取任務(wù)。使用GetMapEventsThread線程。該線程的run方法不停的調(diào)用getMapCompletionEvents方法,該方法又使用RPC調(diào)用TaskUmbilicalProtocol協(xié)議的getMapCompletionEvents,方法使用所屬的jobID向其父TaskTracker詢問此作業(yè)個Map任務(wù)的完成狀況(TaskTracker要向JobTracker詢問后再轉(zhuǎn)告給它...)。返回一個數(shù)組TaskCompletionEvent events[]TaskCompletionEvent包含taskidip地址之類的信息。

    2)當(dāng)獲取到相關(guān)Map任務(wù)執(zhí)行服務(wù)器的信息后,有一個線程MapOutputCopier開啟,做具體的拷貝工作。 它會在一個單獨的線程內(nèi),負(fù)責(zé)某個Map任務(wù)服務(wù)器上文件的拷貝工作。MapOutputCopierrun循環(huán)調(diào)用copyOutputcopyOutput又調(diào)用getMapOutput,使用HTTP遠(yuǎn)程拷貝。

    3getMapOutput遠(yuǎn)程拷貝過來的內(nèi)容(當(dāng)然也可以是本地了...),作為MapOutput對象存在,它可以在內(nèi)存中也可以序列化在磁盤上,這個根據(jù)內(nèi)存使用狀況來自動調(diào)節(jié)。

    4) 同時,還有一個內(nèi)存Merger線程InMemFSMergeThread和一個文件Merger線程LocalFSMerger在同步工作,它們將下載過來的文件(可能在內(nèi)存中,簡單的統(tǒng)稱為文件...),做著歸并排序,以此,節(jié)約時間,降低輸入文件的數(shù)量,為后續(xù)的排序工作減 負(fù)。InMemFSMergeThreadrun循環(huán)調(diào)用doInMemMerge, 該方法使用工具類Merger實現(xiàn)歸并,如果需要combine,則combinerRunner.combine

    6.4.2 Sort

    排序工作,就相當(dāng)于上述排序工作的一個延續(xù)。它會在所有的文件都拷貝完畢后進(jìn)行。使用工具類Merger歸并所有的文件。經(jīng)過這一個流程,一個合并了所有所需Map任務(wù)輸出文件的新文件產(chǎn)生了。而那些從其他各個服務(wù)器網(wǎng)羅過來的 Map任務(wù)輸出文件,全部刪除了。

    6.4.3 Reduce

    Reduce任務(wù)的最后一個階段。他會準(zhǔn)備好 keyClass"mapred.output.key.class""mapred.mapoutput.key.class", valueClass("mapred.mapoutput.value.class""mapred.output.value.class")Comparator(“mapred.output.value.groupfn.class”或 “mapred.output.key.comparator.class”)。最后調(diào)用runOldReducer方法。(也是兩套API,我們分析runOldReducer

    6.4.4 runReducer

    1)輸出方面。它會準(zhǔn)備一個OutputCollector收集輸出,與MapTask不同,這個OutputCollector更為簡單,僅僅是打開一個RecordWritercollect一次,write一次。最大的不同在于,這次傳入RecordWriter的文件系統(tǒng),基本都是分布式文件系統(tǒng), 或者說是HDFS

    2)輸入方面,ReduceTask會用準(zhǔn)備好的KeyClassValueClassKeyComparator等等之類的自定義類,構(gòu)造出Reducer所需的鍵類型, 和值的迭代類型Iterator(一個鍵到了這里一般是對應(yīng)一組值)。

    3)有了輸入,有了輸出,不斷循環(huán)調(diào)用自定義的Reducer,最終,Reduce階段完成。



     

     

    posted @ 2011-01-14 09:05 俞靈 閱讀(8374) | 評論 (7)編輯 收藏

    僅列出標(biāo)題
    共3頁: 上一頁 1 2 3 
    主站蜘蛛池模板: 久久夜色精品国产噜噜噜亚洲AV| 亚洲av成人一区二区三区在线观看| 久九九精品免费视频| 69堂人成无码免费视频果冻传媒| 成人人观看的免费毛片| 亚洲国产成人久久一区久久| 亚洲精品自在在线观看| 精品亚洲麻豆1区2区3区| 亚洲欧美第一成人网站7777| 最好2018中文免费视频| 久久黄色免费网站| 毛片免费视频播放| 亚洲一区二区视频在线观看 | 久久久久av无码免费网| 日本特黄特色免费大片| 亚洲人色婷婷成人网站在线观看| 97久久精品亚洲中文字幕无码| 亚洲人成网站999久久久综合| 人人鲁免费播放视频人人香蕉| 久久青草免费91观看| 性色av免费观看| 亚洲日韩小电影在线观看| 亚洲免费闲人蜜桃| 四虎影视永久在线精品免费| 久久大香香蕉国产免费网站| 国内一级一级毛片a免费| 国产午夜亚洲不卡| 亚洲五月综合缴情婷婷| ww在线观视频免费观看w| 亚欧免费视频一区二区三区| 亚洲精品亚洲人成在线观看下载| 亚洲电影在线免费观看| 一级日本高清视频免费观看| av无码久久久久不卡免费网站| 亚洲午夜精品一级在线播放放| 亚洲成人免费网站| 国产成人1024精品免费| 免费可以在线看A∨网站| 久久91亚洲人成电影网站| 色婷婷亚洲一区二区三区| 95免费观看体验区视频|