有一個設想
當有持續不斷的結構化或非結構化大數據集以流(streaming)的方式進入分佈式計算平臺, 能夠保存在大規模分佈式存儲上,並且能夠提供準實時SQL查詢,這個系統多少人求之不得。
今天,咱們就來介紹一下這個計算框架和過程。
問題分解一下
數據哪裏來?
假設,你已經有一個數據收集的引擎或工具(不在本博客討論範圍內,請出門左轉Google右轉百度),怎麼都行, 反正數據能以流的方式給出來,塞進Kafka類似的消息系統。
結構化?非結構化?如何識別業務信息?
關於結構化或非結構化,也不在今天的主要討論範圍,但是,必須要說明的是, 你的數據能夠以某種規則進行正則化,比如:空格分隔,CSV,JSON等。咱們今天以Apache網站日誌數據作爲參照。
類似如下:
124.67.32.161 - - [10/Apr/2016:05:37:36 +0800] "GET /blog/app_backend.html HTTP/1.1" 200 26450
如何處理?寫到哪裏去?
拿到數據,我們需要一些處理,將業務邏輯分離開來,做成二維表,行列分明,就像是關係型數據庫的表。這個事情有Spark DataFrame來完成。
就像寫入關係型數據庫一樣,我們需要將DataFrame寫入某處,這裏,就是Parquet文件,天然支持schema,太棒了。
怎麼取出來?還能是SQL?
我們的數據已經被當做“二維表,Table”寫入了Parquet,取出來當然也得是“表”或其他什麼的,當然最好是能暴露出JDBC SQL,相關人員使用起來就方便了。
這個事情交給Spark的 SparkThriftServer 來完成。
設計藍圖
以上分解似乎完美,一起來看看“設計框架”或“藍圖”。
算了,不解釋了,圖,自己看。
Coding Style
從Kafka Stream獲取數據
// 從Kafka Stream獲取數據
JavaPairInputDStream<String, String> messages = KafkaUtils.createDirectStream(jssc, String.class, String.class,
StringDecoder.class, StringDecoder.class, kafkaParams, topicsSet);
寫入Parquet
accessLogsDStream.foreachRDD(rdd -> {
// 如果DF不爲空,寫入(增加模式)到Parquet文件
DataFrame df = sqlContext.createDataFrame(rdd, ApacheAccessLog.class);
if (df.count() > 0) {
df.write().mode(SaveMode.Append).parquet(Flags.getInstance().getParquetFile());
}
return null;
});
創建Hive表
使用spark-shell,獲取Parquet文件, 寫入一個臨時表;
scala代碼如下:
import sqlContext.implicits._
val parquetFile = sqlContext.read.parquet("/user/spark/apachelog.parquet")
parquetFile.registerTempTable("logs")
複製schema到新錶鏈接到Parquet文件。
在Hive中複製表,這裏你會發現,文件LOCATION位置還是原來的路徑,目的就是這個,使得新寫入的文件還在Hive模型中。
我總覺得這個方法有問題,是不是哪位Hive高人指點一下,有沒有更好的辦法來完成這個工作?
CREATE EXTERNAL TABLE apachelog LIKE logs STORED AS PARQUET LOCATION '/user/spark/apachelog.parquet';
啓動你的SparkThriftServer
當然,在集羣中啓用ThriftServer是必須的工作,SparkThriftServer其實暴露的是Hive2服務器,用JDBC驅動就可以訪問了。