本書結合理論和實踐,由淺入深,多方位介紹了Hadoop這一高性能的海量數據處理和分析平臺。全書5部分24章,第Ⅰ部分介紹Hadoop基礎知識,主題涉及Hadoop、MapReduce、Hadoop分布式文件系統、YARN、Hadoop的I/O操作。第Ⅱ部分介紹MapReduce,主題包括MapReduce應用開發;MapReduce的工作機制、MapReduce的類型與格式、MapReduce的特性。第Ⅲ部分介紹Hadoop的運維,主題涉及構建Hadoop集群、管理Hadoop。第Ⅳ部分介紹Hadoop相關開源項目,主題涉及Avro、Parquet、Flume、Sqoop、Pig、Hive、Crunch、Spark、HBase、ZooKeeper。第Ⅴ部分提供了三個案例,分別來自醫療衛生信息技術服務商塞納(Cerner)、微軟的人工智能項目ADAM(一種大規模分布式深度學習框架)和開源項目Cascading(一個新的針對MapReduce的數據處理API)。 本書是一本、的Hadoop參考書和工具書,闡述了Hadoop生態圈的發展和應用,程序員可以從中探索海量數據集的存儲和分析,管理員可以從中了解Hadoop集群的安裝和運維。
本書結合理論和實踐,由淺入深,多方位介紹了Hadoop 這一高性能的海量數據處理和分析平臺。全書5部分24 章,第Ⅰ部分介紹Hadoop 基礎知識,第Ⅱ部分介紹MapReduce,第Ⅲ部分介紹Hadoop 的運維,第Ⅳ部分介紹Hadoop 相關開源項目,第Ⅴ部分提供了三個案例,分別來自醫療衛生信息技術服務商塞納(Cerner)、微軟的人工智能項目ADAM(一種大規模分布式深度學習框架)和開源項目Cascading(一個新的針對MapReduce 的數據處理API)。本書是一本專業、的Hadoop 參考書和工具書,闡述了Hadoop 生態圈的新發展和應用,程序員可以從中探索海量數據集的存儲和分析,管理員可以從中了解Hadoop 集群的安裝和運維。
作者簡介
Tom White是最杰出的Hadoop專家之一。自2007年2月以來,Tom White一直是Apache Hadoop的提交者(committer),也是Apache軟件基金會的成員。Tom是Cloudera的軟件工程師,他是Cloudera的首批員工,對Apache和Cloudera做出了舉足輕重的貢獻。在此之前,他是一名獨立的Hadoop顧問,幫助公司搭建、使用和擴展Hadoop。他是很多行業大會的專題演講人,比如ApacheCon、OSCON和Strata。Tom在英國劍橋大學獲得數學學士學位,在利茲大學獲得科學哲學碩士學位。他目前與家人居住在威爾士。
譯者簡介
王海博士,解放軍理工大學通信工程學院教授,博導,教研中心主任,長期從事無線自組網網絡的設計與研發工作,主持國家自然科學基金、國家863計劃課題等多項課題,近5年獲軍隊科技進步二等獎1項,三等獎6項,作為及時發明人申請國家發明專利十余項,發表學術論文50余篇。
華東博士,現任南京醫科大學計算機教研室教師,一直致力于計算機輔助教學的相關技術研究,陸續開發了人體解剖學網絡自主學習考試平臺、診斷學自主學習平臺和面向執業醫師考試的預約化考試平臺等系統,并在各個學科得到廣泛的使用,獲得全國高等學校計算機課件評比一等獎和三等獎各一項。主編、副主編教材兩部,獲發明專利一項、軟件著作權多項。
劉喻博士,長期從事軟件開發、軟件測試和軟件工程化管理工作,目前任教于清華大學軟件所。
呂粵海,長期從事軍事通信網絡技術研究與軟件開發工作,先后通過華為光網絡高級工程師認證、思科網絡工程師認證。
第Ⅰ部分 Hadoop基礎知識
第1章 初識Hadoop 3
MapReduce作業 37
數據 56
讀取數據 58
壓縮 106
集合 121
面向列的格式 136
第Ⅱ部分 關于MapReduce
第6章 MapReduce應用開發 141
Tool和ToolRunner 149
運行作業 156
界面 165
MapReduce作業 177 第Ⅰ部分 Hadoop基礎知識
第3章 Hadoop分布式文件系統
當數據集的大小超過一臺獨立的物理計算機的存儲能力時,就有必要對它進行分區(partition)并存儲到若干臺單獨的計算機上。管理網絡中跨多臺計算機存儲的文件系統稱為分布式文件系統(distributed filesystem)。該系統架構于網絡之上,勢必會引入網絡編程的復雜性,因此分布式文件系統比普通磁盤文件系統更為復雜。例如,使文件系統能夠容忍節點故障且不丟失任何數據,就是一個極大的挑戰。
Hadoop自帶一個稱為HDFS的分布式文件系統,即Hadoop Distributed Filesystem。在非正式文檔或舊文檔以及配置文件中,有時也簡稱為DFS,它們是一回事兒。HDFS是Hadoop的旗艦級文件系統,也是本章的重點,但實際上Hadoop是一個綜合性的文件系統抽象,因此接下來我們將了解將Hadoop與其他存儲系統集成的途徑,例如本地文件系統和Amazon S3系統。
3.1 HDFS的設計
HDFS以流式數據訪問模式來存儲超大文件,運行于商用硬件集群上。①讓我們仔細看看下面的描述。
超大文件 “超大文件”在這里指具有幾百MB、幾百GB甚至幾百TB大小的文件。目前已經有存儲PB級數據的Hadoop 集群了。②
流式數據訪問 HDFS的構建思路是這樣的:一次寫入、多次讀取是較高效的訪問模式。數據集通常由數據源生成或從數據源復制而來,接著長時間在此數據集上進行各種分析。每次分析都將涉及該數據集的大部分數據甚至全部,因此讀取整個數據集的時間延遲比讀取及時條記錄的時間延遲更重要。
商用硬件 Hadoop并不需要運行在昂貴且高的硬件上。它是設計運行在商用硬件(在各種零售店都能買到的普通硬件③)的集群上的,因此至少對于龐大的集群來說,節點故障的幾率還是非常高的。HDFS遇到上述故障時,被設計成能夠繼續運行且不讓用戶察覺到明顯的中斷。
同樣,那些不適合在HDFS上運行的應用也值得研究。目前HDFS對某些應用領域并不適合,不過以后可能會有所改進。
低時間延遲的數據訪問 要求低時間延遲數據訪問的應用,例如幾十毫秒范圍,不適合在HDFS上運行。記住,HDFS是為高數據吞吐量應用優化的,這可能會以提高時間延遲為代價。目前,對于低延遲的訪問需求,HBase(參見第20 章)是更好的選擇。
大量的小文件 由于namenode將文件系統的元數據存儲在內存中,因此該文件系統所能存儲的文件總數受限于namenode的內存容量。根據經驗,每個文件、目錄和數據塊的存儲信息大約占150字節。因此,舉例來說,如果有一百萬個文件,且每個文件占一個數據塊,那至少需要300 MB 的內存。盡管存儲上百萬個文件是可行的,但是存儲數十億個文件就超出了當前硬件的能力。④
多用戶寫入,任意修改文件 HDFS中的文件寫入只支持單個寫入者,而且寫操作總是以“只添加”方式在文件末尾寫數據。它不支持多個寫入者的操作,也不支持在文件的任意位置進行修改。可能以后會支持這些操作,但它們相對比較低效。
3.2 HDFS的概念
3.2.1 數據塊
每個磁盤都有默認的數據塊大小,這是磁盤進行數據讀/寫的最小單位。構建于單個磁盤之上的文件系統通過磁盤塊來管理該文件系統中的塊,該文件系統塊的大小可以是磁盤塊的整數倍。文件系統塊一般為幾千字節,而磁盤塊一般為512字節。這些信息(文件系統塊大小)對于需要讀/寫文件的文件系統用戶來說是透明的。盡管如此,系統仍然提供了一些工具(如df和fsck)來維護文件系統,由它們對文件系統中的塊進行操作。
HDFS同樣也有塊(block)的概念,但是大得多,默認為128 MB。與單一磁盤上的文件系統相似,HDFS上的文件也被劃分為塊大小的多個分塊(chunk),作為獨立的存儲單元。但與面向單一磁盤的文件系統不同的是,HDFS中小于一個塊大小的文件不會占據整個塊的空間(例如,當一個 1MB的文件存儲在一個128 MB 的塊中時,文件只使用1 MB的磁盤空間,而不是128 MB)。如果沒有特殊指出,本書中提到的“塊”特指HDFS中的塊。
HDFS中的塊為什么這么大?
HDFS的塊比磁盤的塊大,其目的是為了最小化尋址開銷。如果塊足夠大,從磁盤傳輸數據的時間會明顯大于定位這個塊開始位置所需的時間。因而,傳輸一個由多個塊組成的大文件的時間取決于磁盤傳輸速率。
我們來做一個速算,如果尋址時間約為10 ms,傳輸速率為100 MB/s,為了使尋址時間僅占傳輸時間的1%,我們要將塊大小設置約為100 MB。默認的塊大小實際為128 MB,但是很多情況下HDFS安裝時使用更大的塊。以后隨著新一代磁盤驅動器傳輸速率的提升,塊的大小會被設置得更大。
但是這個參數也不會設置得過大。MapReduce中的map任務通常一次只處理一個塊中的數據,因此如果任務數太少(少于集群中的節點數量),作業的運行速度就會比較慢。
對分布式文件系統中的塊進行抽象會帶來很多好處。及時個最明顯的好處是,一個文件的大小可以大于網絡中任意一個磁盤的容量。文件的所有塊并不需要存儲在同一個磁盤上,因此它們可以利用集群上的任意一個磁盤進行存儲。事實上,盡管不常見,但對于整個HDFS集群而言,也可以僅存儲一個文件,該文件的塊占滿集群中所有的磁盤。
第二個好處是,使用抽象塊而非整個文件作為存儲單元,大大簡化了存儲子系統的設計。簡化是所有系統的目標,但是這對于故障種類繁多的分布式系統來說尤為重要。將存儲子系統的處理對象設置為塊,可簡化存儲管理(由于塊的大小是固定的,因此計算單個磁盤能存儲多少個塊就相對容易)。同時也消除了對元數據的顧慮(塊只是要存儲的大塊數據,而文件的元數據,如權限信息,并不需要與塊一同存儲,這樣一來,其他系統就可以單獨管理這些元數據)。
不僅如此,塊還非常適合用于數據備份進而提供數據容錯能力和提高可用性。將每個塊復制到少數幾個物理上相互獨立的機器上(默認為3個),可以確保在塊、磁盤或機器發生故障后數據不會丟失。如果發現一個塊不可用,系統會從其他地方讀取另一個復本,而這個過程對用戶是透明的。一個因損壞或機器故障而丟失的塊可以從其他候選地點復制到另一臺可以正常運行的機器上,以保障復本的數量回到正常水平(參見5.1節對數據完整性的討論,進一步了解如何應對數據損壞)。同樣,有些應用程序可能選擇為一些常用的文件塊設置更高的復本數量進而分散集群中的讀取負載。
與磁盤文件系統相似,HDFS中fsck指令可以顯示塊信息。例如,執行以下命令將列出文件系統中各個文件由哪些塊構成,詳情可以參見11.1.4節對文件系統檢查(fsck)的討論:
% hdfs fsck / -files -blocks
3.2.2 namenode和datanode
HDFS集群有兩類節點以管理節點-工作節點模式運行,即一個namenode(管理節點)和多個datanode(工作節點)。namenode管理文件系統的命名空間。它維護著文件系統樹及整棵樹內所有的文件和目錄。這些信息以兩個文件形式長期保存在本地磁盤上:命名空間鏡像文件和編輯日志文件。namenode也記錄著每個文件中各個塊所在的數據節點信息,但它并不長期保存塊的位置信息,因為這些信息會在系統啟動時根據數據節點信息重建。
客戶端(client)代表用戶通過與namenode和datanode交互來訪問整個文件系統。客戶端提供一個類似于POSIX(可移植操作系統界面)的文件系統接口,因此用戶在編程時無需知道namenode和datanode也可實現其功能。
datanode是文件系統的工作節點。它們根據需要存儲并檢索數據塊(受客戶端或namenode調度),并且定期向namenode發送它們所存儲的塊的列表。
沒有namenode,文件系統將無法使用。事實上,如果運行namenode服務的機器毀壞,文件系統上所有的文件將會丟失,因為我們不知道如何根據datanode的塊重建文件。因此,對namenode實現容錯非常重要,Hadoop為此提供兩種機制。
及時種機制是備份那些組成文件系統元數據持久狀態的文件。Hadoop可以通過配置使namenode在多個文件系統上保存元數據的持久狀態。這些寫操作是實時同步的,且是原子操作。一般的配置是,將持久狀態寫入本地磁盤的同時,寫入一個遠程掛載的網絡文件系統(NFS)。
另一種可行的方法是運行一個輔助namenode,但它不能被用作namenode。這個輔助namenode的重要作用是定期合并編輯日志與命名空間鏡像,以防止編輯日志過大。這個輔助namenode一般在另一臺單獨的物理計算機上運行,因為它需要占用大量CPU時間,并且需要與namenode一樣多的內存來執行合并操作。它會保存合并后的命名空間鏡像的副本,并在namenode發生故障時啟用。但是,輔助namenode保存的狀態總是滯后于主節點,所以在主節點全部失效時,難免會丟失部分數據。在這種情況下,一般把存儲在NFS上的namenode元數據復制到輔助namenode并作為新的主namenode運行。(注意,也可以運行熱備份namenode代替運行輔助namenode,具體參見3.2.5節對HDFS高可用性的討論。
關于文件系統鏡像和編輯日志的更多討論,請參見11.1.1節。
3.2.3 塊緩存
通常datanode從磁盤中讀取塊,但對于訪問頻繁的文件,其對應的塊可能被顯式地緩存在datanode的內存中,以堆外塊緩存(off-heap block cache)的形式存在。默認情況下,一個塊僅緩存在一個datanode的內存中,當然可以針每個文件配置datanode的數量。作業調度器(用于MapReduce、Spark和其他框架的)通過在緩存塊的datanode上運行任務,可以利用塊緩存的優勢提高讀操作的性能。例如,連接(join)操作中使用的一個小的查詢表就是塊緩存的一個很好的候選。
用戶或應用通過在緩存池(cache pool)中增加一個cache directive來告訴namenode需要緩存哪些文件及存多久。緩存池是一個用于管理緩存權限和資源使用的管理性分組。
3.2.4 聯邦HDFS
namenode在內存中保存文件系統中每個文件和每個數據塊的引用關系,這意味著對于一個擁有大量文件的超大集群來說,內存將成為限制系統橫向擴展的瓶頸(參見10.3.2節)。在2.x發行版本系列中引入的聯邦HDFS允許系統通過添加namenode實現擴展,其中每個namenode管理文件系統命名空間中的一部分。例如,一個namenode可能管理/user目錄下的所有文件,而另一個namenode可能管理/share目錄下的所有文件。
在聯邦環境下,每個namenode維護一個命名空間卷(namespace volume),由命名空間的元數據和一個數據塊池(block pool)組成,數據塊池包含該命名空間下文件的所有數據塊。命名空間卷之間是相互獨立的,兩兩之間并不相互通信,甚至其中一個namenode的失效也不會影響由其他namenode維護的命名空間的可用性。數據塊池不再進行切分,因此集群中的datanode需要注冊到每個namenode,并且存儲著來自多個數據塊池中的數據塊。
要想訪問聯邦HDFS集群,客戶端需要使用客戶端掛載數據表將文件路徑映射到namenode。該功能可以通過ViewFileSystem和viewfs://URI進行配置和管理。
3.2.5 HDFS的高可用性
通過聯合使用在多個文件系統中備份namenode的元數據和通過備用namenode創建監測點能防止數據丟失,但是依舊無法實現文件系統的高可用性。namenode 依舊存在單點失效(SPOF, single point of failure)的問題。如果namenode失效了,那么所有的客戶端,包括MapReduce作業,均無法讀、寫或列舉(list)文件,因為namenode是存儲元數據與文件到數據塊映射的地方。在這一情況下,Hadoop系統無法提供服務直到有新的namenode上線。
在這樣的情況下,要想從一個失效的namenode恢復,系統管理員得啟動一個擁有文件系統元數據副本的新的namenode,并配置datanode和客戶端以便使用這個新的namenode。新的namenode直到滿足以下情形才能響應服務:(1)將命名空間的映像導入內存中;(2)重演編輯日志;(3)接收到足夠多的來自datanode的數據塊報告并退出安全模式。對于一個大型并擁有大量文件和數據塊的集群,namenode的冷啟動需要30分鐘,甚至更長時間。
系統恢復時間太長,也會影響到日常維護。事實上,預期外的namenode失效出現概率很低,所以在現實中,計劃內的系統失效時間實際更為重要。
Hadoop2針對上述問題增加了對HDFS高可用性(HA)的支持。在這一實現中,配置了一對活動-備用(active-standby) namenode。當活動namenode失效,備用namenode就會接管它的任務并開始服務于來自客戶端的請求,不會有任何明顯中斷。實現這一目標需要在架構上做如下修改。
namenode之間需要通過高可用共享存儲實現編輯日志的共享。當備用namenode接管工作之后,它將通讀共享編輯日志直至末尾,以實現與活動namenode的狀態同步,并繼續讀取由活動namenode寫入的新條目。
datanode需要同時向兩個namenode發送數據塊處理報告,因為數據塊的映射信息存儲在namenode的內存中,而非磁盤。
客戶端需要使用特定的機制來處理namenode的失效問題,這一機制對用戶是透明的。
輔助namenode的角色被備用namenode所包含,備用namenode為活動的namenode命名空間設置周期性檢查點。
可以從兩種高可用性共享存儲做出選擇:NFS過濾器或群體日志管理器(QJM,quorum journal manager)。QJM是一個專用的HDFS實現,為提供一個高可用的編輯日志而設計,被推薦用于大多數HDFS部署中。QJM以一組日志節點(journal node)的形式運行,每一次編輯必須寫入多數日志節點。典型的,有三個journal節點,所以系統能夠忍受其中任何一個的丟失。這種安排與ZooKeeper的工作方式類似,當然必須認識到,QJM的實現并沒使用ZooKeeper。(然而,值得注意的是,HDFS HA在選取活動的namenode時確實使用了ZooKeeper技術,詳情參見下一章。
在活動namenode失效之后,備用namenode能夠快速(幾十秒的時間)實現任務接管,因為近期的狀態存儲在內存中:包括近期的編輯日志條目和近期的數據塊映射信息。實際觀察到的失效時間略長一點(需要1分鐘左右),這是因為系統需要保守確定活動namenode是否真的失效了。
在活動namenode失效且備用namenode也失效的情況下,當然這類情況發生的概率非常低,管理員依舊可以聲明一個備用namenode并實現冷啟動。這類情況并不會比非高可用(non-HA)的情況更差,并且從操作的角度講這是一個進步,因為上述處理已是一個標準的處理過程并植入Hadoop中。
故障切換與規避
系統中有一個稱為故障轉移控制器(failover controller)的新實體,管理著將活動namenode轉移為備用namenode的轉換過程。有多種故障轉移控制器,但默認的一種是使用了ZooKeeper來確保有且僅有一個活動namenode。每一個namenode運行著一個輕量級的故障轉移控制器,其工作就是監視宿主namenode是否失效(通過一個簡單的心跳機制實現)并在namenode失效時進行故障切換。
管理員也可以手動發起故障轉移,例如在進行日常維護時。這稱為“平穩的故障轉移”(graceful failover),因為故障轉移控制器可以組織兩個namenode有序地切換角色。
但在非平穩故障轉移的情況下,無法確切知道失效namenode是否已經停止運行。例如,在網速非常慢或者網絡被分割的情況下,同樣也可能激發故障轉移,但是先前的活動namenode依然運行著并且依舊是活動namenode。高可用實現做了更進一步的優化,以確保先前活動的namenode不會執行危害系統并導致系統崩潰的操作,該方法稱為“規避”(fencing)。
同一時間QJM僅允許一個namenode向編輯日志中寫入數據。然而,對于先前的活動namenode而言,仍有可能響應并處理客戶過時的讀請求,因此,設置一個SSH規避命令用于殺死namenode的進程是一個好主意。當使用NFS過濾器實現共享編輯日志時,由于不可能同一時間只允許一個namenode寫入數據(這也是為什么推薦QJM的原因),因此需要更有力的規避方法。規避機制包括:撤銷namenode訪問共享存儲目錄的權限(通常使用供應商指定的NFS命令)、通過遠程管理命令屏蔽相應的網絡端口。訴諸的手段是,先前活動namenode可以通過一個相當形象的稱為“一槍爆頭”STONITH,shoot the other node in the head)的技術進行規避,該方法主要通過一個特定的供電單元對相應主機進行斷電操作。
客戶端的故障轉移通過客戶端類庫實現透明處理。最簡單的實現是通過客戶端的配置文件實現故障轉移的控制。HDFS URI使用一個邏輯主機名,該主機名映射到一對namenode地址(在配置文件中設置),客戶端類庫會訪問每一個namenode地址直至處理完成。
3.3 命令行接口
現在我們通過命令行交互來進一步認識HDFS。HDFS還有很多其他接口,但命令行是最簡單的,同時也是許多開發者最熟悉的。
參照附錄A中偽分布模式下設置Hadoop的說明,我們先在一臺機器上運行HDFS。稍后介紹如何在集群上運行HDFS,以提供可擴展性與容錯性。
在我們設置偽分布配置時,有兩個屬性項需要進一步解釋。及時項是fs.defaultFS,設置為hdfs://localhost/,用于設置Hadoop的默認文件系統。⑤文件系統是由URI指定的,這里我們已使用hdfs URI來配置HDFS為Hadoop的默認文件系統。HDFS的守護程序通過該屬性項來確定HDFS namenode的主機及端口。我們將在localhost默認的HDFS端口8020上運行namenode。這樣一來,HDFS客戶端可以通過該屬性得知namenode在哪里運行進而連接到它。
第二個屬性dfs.replication,我們設為1,這樣一來,HDFS就不會按默認設置將文件系統塊復本設為3。在單獨一個datanode上運行時,HDFS無法將塊復制到3個datanode上,所以會持續給出塊復本不足的警告。設置這個屬性之后,上述問題就不會再出現了。
文件系統的基本操作
至此,文件系統已經可以使用了,我們可以執行所有常用的文件系統操作,例如,讀取文件,新建目錄,移動文件,刪除數據,列出目錄,等等。可以輸入hadoop fs -help命令獲取每個命令的詳細幫助文件。
首先從本地文件系統將一個文件復制到HDFS:
% hadoop fs -copyFromLocal input/docs/quangle.txt \ hdfs://localhost/user/tom/quangle.txt
該命令調用Hadoop文件系統的shell命令fs,后者提供了一系列子命令,在這個例子中,我們執行的是-copyFromLocal。本地文件quangle.txt被復制到運行在localhost上的 HDFS實例中,路徑為/user/tom/quangle.txt。事實上,我們可以簡化命令格式以省略主機的URI并使用默認設置,即省略hdfs://localhost,因為該項已在core-site.xml中指定。
% hadoop fs -copyFromLocal input/docs/quangle.txt /user/tom/quangle.txt
我們也可以使用相對路徑,并將文件復制到HDFS的home目錄中,本例中為/user/tom:
% hadoop fs -copyFromLocal input/docs/quangle.txt quangle.txt
我們把文件復制回本地文件系統,并檢查是否一致:
% hadoop fs -copyToLocal quangle.txt quangle.copy.txt
% md5 input/docs/quangle.txt quangle.copy.txt
MD5 (input/docs/quangle.txt) = e7891a2627cf263a079fb0f18256ffb2
MD5 (quangle.copy.txt) = e7891a2627cf263a079fb0f18256ffb2
MD5鍵值相同,表明這個文件在HDFS之旅中得以幸存并保存完整。
,看一下HDFS文件列表。我們新建一個目錄,看它在列表中怎么顯示:
% hadoop fs -mkdir books
% hadoop fs -ls .
Found 2 items
drwxr-xr-x - tom supergroup 0 2014-10-04 13:22 books
-rw-r--r-- 1 tom supergroup 119 2014-10-04 13:21 quangle.txt
返回的結果信息與Unix命令ls -l的輸出結果非常相似,僅有細微差別。第1列顯示的是文件模式。第2列是這個文件的備份數(這在傳統Unix文件系統是沒有的)。由于我們在整個文件系統范圍內設置的默認復本數為1,所以這里顯示的也都是1。這一列的開頭目錄為空,因為本例中沒有使用復本的概念,目錄作為元數據保存在namenode中,而非datanode中。第3列和第4列顯示文件的所屬用戶和組別。第5列是文件的大小,以字節為單位,目錄為0。第6列和第7列是文件的修改日期與時間。,第8列是文件或目錄的名稱。
H
較好的大數據書籍,值得閱讀。
大數據必備
一直想買 終于買下來了
還沒有看,不過紙張不錯
目前在學基礎概念部分
很不錯的學習資料
呃!剛收到還沒看!
不錯,都是經典
內容不錯,但有些代碼使用的接口有點過時。
不錯不錯不錯不錯
書本很滿意
差評,寫了發票,沒有給發票
個………………
書本還行,價格稍貴
初次接觸分布式,前輩推薦這個,就買了。應該不錯。當當物流快,趕上雙11還半價,真心不錯。
很好很好很好
很不錯的書,推薦購買。
書絕對是好書,但是這快遞,我簡直不想多吐槽了,好好的書,被這么對待!
很好,不錯的
剛拿到書本,感覺紙質一般吧,內容還沒看,過后有機會會補充!
內容挺多的,要花時間去充電了
非常好,相當不錯哦
到貨速度快,贊贊贊贊贊贊贊贊贊贊贊贊
所以說沒有自營配送的自營=耍流氓。100塊錢買的書給中通砸核桃用了。
大數據從業者必備,從第二版到第四版,第二版最好,第三版錯誤較多,第四版翻譯偏差。買了第二天某東就比當當便宜了10塊
書不錯,快遞太差勁,糟糕的購物體驗。
紙質、印刷、物流等等依然很不錯,之所以打一分是因為這本書才看了二十來頁就出現了多出錯字漏字現象,即使不影響理解,依然十分失望。不知道是書本身翻譯校錯的問題,還是買的盜版書...非常不愉快的一次購物經歷...
還沒看 給單位買的 以后慢慢看。
很不錯,學習一下,要這么多字數嗎,有啥用
不錯很好的
非常不錯,值得信賴。
數據算法還不錯,做工精良,就是書的背面有中等程度的褶皺。希望在包裝上多多下功夫
物流不錯,物美價廉
很厚,應該比較男肯。
如圖,我還能說啥。要是當當以后都用郵政,就不會再買了。
書不錯正在看
hao~~
從下單到收到書本速度快,快遞員服務好。
很好。。。
經典之作,學習hadoop的好書
收到了,正版,完好無損,物流很快
書不錯就是物流太慢了
我就吐槽一下包裝吧,收到的時候書已經破了一角,雖然不影響使用,但是就是有點不爽,懶得退了
很好收獲很快
書還不錯。
做活動買的,很便宜,是正版書,就是包裝很差,書角都磕破了
很好的一本書
內容很不錯,但紙質差了點,單看書的質量,不值這個價。。。
快遞員就一傻逼,媽的貨到了之后,就扔到蜂巢柜里,他們也不給說一聲,沒有任何通知形式,短信,電話都沒通知,之后我打電話問他,他才說放到柜子里了,而且他媽的態度也不好,我要不問,是不是他媽的我就一直等著。