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

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

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

    敏捷、分布式、ALM過程自動化、企業應用架構
    posts - 14, comments - 0, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    2012年4月1日

    Hadoop實施已經有快一個月了,對Hadoop的概念理解、使用,Linux與shell腳本,甚至mysql都有了更多的理解。


    項目背景:用于互聯網信息收集后的關鍵詞匹配與內容提取。

    主要系統架構分為互聯網爬蟲、分析、業務應用三塊:

    簡單架構描述

    由于我在當中的角色主要負責分析架構的搭建,所以其他兩塊都畫得簡單,下面也不會過多的描述。


    Hadoop理解:提到Hadoop都想到的是云、分布式計算,在一段時間的實施之后有了一些具體的理解。

    Hadoop的優勢:

    針對性能指標,當業務數據量總量或增速上升到一定級別,依靠關系型數據庫一定無法支持。對于非關系型數據庫,包括Nosql和Solr一類存儲方式,稍顯復雜,對于機器集群性能要求偏高(相對于文件系統)。從數據使用模式上來講,目前海量數據的常常是不包含復雜邏輯的簡單統計整理(比如上述系統中的關鍵詞匹配)。這時候文件系統的優勢反而比較明顯(結構簡單,邏輯簡單)。

    如上述系統的應用場景是怎么樣的呢,在一個強大的爬蟲系統之下,每個小時的數據增量在G到10G的級別,需要搜索所有的文件,獲取關鍵字的匹配,并且對匹配內容進行摘要。很類似我們windows里面的搜索功能,需要解決的就是如何在這樣增幅的文件系統之下,如何滿足業務系統的需求。

    分析系統有什么要求呢?

    能夠建立集群,分布式的保存數據文件內容(統一控制,可配置)。

    有一定的保護機制,保證數據或節點丟失不會影響系統使用。

    如果有一個任務腳本執行框架機制就好了(用于并行計算)。

    能夠進行節點間的數據均衡。

    能夠簡單的查看所有的狀態與日志(web客戶端)

    可能主要是這些了。若自己實現,確實是個復雜而龐大的工程,現在我們有了Hadoop。


    系統物理架構:

    我們使用了一臺服務器,利用虛擬化,安裝了7套64x位的CentOS。一個Namenode,6個Datanode,復制數設置為3。每個系統分配到一個cpu,2G內存,Datanode掛載了500G的存儲空間。

    理想的Hadoop的搭建環境,參照《Best Practices for Selecting Apache Hadoop Hardware》(http://hortonworks.com/blog/best-practices-for-selecting-apache-hadoop-hardware/)一文,以及一些其他的文章。

    CPU:最好是雙CPU,8核左右。不用太高了。

    內存:推薦48G,但是4G應該就可以運行Hadoop了。

    硬盤:7200轉的SATA硬盤即可,Hadoop很占空間,所以盡量加。

    網絡:內部的數據交換要求非常高,內網最好是千兆網卡,帶寬為1GB。

    理想與現實,有錢與沒錢,呵呵。


    系統軟件架構:

    Hadoop:版本使用的是1.0.3,再下來就是2了,為了盡量簡化應用,所以不考慮2的新特性。對Hadoop沒有做太多的設置,基本基于默認。70為Namenode,71-76為Datanode。

    JDK:1.6.0_33 (64x)


    系統實施過程:

    HDFS部分:

    爬蟲抓取數據,整理后存放在50文件服務器,70以外部掛載的形式讀取。網頁文件比較小,假如直接寫入Hadoop對Namenode負載過大,所以入庫前合并,將每小時網頁整合成為一個文件寫入HDFS,由于區分類別,所以每小時基本寫入10個文件左右,總量在5-8G,耗時在40-50分鐘。(這個過程中,由于爬蟲的IO過于頻繁,導致文件讀取困難,所以做了定時任務,每小時啟動一次,將需要處理的文件先拷貝到臨時區域,合并入庫之后再刪除。此處應該是受到單核cpu的限制,所有操作均是串行,包括拷貝(cp)和合并入庫(java),所以Namenode嚴重建議配置稍高。)

    此處沒有太多問題。

    MapReduce部分:

    寫入完成后,進行分析工作,MapReduce。此處的工作過程為:數據庫定時生成關鍵詞列表文件。Job執行時會讀取列表文件,匹配指定范圍內的HDFS文件(過去一小時),匹配出對應的表達式與HTML,Map過程結束。在Reduce階段,會將Map的所有數據入數據庫(Mysql)。

    此處出現過一些問題,記錄下來。

    1. Reduce階段需要加載Mysql的第三方驅動包。我在三個環境測試過(公司、家里、發布環境),使用 -libjars 一定可以,有的地方不需要也可以。不明確,懷疑與HADOOP_HOME環境變量有關。

    2. MR過程中使用log4j打印日志,在Hadoop臨時目錄(如果你沒有配置dfs.name.dir,dfs.data.dir,mapred.local.dir.mapred.system.dir等目錄,這些都會在hadoop.tmp.dir當中,我就偷懶都沒配置)mapred文件夾中查看一下。

    整個過程實際上還是比較簡單的,基本編碼量就在Job的部分,但是一個Java文件就夠了。在目前初級階段應該還是比較好用的。現在還沒有測試Job的執行效率。完成后會繼續記錄下來。有什么問題可以提出。我想到什么也會在本文繼續更新。

    posted @ 2012-08-08 20:21 一酌散千憂 閱讀(585) | 評論 (0)編輯 收藏

    硬件資源:

    三臺CentOS5.6虛擬機(Vmware

    本機 windows7 64x

     

    基本資源配置:

    三臺虛擬機均是克隆自同一個鏡像

    已經安裝了Java環境(jdk1.6.0_25

    Hadoop路徑在/usr/hadoop/hadoop-0.20.205.0

     

    操作步驟:

    1、機器名稱規范

    ip分別為128129130,將128設置為master,其他設置為slave

    修改

    /etc/sysconfig/network

    /etc/hosts

    兩處配置,名稱分別為hadoop-master\hadoop-slave01\hadoop-slave02

    注意:此處名稱最好不用使用下劃線,有可能引發namenode的啟動異常。

     

    2、修改Hadoop配置 

    master節點的conf中修改masterslave文件,分別為機器的ip地址

     

    修改master節點的conf中:

    core-site.xml

    <property>

    <name>fs.default.name</name>

    <value>hdfs://ip-master:9000</value>

    </property>

     

    mapred-site.xml

    <property>

    <name>mapred.job.tracker</name>                                   

    <value>master:9001</value>                                

    </property>

     

    hdfs-site.xm

    <property>

    <name>dfs.replication</name>

    <value>2</value>

    </property>

    注意此處的端口號均為默認。

     

     

    3、建立m-s之間的ssh連接

    首先masterslave機器都需要進行ssh信任文件生成,執行如下命令:

    $ ssh-keygen -t rsa

    中間需要輸入的地方直接回車,接受缺省值即可

     

    由于使用root用戶登錄,所以密鑰文件生成在 /root/.ssh/文件夾下,存有一對密鑰id_dsaid_dsa.pub

    此處id_dsa(私鑰)必須為其他用戶不可讀,所以文件屬性應當是600

     

    master機器執行:

    id_dsa.pub(公鑰)復制為 authorized_keys

    $ cp id_dsa.pub authorized_keys

    如果是多臺機器需要,無密碼登陸,則各自機器產生公鑰追加到authorized_keys即可.

     

    使用scp協議覆蓋slave端的密鑰文件夾,使得slave機器信任來自master的連接:

    $ scp /root/.ssh/* ip-slave:/root/.ssh

     

     

    4、啟動服務 

    建議將$HADOOP_HOME/bin下的所有文件給與執行權限:

    $ chmod 777 bin

     

    master作為namenod需要執行如下腳本:

    $HADOOP_HOME/bin/hadoop namenode –format

     

    完成后執行 $HADOOP_HOME/bin/start-all.sh

     

    5、問題檢查

    Hadoop根目錄下的logs文件中,檢查各個服務日志的啟動情況

     

     

    6、其他情況說明:

    Q: $HADOOP_HOME is deprecated

    A: 基本不會產生任何影響。由于腳本啟動時設置了該環境變量,就會提示用戶原有環境變量失效。可以取消環境變量設置,或者直接去bin/hadoop中找到這句話,去掉即可

     

    Q: 無效的選項 -jvm / Unrecognized option: -jvm

    A: 在使用root用戶登錄時 bin/hadoop 腳本就會進行判斷,加上-jvm參數。此處是為了進入jsvchttp://commons.apache.org/daemon/jsvc.html),此處并不確定是否bug,也不再進行詳細的追溯,解決方法就是進入 bin/hadoop 腳本中 找到 jvm 參數并去掉。

     

     

     

     

     

     

     

    posted @ 2012-07-04 07:38 一酌散千憂 閱讀(588) | 評論 (0)編輯 收藏

    公司里有同事時常抱怨,項目的用戶體驗太差,常常挨領導的罵。大家都認為是在用戶體驗的設計方面,公司人員的能力和經驗都不足引起的。發牢騷的時候也會說,如果公司能夠請得起“淘寶”的UI設計師,咱們的系統肯定會更上一層樓。我之前也一直認為如此,即我們的設計是影響項目體驗的重要原因。最近被領導調動去協助一個項目,產生了一些不一樣的體會。

    項目背景,一個新的產品,小型項目,純開發人員3-4人,2名熟練開發人員,1名新手,偶爾會有協助人員。沒有技術經理,項目經理身負多個項目,對項目進度關心不足,部門經理會協助進行工作和進度管理。可以看到管理還是比較混亂。

    由于項目進度太慢,領導要求從我這邊調一個熟練人員協助開發。我也基本了解他們的項目狀況,為了不讓我的人進去抓瞎,我就和他一起去了解項目情況。

    項目狀況比較糟糕,介入項目時已經開發了一段時間,保留的文檔只有兩份,一副數據庫說明,一份非常粗略的需求說明,而且還與開發進度不同步,就是沒有維護。

    我了解了一下項目目前的難度,開發人員和我反映一個是人員熟練程度的問題,二是需求變更的問題。我整體了解了一下項目目前的需求和設計,以及進度。就挑了一個模塊詢問他們的變更情況,這個模塊是一個關鍵詞匹配功能。結果是領導看了他們的頁面之后,嫌信息量太少,就要求提供一些更細化的數據展示。開發人員問我有什么意見,我就簡單講了一下頁面大概怎么構建。其中有一個點,是用于變更數據范圍,即查詢的表變更,我一開始覺得使用下拉框就可以,產生了一些意見。有人建議分為不同子模塊,或者tab頁,或者分為多塊并列展示。我想了想,就給他們講了我認為幾種方案的優點缺點及適用范圍。

     

    1.       多塊并行展示:

    多個不同范圍的數據在同一頁面中分為不同區域以相同形式展示。原因是由于多塊數據之間有一定的關聯因果關系,或值得對比。適用范圍:如購物網站中的多個物品比較。

    2.       Tab頁:

    同一個頁面的多個tab頁,表示多個tab頁中的數據可能在一定的領域概念之下有一定的關聯,但關聯度不強。因為tab頁更重要的是強調一個同步工作的狀態,即A tab頁查看一定信息,會打開B tab頁查看其他信息,中途還會切回A tab頁。適用范圍:如郵箱中,收件箱和草稿箱。

    3.       下拉框

    下拉框作為查詢條件的一部分,常用于有著常規或固定的可選擇內容中(如性別,月份),更多是以過濾的形態出現,即下拉框更適合針對某表的某個字段過濾,如果針對的是數據范圍或是對用戶需要直觀了解的重要業務條件則不太合適。適用范圍:如在考試成績中使用下拉框過濾“男女”或“及格不及格”。

    4.       單選框

    單選框與下拉框的作用范圍相似,但是不同之處在于將被選項全部展示,目的在于能夠讓用戶清楚的了解當前數據顯示的實際范圍或條件,以及備選的其他范圍或條件。更適用于選項與實際業務及當前展示數據關系重要,不同選項可能會引發用戶的不同行為。適用范圍:如銀行系統顯示了當前用戶下綁定多個帳號時,使用單選框。

     

    經過上述討論,我們仔細分析了這個模塊中用戶的實際需求,以及可能后續操作,最終選擇的單選框的方案。

    目前還沒有后續,但是我想我們基于用戶真是需求的挖掘和后續操作的認真分析,會讓我們在與領導進行需求討論的時候有更加充分合理的依據。

    回來之后我又看了看淘寶的搜索頁面,比如就搜索“鞋子”來講,將品牌這欄設置為單選和下拉將是完全不同的效果,而確定方案的理由則是對于用戶的需求和實際行為的深入研究。這個應該是需求分析和調研的結果。將搜索條件以tag的形式標注于頁面上,并且可以直接點擊X按鈕進行刪除,我覺得更加可以傾向為用戶體驗。滿足并充分考慮了用戶實際需求的是好的需求分析,能夠簡化并引導用戶行為的是好的用戶體驗。

    當我們面臨的系統感覺非常難用的時候,往往這時候并非是用戶體驗差,我們應該檢討的是我們對用戶需求有沒有好好挖掘,做出來的是不是用戶想要、用戶能用的系統。

    posted @ 2012-05-22 05:02 一酌散千憂 閱讀(265) | 評論 (0)編輯 收藏

    Zookeeper的核心概念:

    ZNode

    Znode就是核心結構,Zookeeper服務中是由大量的Znode構成。Znode一般是由客戶端建立和修改,作為信息或標志的載體,甚至本身就是標志。

    Znode可以設置為持久(PERSISTENT)或臨時(EPHEMERAL),區別在于臨時的節點若斷開連接后就自動刪除。建立節點時可選擇是否使用序列號命名(SEQUENTIAL),若啟用則會自動在節點名后加入唯一序列編號。

    Session

    作為客戶端和Zookeeper服務之間交互的憑證。

    Watch

    當客戶端對節點信息進行查詢操作之后,可以選擇是否設置一個Watch。其作用就是當本次查詢的數據在服務器端發生變化之后,會對設置Watch的客戶端發送通知。一次發送之后,就將刪除該Watch,以后的變更或不再設置Watch則不會通知。

    ACLs

    節點的權限限制使用ACL,如增刪改查操作。

    Zookeeper的服務器安裝:

    1、下載對應版本號的tar.gz文件

    2、使用 tar xzvf zookeeper-3.4.2.tar.gz -C ./ 解壓

    3、設置,將conf/zoo.example.cfg復制到conf/zoo.cfg或者手動建立一個新的。

    4、啟動Zookeeper服務:bin/zkServer.sh start

    5、啟動客戶端連接:bin/zkCli.sh -server 127.0.0.1:2181(此處在本機,且使用了默認端口,且在Java環境中)

    6、使用命令:ls、get、set等。

    7、關閉Zookeeper服務:bin/zkServer.sh stop

    Zookeeper代碼編寫:

    代碼編寫部分比較簡單,因為暴露的接口很少,主要復雜在于項目如何使用節點以及節點信息。

    啟動Zookeeper服務之后,客戶端代碼進行節點的增刪,Watch的設置,內容的改查等。

    此處建議查看官方的《Programming with ZooKeeper - A basic tutorial》部分,當中舉了兩個例子來模擬分布式系統的應用。

    代碼基本沒有問題,唯一需要注意的就是:若之間按照原版進行調試時,有可能在調用

     Stat s = zk.exists(root, false);

    這句代碼時會出現一個異常,當中包括“KeeperErrorCode = ConnectionLoss for”。

    這個問題引起的原因可以看一下代碼

                    System.out.println("Starting ZK:");
                    zk 
    = new ZooKeeper(address, 3000this);
                    mutex 
    = new Integer(-1);
                    System.out.println(
    "Finished starting ZK: " + zk);

    最后一行有打印出Zookeeper目前的信息,若未修改的原代碼,此處的State應當是CONECTING。連接中的時候去驗證是否存在節點會報錯。解決的方法也很簡單,就是等到Zookeeper客戶端以及完全連接上服務器,State為CONECTED之后再進行其他操作。給出代碼示例:

    // 使用了倒數計數,只需要計數一次
    private CountDownLatch connectedSignal = new CountDownLatch(1); 
    SyncPrimitive(String address) {
        
    if(zk == null){
            
    try {
                System.out.println(
    "Starting ZK:");
                zk 
    = new ZooKeeper(address, 3000this);
                mutex 
    = new Integer(-1);
                connectedSignal.await(); 
    // 等待連接完成
                System.out.println("Finished starting ZK: " + zk);
            } 
    catch (IOException e) {
                System.out.println(e.toString());
                zk 
    = null;
            } 
    catch (InterruptedException e) {
                
    // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        
    //else mutex = new Integer(-1);
    }
    synchronized public void process(WatchedEvent event) {
        
    // 此處設立在Watch中會在狀態變化后觸發事件
        if (event.getState() == KeeperState.SyncConnected) {
            connectedSignal.countDown();
    // 倒數-1
        }
        
            
    synchronized (mutex) {
                
    //System.out.println("Process: " + event.getType());
                mutex.notify();
            }
    }

    這樣就可以正確運行代碼了。

    Zookeeper的應用場景及方式:

    此處是為引用,原地址為(http://rdc.taobao.com/team/jm/archives/1232 

    ZooKeeper是一個高可用的分布式數據管理與系統協調框架。基于對Paxos算法的實現,使該框架保證了分布式環境中數據的強一致性,也正是基于這樣的特性,使得zookeeper能夠應用于很多場景。網上對zk的使用場景也有不少介紹,本文將結合作者身邊的項目例子,系統的對zk的使用場景進行歸類介紹。 值得注意的是,zk并不是生來就為這些場景設計,都是后來眾多開發者根據框架的特性,摸索出來的典型使用方法。因此,也非常歡迎你分享你在ZK使用上的奇技淫巧。

    場景類別

    典型場景描述(ZK特性,使用方法)

    應用中的具體使用

    數據發布與訂閱

    發布與訂閱即所謂的配置管理,顧名思義就是將數據發布到zk節點上,供訂閱者動態獲取數據,實現配置信息的集中式管理和動態更新。例如全局的配置信息,地址列表等就非常適合使用。

    1. 索引信息和集群中機器節點狀態存放在zk的一些指定節點,供各個客戶端訂閱使用。2. 系統日志(經過處理后的)存儲,這些日志通常2-3天后被清除。 

    3. 應用中用到的一些配置信息集中管理,在應用啟動的時候主動來獲取一次,并且在節點上注冊一個Watcher,以后每次配置有更新,實時通知到應用,獲取最新配置信息。

    4. 業務邏輯中需要用到的一些全局變量,比如一些消息中間件的消息隊列通常有個offset,這個offset存放在zk上,這樣集群中每個發送者都能知道當前的發送進度。

    5. 系統中有些信息需要動態獲取,并且還會存在人工手動去修改這個信息。以前通常是暴露出接口,例如JMX接口,有了zk后,只要將這些信息存放到zk節點上即可。

    Name Service

    這個主要是作為分布式命名服務,通過調用zk的create node api,能夠很容易創建一個全局唯一的path,這個path就可以作為一個名稱。

     

    分布通知/協調

    ZooKeeper中特有watcher注冊與異步通知機制,能夠很好的實現分布式環境下不同系統之間的通知與協調,實現對數據變更的實時處理。使用方法通常是不同系統都對ZK上同一個znode進行注冊,監聽znode的變化(包括znode本身內容及子節點的),其中一個系統update了znode,那么另一個系統能夠收到通知,并作出相應處理。

    1. 另一種心跳檢測機制:檢測系統和被檢測系統之間并不直接關聯起來,而是通過zk上某個節點關聯,大大減少系統耦合。2. 另一種系統調度模式:某系統有控制臺和推送系統兩部分組成,控制臺的職責是控制推送系統進行相應的推送工作。管理人員在控制臺作的一些操作,實際上是修改了ZK上某些節點的狀態,而zk就把這些變化通知給他們注冊Watcher的客戶端,即推送系統,于是,作出相應的推送任務。 

    3. 另一種工作匯報模式:一些類似于任務分發系統,子任務啟動后,到zk來注冊一個臨時節點,并且定時將自己的進度進行匯報(將進度寫回這個臨時節點),這樣任務管理者就能夠實時知道任務進度。

    總之,使用zookeeper來進行分布式通知和協調能夠大大降低系統之間的耦合。

    分布式鎖

    分布式鎖,這個主要得益于ZooKeeper為我們保證了數據的強一致性,即用戶只要完全相信每時每刻,zk集群中任意節點(一個zk server)上的相同znode的數據是一定是相同的。鎖服務可以分為兩類,一個是保持獨占,另一個是控制時序。 

    所謂保持獨占,就是所有試圖來獲取這個鎖的客戶端,最終只有一個可以成功獲得這把鎖。通常的做法是把zk上的一個znode看作是一把鎖,通過create znode的方式來實現。所有客戶端都去創建 /distribute_lock 節點,最終成功創建的那個客戶端也即擁有了這把鎖。

    控制時序,就是所有視圖來獲取這個鎖的客戶端,最終都是會被安排執行,只是有個全局時序了。做法和上面基本類似,只是這里 /distribute_lock 已經預先存在,客戶端在它下面創建臨時有序節點(這個可以通過節點的屬性控制:CreateMode.EPHEMERAL_SEQUENTIAL來指定)。Zk的父節點(/distribute_lock)維持一份sequence,保證子節點創建的時序性,從而也形成了每個客戶端的全局時序。

     

    集群管理

    1. 集群機器監控:這通常用于那種對集群中機器狀態,機器在線率有較高要求的場景,能夠快速對集群中機器變化作出響應。這樣的場景中,往往有一個監控系統,實時檢測集群機器是否存活。過去的做法通常是:監控系統通過某種手段(比如ping)定時檢測每個機器,或者每個機器自己定時向監控系統匯報“我還活著”。 這種做法可行,但是存在兩個比較明顯的問題:1. 集群中機器有變動的時候,牽連修改的東西比較多。2. 有一定的延時。 

    利用ZooKeeper有兩個特性,就可以實時另一種集群機器存活性監控系統:a. 客戶端在節點 x 上注冊一個Watcher,那么如果 x 的子節點變化了,會通知該客戶端。b. 創建EPHEMERAL類型的節點,一旦客戶端和服務器的會話結束或過期,那么該節點就會消失。

    例如,監控系統在 /clusterServers 節點上注冊一個Watcher,以后每動態加機器,那么就往 /clusterServers 下創建一個 EPHEMERAL類型的節點:/clusterServers/{hostname}. 這樣,監控系統就能夠實時知道機器的增減情況,至于后續處理就是監控系統的業務了。
    2. Master選舉則是zookeeper中最為經典的使用場景了。

    在分布式環境中,相同的業務應用分布在不同的機器上,有些業務邏輯(例如一些耗時的計算,網絡I/O處理),往往只需要讓整個集群中的某一臺機器進行執行,其余機器可以共享這個結果,這樣可以大大減少重復勞動,提高性能,于是這個master選舉便是這種場景下的碰到的主要問題。

    利用ZooKeeper的強一致性,能夠保證在分布式高并發情況下節點創建的全局唯一性,即:同時有多個客戶端請求創建 /currentMaster 節點,最終一定只有一個客戶端請求能夠創建成功。

    利用這個特性,就能很輕易的在分布式環境中進行集群選取了。

    另外,這種場景演化一下,就是動態Master選舉。這就要用到 EPHEMERAL_SEQUENTIAL類型節點的特性了。

    上文中提到,所有客戶端創建請求,最終只有一個能夠創建成功。在這里稍微變化下,就是允許所有請求都能夠創建成功,但是得有個創建順序,于是所有的請求最終在ZK上創建結果的一種可能情況是這樣: /currentMaster/{sessionId}-1 , /currentMaster/{sessionId}-2 , /currentMaster/{sessionId}-3 ….. 每次選取序列號最小的那個機器作為Master,如果這個機器掛了,由于他創建的節點會馬上小時,那么之后最小的那個機器就是Master了。

    1. 在搜索系統中,如果集群中每個機器都生成一份全量索引,不僅耗時,而且不能保證彼此之間索引數據一致。因此讓集群中的Master來進行全量索引的生成,然后同步到集群中其它機器。2. 另外,Master選舉的容災措施是,可以隨時進行手動指定master,就是說應用在zk在無法獲取master信息時,可以通過比如http方式,向一個地方獲取master。

    分布式隊列

    隊列方面,我目前感覺有兩種,一種是常規的先進先出隊列,另一種是要等到隊列成員聚齊之后的才統一按序執行。對于第二種先進先出隊列,和分布式鎖服務中的控制時序場景基本原理一致,這里不再贅述。 

    第二種隊列其實是在FIFO隊列的基礎上作了一個增強。通常可以在 /queue 這個znode下預先建立一個/queue/num 節點,并且賦值為n(或者直接給/queue賦值n),表示隊列大小,之后每次有隊列成員加入后,就判斷下是否已經到達隊列大小,決定是否可以開始執行了。這種用法的典型場景是,分布式環境中,一個大任務Task A,需要在很多子任務完成(或條件就緒)情況下才能進行。這個時候,凡是其中一個子任務完成(就緒),那么就去 /taskList 下建立自己的臨時時序節點(CreateMode.EPHEMERAL_SEQUENTIAL),當 /taskList 發現自己下面的子節點滿足指定個數,就可以進行下一步按序進行處理了。

     

    posted @ 2012-05-15 11:02 一酌散千憂 閱讀(4835) | 評論 (0)編輯 收藏

    MongoDB介紹

    當今NoSQL領域中有很多有力的競爭者通過多種方式來處理海量數據問題。其中重要的解決方案之一就是MongoDB。MongoDB是面向文檔的弱結構化存儲方案,使用JSON格式來展現、查詢和修改數據。

    MongoDB文檔相當完備,擴展規模與安裝一樣簡單。它提供冗余、切片、索引以及map/reduce等概念支持。MongoDB的開源社區非常大且非常活躍。MongoDB在很多大型產品中被實際運用,如:Disney, Craigslist, Foursquare, Github 和SourceForge。MongoDB是一個開源項目,由10gen.com建立并維護,該公司由DoubleClick的前任執行人員創立。同時,10gen也提供了極好的商業支持與參與建設。

    MongoDB NoSQL: 缺陷與優勢

    MongoDB作為一個可用NoSQL方案具有很多優勢。我剛開始接觸NoSQL數據庫了解了一系列基于Java的方案,并且花了大量的時間來弄懂什么是列家族,Hadoop與HBase的關系,ZooKeeper到底是什么。當我終于全部清楚之后,發現Cassandra與HBase確實是對于NoSQL領域非常可靠、可信賴的解決方案。但與其他的解決方案相比,MongoDB讓我在能夠開始寫代碼之前,不用理解那么多的概念。

    與其他軟件相似,MongoDB也存在缺陷。經過一段時間使用MongoDB,我列舉經歷過并需要注意的一些事情,我成為“Gotchas”:

    • 不要按照關系型數據庫來思考。這很明顯,MongoDB使得構建和執行復雜查詢變得非常容易。當實際使用的時候,你會主要關注于效率問題(像我一樣)。
    • MongoDB的索引是二進制的樹。如果你不是很熟悉B-tree,可能需要了解一下。這些都涉及到構建符合提供查詢條件需求的建立索引的方式。
    • 小心的設計索引結構。這涉及到上面提到的B-tree。剛開始我的索引包含文檔中的很多字段,以防我會使用到他們。不要犯同樣的錯誤。我有一個很小集合的索引(大約1千萬記錄)增長到超過17GB的空間,比集合本身還大。你應該不會想要索引一個包含成百上千個實體的列表字段。
    • MongoDB采用了非常有意思的方式來實現NoSQL:采用BSON作為存儲,JSON作為展示,JavaScript用于管理和Map/Reduce。因此也引起了一些小問題比如這個 (破壞了Number和Long的相等操作),在MongoDB逐漸流行之后,可能會不斷的展示出來。

     

    MongoDB, 命令行與驅動

    MongoDB基本是使用JavaScript客戶端命令行程序來進行復雜任務管理的,如數據整合和簡單信息處理,編程都是完全使用JavaScript語言來的。本文中,我們會展示命令行的使用示例。現在有大量的MongoDB客戶端產品提供,并且由MongoDB社區來支持驅動。通常每種編程語言都有驅動,并且所有流行的語言都有包括,一些不那么流行的也包含在內。這篇文章展示了使用MongoDB的Java驅動,并使用一個ORM庫(MJORM)與之進行比較。

    介紹 MJORM: MongoDBORM方案

    在解決的眾多有意思的問題中,最近NoSQL數據存儲在開發者中主要的問題趨勢就是對象關系映射。對象關系映射就是將傳統中保存在關系型數據庫中的持久化數據映射為在應用程序中使用的對象。這使得編程語言使用起來更加流暢和自然。

    MongoDB面向文檔的架構使得它非常適合對象關系映射,因為文檔本身就是以對象形式存儲的。可惜沒有太多的MongoDB的Java對象關系映射庫,但是還是有一些,如morphia-(A type-safe Java library for MongoDB) spring-data(SpringData項目的MongoDB實現)

    這些ORM庫大量使用了注解,因為一些原因對我不適合,其中最重要的就是這些被注解的對象在多個項目中的兼容性問題。這讓我開始了mongo-Java-orm 或者 "MJORM" (發音 me-yorm)項目,一個MongoDB的Java對象關系映射項目。MJORM是在MIT許可之下,并且在發布在了google code project。項目采用maven構建,并且maven構件倉庫托管于google code版本控制服務器。MJORM的最新可用發布版本為0.15,已經由一些項目使用與生產環境中。

    開始使用ORM

    加入MJORM

    Maven的使用者首先應當在pom.xml中加入MJORM的maven倉庫,使得MJORM構件可用。

    <repository>
             <id>mjorm-webdav-maven-repo</id>
             <name>mjorm maven repository</name>
             <url>http://mongo-Java-orm.googlecode.com/svn/maven/repo/</url>
             <layout>default</layout>
    </repository>

    然后加入依賴:

    <dependency>
             <groupId>com.googlecode</groupId>
             <artifactId>mongo-Java-orm</artifactId>
             <version>0.15</version>
    </dependency>

    這樣就可以在應用中引入MJORM代碼。假如沒有使用maven,則你需要手動下載MJORM的pom.xml中列舉的所有依賴。

    建立 POJOs

    依賴已經導入,可以開始編碼了。我們從POJO開始:

     
    class Author {
             private String firstName;
             private String lastName;
             // ... setters and getters ...
    }
     
    class Book {
             private String id;
             private String isbn;
             private String title;
             private String description;
             private Author author;
             // ... setters and getters ...
    }

    我們在這個對象模型中的描述是,作者有ID、姓和名,書有ID、ISNB、標題、描述和作者。

    你可能注意到書的id屬性是一個字符串,這是為了適應MongoDB的對象ID類型。MongoDB的ID是一個12字節的二進制值顯示為一個十六進制的字符串。MongoDB要求集合中的每個文檔都必須有一個唯一id,但不要求一定要是ObjectId。目前MJORM只支持ObjectId,并且顯示為字符串。

    你也可能注意到了Author沒有id字段。這是因為Book是它的父文檔,因此不需要有id。記住,MongoDB只要求集合中的文檔在根級別的id。

    創建XML映射文件

    下一個步驟就是建立XML映射文件,MJORM能夠將MongoDB文檔轉換為對象。我們為每個文檔創建一個對象作為示范,無論將所有的映射放在一個XML文件中還是分開都是可以的。

    Author.mjorm.xml:

    <?xml version="1.0"?>
    <descriptors>
             <object class="Author">
                     <property name="firstName" />
                     <property name="lastName" />
             </object>
    </descriptors>

    Book.mjorm.xml:

    <?xml version="1.0"?>
    <descriptors>
             <object class="Book">
                     <property name="id" id="true" auto="true" />
                     <property name="isbn" />
                     <property name="title" />
                     <property name="description" />
                     <property name="author" />
             </object>
    </descriptors>

     

    這些映射文件能夠很好的自解釋。descriptors 元素是根元素,必須包含在每個映射文件中。在它下面是object元素定義了文檔與之對應的類。Object包含的property 元素主要用于描述POJO中的屬性以及這些屬性如何與MongoDB中的文檔想對應。property 元素至少必須包含一個name 屬性,這個元素就是POJO和MongoDB的文檔中的屬性名稱。column 屬性則是可選的,用于特定一個在MongoDB文檔中的可選屬性名稱。

    property 元素當中的id屬性應該是對象的唯一識別。一個對象只能有一個property 元素包含id屬性。auto 的設置會使得MJORM在持久化時為該屬性自動生成一個值。

    可以在google code的MJORM項目主頁中查看XML映射文件的更多細節描述。

    整合POJOXML

    我們創建了數據模型以及映射文件,使得MJORM可以從MongoDB序列號以及反序列號POJO。我們可以進行一些有意思的事情了,首先打開MongoDB的鏈接:

    Mongo mongo = new Mongo(
             new MongoURI("mongodb://localhost/mjormIsFun")); // 10gen driver

    Mongo 對象是由10gen編寫的Java驅動提供的。示例中連接了一個本地的MongoDB實例中的mjormIsFun數據庫。接下來我們創建MJORM ObjectMapper 。目前ObjectMapper 在MJORM中的唯一實現就是XmlDescriptorObjectMapper,使用XML結構描述信息。可能之后會增加對注解或其他結構定義的支持。

    XmlDescriptorObjectMapper objectMapper = new XmlDescriptorObjectMapper();
    mapper.addXmlObjectDescriptor(new File("Book.mjorm.xml"));
    mapper.addXmlObjectDescriptor(new File("Author.mjorm.xml"));

    建立好了XmlDescriptorObjectMapper 并且加入了映射文件。接下來建立由MJORM提供的MongoDao 對象的實例。

    DB db = mongo.getDB("mjormIsFun"); // 10gen driver
    MongoDao dao = new MongoDaoImpl(db, objectMapper);

    首先我們要獲得10gen驅動提供的DB對象實例。然后使用DB和ObjectMapper 建立MongoDao 。我們準備開始持久化數據,建立一個Book 然后保存到MongoDB中。

    Book book = new Book();
    book.setIsbn("1594743061");
    book.setTitle("MongoDB is fun");
    book.setDescription("...");
     
    book = dao.createObject("books", book);
    System.out.println(book.getId()); // 4f96309f762dd76ece5a9595

    首先建立Book 對象并且填值,然后調用MongoDao 的 createObject 方法,將Book 對象傳入"books" 的集合中。MJORM會按照之前的xml映射文件將Book 轉換為DBObject (這是10gen的Java驅動使用的基本類型),并保存一個新的文檔進"books" 集合。MJORM返回Book對象時,id屬性會被填充。請注意,MongoDB默認是不需要在使用前建立數據庫或集合的,系統會在需要時自動創建,這可能會造成某些困擾。在MongoDB的命令行中查看Book對象大概如下:

    > db.books.find({_id:ObjectId("4f96309f762dd76ece5a9595")}).pretty()
    {
             "_id":          ObjectId("4f96309f762dd76ece5a9595"),
             "isbn":         "1594743061",
             "title":        "MongoDB is fun",
             "description": "..."
    }

     

    我們來看看假如不用MJORM而直接使用10gen的Java驅動,如何使用createObject 方法:

    Book book = new Book();
    book.setIsbn("1594743061");
    book.setTitle("MongoDB is fun");
    book.setDescription("...");
     
    DBObject bookObj = BasicDBObjectBuilder.start()
             .add("isbn",              book.getIsbn())
             .add("title",             book.getTitle())
             .add("description",       book.getDescription())
             .get();
     
    // 'db' is our DB object from earlier
    DBCollection col = db.getCollection("books");
    col.insert(bookObj);
     
    ObjectId id = ObjectId.class.cast(bookObj.get("_id"));
    System.out.println(id.toStringMongod()); // 4f96309f762dd76ece5a9595

     

    下面進行對象的查詢:

    Book book = dao.readObject("books", "4f96309f762dd76ece5a9595", Book.class);
    System.out.println(book.getTitle()); // "MongoDB is fun"

    readObject 方法根據給定文檔的id從指定的集合中讀取文檔,轉換為對象(再次使用映射文件)并返回。

    敏銳的讀者會注意到Book還沒有指定Author,仍然保存了。這歸咎于MongoDB的結構不敏感的特性。我們不能要求集合中的文檔包含所有屬性(id屬性是必須的),所有在MongoDB中沒有Author的Book是可以的。我們現在為Book添加一個Author并且更新一下:

    Author author = new Author();
    author.setFirstName("Brian");
    author.setLastName("Dilley");
     
    book.setAuthor(author);
     
    dao.updateObject("books", "4f96309f762dd76ece5a9595", book);

    現在Book就包含了Author,并且在MongoDB中持久化了。現在在命令行查看了Book:

    > db.books.find({_id:ObjectId("4f96309f762dd76ece5a9595")}).pretty()
    {
             "_id":          ObjectId("4f96309f762dd76ece5a9595"),
             "isbn":         "1594743061",
             "title":        "MongoDB is fun",
             "description": "..."
             "author": {
                 "firstName": "Brian",
                 "lastName": "Dilley"
             }
    }

    可以看到持久化的Book中已經包含了author。不使用MJORM來操作一遍:

    Author author = new Author();
    author.setFirstName("Brian");
    author.setLastName("Dilley");
     
    book.setAuthor(author);
     
    DBObject bookObj = BasicDBObjectBuilder.start()
             .add("isbn",              book.getIsbn())
             .add("title",             book.getTitle())
             .add("description",       book.getDescription())
             .push("author")
                     .add("firstName",         author.getFirstName())
                     .add("lastName",  author.getLastName())
                     .pop()
             .get();
     
    DBCollection col = db.getCollection("books");
    col.update(new BasicDBObject("_id", bookObj.get("_id")), bookObj);
     

     

    對于MongoDao 方法的深入討論已經超出了本文的范圍。對于將MJORM有興趣用于實際項目中的用戶強烈建議了解一下MJORM項目提供的相關文檔,或者MongoDao 接口提供的相關用法。

    總結

    希望這篇文章對MongoDB和MJORM的亮點有所展示。MongDB是一個優秀的呃NoSQL數據存儲,有著大量優秀的特性,會是NoSQL市場中長期競爭者。若你會在一個Java項目中使用MongoDB,希望你也能夠考慮使用MJORM作為你的ORM框架。十分歡迎大家提交特性需求、錯誤異常報告、文檔和源碼修正。

     

    作者 Bio

    Brian Dilley 是一個經驗豐富的高級工程師以及項目領導,在Java/Java EE /Spring Framework/Linux內部結構理解和管理有著超過13年的經驗。Brian對于創業公司有很多經驗,推向市場,構建/維護產品等。他是IaascloudPHPLinux的專家,熟悉產品的采購、安裝及配置定義,以及公司的軟硬件架構包括負載均衡、數據庫、微博等。可以follow Brian Twitter

    posted @ 2012-05-09 13:46 一酌散千憂 閱讀(1545) | 評論 (0)編輯 收藏

    “企業信息集成(EII):實用方式”于2005年發布,描述了一套集成不同數據源的方法論,利用了當時的先進技術,如面向服務架構(SOA)、Web ServicesXML、資源描述架構(RDF)、基于XML的元數據格式以及數據提取、轉換和加載(ETL)。EII能夠基本為關系型數據元素提供統一視角,但在性能效率上缺乏能夠替代數據倉庫和多維數據庫的能力。五年之后技術已經得到了顯著提升,不僅在于對于分散數據的操作,還有簡化了單一容器下不同數據的整合,以及對數據深入挖掘的能力。

    轉變了數據管理方式的技術正是虛擬化。低成本存儲、云計算、NoSQL數據庫以及Hadoop。當我們提起虛擬化時,已經遠遠超出為一臺物理機器提供一套軟件實例這一概念。時至今日,我們可以虛擬化服務器、存儲以及網絡。所有這些虛擬化意味著我們不再被這些物理條件所限制,能夠迅速構建物理環境以支持我們特定時刻的特定需求。當面對GbTbPb等級數據量的處理需求時,我們基本能擺脫結構化的數據倉庫。我們不在需要僅僅為了發掘業務的某一方面而建立一個特殊的環境了。

    低成本存儲在業務的數據存儲方面節省了開支。高昂的存儲成本會使得企業尋找在限定規模的數據之上進行關鍵業務分析的方案,這樣使得如何選擇最重要的數據變得十分關鍵,而且還限制了系統能夠處理的數據的質量。

    負面影響便是業務最終可能面臨很少的選擇,因為沒有足夠的歷史數據提供從而識別一個有效關鍵模式。或者因為高昂的投入使得業務被停止,而使用常規慣例來識別模式。

    云計算為那些需要通過海量數據源在合理時間范圍內產生結果的需求提供了一個可用的方式。海量數據處理需要兩點:彈性存儲,CPU。高速網絡很有幫助,但是待會我們會看到在發掘軟件在處理海量數據時,它并非是系統的瓶頸。彈性存儲意味著企業不會在期望操作的數據規模或類型上受到限制,降低了使用數據倉庫無法獲取最佳結果的風險。更多的CPU使得結果能夠在期望的時間范圍內更快的被交付。

    NoSQL提供了海量數據的支持,但與傳統的關系型數據庫沒有關聯。而且大部分NoSQL數據庫是開源的,無須支付購買證書等費用。NoSQL對于表結構有著驚人的靈活性,無須隨著系統的改進而不斷修改完善定義。NoSQL可以支持不同數據源的合并查看,從而成為EII之后另一個備選方案,這或許是NoSQL最重要的方面了。

    NoSQL內置了數據冗余與分布式數據存儲機制。海量數據的最大問題之一就是磁盤讀寫,NoSQL通過將數據分布至一系列節點來緩解這個問題。當一個查詢請求發出時,這些節點能夠并行查詢自身節點,而不是僅僅依靠一塊磁盤,一個磁盤陣列或一條網絡連接等,數據查詢能夠在節省了讀寫開支之后變得更加迅速。

    最終,我們來討論Hadoop,集合了上述所有技術力量與一身的用于檢測和分析數據的框架。有些人可能認為Hadoop是一項NoSQL技術,實際上Hadoop是一個分布組件的java框架,用于分解“吃大象”(此處也雙關Hadoop是以創立者的兒子給自己的一個大象玩具起的名字)的工作——每次一口。

    Hadoop自身實際上與待處理數據是各自獨立的。它將大型查詢任務分解為小的并行查詢任務,然后收集結果,并整合出答案返回給用戶。Hadoop相對于NoSQL來說是一個并行查詢框架,通過云計算驅動節點,運行在低成本存儲及虛擬化技術之上。

    Kicking的知識回顧

    EII第一次作為最佳實踐出現于2003-2004年,關鍵要素就是無需再移動數據了。當時大部分的數據中心仍然運行于低速網絡中,有限的空間用于復制數據。之后,EII成為了當時可用技術和問題域中最優秀的解決方案。EII的某些方面的優秀即使在海量數據中也是很顯著的。

    EII的優點之一就是將處理過程轉移到數據所在地。海量數據方案的關鍵架構要素之一就是將處理過程轉移到數據所在地,而不是轉移數據。EII中的一個重要原則就是使用數據歸屬地的查詢功能。這項實踐就是構建靠近數據源網絡的Web Service,能夠建立起通用查詢接口,但只針對本地數據庫進行查詢。我們通過開放的基于Web的接口解決了數據的專有格式的問題,從而使得多個數據子集能夠迅速的整合并以統一模式展示。

    有了低成本存儲和10G網絡之后,我們就不必那么擔心數據冗余與數據遷移,但還是有其他問題存在的,數據倉庫無法確保數據的原始性便是其中之一。在EII中,我們將從原始數據源獲取數據視為“黃金準則”,這樣就能夠保證信息未被修改過,且是準確的。

    Big Data要求數據必須轉移到新的物理位置,這樣可信任度又成為了問題。EII的那些獲取基線數據的最佳實踐仍然是相關而且重要的。實際上,那些為EII設計開發的Web Services接口最終在Big Data的啟用中扮演主要角色。

    當然,討論數據管理不能不涉及到安全問題。EII在安全領域中還是超過了Big Data。技術上來說,Big Data在數據集成方面更加高效與敏捷,但是大部分缺少了固有的安全性,因為在設計上會加大處理的難度。所以,可能要由源系統來擔任起數據訪問安全方面的責任。因為EII直接在源系統中查詢數據,所以必須要求有適當的授權,否則查詢就將失敗。

    上述關于安全討論描述的是內在的安全控制情況。將訪問權限控制列表集成進數據庫是非常合理的,這將確保安全能夠作為查詢的一部分進行維護。然后,一旦能夠直接查詢NoSQL數據源,就意味著能夠自由的訪問你所有的數據。

    總結

    引用老的Virginia Slims的廣告中的臺詞:“我們已經歷很長的路途了,寶貝兒!”文中討論到的技術的發展已經對21世紀第二個10年中的的數據解決方案產生了巨大的影響。商業化與小型化掃除了一些思想體系上的障礙,使得架構師能夠專注于問題本身,而不是尋找一些實用及可實現的問題解決方案。構建10000個節點的處理引擎,能夠在數秒內處理Pb級別的數據量,卻只消耗每小時幾便士,這就是數據處理的美好前景。

    有了這些新工具,我們就要重新考慮如何推進數據管理。為何數據無法被很好地被維護整合,并且需要花費數萬美元。數據管理幾乎是每個大中型企業的心病。數據管理曾經在存儲、管理、訪問、整合以及查詢上花費巨大,但是今后不再會是這樣了。

    關于作者

    JP Morgenthal 是在IT策略與云計算方面的世界級專家之一。他在企業復雜問題域的解決方案實施上有著25年的經驗。JP Morgenthal以其在技術方面的深度和廣度,有利的支持他在企業問題域中的敏感度。他在集成、軟件開發和云計算是一位讓人尊敬的作者,同時也是InfoQ在引領云計算方面的編輯,并且參與了“云計算:評估風險”項目。 

     

    原文接:http://www.infoq.com/articles/DataIntegrationFromEIItoBigData

    posted @ 2012-04-19 07:15 一酌散千憂 閱讀(289) | 評論 (0)編輯 收藏

    項目經理(Project manager)是項目的支柱與核心,維基百科的定義:項目經理是項目管理方面的專家,負責項目的策劃、執行和結束,即整個生命周期過程。項目經理手中的“干將莫邪”便是軟件開發過程方法(software development process/software development life cycle (SDLC)),可能采取的有RUPRational Unified Process),敏捷等。

    其實軟件開發區分階段已經廣為大家接受,普遍的概念即需要區分為分析、設計、實施、測試、發布,過程中會產生若干產物,如需求說明書、概要設計、詳細設計等。若提及過程方法,如RUP的話,主要分為四大階段,先啟(Inception)、精華(Elaboration)、構建(Construction)、交付(Transition)迭代的開發方式,而Scrum的核心概念則是Sprint

     

    Maven在項目管理中有那些幫助呢?Maven能夠從一個信息中心為項目提供構建,報告,文檔編制等工作。在Maven官方介紹《What is maven》中介紹了maven的項目目標(Objectives)(http://maven.apache.org/what-is-maven.html),如下:

    l         簡化構建過程

    l         提供統一的構建系統

    l         提供項目質量信息

    l         提供對于開發最佳實踐的指導

    l         允許對于新特性的透明整合

     

    對于Maven影響最為深刻的就是它的構建系統,幾乎貫穿了整個實施階段。作為對比我們參考一下RUPConstruction階段,以及Scrum的單個Sprint過程。

     

    RUPConstruction階段的目標:

    這個階段的目標是澄清需求并基于架構基線完成開發。

    l          通過優化資源來縮減開支,并避免無意義的爭執與返工。

    l          實用性與質量兼具。

    l          盡快發布可用版本。

    l          完成對所有功能的分析、設計、開發、測試。

    l          采用增量迭代的模式完成開發并準備交付。

    l          檢查項目發布的所有資源是否已經準備完全。

    l          形成項目組之間的并行開發。

     

    在《硝煙中的ScrumXP》一書中,介紹了作者實施Scrum的過程。在一個Sprint中,不是只有Sprint backlogburn down chat等,實施過程中的敏捷思想也是其中的核心,我們來看看敏捷信奉的一部分最佳實踐:

    l          簡單設計(Simple Design

    l          結對編程(Pair Programming

    l          測試驅動(Test-Driven Development

    l          小規模發布(Small Releases

    l          持續集成(Continuous Integration

    l          集體擁有代碼(Collective Code Ownership

    l          編碼標準(Coding Standard

     

    Maven對于上述目標中的質量(實用性與質量,以測試驅動)、可用(可用版本,小規模)、資源管理等均能發揮較大的作用。主要是其定義了一套完整優秀的構建生命周期機制,其基本階段如下:

    l         validate驗證項目正確性及依賴有效性

    l         compile編譯項目源碼

    l         test使用合適的單元測試框架對編譯后的源碼進行測試,測試代碼不會被打包或發布

    l         package將編譯后的代碼以規定格式打包,如Jar

    l         integration-test將打包后的代碼放置于環境中進行集成測試

    l         verify檢查打包的有效性并驗證質量標準

    l         install將包裝載入本地倉庫,以提供與其他項目的依賴

    l         deploy將包發布至遠程倉庫中

    其上每一個階段實際都分為前中后三個階段,用戶可以定義在每一個階段前后進行自定義的操作,打造自己的構建流程(如在某個階段執行前制定特殊的配置文件,完成后再改回默認)。對于階段的實際使用方式,如:validate可以項目所有依賴有效,test可以針對dao層進行單元測試,intergration-test可以對完整業務流程或服務層等進行集成測試。

     

    在項目中實際使用的經驗,對于標簽的使用心得:

    1.<dependency> - 依賴標簽,最重要的標簽,也是Maven的基礎功能。

                  <dependency>

                         <groupId>junit</groupId>

                         <artifactId>junit</artifactId>

                         <version>4.8.1</version>

                         <scope>test</scope>

                  </dependency>

     

    2. <repository> - 資源倉庫,可以包含多個,常用的有MavenJboss等,如下是公司內建的Nexus資源庫。

    <repository>

                         <id>Suntang's Maven Repository</id>

                         <name>Suntang Nexus Repository</name>

                         <url>http://10.10.10.33:8081/nexus/content/groups/public</url>

                  </repository>

    3. <profile> - 解釋為情景模式可能較為合適。可以有多個,在何種場景下會使用哪些屬性、插件等。如下例子便是當缺失某個文件時激活。

    (感覺寫的不錯的一篇,http://blog.csdn.net/turkeyzhou/article/details/4894657

    <profile>

     <activation>

    <file>

    <missing>target/generated-sources/axistools/wsdl2java/org/apache/maven</missing>

    </file>

    </activation>

     </profile>

    4.<build> - 構建過程。是進行整個項目管理的核心標簽。重點需要掌握的知識就是生命周期。

    http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html#Lifecycle_Reference

    下面的例子就是制定了打包時的資源路徑,并且定義了最終打包的名稱。

     

           <build>

                  <resources>

                         <resource>

                                <directory>src/main/resources</directory>

                                <includes>

                                       <include>**/*</include>

                                </includes>

                         </resource>

                         <resource>

                                <directory>src/main/assembly</directory>

                                <includes>

                                       <include>**/*</include>

                                </includes>

                         </resource>

                  </resources>

     

                  <finalName>po</finalName>

           </build>

     

    4.< plugin > - 支持插件。如單元測試自動化,之前提到的Ant的插件等。若有某些功能覺得不順手,可以嘗試官網找一下有沒有合適的插件(http://maven.apache.org/plugins/index.html)。

    下面的例子就是在集成測試中,只運行后綴為TestSuitex.java的測試類

     

                         <plugin>

                                <groupId>org.apache.maven.plugins</groupId>

                                <artifactId>maven-surefire-plugin</artifactId>

                                <version>2.4.3</version>

                                <configuration>

                                       <junitArtifactName>junit:junit</junitArtifactName>

                                       <forkMode>once</forkMode>

                                </configuration>

                                <executions>

                                       <execution>

                                              <id>default-test</id>

                                              <phase>integration-test</phase>

                                              <goals>

                                                     <goal>test</goal>

                                              </goals>

                                              <configuration>

                                                     <skip>false</skip>

                                                     <includes>

                                                            <include>**/*TestSuitex.java</include>

                                                     </includes>

                                              </configuration>

                                       </execution>

                                </executions>

                         </plugin>

     

    posted @ 2012-04-06 14:48 一酌散千憂 閱讀(495) | 評論 (0)編輯 收藏

    環境背景:

    我作為項目經理和技術架構管理人員負責公司一條生產線。討論之后,首席架構師希望我們能夠實施TDD。在實施TDD的過程中,設計實施過程的整體思路就是:單元測試用例文檔 - 實施單元測試 - 實施業務代碼修改業務代碼邏輯。實施人員需要參與每個環節,按照規范編寫單元測試用例文檔。單元測試我們按照模塊(模塊與人員基本沒有重合)劃分包(suite),保證實施起來不會產生干擾。。技術架構決定采用:mavenjunitsvn

     

    技術背景:

    技術架構設計上,我們封裝了dao層的實現,所以實施人員基本無需涉及dao層的開發。服務層我們采用了JAX-RS的服務規范,對外開發服務接口。

    在測試覆蓋率方面,我們基本不要求對dao層的單元測試,但要求在服務層的單元測試達到100%。由于服務層是Restful WS的模式,所以我們采用了模擬HTTP請求的方式在測試服務層。

    由于需要模擬HTTP的請求,所以我們在單元測試中采用了jetty作為內嵌服務器,單元測試開始時同一啟動,完成后關閉。

     

    實施過程:

    開發過程中,實際實施的時候發現一個問題,對于測試數據的管理問題。即測試當中需要一定的數據環境來驗證業務邏輯。這個數據環境如何建立?

     

    方案一,使用dbunithsqldb。在測試啟動時重建數據環境。

    否決,原因:

    1.與實際運行環境差異較大。

    2.反復重建數據環境,效率上有缺失。

    3.技術架構增加,學習和維護曲線較大。

     

    討論后決定使用

    方案二,獨立出一套測試數據庫,完整數據環境。考慮到增刪改與查詢的沖突,制定默認規則,如id20之內的不允許進行任何改動。以盡量隔離增刪改的影響。

     

    針對方案二,有一個較大的問題,如何在開發過程中自由的切換數據庫配置呢?由于我們還是用了Hudson作為CI服務器,還要考慮到打包的過程。整體考慮之后,有兩個步驟需要注意:

    一、開發過程。開發過程中,我們將配置直接指向測試數據庫。

    二、打包過程。使用了maven,存在單元測試配置與最終產品配置的沖突。

    所以最終問題的焦點集中在打包過程的maven配置方案。

     

    搜索之后比較好的資料有

    MAVEN:如何為開發和生產環境建立不同的配置文件 --我的簡潔方案

    http://www.tkk7.com/scud/archive/2010/10/27/336326.html

    這篇博客是介紹在maven 中使用mvn package -P test 這樣的自定義profile來實現的。這樣是可行的,但是在Hudson中無法實現一條命令切換兩套配置。

    于是繼續尋找,最終在maven的官方網站找到《Building For Different Environments with Maven 2》(http://maven.apache.org/guides/mini/guide-building-for-different-environments.html)看完文章之后發現,實際maven提供了一個非常好的插件maven-antrun-plugin,以實現某些ant的功能。此處還需要了解的知識就是maven的構建生命周期標準(http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html)。基于上述兩個知識點,我們制定出如下方案,在項目中建立測試配置目錄及產品配置目錄,在mavenpackage階段開始前,都使用測試配置,運行集成測試,完成在package階段前將產品配置覆蓋至打包文件夾內,然后進行打包。思路就是這樣,下面貼出pom文件的關鍵部分。

     

     

    POM.xml

    <!—profile 節點定義覆蓋文件的方式內容 -->

           <profiles>

                  <profile>

                         <id>product</id>

                         <build>

                                <plugins>

                                       <plugin>

                                              <artifactId>maven-antrun-plugin</artifactId>

                                              <executions>

                                                     <execution>

                                                            <id>pre_product</id>

                                                            <phase>prepare-package</phase>

                                                            <goals>

                                                                   <goal>run</goal>

                                                            </goals>

                                                            <configuration>

    <!—此處與ant的任務相似 -->

                                                                   <tasks>

                                                                          <delete file="${project.build.outputDirectory}/spring/dataSourceContext.xml" />

                                                                          <delete file="${project.build.outputDirectory}/log4j.properties" />

                                                                          <copy file="src/product/assembly/log4j.properties" tofile="${project.build.outputDirectory}/log4j.properties" />

                                                                          <copy file="src/product/assembly/spring/dataSourceContext.xml" tofile="${project.build.outputDirectory}/spring/dataSourceContext.xml" />

                                                                   </tasks>

                                                            </configuration>

                                                     </execution>

                                              </executions>

                                       </plugin>

                                </plugins>

                         </build>

                  </profile>

           </profiles>

     

    <!—構建過程 -->

           <build>

    <!—指定資源目錄 -->

                  <resources>

                         <resource>

                                <directory>src/test/resources</directory>

                                <includes>

                                       <include>**/*</include>

                                </includes>

                         </resource>

                         <resource>

                                <directory>src/test/assembly</directory>

                                <includes>

                                       <include>**/*</include>

                                </includes>

                         </resource>

                  </resources>

     

                  <finalName>po</finalName>

     

    <!—指定集成測試配置 -->

                  <plugins>

                         <plugin>

                                <groupId>org.apache.maven.plugins</groupId>

                                <artifactId>maven-surefire-plugin</artifactId>

                                <version>2.4.3</version>

                                <configuration>

                                       <junitArtifactName>junit:junit</junitArtifactName>

                                       <forkMode>once</forkMode>

                                </configuration>

                                <executions>

                                       <execution>

                                              <id>default-test</id>

                                              <phase>integration-test</phase>

                                              <goals>

                                                     <goal>test</goal>

                                              </goals>

                                              <configuration>

                                                     <skip>false</skip>

                                                     <includes>

                                                            <include>**/*TestSuitex.java</include>

                                                     </includes>

                                              </configuration>

                                       </execution>

                                </executions>

                         </plugin>

                  </plugins>

           </build>

    posted @ 2012-04-05 11:26 一酌散千憂 閱讀(1750) | 評論 (0)編輯 收藏

         摘要: Nosql企業之道 http://www.infoq.com/articles/nosql-in-the-enterprise   介紹 作為一個企業架構師的好處,就是我一直在找一些新的有希望的概念或想法,能夠幫助我的企業用戶處理不同垂直行業之間的問題。甚至在NoSQL這個詞被杜撰(錯誤的杜撰?此處作者認為NoSQL這個詞并不恰當,后面會提到)出來之前,因為上述的原因我曾持續...  閱讀全文

    posted @ 2012-04-04 21:41 一酌散千憂 閱讀(372) | 評論 (0)編輯 收藏

    《Hadoop in action》Manning出版,磕磕絆絆總算是看完了。書的內容就不做介紹,主要講一下實踐的過程。并且在實踐過程中參考的書籍的部分也會簡單介紹。

    灰色背景部分為一些介紹,或過程中出現問題的描述,可以直接忽略。

    由于公司的業務需要,要在網絡收集網頁之后對網頁進行結構化的解析,這個結構化過程希望能夠基于HDFS并且使用MR算法實現。

    我虛擬了一個需求,針對http://hadoop.apache.org/common/releases.html 頁面,假設已經下載了頁面并入庫。要求最終體現的數據是 “版本號+完整鏈接(即a標簽全部內容)” 的結構。

     

    偽分布式環境搭建在虛擬機上,操作系統是centos5.5hadoop的版本是1.0.0.

     

    插入書中的一些環境搭建的介紹

    書中的2.1節中介紹了每個進程的作用。2.2節中的ssh設置也比較重要,否則好像會一直提示你輸入密碼。2.3.2節介紹了偽分布式的配置方式,對core-site.xmlmapred-site.xmlhdfs-site.xml進行配置之后,需要對namenode節點進行格式化。

    bin/hadoop namenode –format

     

    hadoop的根目錄為/usr/local/hadoop-1.0.0,直接啟動start-all.sh

     

    [root@localhost hadoop-1.0.0]# ./bin/start-all.sh

     

    啟動成功后使用jps命令

    jdk小工具jps介紹 

    jps(Java Virtual Machine Process Status Tool)JDK 1.5提供的一個顯示當前所有java進程pid的命令,簡單實用,非常適合在linux/unix平臺上簡單察看當前java進程的一些簡單情況。 jps存放在JAVA_HOME/bin/jps

     

    [root@localhost hadoop-1.0.0]# jps

    5694 SecondaryNameNode

    5461 NameNode

    5578 DataNode

    6027 Jps

    5784 JobTracker

    5905 TaskTracker

    這幾個進程是非常重要的。很多時候出現意外就是因為某項服務未啟動或異常。可以看到上面的命令上打印出日志位置。出現異常后可以在日志中查看詳細的堆棧信息。

     

    至此,hadoop已經啟動,環境已經準備就緒。

     

    下面準備我們的測試數據,將目標頁面的html保存為news.txt,偽分布式也同樣支持hdfs,所以我們使用 fs –put news.txt存入hdfs中。

    [root@localhost hadoop-1.0.0]# ./bin/hadoop fs -put /mnt/hgfs/shared/news.txt /user/root

    [root@localhost hadoop-1.0.0]# ./bin/hadoop fs -lsr /userdrwxr-xr-x   - root supergroup          0 2012-04-01 11:22 /user/root

    -rw-r--r--   1 root supergroup       3935 2012-04-01 11:22 /user/root/news.txt

     

    實現的代碼在eclipse中使用maven打包,上傳至虛擬機。

    文件名com.suntang.analyse.hadoop-0.0.1.jar
    使用hadoop的中的jar命令調用該jar文件。


    [root@localhost hadoop-1.0.0]# ./bin/hadoop jar com.suntang.analyse.hadoop-0.0.1.jar com.suntang.analyse.hadoop.AnalyseJob /user/root/news.txt output_root_test

    12/04/01 14:40:04 INFO input.FileInputFormat: Total input paths to process : 1

    12/04/01 14:40:05 INFO mapred.JobClient: Running job: job_201204011420_0001

    12/04/01 14:40:06 INFO mapred.JobClient:  map 0% reduce 0%

    12/04/01 14:40:19 INFO mapred.JobClient:  map 100% reduce 0%

    12/04/01 14:40:31 INFO mapred.JobClient:  map 100% reduce 100%

    12/04/01 14:40:37 INFO mapred.JobClient: Job complete: job_201204011420_0001

     

     

    此處注意我犯的一個錯誤:

    [root@localhost hadoop-1.0.0]# ./bin/hadoop jar com.suntang.analyse.hadoop-0.0.1.jar AnalyseJob -libjars hadoop-core-1.0.0.jar /user/root/news.txt output_root_test

    Exception in thread "main" java.lang.ClassNotFoundException: AnalyseJob

    提示找不到類,因為我忘了寫完整類名,命令應該改為

    ./bin/hadoop jar com.suntang.analyse.hadoop-0.0.1.jar com.suntang.analyse.hadoop.AnalyseJob -libjars hadoop-core-1.0.0.jar /user/root/news.txt output_root_test 即可。

     

    此處運行可能出現另外一個錯誤。在命令行中出現

    12/04/01 14:01:38 INFO mapred.JobClient: Task Id : attempt_201204011356_0001_m_000001_0, Status : FAILED

    java.lang.Throwable: Child Error

            at org.apache.hadoop.mapred.TaskRunner.run(TaskRunner.java:271)

    Caused by: java.io.IOException: Creation of symlink from /mnt/hgfs/shared/hadoop-1.0.0/libexec/../logs/userlogs/job_201204011356_0001/attempt_201204011356_0001_m_000001_0 to 。。。

    就不打全了,重點在與

    Creation of symlink,看詳細日志中hadoop-root-tasktracker-localhost.localdomain.log中提示org.apache.hadoop.fs.FileUtil: Command 'ln -s ....': Operation not supported,即ln操作不支持。google可知這個是由于vm中的共享區域的問題,解決方法就是將hadoop完全轉移至linux目錄中。本例中從/mnt/hgfs/shared/hadoop-1.0.0轉移至/usr/local/hadoop-1.0.0

     

    執行完成后可在hdfs中查看結果,查看目錄結構為

    -rw-r--r--   1 root supergroup          0 2012-04-01 14:40 /user/root/output_root_test/_SUCCESS

    drwxr-xr-x   - root supergroup          0 2012-04-01 14:40 /user/root/output_root_test/_logs

    drwxr-xr-x   - root supergroup          0 2012-04-01 14:40 /user/root/output_root_test/_logs/history

    -rw-r--r--   1 root supergroup      13634 2012-04-01 14:40 /user/root/output_root_test/_logs/history/job_201204011420_0001_1333262405103_root_ccAnalyseJob

    -rw-r--r--   1 root supergroup      20478 2012-04-01 14:40 /user/root/output_root_test/_logs/history/job_201204011420_0001_conf.xml

    -rw-r--r--   1 root supergroup       3580 2012-04-01 14:40 /user/root/output_root_test/part-r-00000

     

    /user/root/output_root_test/part-r-00000即為最終結果文件。

     

     =======================================================================

    附加AnalyseJob代碼

    package com.suntang.analyse.hadoop;

     

    import java.io.IOException;

     

    import org.apache.hadoop.conf.Configuration;

    import org.apache.hadoop.conf.Configured;

    import org.apache.hadoop.fs.Path;

    import org.apache.hadoop.io.LongWritable;

    import org.apache.hadoop.io.Text;

    import org.apache.hadoop.mapreduce.Job;

    import org.apache.hadoop.mapreduce.Mapper;

    import org.apache.hadoop.mapreduce.Reducer;

    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

    import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;

    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

    import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;

    import org.apache.hadoop.util.Tool;

    import org.apache.hadoop.util.ToolRunner;

     

    public class AnalyseJob extends Configured implements Tool {

     

           public static class MapClass extends Mapper<LongWritable, Text, Text, Text> {

     

                  @Override

                  protected void map(LongWritable key, Text value, Context context)

                                throws IOException, InterruptedException {

                        

                        

                         // TODO Auto-generated method stub

                         // super.map(key, value, context);

                         if (value.toString().matches("<a[^>]*>.*?release.*?</a>"))

                                context.write(

                                              new Text(value.toString().substring(

                                                            value.toString().indexOf("release") + 8,

                                                            value.toString().indexOf("available") - 1)),

                                              value);

                  }

     

           }

     

           public static class ReduceClass extends Reducer<Text, Text, Text, Text> {

     

                  @Override

                  protected void reduce(Text arg0, Iterable<Text> arg1, Context arg2)

                                throws IOException, InterruptedException {

                         // TODO Auto-generated method stub

                         // super.reduce(arg0, arg1, arg2);

                         arg2.write(arg0, arg1.iterator().next());

                  }

     

           }

     

           public int run(String[] args) throws Exception {

                  Configuration conf = getConf();

     

                  Job job = new Job(conf, "myAnalyseJob");

                  job.setJarByClass(getClass());

     

                  Path in = new Path(args[0]);

                  Path out = new Path(args[1]);

                  FileInputFormat.setInputPaths(job, in);

                  FileOutputFormat.setOutputPath(job, out);

     

                  job.setMapperClass(MapClass.class);

                  job.setReducerClass(ReduceClass.class);

     

                  job.setInputFormatClass(TextInputFormat.class);

                  job.setOutputFormatClass(TextOutputFormat.class);

                  job.setOutputKeyClass(Text.class);

                  job.setOutputValueClass(Text.class);

     

                  System.exit(job.waitForCompletion(true) ? 0 : 1);

     

                  return 0;

           }

     

           public static void main(String[] args) throws Exception {

                  int res = ToolRunner.run(new Configuration(), new AnalyseJob(), args);

                  System.exit(res);

           }

    }

    posted @ 2012-04-01 15:00 一酌散千憂 閱讀(915) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 100部毛片免费全部播放完整| 99999久久久久久亚洲| 久久久久亚洲av毛片大| 国产无遮挡吃胸膜奶免费看视频| 日韩一级视频免费观看| 手机看片久久国产免费| vvvv99日韩精品亚洲| 亚洲精品老司机在线观看| 亚洲中文字幕伊人久久无码| 久久久久一级精品亚洲国产成人综合AV区| 日产国产精品亚洲系列| 中文字幕亚洲专区| 亚洲AV无码一区二区乱孑伦AS| 久久亚洲精品成人AV| 亚洲一区二区三区播放在线| 天堂亚洲国产中文在线| 日韩成人精品日本亚洲| 一级毛片大全免费播放下载| 免费毛片在线看不用播放器| 18成禁人视频免费网站| 可以免费看的卡一卡二| 国产成人免费a在线视频app| 亚洲午夜精品久久久久久浪潮| 亚洲AV永久纯肉无码精品动漫| 亚洲国产美女在线观看| 久久亚洲色WWW成人欧美| eeuss免费影院| 久久w5ww成w人免费| 最近最好的中文字幕2019免费 | 久久九九久精品国产免费直播 | 亚洲精品无码aⅴ中文字幕蜜桃| 国产亚洲一卡2卡3卡4卡新区| www在线观看免费视频| 日韩在线永久免费播放| 成全影视免费观看大全二| 亚洲第一黄色网址| 亚洲午夜精品一区二区| 亚洲av无码兔费综合| 免费看黄的成人APP| 国内一级一级毛片a免费| 亚洲夜夜欢A∨一区二区三区|