整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          Flink 1.9 實戰:使用 SQL 讀取 Kaf

          Flink 1.9 實戰:使用 SQL 讀取 Kafka 并寫入 MySQL

          周六在深圳分享了《Flink SQL 1.9.0 技術內幕和最佳實踐》,會后許多小伙伴對最后演示環節的 Demo 代碼非常感興趣,迫不及待地想嘗試下,所以寫了這篇文章分享下這份代碼。希望對于 Flink SQL 的初學者能有所幫助。

          這份代碼主要由兩部分組成:1) 能用來提交 SQL 文件的 SqlSubmit 實現。2) 用于演示的 SQL 示例、Kafka 啟動停止腳本、 一份測試數據集、Kafka 數據源生成器。

          通過本實戰,你將學到:

          1. 如何使用 Blink Planner
          2. 一個簡單的 SqlSubmit 是如何實現的
          3. 如何用 DDL 創建一個 Kafka 源表和 MySQL 結果表
          4. 運行一個從 Kafka 讀取數據,計算 PVUV,并寫入 MySQL 的作業
          5. 設置調優參數,觀察對作業的影響

          SqlSubmit 的實現

          筆者一開始是想用 SQL Client 來貫穿整個演示環節,但可惜 1.9 版本 SQL CLI 還不支持處理 CREATE TABLE 語句。所以筆者就只好自己寫了個簡單的提交腳本。后來想想,也挺好的,可以讓聽眾同時了解如何通過 SQL 的方式,和編程的方式使用 Flink SQL。

          SqlSubmit 的主要任務是執行和提交一個 SQL 文件,實現非常簡單,就是通過正則表達式匹配每個語句塊。如果是 CREATE TABLE 或 INSERT INTO 開頭,則會調用 tEnv.sqlUpdate(...)。如果是 SET 開頭,則會將配置設置到 TableConfig 上。其核心代碼主要如下所示:

          使用 DDL 連接 Kafka 源表

          在 flink-sql-submit 項目中,我們準備了一份測試數據集(來自阿里云天池公開數據集,特別鳴謝),位于 src/main/resources/user_behavior.log。數據以 JSON 格式編碼,大概長這個樣子:

          {"user_id": "543462", "item_id":"1715", "category_id": "1464116", "behavior": "pv", "ts": "2017-11-26T01:00:00Z"}
          {"user_id": "662867", "item_id":"2244074", "category_id": "1575622", "behavior": "pv", "ts": "2017-11-26T01:00:00Z"}
          

          為了模擬真實的 Kafka 數據源,筆者還特地寫了一個 source-generator.sh 腳本(感興趣的可以看下源碼),會自動讀取 user_behavior.log 的數據并以默認每毫秒1條的速率灌到 Kafka 的 user_behavior topic 中。

          有了數據源后,我們就可以用 DDL 去創建并連接這個 Kafka 中的 topic(詳見 src/main/resources/q1.sql)。

          注:可能有用戶會覺得其中的 connector.properties.0.key 等參數比較奇怪,社區計劃將在下一個版本中改進并簡化 connector 的參數配置。

          使用 DDL 連接 MySQL 結果表

          連接 MySQL 可以使用 Flink 提供的 JDBC connector。例如

          PV UV 計算

          假設我們的需求是計算每小時全網的用戶訪問量,和獨立用戶數。很多用戶可能會想到使用滾動窗口來計算。但這里我們介紹另一種方式。即 Group Aggregation 的方式。

          INSERT INTO pvuv_sink
          SELECT
           DATE_FORMAT(ts, 'yyyy-MM-dd HH:00') dt,
           COUNT(*) AS pv,
           COUNT(DISTINCT user_id) AS uv
          FROM user_log
          GROUP BY DATE_FORMAT(ts, 'yyyy-MM-dd HH:00')
          

          它使用 DATE_FORMAT 這個內置函數,將日志時間歸一化成“年月日小時”的字符串格式,并根據這個字符串進行分組,即根據每小時分組,然后通過 COUNT(*) 計算用戶訪問量(PV),通過 COUNT(DISTINCT user_id) 計算獨立用戶數(UV)。這種方式的執行模式是每收到一條數據,便會進行基于之前計算的值做增量計算(如+1),然后將最新結果輸出。所以實時性很高,但輸出量也大。

          我們將這個查詢的結果,通過 INSERT INTO 語句,寫到了之前定義的 pvuv_sink MySQL 表中。

          注:在深圳 Meetup 中,我們有對這種查詢的性能調優做了深度的介紹。

          實戰演示

          環境準備

          本實戰演示環節需要安裝一些必須的服務,包括:

          • Flink 本地集群:用來運行 Flink SQL 任務。
          • Kafka 本地集群:用來作為數據源。
          • MySQL 數據庫:用來作為結果表。
          • Flink 本地集群安裝

          1.下載 Flink 1.9.0 安裝包并解壓:https://www.apache.org/dist/flink/flink-1.9.0/flink-1.9.0-bin-scala_2.11.tgz

          2.下載以下依賴 jar 包,并拷貝到 flink-1.9.0/lib/ 目錄下。因為我們運行時需要依賴各個 connector 實現。

          • flink-sql-connector-kafka_2.11-1.9.0.jar
          • http://central.maven.org/maven2/org/apache/flink/flink-sql-connector-kafka_2.11/1.9.0/flink-sql-connector-kafka_2.11-1.9.0.jar
          • flink-json-1.9.0-sql-jar.jar
          • http://central.maven.org/maven2/org/apache/flink/flink-json/1.9.0/flink-json-1.9.0-sql-jar.jar
          • flink-jdbc_2.11-1.9.0.jar
          • http://central.maven.org/maven2/org/apache/flink/flink-jdbc_2.11/1.9.0/flink-jdbc_2.11-1.9.0.jar
          • mysql-connector-java-5.1.48.jar
          • https://dev.mysql.com/downloads/connector/j/5.1.html

          3.將 flink-1.9.0/conf/flink-conf.yaml 中的 taskmanager.numberOfTaskSlots 修改成 10,因為我們的演示任務可能會消耗多于1個的 slot。

          4.在 flink-1.9.0 目錄下執行 ./bin/start-cluster.sh,啟動集群。

          運行成功的話,可以在 http://localhost:8081 訪問到 Flink Web UI。

          另外,還需要將 Flink 的安裝路徑填到 flink-sql-submit 項目的 env.sh 中,用于后面提交 SQL 任務,如我的路徑是

          FLINK_DIR=/Users/wuchong/dev/install/flink-1.9.0
          

          Kafka 本地集群安裝

          下載 Kafka 2.2.0 安裝包并解壓:https://www.apache.org/dist/kafka/2.2.0/kafka_2.11-2.2.0.tgz

          將安裝路徑填到 flink-sql-submit 項目的 env.sh 中,如我的路徑是

          KAFKA_DIR=/Users/wuchong/dev/install/kafka_2.11-2.2.0
          

          在 flink-sql-submit 目錄下運行 ./start-kafka.sh 啟動 Kafka 集群。

          在命令行執行 jps,如果看到 Kafka 進程和 QuorumPeerMain 進程即表明啟動成功。

          MySQL 安裝

          可以在官方頁面下載 MySQL 并安裝:

          https://dev.mysql.com/downloads/mysql/

          如果有 Docker 環境的話,也可以直接通過 Docker 安裝

          https://hub.docker.com/_/mysql

          $ docker pull mysql
          $ docker run --name mysqldb -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql
          

          然后在 MySQL 中創建一個 flink-test 的數據庫,并按照上文的 schema 創建 pvuv_sink 表。

          提交 SQL 任務

          1.在 flink-sql-submit 目錄下運行 ./source-generator.sh,會自動創建 user_behavior topic,并實時往里灌入數據。

          2.在 flink-sql-submit 目錄下運行 ./run.sh q1, 提交成功后,可以在 Web UI 中看到拓撲。

          在 MySQL 客戶端,我們也可以實時地看到每個小時的 pv uv 值在不斷地變化

          結尾

          本文帶大家搭建基礎集群環境,并使用 SqlSubmit 提交純 SQL 任務來學習了解如何連接外部系統。flink-sql-submit/src/main/resources/q1.sql 中還有一些注釋掉的調優參數,感興趣的同學可以將參數打開,觀察對作業的影響。關于這些調優參數的原理,可以看下我在 深圳 Meetup 上的分享《Flink SQL 1.9.0 技術內幕和最佳實踐》。

          作者:巴蜀真人


          lt;table> 表格的樣式:


          表格 <table>標簽的定義:

          HTML 表格:<table> 標簽定義 。

          簡單的 HTML 表格包括: table 元素,一個或多個 tr、th 以及 td 元素。


          <table>表格結構:

          <table border=1px;>
           <tr> <th> row1,col1 </th><th>row1,col2 </th> </tr>
           <tr> <th> row2,col1 </th><td>row2,col2 </td> </tr>
          </table>
          

          <table>表格元素:

          tr(行標簽)、 th(表頭單元格標簽)、 td(普通單元格標簽) caption(表格標題)、 col(定義列)、 colgroup(對表格中的列進行組合)、thead(組合表頭的內容) tbody(組合表格的主題內容) 、tfoot(組合表格的腳注內容) 等

          <td>(普通單元格標簽) : 元素定義表格單元格

          	<td>11,980</td>
          

          <th>(表頭單元格標簽) : 元素定義表格表頭

          <th scope="row">工資</th>
          

          <tr>(行標簽) : 元素定義表格行

          <tr>
          		<th scope="row">工資</th>
          		<td>11,980</td>
          		<td>12,650</td>
          		<td>9,700</td>
          		<td>10,600</td>
           <td rowspan="5">工作</td>
          	</tr>
          

          <caption>(表格標題):元素定義表格標題

          <caption class="c1">月度收入4月 - 7月 </caption>
          

          還有一些復雜的表格才能用到的元素 :<col>、 <colgroup>、<thead>、 <tbody> 、<tfoot>等.

          • thead主要用來存放表格的表頭的;
          • tbody 用來存放真正的數據的;
          • tfoot是表格的腳部, 主要是用來對表格做總結性的統計, 備注等.

          由于thead, tbody, tfoot是從語義 上來劃分 表格結構的, 主要用于比較復雜的表格中。


          <colspan>合并行元素 :定義<table>中的行的合并

           <td colspan="5">153,629</td>
          

          <rowspan>合并列元素 :定義<table>中的列的合并

           <td rowspan="5">工作</td>
          

          <table>表格的嵌套:

          <tr>
          		<th scope="row">總計</th>
          		<td>36,060</td>
          		<td>38,759</td>
          		<td>38,110</td>
          		<td>40,700</td>
           <td class="ct">
           <table id="t2"> 
           <tr><td></td></tr>
           </table>
           </td>
          	</tr>
          

          嵌套


          HTML基礎表格的應用,上面的簡單元素就可以滿足,運用表格邏輯思維去思考,可以更快的掌握<table>表格標簽。

          本文部分圖片來自網絡,如有侵權,請聯系修改。

          lt;table>和<form>結合效果圖:

          在HTML/CSS 中,我們經常用HTML來布局和填充內容,用CSS來添加效果,修飾內容和布局,使整個頁面變得更好看。


          HTML和CSS的配合方法:

          即在<head></head>標簽內添加CSS樣式表的鏈接:

          代碼展示如下:

          <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          	<title>Make a Table Frame</title>
           <link rel="stylesheet" type="text/css" href="CSS/tableframe.css" >
          </head>
          

          CSS選擇器

          定義:

          對帶有指定屬性的 HTML 元素設置樣式。

          注意:

          只有在規定了 !DOCTYPE 時,IE7 和 IE8 才支持屬性選擇器。在 IE6 及更低的版本中,不支持屬性選擇。

          功能:

          “選擇器”指明了{}中的“樣式”的作用對象,也就是“樣式”作用于網頁中的哪些元素。

          CSS中的選擇器有三個:

          標簽選擇器、class類選擇器、id選擇器

          1.標簽選擇器樣式表:a{}、 div{}、table{} ...

          {對全局所有的選中類型標簽的樣式修改}

          2.class類選擇器 樣式表: .class{}

          {在HTML中每個標簽都可以同時綁定多個類名,每個標簽都可以設置class;同一個界面中class是不可重復}

          3. id選擇器樣式表: #d1 {}

          {每個標簽都可有id,每個頁面不可重復id,}

          【一個HTML標簽只能綁定一個id屬性,一個HTML標簽可以綁定多個class屬性】

          單純選擇<div>標簽的時候 是對全局的的(所有的)<div>進行修飾;

          選擇器優先級:

          id選擇器>class類選擇器>標簽選擇器

          所以有id和class 選擇器的標簽將不會被覆蓋。交叉時是按照優先級覆蓋顯示的。


          <table>部分:電腦配件管理表2018年5月-8月

          單純的HTML 表格表單內容

          標題<caption>標簽:

          表格的標題<caption>的內容填充(HTML)

          <caption> 表格標題</caption> 
          

          標題<caption>的樣式修飾(CSS)

          table.formdata caption
          {
          	text-shadow: #FF00ff;
          	text-align: center;
          	padding-bottom: 6px;
          	font-weight: bold;
          }
          

          其他<table>標簽相關內容可參考 HTML中表格的實例應用 一文。


          <form>部分:

          form在網頁中主要負責數據采集功能。

          一個表單有三個基本組成部分:

          (1)表單標簽:包含了處理表單數據所用CGI程序的URL以及數據提交到服務器的方法。

          (2)表單域:包含了文本框、密碼框、隱藏域、多行文本框、復選框、單選框、下拉選擇框和文件上傳框等。

          (3)表單按鈕:提交按鈕、復位按鈕和一般按鈕;用于將數據傳送到服務器上的CGI腳本或者取消輸入。還可以用表單按鈕來控制其他定義了處理腳本的處理工作。

          <input>標簽

          定義:

          <input> 標簽規定用戶可輸入數據的輸入字段。

          根據不同的 type 屬性,輸入字段有多種形態。輸入字段可以是文本字段、復選框、密碼字段、單選按鈕、按鈕等等

          語法代碼:

          <input type="value" >
          

          實例代碼:

          <td><input type="text" name="Mainboard 6月" id="Mainboard 6月"></td>
          

          關系展示:


          <input>中 submit屬性 和reset屬性

          實例代碼:

          <p>

          <input type="submit" name="btnSubmit" id="btnSubmit" value="Add Data" class="btn">

          <input type="reset" value="Reset All" class="btn">

          </p>

          實例展示:

          <input>標簽的其他屬性值:


          <input>標簽外是否添加<form>標簽?

          input標簽外是否添加form標簽需要按情形區分:

          應用場景的區別:

          1.所有向后臺提交數據(包括原生和ajax提交)的<input>都建議用<form>包裹.

          2.如果只是用來做前臺交互效果則不推薦使用form包裹。

          但提交數據時,其實也可以不用form包裹input標簽:

          1.如果有form標簽,在點擊提交銨鈕時,瀏覽器自動收集參數,并打包一個http請求到服務器,完成表單提交。在這一過程中,瀏覽器會根據method的不同,將參數編碼后,放在urI中(get),或者放在請求的data中(post)。然后發送到服務器。

          2.如果沒有form,post方式的提交要使用ajax手工完成。get方式的提交需要自己拼接url。


          <form>表單其他相關內容可參考 HTML中 表單 的應用實例 一文。


          最后,附帶一下該可輸入的EXCEL表格的源碼。

          HTML code:

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
          <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
          	<title>Make a Table Frame</title>
           <link rel="stylesheet" type="text/css" href="CSS/tableframe.css" >
          </head>
          <body image="">
           <form method="psot">
          	<table border="1px" class="formdata">
           	<caption>電腦配件管理表2018年5月-8月</caption>
           	<tr>
           		<th></th>
           		<th scope="col">5月</th>
           		<th scope="col">6月</th>
           		<th scope="col">7月</th>
           		<th scope="col">8月</th>
           	</tr>
           	<tr>
           		<th scope="row">Hard Disk</th>
           		<td><input type="text" name="Hard Disk 5月" id="Hard Disk 5月"></td>
           		<td><input type="text" name="Hard Disk 6月" id="Hard Disk 6月"></td>
           		<td><input type="text" name="Hard Disk 7月" id="Hard Disk 7月"></td>
           		<td><input type="text" name="Hard Disk 8月" id="Hard Disk 8月"></td>
           	</tr>
           	<tr>
           		<th scope="row">Mainboard</th>
           		<td><input type="text" name="Mainboard 5月" id="Mainboard 5月"></td>
           <td><input type="text" name="Mainboard 6月" id="Mainboard 6月"></td>
           <td><input type="text" name="Mainboard 7月" id="Mainboard 7月"></td>
           <td><input type="text" name="Mainboard 8月" id="Mainboard 8月"></td>
           	</tr>
           	<tr>
           		<th scope="row">Case</th>
           		<td><input type="text" name="Case 5月" id="Case 5月"></td>
           <td><input type="text" name="Case 6月" id="Case 6月"></td>
           <td><input type="text" name="Case 7月" id="Case 7月"></td>
           <td><input type="text" name="Case 8月" id="Case 8月"></td>
           	</tr>
           	<tr>
           	 <th scope="row">Power</th>
           	 <td><input type="text" name="Power 5月" id="Power 5月"></td>
           <td><input type="text" name="Power 6月" id="Power 6月"></td>
           <td><input type="text" name="Power 7月" id="Power 7月"></td>
           <td><input type="text" name="Power 8月" id="Power 8月"></td>	
           	</tr>
           	<tr>
           		<th scope="row">CPU Fan</th>
           		<td><input type="text" name="CPU Fan 5月" id="CPU Fan 5月"></td>
           <td><input type="text" name="CPU Fan 6月" id="CPU Fan 6月"></td>
           <td><input type="text" name="CPU Fan 7月" id="CPU Fan 7月"></td>
           <td><input type="text" name="CPU Fan 8月" id="CPU Fan 8月"></td> 
           	</tr>
           	<tr>
           		<th scope="row">Total</th>
           		<td><input type="text" name="Total 5月" id="Total 5月"></td>
           <td><input type="text" name="Total 6月" id="Total 6月"></td>
           <td><input type="text" name="Total7月" id="Total 7月"></td>
           <td><input type="text" name="Total 8月" id="Total 8月"></td>
           	</tr>
          	</table>
           <p>
           <input type="submit" name="btnSubmit" id="btnSubmit" value="Add Data" class="btn">
           <input type="reset" value="Reset All" class="btn">
           </p>
           </form>
          </body>
          </html>
          

          CSS code :

          body
          {
          	font-family: Arial;
          	/*background-image: url(image/mainroad.jpg) no-repeat;*/
          	background-color: #00ff00;
          	background-size: 100%;
          }
          table.formdata
          {
          	width: 300px;
          	height: 150px;
          	border: 2px solid #F00;
          	border-collapse: collapse;
          	font-family: Arial;
          }
          table.formdata caption
          {
          	text-shadow: #FF00ff;
          	text-align: center;
          	padding-bottom: 6px;
          	font-weight: bold;
          }
          table.formdata th
          {
          	border:1px solid #be34hc;
          	background-color: #E2E2E2;
          	color:#000000;
          	text-aglin:center;
          	font-weight: normal;
          	padding: 2px 8px 2px 6px;
          	margin: 0px;
          }
          table.formdata input
          {
          	width: 100px;
          	padding: 1px 3px 1px 3px;
          	margin: 0px;
          	border:none;
          	font-family: Arial;
          }
          .btn
          {
          	width:100px;
          	background-color: #FF00ee;
          	border:1px solid #00f2f2;
          	font-family: Arial;
          }
          

          本文部分內容來自網絡,如有侵權,請聯系修改。


          主站蜘蛛池模板: 无码人妻视频一区二区三区 | 国产精品亚洲一区二区三区| 国产一区二区三区播放心情潘金莲 | 国产成人无码AV一区二区| 精品一区二区三区在线成人| 乱色熟女综合一区二区三区| 伦精品一区二区三区视频| 午夜福利一区二区三区高清视频| 爱爱帝国亚洲一区二区三区| 亚洲午夜精品一区二区公牛电影院| 视频一区视频二区制服丝袜| 国产精品无码一区二区三区在| 精品午夜福利无人区乱码一区| 日本激情一区二区三区| 久久久91精品国产一区二区三区 | 亚洲国模精品一区| 亚洲AⅤ无码一区二区三区在线 | 制服美女视频一区| 男人的天堂精品国产一区| 一区二区福利视频| 国产一在线精品一区在线观看| 亚洲国产综合无码一区二区二三区| 日韩av片无码一区二区三区不卡| 精品国产一区二区二三区在线观看| 日本高清一区二区三区 | 麻豆亚洲av熟女国产一区二| 无码精品黑人一区二区三区 | 国产精品一区二区综合| 性色av闺蜜一区二区三区| 精品女同一区二区三区免费播放 | 在线视频一区二区三区| 日韩一区二区三区射精| 日韩A无码AV一区二区三区| 日韩AV无码一区二区三区不卡毛片 | 国产高清在线精品一区| 国产av夜夜欢一区二区三区| 国产无套精品一区二区| 久久精品国产AV一区二区三区| 国产一区美女视频| 少妇激情一区二区三区视频| av一区二区三区人妻少妇|