大數據實戰項目(1)-項目簡介、開發技術、工具、架構等
大數據實戰項目(2)-數據採集、處理、分發流程所涉及到的框架及配置
這一部分主要是對數據進行離線處理和實時處理的總結。
離線數據處理
MySQL+Hive
MySQL一方面用來存儲Hive的元數據,另一方面存儲離線分析的結果。
1)MySQL的安裝
2)Hive的安裝
#hive-log4j.properties
#日誌目錄需要提前創建
property.hive.log.dir = /opt/modules/hive-2.1.0/logs
#修改hive-env.sh配置文件
#Set HADOOP_HOME to point to a specific hadoop install directory
HADOOP_HOME=/opt/modules/hadoop-2.6.0
HBASE_HOME=/opt/modules/hbase-1.0.0-cdh5.4.0
# Hive Configuration Directory can be controlled by:
export HIVE_CONF_DIR=/opt/modules/hive-2.1.0/conf
# Folder containing extra ibraries required for hive compilation/execution can be controlled by:
export HIVE_AUX_JARS_PATH=/opt/modules/hive-2.1.0/lib
3)Hive與MySQL集成
- 創建hive-site.xml文件,配置mysql元數據庫metastore
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://bigdata-pro01.bigDAta.com/metastore?createDatabaseIfNotExist=true</value>
</property>
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionUserName</name>
<value>root</value>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>123456</value>
</property>
<!--打印表頭-->
<property>
<name>hive.cli.print.header</name>
<value>true</value>
</property>
<!--打印當前所在數據庫-->
<property>
<name>hive.cli.print.current.db</name>
<value>true</value>
</property>
<!--該屬性在Hive與HBase集成時用到,Hive通過該屬性去連接HBase集羣-->
<property>
<name>hbase.zookeeper.quorum</name>
<value>bigdata-pro01.bigDAta.com,bigdata-pro02.bigDAta.com,bigdata-pro03.bigDAta.com</value>
</property>
</configuration>
- 在MySQL數據中設置用戶連接信息,可以無阻礙訪問mysql數據庫,其次要保證Hive所在節點能無密鑰登錄其他集羣內節點
4)Hive與MySQL集成測試
- 啓動HDFS和YARN服務
- 啓動Hive
- 通過Hive服務創建表,並向這個表中加載數據,在Hive查看錶中內容
- 在MySQL數據庫metastore中查看元數據
Hive+HBase集成
Hive是一個數據倉庫,主要是轉爲MapReduce完成對大量數據的離線分析和決策,之前完成了Flume集成HBase,此時HBase中能源源不斷地插入數據,那麼如何使Hive中也有數據呢?使用外部表
進行Hive與HBase的關聯
<!--在hive-site.xml中添加該屬性-->
<property>
<name>hbase.zookeeper.quorum</name>
<value>bigdata-pro01.bigDAta.com,bigdata-pro02.bigDAta.com,bigdata-pro03.bigDAta.com</value>
</property>
將 HBase中的部分jar包拷貝到Hive中,如果兩者都是CDH版本,就不需要進行拷貝;若hive安裝時自帶了以下jar包,將其刪除。使用軟連接的方式
export HBASE_HOME=/opt/modules/hbase-1.0.0-cdh5.4.0
export HIVE_HOME=/opt/modules/hive-2.1.0
ln -s $HBASE_HOME/lib/hbase-server-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-server-1.0.0-cdh5.4.0.jar
ln -s $HBASE_HOME/lib/hbase-client-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-client-1.0.0-cdh5.4.0.jar
ln -s $HBASE_HOME/lib/hbase-protocol-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-protocol-1.0.0-cdh5.4.0.jar
ln -s $HBASE_HOME/lib/hbase-it-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-it-1.0.0-cdh5.4.0.jar
ln -s $HBASE_HOME/lib/htrace-core-3.0.4.jar $HIVE_HOME/lib/htrace-core-3.0.4.jar
ln -s $HBASE_HOME/lib/hbase-hadoop2-compat-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-hadoop2-compat-1.0.0-cdh5.4.0.jar
ln -s $HBASE_HOME/lib/hbase-hadoop-compat-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-hadoop-compat-1.0.0-cdh5.4.0.jar
ln -s $HBASE_HOME/lib/high-scale-lib-1.1.1.jar $HIVE_HOME/lib/high-scale-lib-1.1.1.jar
ln -s $HBASE_HOME/lib/hbase-common-1.0.0-cdh5.4.0.jar $HIVE_HOME/lib/hbase-common-1.0.0-cdh5.4.0.jar
在Hive中創建一個與HBase中的表建立關聯的外部表
create external table weblogs(
id string,
datatime string,
userid string,
searchname string,
retorder string,
cliorder string,
cliurl string
)
STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES("hbase.columns.mapping" = ":key,info:datatime,info:userid,info:searchname,info:retorder,info:cliorder,info:cliurl")
TBLPROPERTIES("hbase.table.name" = "weblogs");
可通過在Hive與HBase中輸入count ‘weblogs’,查看數據是否同步。
Cloudera Hue可視化分析
1)下載、安裝及編譯
詳細過程,記錄在Hadoop可視化神器-Hue安裝、編譯、運行
2)基本配置
1.配置desktop/conf/hue.ini
2.修改desktop.db文件權限
3)集成
具體內容參考:Hue集成HDFS、YARN、Hive、MySql、HBase的相關配置,此處僅是流程。
-
與HDFS集成
-
與YARN集成
-
與Hive集成
- 與MySQL集成
- 與HBase集成
實時數據處理
Spark與Kafka集成
1)Spark下載 安裝與編譯
2)Structured Streaming 與Kafka集成
-
將
kafka_2.11-0.10.0.0.jar kafka-clients-0.10.0.0.jar spark-sql-kafka-0-10_2.11-2.2.0.jar spark-streaming-kafka-0-10_2.11-2.1.0.jar
等包添加到spark下的jars目錄下 -
在IDEA中編寫如下代碼,Structured Streaming從kafka中讀取數據,並進行計算
val spark = SparkSession.builder() .master("local[2]") .appName("streaming").getOrCreate() val df = spark .readStream .format("kafka") .option("kafka.bootstrap.servers", "bigdata-pro01.bigDAta.com:9092,bigdata-pro02.bigDAta.com:9092,bigdata-pro03.bigDAta.com:9092") .option("subscribe", "weblogs") .load() import spark.implicits._ val lines = df.selectExpr("CAST(value AS STRING)").as[String] val weblog = lines.map(_.split(",")) .map(x => Weblog(x(0), x(1), x(2),x(3),x(4),x(5))) val titleCount = weblog .groupBy("searchname").count().toDF("titleName","count")
Spark與MySQL集成
由於這裏僅僅需要對報表進行展示,前臺展示的字段並不多,MySQL完全可以支撐。在HBase中有幾百萬條數據( 一個瀏覽話題可能有十幾萬人搜索過,也就是說一個話題就有十幾萬條數據,這麼大量數據當然要存在Hbase中 ),而經過Spark的計算, 這十幾萬條數據在mysql中就變成了一條數據(titleName,count)。
如果需要實時查詢用戶各種信息(數據量很大,字段很多),那麼就需要實時的直接從Hbase裏查,而不會在Mysql中。
val url ="jdbc:mysql://bigdata-pro01.bigDAta.com:3306/test"
val username="root"
val password="123456"
val writer = new JDBCSink(url,username,password)
val query = titleCount.writeStream
.foreach(writer)
.outputMode("update")
.trigger(ProcessingTime("5 seconds"))
.start()
query.awaitTermination()
其中的JDBCSink具體代碼如下所示:
import java.sql._
import org.apache.spark.sql.{ForeachWriter, Row}
class JDBCSink(url:String, username:String,password:String) extends ForeachWriter[Row]{
//var是一個變量
//val常量
var statement : Statement =_
var resultSet : ResultSet =_
var connection : Connection=_
override def open(partitionId: Long, version: Long): Boolean = {
connection = new MySqlPool(url,username,password).getJdbcConn();
statement = connection.createStatement()
return true
}
//處理數據
override def process(value: Row): Unit = {
// 將titleName中的[[]]用空格代替。標記一箇中括號表達式的開始。要匹配 [,請使用 \[
val titleName = value.getAs[String]("titleName").replaceAll("[\\[\\]]","")
val count = value.getAs[Long]("count");
val querySql = "select 1 from webCount " +
"where titleName = '"+titleName+"'"
val updateSql = "update webCount set " +
"count = "+count+" where titleName = '"+titleName+"'"
val insertSql = "insert into webCount(titleName,count)" +
"values('"+titleName+"',"+count+")"
try{
var resultSet = statement.executeQuery(querySql)
if(resultSet.next()){
//如果有執行updateSql
statement.executeUpdate(updateSql)
}else{
//沒有的話就執行insertSql
statement.execute(insertSql)
}
}catch {
case ex: SQLException => {
println("SQLException")
}
case ex: Exception => {
println("Exception")
}
case ex: RuntimeException => {
println("RuntimeException")
}
case ex: Throwable => {
println("Throwable")
}
}
}
override def close(errorOrNull: Throwable): Unit = {
if(statement==null){
statement.close()
}
if(connection==null){
connection.close()
}
}
}
而在JDBCSink中用到的MySqlPool連接池的具體代碼如下所示
import java.sql.{Connection, DriverManager}
import java.util
class MySqlPool(url:String, user:String, pwd:String) extends Serializable{
private val max = 3 //連接池連接總數
private val connectionNum = 1 //每次產生連接數
private var conNum = 0 //當前連接池已產生的連接數
private val pool = new util.LinkedList[Connection]() //連接池
//獲取連接
def getJdbcConn() : Connection = {
//同步代碼塊
AnyRef.synchronized({
if(pool.isEmpty){
//加載驅動
preGetConn()
for(i <- 1 to connectionNum){
val conn = DriverManager.getConnection(url,user,pwd)
pool.push(conn)
conNum += 1
}
}
pool.poll()
})
}
//釋放連接
def releaseConn(conn:Connection): Unit ={
pool.push(conn)
}
//加載驅動
private def preGetConn() : Unit = {
//控制加載
if(conNum < max && !pool.isEmpty){
println("Jdbc Pool has no connection now, please wait a moments!")
Thread.sleep(2000)
preGetConn()
}else{
Class.forName("com.mysql.jdbc.Driver");
}
}
}
WEB系統開發
- 從MySQL中查詢數據 WeblogService:包括查詢20條 titleName,count,以及titleSum
- 基於WebSocket協議的數據推送服務開發
- 基於Echarts框架,編寫前端頁面的展示index.html
啓動各個服務,展示最終結果
經歷了各種版本問題,各種各樣的bug,閱讀了所使用的框架的官網網站(有些內容很難找到,尤其是英文網站,但是隻要找到位置後,閱讀還是比較容易理解的,記得大致瀏覽下該位置所在頁面上的其他內容,因爲有些注意事項會在下文寫出)查閱了大量博客文獻(感謝各位博主的分享),終於將此次大數據實戰項目搞定,至此該大數據實戰項目告一段落,但仍然需要對其中所涉及到的框架的原理進入深入理解,否則在出現bug的時候,很難快速解決問題。
加油!!!