學習和使用一段時間的spark, 對spark的總結一下,希望對大家有用,不介紹怎么使用, 只從設計上談談。
spark解決了什么問題?
說spark前一定要說一下, 就不得不提Google的三駕馬車:Google FS、MapReduce、BigTable。其中對應開源實現如下:
Google FS -> hdfs、
MapReduce -> hadoop mapreduce
BigTable -> hbase
spark就是處理 mapreduce慢的問題。
在spark沒出現前, hadoop是 v1 版本 有兩個問題,
- 一個就是 hadoop的namenode單點以及內存問題(數據的node是放在內存中), v2也都解決了。
- hadoop的機器資源管理和計算管理都是 mapreduce進程管理,就是執行任務和資源都是mapduce一個在管理, v2獨立出 yarn才解決這個問題的
- mapreduce慢的問題, 還是不能解決。 一開始定位就是在廉價的機器上運行。 定位不同。
說下mapreduce核心
:
-
移動數據不如移動計算
。 比如數據在一個節點上, 那就把計算放在這個節點上, 這樣就沒有網絡磁盤IO了, 當然需要考慮機器的負載繁忙等。 -
合久必分,分久必合
。 數據量很大, 處理不了,就拆分,分發到多臺機器上,開始運算,運算結果再進行合并,最后輸出。
這就是 map(分) reduce(合) 中間還有shuffle(洗牌)。 map和reduce都是并行的。
hadoop mapreduce是基于 文件
的,相當于以數據為中心。 大量的磁盤網絡IO。 一個mapreduce只能計算一個結果,不能迭代計算。 必須是前一個mapreduce的輸出文件作為下一個輸出。
spark就是解決mapreduce的慢的, spark是內存計算, 將數據加載到內存中計算, 所有速度快。 spark也有map reduce概念。
進行迭代計算。 數據在內存中, 上一步的計算結果,可以在下一步進行使用。
另外一個原因:
spark開發更容易,hadoop的mapreduce很麻煩,每次都要有 map,reuduce, driver三個類。
spark介紹
Apache Spark 是專為大規模數據處理而設計的快速通用的計算引擎,是一種開源的類Hadoop MapReduce的通用并行框架,擁有Hadoop MapReduce所具有的優點。
Spark不同于MapReduce的是,Spark的Job中間輸出結果可以保存在內存中,從而不再需要讀寫HDFS,因此Spark能更好地適用于數據挖掘與機器學習等需要迭代的MapReduce的算法。
Spark 主要有三個特點
首先,高級 API 剝離了對集群本身的關注,Spark 應用開發者可以專注于應用所要做的計算本身。
其次,Spark 很快,支持交互式計算和復雜算法。
最后,Spark 是一個通用引擎,可用它來完成各種各樣的運算,包括 SQL 查詢、文本處理、機器學習等,而在 Spark 出現之前,我們一般需要學習各種各樣的引擎來分別處理這些需求。
總結一下:從各種方向上(比如開發速度和運行速度等)來看,Spark都優于Hadoop MapReduce;同時,Spark還提供大數據生態的一站式解決方案
spark架構
spark core是基礎,上面都是轉成 core來執行的。
spark是分布式,分成master和 work.
部署方式有很多種, 不同方式,對節點稱呼不同
- spark的自身集群管理 master worker, 發布的是driver
- YARN 集群配合 hdfs使用的, 這個使用最多, spark沒有存儲。 所有用yarn和hdfs最密切。
- mesos
- k8s
spark核心
spark core的數據類型計算三種 RDD,Broadcast Variables,Accumulators
RDD:彈性分布式數據集
Broadcast Variables: 廣播變量 將變量廣播到所有執行的節點 只讀
Accumulators: 累加器, 執行節點可以將累加結果回傳到 driver, 執行節點,只寫。
核心是 RDD,包括SQL的數據類型 DataFrame和DataSet以及 stream的 DStream也是對RDD包裝的。
RDD特點
1)一組分區(Partition),即數據集的基本組成單位;
2)一個計算每個分區的函數;
3)RDD之間的依賴關系;
4)一個Partitioner,即RDD的分片函數;
5)一個列表,存儲存取每個Partition的優先位置(preferred location)。
spark的功能都是在上面RDD數據結構特點上擴展完成的。
1. 分區
spark是分布式的, 分區就天然支持了, 可以提高并行度。 比如統計一個文件的word數量, 那不同分區,不同task進行處理,
最后將各個分區的結果合并就可以了。 分區可以改變。
2. 數據是只讀
RDD加的數據都是只讀的。 只讀保證了任務失敗重跑冪等性。 每一步執行都是產生新的RDD,不會修改原RDD。
3. 函數
函數就是操作,這就是spark中的算子,RDD的操作算子包括兩類,一類叫做transformations,它是用來將RDD進行轉化,構建RDD的血緣關系;另一類叫做actions,它是用來觸發RDD的計算,得到RDD的相關計算結果或者將RDD保存的文件系統中。
就是所說的 惰性計算,沒有觸發計算,都是記錄計算步驟,觸發了步驟,才開始執行。
4. 依賴
RDDs通過操作算子進行轉換,轉換得到的新RDD包含了從其他RDDs衍生所必需的信息,RDDs之間維護著這種血緣關系,也稱之為依賴。
這是spark數據失敗重跑的依據。 DAG: 有向無環圖。 spark的迭代計算。 函數式編程鏈式,在RDD中會保存一個依賴, 在上一個執行完。 每一步就一個點, 這樣構成一個圖。
5. 緩存
如果在應用程序中多次使用同一個RDD,可以將該RDD緩存起來,該RDD只有在第一次計算的時候會根據血緣關系得到分區的數據,在后續其他地方用到該RDD的時候,會直接從緩存處取而不用再根據血緣關系計算,這樣就加速后期的重用。
6. checkpoint
雖然RDD的血緣關系天然地可以實現容錯,當RDD的某個分區數據失敗或丟失,可以通過血緣關系重建。但是對于長時間迭代型應用來說,隨著迭代的進行,RDDs之間的血緣關系會越來越長,一旦在后續迭代過程中出錯,則需要通過非常長的血緣關系去重建,勢必影響性能。為此,RDD支持checkpoint將數據保存到持久化的存儲中,這樣就可以切斷之前的血緣關系,因為checkpoint后的RDD不需要知道它的父RDDs了,它可以從checkpoint處拿到數據。就是將數據持久化, 切斷DAG圖。
編程模型
給個示例:
package org.jackson.exp
import org.apache.spark.{SparkConf, SparkContext}
object Wd {
def main(args: Array[String]): Unit = {
// 設置 conf
val conf = new SparkConf().setMaster("local[*]").setAppName("WC")
// 創建SparkContext,該對象是提交spark App的入口
val sc = new SparkContext(conf)
sc.textFile("/Users/zego/IdeaProjects/sparkOne/input").
flatMap(_.split(" ")). // 將一行進行按 " "拆分
map((_, 1)). // 轉換數據類型 tuple
reduceByKey(_ + _). // 基于key進行 value 相加
coalesce(1). // 修改分區數
saveAsTextFile("/Users/zego/IdeaProjects/sparkOne/output")
sc.stop()
}
}
不同分區,不同task