簡歷專案描述程序詳解
- 一、專案分點
- 1.1 集群規模
- 1.2 框架結構,畫出來
- 1.3 框架
- 1.3.1 第一個Flume
- 1.3.1.1 碰到的問題
- 1.3.2 kafka
- 1.3.2.1 框架介紹
- 1.3.2.2 碰到的問題
- 1.3.2.3 優化
- 1.3.3 第二個flume
- 1.3.3.1 框架
- 1.3.3.2 遇到的問題
- 1.3.4 hdfs
- 1.3.4.1 遇到的問題
- 1.3.5 業務資料
- 1.3.5.1 組成
- 1.3.5.2 碰到的問題
- 1.3.6 hive
- 1.3.6.1 組成
- 1.3.6.2 使用
- 1.3.6.3 碰到的問題
- 1.3.6.4 常規操作
- 1.4 數倉
- 1.4.1 ODS層
- 1.4.2 DWD層
- 1.4.2.1 建模理論
- 1.4.2.2 維度表
- 1.4.2.3 事實表
- 1.4.2.4 還做了其他3件事情
- 1.4.3 DWS層
- 1.4.4 DWT層
- 1.4.5 ADS層
- 1.5 實時專案
- 1.5.1 框架部分
- 1.5.1.1 Canal
- 1.5.2 實時指標
- 1.5.3 實作方式
個人介紹
一、專案分點
1.1 集群規模
(12臺物理機:128G記憶體,8T機械硬碟,2T固態硬碟,20核40執行緒,戴爾4萬多一臺)
1.2 框架結構,畫出來
日志部分:
app前端埋點 -> 日志服務器 -> 落盤日志 -> flume -> kafka -> flume -> hdfs -> hive -> mysql
業務資料部分
Java后臺采集資料 -> 日志服務器 -> mysql -> hdfs -> hive -> mysql
1.3 框架
1.3.1 第一個Flume
組件:source 、 channel 、 sink 、三個器 、碰到的問題
①source
我們使用的是taildirsource,這個是apache 1.7版本才有,選擇這個source的原因是taildirsource可以實時監控多個檔案且有斷點續傳功能
②channel
Channel一共有三種:filechannel、memorychannel和kafkachannel
fileChannel是基于磁盤,io多,性能差,但是可靠性高
Memorychannel基于記憶體,性能高,但是可靠性相對低,存在丟失資料的風險
Kafkachannel是基于磁盤,可靠性高,性能還優于memorychannel + kafkasink
我們是將資料采集到kafka,所以我們使用了kafkachannel
③sink
kafkachannel可以直接將資料發送到kafka,所以我們沒有使用sink,
④攔截器
我們使用了etl攔截器,過濾掉不完整的josn資料
同時還使用了分類攔截器,我們的日志分為了5類資料,啟動、頁面、動作、曝光和錯誤資料,我通過給event的header加上對應的標簽,后面配合多路復用的選擇器,指定不同型別的資料去到不同的topic中,
我們定義攔截器的步驟:
①自定義一個類,實作interceptor,實作4個抽象方法:分別是:初始化、關閉資源、單個event和多個event方法,
②創建一個內部類實作builder類,實作兩個抽象方法,
③最后打包 -> 上傳到flume 的lib包下 -> 在組態檔中添加攔截器,寫上全類名$bulid類
⑤選擇器:
一共有兩種選擇器,一種是replicating,默認的選擇器,每一個通道發送一份資料,另外一種是multiplexing,多路復用,根據event的header指定資料去到哪個通道,我們選擇的多路復用選擇器,將資料發送到kafka不同topic中,
⑥監控器
我們還使用到ganglia監控器,對flume的運行狀況進行監控,主要是監控flume的put和take事務,當嘗試提交的次數遠遠大于成功提交的次數以后,我們對flume進行優化,通過配置flume-env檔案,增大flume的記憶體,默認是2G,我們調整到4G
同時在雙十一、618等大型活動,flume采集通道也是抗不住這么大的資料量,我們通過臨時購買阿里云的日志服務器,然后將flume部署到日志服務器上,
1.3.1.1 碰到的問題
我們遇到過flume掛掉的情況,我們當時的分析是:
Source -> channel有put事務,channel 到sink有take事務,所以這個兩個環節是沒有問題的,后端是kafka,那么是暫時無法獲取資料,也沒有關系,
采集資料的前端,使用的是taildirsource,它的特性是先拉取資料,再維護offset,所以不會丟失資料,可能存在重復資料,針對重復資料,我們開會分討論是:
可以通過增加事務的方式實作不重復資料,但我們評估這樣做性能非常低,我們在hive的dwd層,可以通過groupby進行去重,也可以使用sparkSQL或者redis進行去重,所以在這里我們就沒有進行處理,
1.3.2 kafka
Kafka我們從三個方面向您介紹,框架、碰到的問題和優化
1.3.2.1 框架介紹
①kafka有4個組件:生產者 、消費者 、 brokers 和 zk
Zk保存著消費者的offset和brokers的ids等資訊
②資料量:日常每天80-100g,大概平均的資料生產速度1M/s,不過到了峰值時間,晚上7-9點時間段,最高達到了20MB/S,大概有2W人同時在線
③kafka的臺數,通過kafak自帶的壓測工具,測驗生產峰值速度,我們當時選擇了3臺kafka,
④磁區的數量
磁區數量 = 期望的吞吐量 / min(生產峰值速度,消費最大的速度)
我們當時設定的是5個磁區
⑤存盤大小
Kafka資料默認保存7天,我們調整到3天,因為正常情況下,我們是可以跑完當天的資料,當出現例外時,第二天可以重跑一次,所以我們保留3天是足夠的,我們給kakfa硬碟的大小為:每天的資料量 *副本數 * 保留的天數 / buffer(0.7) ,大概是0.8T,我們預留了1T
1.3.2.2 碰到的問題
我們還遇到了kafka掛了,資料重復、資料丟失、資料擠壓問題
①對于kafka掛了,kafka收不到訊息,后端flume無法獲取資料,沒有什么問題,前面的flume,資料會快速擠壓在channel中,最多就是后面擠壓滿了,但是往前是日志服務器,保留了30天的資料,所以就沒有什么關系,直接重啟就可以了
②對于資料丟失,這個重要看ack的配置,ack有0,1,-1三種,0表示leader一收到資料就回復ack,可能丟失資料,企業中已經不使用,1表示leader落盤以后回復ack,可靠性相對可靠,-1表示所有的副本都落盤以后再回復ack,可靠性高,性能相對較慢,我們傳輸的是日志資料,所以采用了ack=1的方式,
③對于資料重復,可以通過事務 + ack =-1 + 冪等性來解決這個問題,冪等性通過(生產者id,磁區號,序列號)對一個磁區內的資料進行標識,可以保證磁區內的資料不會重復,當生產者重啟時,生產者的id號會發生改變,這樣同一條資料就可能會被重復發送到kafka,通過事務將pid和事務id進行系結,解決了這個問題,不過我們通過會議討論,這樣會嚴重影響性能,所以這里我們就不做處理,等hive的dwd層進行去重,
④同時我們還遇到了資料擠壓的問題,我們做了兩個優化:
一是:增加磁區,同時增加下一級消費者的cpu核數
二是:通過修改batchsize引數,提高消費者每次拉取的資料量,默認是1000條,我們把它調整到2000,極端情況下我們也調整過到3000條/s
1.3.2.3 優化
我們通過修改引數對kafka進行優化:
①將資料保存時間由默認的7天修改為3天
②副本數由默認1個修改為2個,增加可靠性
③增加副本拷貝程序中leader和follower之間的通信時間,避免因為網路問題,不斷的拷貝同一副本
④對producer發送的資料采用是壓縮
⑤我們還調整了kafka的記憶體大小,由1g調整到6g,提高性能
1.3.3 第二個flume
我從三個方面介紹:
框架 、 遇到的問題、優化
1.3.3.1 框架
①source:我們是采集kafka的資料,所以使用kafka source
②channel:我們選擇了memory channel,傳輸普通的日志,如果出現宕機,最多是100evnet個資料發生丟失,我們評估能接受
③sink:資料寫到hdfs上,使用了hdfs sink
1.3.3.2 遇到的問題
①剛開始我們把資料寫到hdfs時,遇到了有很多小檔案問題,通過flume的官網,發現有三個引數可以減少小檔案的情況,分別是檔案滾動大小、時間和event的個數,我將檔案滾動的大小設定為128M,時間設定為2H,就是每128m生成一個新檔案,如果超過2h沒有達到128M,也是生成一個檔案,event設定為0,就是不啟用,因為我們不知道每一個event的資料大小,如果使用的話,會造成hdfs上的資料量大小不一,
②還遇到了頭一天的資料發送到了第二天的檔案夾中,通過查詢GitHub的資料,發現是kafkasource會獲取系統時間并添加到event的header中,而我們是依據這個header中時間戳,將資料發送到指定的檔案夾中,
我們解決方式是:通過自定義攔截器,獲取event的body中時間戳,并把時間戳添加到timestamp屬性中,這樣就實作了當天的資料能進入當天的檔案中,
③同時我們還遇到了hadoop宕機了,通過調小從kafka中拉取資料的batchsize大小來調整往hdfs寫資料的速度,解決了這個問題,
1.3.4 hdfs
1.3.4.1 遇到的問題
Log資料寫到hdfs的時候,發現還有一些小檔案,由于在namenode中,一個檔案占用的記憶體大小是固定150位元組,那namenode的資源利用率就低了,并且在后面計算任務的時候,每一個小檔案會創建一個maptask,對集群資源也是浪費,
對于小檔案,我們采用了三種方式
①har歸檔,將多個小檔案壓縮在一起,類似Windows下的zip壓縮,對于namenode來說就是一個整體,同時采用har協議,可以將里面的檔案一個一個取出來,
②后面我們采用combinerInputFormat,將多個小檔案捏合在一起進行統一切片,減少maptask的數量
③同時開啟了jvm重用,提高處理的效率,因為對于小檔案來說,執行的時間比開關jvm的時間還短,這個時候我們就多個任務開關一次,不過開啟jvm重啟是一個雙刃劍,在沒有小檔案的場景下,不要開啟這個功能,
這樣我們的log資料就去到了hdfs中,每天一個檔案夾,每個檔案中存盤了當天日志資料,
1.3.5 業務資料
1.3.5.1 組成
①配置
同時我們還有業務資料,通過sqoop將業務資料匯入到hdfs層,sqoop的配置比較簡單,主要配置的引數有mysql連接的url、用戶、密碼以及資料寫到hdfs的路徑、如果檔案存在則洗掉,
②同步策略
我們將資料匯入到hdfs時,根據資料量和資料的變化情況,使用不同的同步策略,主要是考慮在滿足業務需求的情況下減少資料重復,
同步規則是(畫圖說明)
a、如果表資料比較少,采用全量同步策略,匯入時過濾條件是1=1
b、如果表資料量大,但是資料只有新增數沒有變化,采用新增同步策略,匯入時過濾條件是創建時間等于今天
c、如果表資料量大,資料有新增也有變化,就采用新增及變化同步策略,匯入時過濾條件是創建時間或操作時間等于今天
d、還有一種是特殊表,默認資料不會變化,如地區和省份表,只匯入一次,
我們是每天的凌晨12點半左右開始導表,大概需要40分鐘,遇到資料量比較大的時候,如雙十一、618等大型活動,大概需要1個小時左右,
1.3.5.2 碰到的問題
在匯入的時候也碰到了一些問題
①hive中null值存盤是\N,但是mysql中是null,資料不一樣,我們通過配置–null-string,–null-no-string引數進行資料轉換
1.3.6 hive
最終log資料和業務資料都存盤到了hdfs中,之后通過load的方式,將資料加載到hive里面,像hive這個框架也有很多技術點,從三個方面介紹這個框架
1.3.6.1 組成
Hive有元資料、4個器、計算引擎和存盤
元素據
元資料默認是存盤在derby資料庫,但由于這個資料庫僅支持單客戶端訪問,所以后面我們就把元資料存盤在mysql中,
4個器
這邊4個器是決議器、編譯器、優化器和執行器
計算引擎
計算引擎有mr、tez和spark,
Mr引擎是基于磁盤,任務內部要落盤,io大,性能差,我們一般用來執行周、月、季度等長周期任務,
Tez引擎,是基于記憶體,對記憶體的要求高,計算的資料量如果很大,會出現oom的情況,所以我們一般用來執行一些臨時任務
Spark引擎,是基于記憶體,中間也會有落盤,我們一般用來執行當天的任務,
存盤
資料最終是存盤在hdfs中,
1.3.6.2 使用
內部表和外部表
hive數倉中,我們用到了內部表和外部表,兩者的最大區別是:洗掉內部表元資料和原始資料都會被洗掉,而洗掉外部表,只會洗掉元資料不會洗掉原始資料,我自己使用的一些臨時表采用內部表,其他的表基本是外部表,用來防止因誤操作將原始資料洗掉了,
4個by
當然,還使用了4個by,分別是order by 、 sort by 、distribute by和cluster by,Order by 很少使用,因為是全域排序,很容易出現oom,sort by 和distribute by 一般是配合使用,磁區內排序,當磁區欄位和排序欄位相同時,可以使用cluster by 代替,不過用的比較少,
系統函式
在計算指標時,我們使用了各種函式,如系統函式,用next_day處理周指標,用get_json_object對log資料進行決議,還使用了開窗函式,rank 和over函式,計算topN指標
1.3.6.3 碰到的問題
在數倉的程序中,也遇到了很多問題,
- 問題1:大表 和 大表
- 問題2:小表和大表
- 問題3:單個key資料傾斜
- 問題4:多個key資料傾斜
在數倉計算的程序中,遇到了資料傾斜的問題,當時我們發現有一個reducetask卡在99%,而其他的任務都執行完成了,第一反應可能是資料傾斜了,然后對資料進行group by 求count,發現null的資料很多,然后我們采取使用亂數將null值打散,然后對計算結果資料進行轉換,去掉亂數,再進行一次聚合,這個問題解決了,
后來我們還開啟了負載均衡的功能,
1.3.6.4 常規操作
在hive使用的程序中,做了一些常規優化
一是引數優化:
①開啟mapjoin、開啟map端的combiner和使用壓縮
遇到小檔案時
①開啟了merge功能:就是將任務結束時產生的多個小于16m的小檔案捏合成一個256M的大檔案
②使用combinerhiveinputformat;將多個檔案捏合在一起,減少maptask的數量
③開啟jvm重用
二是業務優化:
①創建磁區表:避免全域掃描
②先過濾再計算
③列式存盤:提高資料查詢的速度
④合理設定reduce的個數:避免資源的浪費
⑤根據需求更換對應的計算引擎
這就是hive當中的一些事情,
1.4 數倉
之后我們基于hive,搭建了一個離線數倉,我們的數倉分為5層,ods、dwd、dws、dwt和ads層,
首先,我們通過ezdml工具分析mysql表之間的關系,
1.4.1 ODS層
從三個方面聊一聊ods層
①表的欄位:
Ods層表的欄位:
Log資料,創建一個新表,表只有一個欄位,line,log一條日志就是一條資料
業務資料,欄位和mysql的欄位保持一致,
②表的維護
獲取hdfs中當天的資料,直接load進去
③在ods層做的3件事情
①創建磁區表,每天一個磁區,每個磁區的資料和資料匯入hdfs的策略保持一致
②資料從hdfs原封不動到ods層,對資料進行備份
③采用lzo壓縮,減少磁盤空間,壓縮后資料從100g大概壓縮到10g左右
1.4.2 DWD層
對于日志資料,我是使用get_json_object對日志資料進行決議,將資料決議為:啟動、頁面、動作、曝光、錯誤資料
對于業務資料,從4個方面闡述
1.4.2.1 建模理論
Dwd層采用了維度建模,標準的4步:
①選擇業務程序
②宣告粒度
③確定維度
④確定事實
因為我們是中小型公司,所以我們把后臺的50多張表全部拿過來,所有的業務我們都要了,宣告粒度,我們是宣告最小的粒度,一行資訊代表一次下單,一次支付、一次收藏,并沒有對它做任何的聚合操作,確定維度,后面通過畫矩形圖方式確定和事實相關的維度,最后是確定事實,就是確定事實表的度量值,有次數、件數、金額、個數,以訂單為例,最關心的就是下單數量和下單金額,
業務資料我們分為維度表和事實表,
1.4.2.2 維度表
對于維度表來說,根據維度退化理論創建,我們當時定了6個維度,用戶、地區、時間、商品、活動和優惠券維度,從這6個維度進行指標統計,我從三個方面介紹維度表:
1、維度表分類
根據資料的特點,將維度表分為全量表、特殊表和拉鏈表三種,
全量表:資料量不大的維度表,采用全量表,如商品維度,活動維度等
特殊表:資料默認不會變化,如地區和時間維度表
拉鏈表:資料會發生變化,但是大部分是不變的表,采用拉鏈表,如用戶表維度表,
2、表的欄位
維度表的欄位:從ods層找到這個維度相關的表,欄位全部取過來,如和商品維度相關的有6張表:sku、spu、一、二、三級表、品類表,
3、表的維護
講一下拉鏈表構建程序,我們是將用戶表做成了拉鏈表
創建拉鏈表步驟是【畫圖說明】:
第一步:初始化用戶表:取ods層用戶表中資料,增加起始時間和結束時間欄位,將起始時間設定為當天導表的時間,結束時間設定為很大的值,我們設定為9999-01-01,我們暫時稱為舊表
第二步:處理新資料:后續導表時,取出ods層當天磁區的資料,增加起始時間和結束時間,起始時間修改為今天,結束時間修改為9999-01-01,形成一張新表
第三步:修改舊表資料:初始表 left join ods_user_info表第二天的資料,當ods_user_info的id不為null且初始表的end_date為9999-01-01的資料,將end_date改為昨天,其余欄位全部使用舊表的資料
第四步:合并資料,舊表和新表進行unoin all
1.4.2.3 事實表
也從3個方面闡述
1、表的分類
事實表都是磁區表,根據資料特點,我們將事實表分為三種:
a、事務型事實表:只有新增資料沒有變化資料建事務型事實表,每個磁區保存當天新增的資料,如支付事實表、退款事實表
b、周期性快照事實表:對于我們只關心當天最后的資料,不關心中間變化程序的表,每個磁區保存當天所有的資料,如收藏表、加購物車表
c、累計型快照事實表:對于表中的一行資料一次性寫不完的表,每個磁區保存當天新增的資料,當天變化的資料,去到原來磁區進行資料修改,如優惠券領用表
2、表的欄位
表的欄位包含三個部分:維度外鍵、度量值和一些冗余欄位,獲取欄位的步驟:
第一步:畫矩陣圖,找到和事實表相關的維度,如和訂單事實表相關的維度有:時間、地區、用戶、活動
第二步:從ods層找到和這個事實相關的表
第三步:取步驟2中表所有的度量值,以及冗余欄位和維度外鍵作為事實表的欄位,
3、表的維護
維護表資料的方式也比較簡單,簡單說一下稍微復雜一點的累積型事實表中訂單表的維護思路:
畫圖說明
相關表:訂單狀態表、活動訂單表、訂單表,
第一步:訂單狀態表:按訂單進行分組,然后使用str_map + concat_ws + collect_set,將多行資料轉換為一行map資料,然后和訂單表join,再和訂單活動進行left join,–新表
第二步:從dwd層取出舊表中磁區等于變化資料的創建時間的資料–舊表
第三步:舊表與新表進行full join,新表有資料,就使用新表資料,否則使用舊表資料
第四步:最后采用動態磁區的方式對原有的磁區資料進行覆寫寫,
1.4.2.4 還做了其他3件事情
①資料清洗:過濾重復資料和關鍵欄位空值資料,臟資料一般控制在萬分之一,如果遇到了臟資料過多,會和前端溝通,
②采用lzo壓縮,減少磁盤空間
③采用了列式存盤:提高查詢的速度
1.4.3 DWS層
之后來到dws層,這里是寬表,是站在維度的角度看事實的度量值,統計當天的一些指標,如會員主題,統計用戶當天下單次數、下單金額、支付次數、支付金額等
我們分為5個主題,設備主題、會員主題、商品主題、活動主題和地區主題,
①設備主題:
- 統計設備id活躍次數
②會員主題:
- user_id
- 登入次數
- 加入購物車次數
- 下單次數
- 下單金額
- 支付金額
- 支付次數
③商品主題表
- 商品id
- 被下單次數
- 被下單件數
- 被下單金額
- 被支付次數
- 被支付件數
- 被支付金額
- 被退款次數
- 被退款件數
- 被退款金額
- 被加購物車次數
- 被收藏次數
- 好評數
- 默認評價數
- 差評數
④活動主題表
- 活動id
- 開始時間
- 結束時間
- 創建時間
- 曝光次數
- 下單次數
- 下單金額
- 支付次數
- 支付金額
⑤地區主題表
- 地區id
- 地區名稱
- 省份名稱
- 省份id
- 活躍設備數
- 下單次數
- 下單金額
- 支付次數
- 支付金額
1.4.4 DWT層
之后來到dwt層,也是站在維度的角度看事實,這次是看事實的開始時間、結束時間、度量值的累積值和一段時間內的累積值,也是5個主題
①設備主題
- 設備id
- 首次活躍時間
- 末次活躍時間
- 當天活躍次數
- 累積活躍次數
②會員主題
- user_id
- 首次登入時間
- 末次登入時間
- 累積登入天數
- 最近30天登入天數
- 首次下單時間
- 末次下單時間
- 累積下單次數
- 累積下單金額
- 最近30天下單次數
- 最近30天下單金額
- 首次支付時間
- 末次支付時間
- 累積支付金額
- 累積支付次數
- 最近30天支付次數
- 最近30天的支付金額
③ 商品主題
- sku_id
- Spu_id
- 最近30天被下單次數
- 最近30天被下單件數
- 最近30天被下單金額
- 累積下單次數
- 累積下單件數
- 累積下單金額
- 最近30天被支付次數
- 最近30天被支付件數
- 最近30天被支付金額
- 累積支付次數
- 累積支付件數
- 累積支付金額
- 最近30天被退款次數
- 最近30天被退款件數
- 最近30天被退款金額
- 累積退款次數
- 累積退款件數
- 累積退款金額
- 最近30天被加購物車次數
- 累積被加購物的次數
- 最近30天被加收藏的次數
- 累積被加收藏的次數
- 最近30天好評數
- 最近30天中評數
- 最近30天差評數
- 最近30天默認的評價數
- 累積好評數
- 累積中評數
- 累積差評數
- 累積默認評價數
④活動主題
- 活動編號
- 活動開始時間
- 活動結束時間
- 活動創建時間
- 當日被曝光次數
- 累積曝光次數
- 當日下單金額
- 當日下單次數
- 累積下單金額
- 累積下單次數
- 當日支付次數
- 當日支付金額
- 累積支付次數
- 累積支付金額
⑤地區主題
- 省份id
- 省份名稱
- 地區id
- 地區名稱
- 當天活躍設備
- 最近30天活躍設備
- 當天下單次數
- 當天下單金額
- 最近30天下單次數
- 最近30天下單金額
- 當天支付次數
- 當天支付金額
- 最近30天支付次數
- 最近30天支付金額
1.4.5 ADS層
指標分析,大概100多個指標,
①設備相關指標
1.榷訓、周活和月活
(從dwt層獲取最后的登入時間在今天、這周、這個月)
2.每日新增設備(首次登入時間是今天)
3.統計1日、2日和3日留存率
從dwt層獲取資料,
第一步:統計當天所有的活躍用戶
第二步:統計昨天的1日留存率,求出昨天的新用戶但是今天上線的用戶/昨天的新用戶
第三步:統計前天的2日留存率,求出前天的新用戶但是今天上線的用戶/前天的新用戶
4.沉默用戶:只在安裝當天啟動過,且啟動時間是在7天前
(統計首次活躍時間 = 最后末次活躍時間,且最后活躍時間在7天前的用戶)
5.本周回流用戶數:上周未活躍,本周活躍的設備,且不是本周新增設備
第一步:獲取本周活躍的用戶且不是本周新增的用戶
第二步:獲取上周的活躍的用戶
第三步:第一步獲取的用戶減少第二步獲取的用戶就是本周回流的用戶
6.流失用戶:最近7天未活躍的設備(獲取最近活躍時間小于7天的用戶)
7.最近連續三周活躍的用戶數
第一步: 從dws層獲取前一周、前兩周以及當前周的所有活躍的用戶
第二步: 然后進行內連接,能連接上的,則說明這連續的3周都活躍了,最后按照用戶進行分組去重后求count,
8.最近7天連續3天活躍
第一步:從dws層獲取最近7天的資料,對資料按照用戶分組進行開窗,按斬訓躍時間進行降序排序
第二步:使用活躍時間減去排名,獲取一列
第三步:按照用戶和第三步的列進行分組,求count(*) >= 3的用戶
第四步:分組求和
第五步:求7天內連續3天的活躍用戶
②會員主題
1.會員主題分析:
1. 總付費會員數:指付費的會員數量
2. 會員活躍率 = 今天會員活躍數量 / 總的會員數量
3. 會員付費率 = 今天會員付費人數 / 總的會員數量
4. 會員新鮮度 = 今天新增會員數量 / 今天活躍的會員數量
2. 漏斗分析;瀏覽頁面 -> 進入詳情的頁面 -> 加入購物車 -> 下單 -> 支付
③商品主題
1.商品個數排名
2.商品銷量排名
3.商品收藏排名
4.商品加入購物車排名
5.商品近30天退款率排名
6.商品差評率
④營銷主題
1.下單數目統計:單日下單筆數、金額和用戶數
2.支付資訊統計:單日支付筆數、金額、人數、商品數和下單到支付的平均時長
3.品牌復購率
⑤地區主題
1.地區主題資訊:當天活躍設備數,下單次數、金額,支付次數和金額,
留轉G復活
留存率計算:會算
轉換率的計算:
GMV計算:會計算
復購率:會計算
榷訓:會計算
高消費的用戶->統計高消費用戶的前10個商品品類,然后推送對應的優惠力度
生日標簽->提前一周觸發優惠券的發放,進行引流
優惠券偏好->統計優惠券出現的次數的排名,確定哪一類優惠券用戶比較喜歡,然后這個類活動可以經常做,
==匯出 ==
后面我們通過sqoop將計算的結果匯入到mysql中,在匯出的程序也遇到了資料不準確的問題,因為sqoop底層是4個map,有可能出現一半成功,一般失敗,這樣在查詢結果的時候,和實際有偏差,我們通過增加–stage-table引數,先將資料匯入到一張臨時表,之后通過事務的方式匯入到mysql中,這樣就要么成功要么失敗,
可視化展示
之后我們的資料直接對接superset,使用superset做可視化,免費開源的,用起來效果非常棒,
即席查詢:
同時數倉當中還采用了各種即席查詢,像presto,還裝了kylin,kylin主要用于多維分析,主要用于dwd層進行分析,presto主要是針對ads層快速出指標,產品經理讓我統計ads層的某一個指標,一般我用presto可以直接得出指標,因為它是完全基于記憶體的,速度比較快,
調度
最后我們使用azkaban作為全流程調度,每天晚上凌晨30分開始統一調度,業務資料使用sqoop將mysql資料匯入hdfs,日志資料通過flume-kafka-flume,匯入到hdfs,然后將hdfs的資料load到hive中,我們指標有100多個,搞活動的時候能達到200多個,資料量還是比較大的,凌晨開始跑,如果跑掛了,我們還配置了郵件報警,電話報警,我們繼承了第三方工具,onealert來打電話,
以上是我做的離線數倉專案,
1.5 實時專案
下面介紹一下我的實時專案,
分4個部分講述我的實時專案:
1.實時專案的框架
2.具體的指標及實作的方式
3.遇到的問題
4.優化
1.5.1 框架部分
log資料:flume -> kafka -> sparkStreaming,日志資料通過flume采集到kafka兩個topic中,start_topic和event_topic,然后SparkStreaming根據需求來讀取資料,
業務資料:MySQL -> Kafka -> SparkStreaming,使用cannl實時監控mysql的變化的資料,并對資料進行決議,根據決議結果資料,發送到kafka不同的topic中,然后SparkStreaming來讀取資料,
1.5.1.1 Canal
簡單介紹一下cannl
我使用cannl實時監控mysql中表變化的資料,并發送到kafka中,
1.實作原理的原理是:
①canal模擬mysql slave的互動協議,偽裝自己為mysql slave,向mysql master發送dump協議
② mysql master收到dump請求,開始推送 binary log 給 slave(也就是 canal)
③ canal 決議 binary log 物件
- Mysql Binarylog一共有三級別:
①statement:binlog 會記錄每次執行的寫操作的陳述句,資料量少,但是對于一些亂數函式和自定義函式,slave在重新執行陳述句時,有可能會出現執行回傳結果和主不同
②row:binlog 會記錄每次操作后每行記錄的變化,保證資料的絕對安全,但是資料量大,因為一條sql陳述句可能改變多條資料,
③mixed:statement的升級版,對于可能導致資料不同的陳述句,采用row方式,其他的陳述句采用statement方式,
由于我是使用cannl監控資料的變化,采用的是row級別,
1.5.2 實時指標
- 每日訂單量實時統計
- 一小時內榷訓實時統計
- 一 每日榷訓實時統計
- 小時內訂單數實時統計
- 一小時內交易額實時統計
- 一小時內廣告點擊實時統計
- 一小時內區域訂單數統計
- 一小時內區域訂單額統計
- 一小時內各品類銷售top3商品統計
- 用戶購買明細靈活分析(根據區域,性別,品類等)
1.5.3 實作方式
前提:
1.使用cannel采集mysql中指定數庫下所有的表,然后對資料進行決議,不同表的資料寫到不同topic中,
2.手動維護offset,創建ssc時,從mysql讀取offset,如果offset有資料,則從獲取的offset位置開始讀取資料,否則從頭earlist開始讀資料,資料操作完成以后,并通過ssc獲取offset,并維護到mysql中,
每日訂單量和每小時實時統計
定義:采集周期為3s,使用sparkStreaming采集資料以后發送到hbase中
實作:
第一步:采集資料
第二步:將資料封裝成一個樣例類,在樣例類內部添加日期和小時兩個欄位,并根據資料創建時間進行轉換
第三步:將資料寫入hbase
購物券風險預警分析:同一個設備id中,更換3個以上的用戶領取優惠券
定義:每間隔6秒計算5分鐘內領取優惠券的數量>3,且沒有做其他任何操作的用戶,同一設備id一分鐘內預警一次,處理邏輯:在spark中只是獲取資料,并進行初步的處理,然后將資料寫入hbase中,
實作邏輯:視窗:5min,步長為6s
第一步,從kafka中獲取event_topic資料
第二步:格式轉換成:mid,資料,并按照mid進行分組
第三步:轉換處理,對value進行判斷
A、EventList集合,用來同一設備5分鐘內所有事件id
B、ItemSet集合,存放優惠券與商品對應的資料
C、UidSet集合,存放領取過優惠券的用戶資訊
設定一個flag,一旦用戶有點擊商品的行為,該條資料就結束
①將資料寫到EventList集合中
對事件id進行匹配
如果等于coupon,將領取優惠券的useid加到UidSet,同時將event的item加入到itemSet中
如果等于click,flag=false則break
等于其他,不做任何處理,
對同一個用戶來說,如果所有的value所有的資料遍歷完成后,
將資料寫出
/** 預警機制的條件:
* !isClickItem,沒有點擊過商品為true
* uidSet.size() >=3,領取優惠券的用戶數量 > 3
* 如果兩個都滿足,回傳true
*/
(!isClickItem && uidSet.size() >= 3, AlertInfo(mid, uidSet, itemSet, eventList, System.currentTimeMillis()))
}
②過濾資料:保留沒有點擊過商品的用戶
③轉換,只要value
④將資料寫入到中,在es中進行查詢
用戶購買明細分析:
定義:將用戶和訂單表和訂單詳情表三個表的資料進行關聯起來,一個訂單對應多條訂單詳情表
實作邏輯:訂單表和訂單詳情表使用雙流join,借用redis進行快取,用戶表的資料去mysql中查詢以后添加進來
具體邏輯:
①手動維護offset:使用cannl監控mysql資料庫,不同的表發送到不同的topic中,從mysql中獲取兩個topic的offset,然后創建兩個流,
②雙流join,
訂單資料和訂單詳情資料維護到redis的資料格式:
訂單資料:
Key:order_info:訂單id
Value:一條訂單資料
訂單詳情資料:
Key:order_detail:order_id:sku_id
Value:一條訂單詳情資料
將兩條流的資料進行資料轉換成kv形式,key為訂單id
A、雙流fulljoin
B、(order_id,(訂單資料,訂單詳情資料))
C、Mappartitions:
第一步:獲取redis的連接
第二步:對資料進行模式匹配
(order_id,(some,some))
將訂單資訊快取到redis中
將訂單資料和訂單詳情資料進行合并,創建一個集合,用來接收合并后的資料,將合并后的資料加到Arraylist集合中,從通過訂單id從redis中獲取訂單詳情資料的資料,可能有多條
遍歷獲取的資料,
將資料封裝成樣例類,將獲取的訂單詳情資料從redis中洗掉,將訂單資訊和資料進行合并,并添加到集合中
最后回傳集合,
(order_id,(none,some))=>訂單資料沒有,有訂單詳情資料
第一步:從redis中獲取訂單快取的資料,判斷是否為空,如果不為空,先將資料進行封裝成樣例類,則進行合并,然后回傳,如果為空,則將訂單詳情資料進行快取,
③合并用戶資料
讀取mysql用戶表的資料,并資料進行轉換(user_id,user),
然后將第二步獲取的資料也轉換,(user_id,saledetail)
然后進行內連接,并進行格式轉換,連接在一起,最后將資料寫到hbase中,
3.Sparkstreaming實作精準一次性消費
1.從mysql中獲取offset,將資料封裝成map(new TopicPartition,offset)
2.根據獲取的offset,如果獲取的值為空,則從頭消費,earlist,如果不為空,則從獲取的offset位置開始消費資料
3.資料經過一些處理完成以后,通過kafka流獲取offsetRanges,并遍歷,最后將資料維護到mysql中,
4.去重
實時統計榷訓,使用redis進行去重,獲取資料以后,將資料寫到Redis中,redis中的資料型別是:dau+日期,value是set集合,存盤mid,根據添加資料后的回傳值,如果回傳1,則添加成功,這條資料就要,如果是回傳0,則這條資料過濾,將去重以后的資料寫到Phoenix中,然后天和小時的榷訓都有了,
5.Oom,資料傾斜問題
Executor記憶體:
主要是shuffle階段:read shuffle 和write shuffle,在shuffle算子的地方會這種情況,
情況1:shuffle階段的reduce端的緩沖區過大,導致生產的大量的物件導致oom,調小一些緩沖區的大小
情況2:資料傾斜,單個key的資料量太多,使用亂數打散,進行二次聚合
情況3:記憶體就是不夠大,增大記憶體
情況4:join的時候,采用廣播變數的方式,避免shuffle
情況5:增加reduce的并行度
Driver記憶體:
情況1:當資料從executor使用collect拉取到drive端時,driver的記憶體不夠用,可以增加記憶體
情況2:在driver創建大集合,導致資料記憶體不足,可以考慮在executor端加載
資料傾斜出現在連個地方,一是shuffle階段,二是map階段,資料量太大導致,
6.Join兩個大表優化
a先過濾,看資料量大小,可以考慮廣播
b使用reducebykey、mappartition、增加reduce的數量
7.常規的一些優化手段
Mappartition優化和mysql的連接
foreachRDD優化和redis的連接
使用mappartition代替map…
8.sparkstreaming寫到hdfs有小檔案怎么辦
方案1:Kafka -> sparkStreaming -> kafka -> flume -> hdfs
方案2:可以使用結構化流實作向hdfs檔案中追加資料
方案3:擴大采集周期 + 使用coalesce
分析完之后,資料我們是灌倒hbase和es中,hebase一般我們存盤的是明細資料,es一般是監控資料,例外資料,因為可以直接通過kibana展示在大屏上,hbase存盤的是明細資料,可以通過Phoenix,對外暴露介面,讓web專案自己進行查詢,主要是運營人員通過他讀取資料,這個程序中我們還用到redis,用它去重,如果資料量大,用redis去重
離線指標:
留轉G復活,topn、熱門商品、退款率、榷訓、周活、月活、日新增流量、
1.流量類指標相關:
Uv(獨立訪問客戶)和pv(頁面訪問數),
頁面跳轉率
新增用戶數量(日、周、月)
留存率(統計1/2/3日留存率)
7天內連續登錄3天的下單、退款、支付
頁面平均訪問的時長
2.交易相關:按地區劃分GMV和下單量(當天、近30天)
3.活動推廣相關:活動曝光次數、當天下單、支付次數金額以及累計的下單次數和支付次數,用來判斷一個活動的推廣情況,
4.商品類相關:topn、哪個商品買的最好、復購率、退款率、評論
5.購物車相關:加購次數、
6.下單相關:筆數、金額、用戶數(當天和累積30天)
7.支付相關:筆數、金額、用戶數(當天和累積30天)
1、交易:終極目標
GMV 和訂單量(GMV:訂單金額)
指標的作用:用來判斷交易結果的好壞
統計方式:從dws層獲取
select
'2020-06-14',
sum(order_count),//訂單數量
sum(order_amount),//訂單金額
sum(if(order_count>0,1,0))//下單用戶量
from dws_user_action_daycount
where dt='2020-06-14';
- 轉化率(轉化率 = 引入訂單量 / 流量)
指標的作用:漏斗分析,統計瀏覽頁面 -> 進入詳情的頁面 -> 加入購物車 -> 下單 -> 支付,
步驟
with
tmp_action as (
select
'2020-06-25' dt,
sum(if(cart_count > 0,1,0)) cart_count,--加入購物車的人數
sum(if(order_count > 0,1,0)) order_count , --下單人數
sum(if(payment_count > 0,1,0)) payment_count --支付人數
from dws_user_action_daycount
where dt ='2020-06-25'
),
tmp_page as (
select
'2020-06-25' dt , --統計日期
sum(if(array_contains(pages,'home'),1,0)) home_count, --瀏覽首頁人數
sum(if(array_contains(pages,'good_detail'),1,0)) good_detail_count, --瀏覽商品詳情頁人數
sum(if(array_contains(pages,'good_detail'),1,0)) * 100 /sum(if(array_contains(pages,'home'),1,0)) home2good_detail_convert_ratio --首頁到商品詳情轉化率
from (
select
mid_id,
--對用戶進行分組,過濾出今天進入首頁和詳情頁的用戶,獲取當天用戶的頁面行為,去重后放到一個集合中
-- 那么一行資料有如下2種情況
-- 用戶 page_id
-- 243 ["good_detail","home"]
-- 63 ["home"]
collect_set(page_id) pages
from dwd_page_log
where dt = '2020-06-25'
and page_id in ('home','good_detail')
group by mid_id
)tmp
)
insert into ads_user_action_convert_day
select
'2020-06-25' dt , --統計日期
home_count, --瀏覽首頁人數
good_detail_count, --瀏覽商品詳情頁人數
home2good_detail_convert_ratio ,--首頁到商品詳情轉化率
cart_count,--加入購物車的人數
cart_count *100/good_detail_count good_detail2cart_convert_ratio,--商品詳情頁到加入購物車轉化率
order_count , --下單人數
order_count *100/cart_count cart2order_convert_ratio ,--加入購物車到下單轉化率
payment_count, --支付人數
payment_count * 100 / order_count order2payment_convert_ratio --下單到支付的轉化率
from tmp_action
join tmp_page on tmp_action.dt = tmp_page.dt
客單價(客單價 = GMV / 引入訂單量)
它描述了每個訂單的平均成交金額,具有比較強的品類特征,比如奢侈品類的客單價,天然是比消費品的客單價高的,同時,如果進行了拼單滿減等運營策略,也能夠刺激用戶一單購買更多的商品,進而提升客單價,
UV 價值(UV 價值 = GMV / 流量)
它描述的是每個 UV 產出的平均金額,也能側面看出流量的質量、流量與業務的匹配程度,試想一個頁面,如果它的 UV 價值高,那么也就代表給它引入更多同類的流量,它就能創造更大的 GMV,因此 UV 價值也是一個很重要的指標,和轉化率一起綜合看,可以用來評估到底哪個業務 / 頁面值得投入更多的流量,
思考:UV 價值和客單價有什么不同?1)影響因素不同:UV 價值更受流量質量的影響;而客單價更受賣的貨的影響;2)使用場景不同:UV 價值可以用來評估頁面 / 模塊的創造價值的潛力;客單價可以用來比較品類和商品特征,但一個頁面客單價高,并不代表它創造價值的能力強,只能得出這個頁面的品類更趨近于是賣高價格品類的,
2、流量:決定成敗
UV & PV(頁面瀏覽人數、頁面訪問次數)
UV 描述了訪問的人數,是一個很重要的資料指標,它的多少往往決定了最終GMV的高低,UV 源自各種途徑,例如站外廣告、站內的資源位分配、用戶主動回訪流量、社交裂變活動的分享引流等,
PV 描述了訪問的次數,例如用戶一天訪問了這個頁面3次,這時候會計算為 3 PV 和 1 UV,也就是說,PV 比 UV 多了某段時間內用戶多次訪問的資訊,若要看頁面的流量量級,無論看 UV 還是 PV 都是可以的,
人均瀏覽次數(人均瀏覽次數 = 頁面訪問次數 / 頁面瀏覽人數)
這個指標描述了某段時間內,每個用戶平均瀏覽頁面的次數,不同的場景會有不同的值,需要根據具體的場景來判斷高低,有些情況會出現 PV 高出 UV 很多的場景,如存在需要用戶多次回訪的玩法、有分時段運營的策略(e.g. 一天三次紅包雨)等等,需要具體場景具體分析,
3、行為:尋根溯源
點擊率(點擊率 = 模塊點擊人數 / 頁面瀏覽人數)
用戶對此模塊的點擊人數,在所有進入頁面的流量中的百分比,可以看作用戶對于模塊的需求強烈程度的評判指標之一,與頁面流量和頁面 GMV的關系類似,模塊的點擊率與模塊的產出是強相關的(如下圖,橫軸是各模塊),
點擊率的影響因素有:1)模塊在頁面中的位置:若放得越高,則越可能被更多的用戶看見,那么點擊率高的可能性,就比放置位置低的模塊要來得更高,畢竟頁面越往下,看到的用戶就更少了,2)模塊本身的吸引程度:比如模塊本身是個優惠券集合樓層,就比沒有利益點的普通模塊更吸引人、更容易獲得更多點擊,此外,模塊的樣式設計、主題表述的清晰與否、主題對用戶的吸引力和潛在用戶群大小,這些都會影響到模塊的吸引力,
曝光點擊率(曝光點擊率 = 模塊點擊人數 / 模塊曝光人數)用戶對此模塊的點擊人數,在所有看到此模塊的流量中的百分比,與點擊率的公式對比可發現,點擊率的分母是所有進入頁面的流量,但用戶的瀏覽行為永遠是瀏覽得越深,流量越少的,這也就導致位置越深的模塊算點擊率就越吃虧,因為相當一部分流量壓根就沒有看到這個模塊,也被算進分母里了,而曝光點擊率,就是一個排除了頁面位置對模塊的影響后,可以用來相對公平地去比較各模塊的吸引力的資料指標,
思考:什么場景用點擊率,什么場景用曝光點擊率呢?1)當想要單純評估樓層對用戶的吸引力時,可以看曝光點擊率;2)當想要綜合評估樓層的整體效果與貢獻時,看點擊率,畢竟它與樓層 GMV 相關性更高;3)曝光需要特殊埋點,且可能會影響頁面性能,因此很多時候我們沒有辦法取到曝光資料,也只能看點擊率了,
曝光點擊率的使用注意:首屏內的樓層的曝光點擊率,資料可能不準確,首屏的曝光UV是最大的,里面包含了各種例外情況,例如一進頁面就跳出,也算作曝光,因此導致首屏的曝光點擊率往往會偏小(如下圖所示),無法與其他樓層比較,若想比較首屏情況,建議與點擊率一起綜合來看,
曝光率(曝光率 = 模塊曝光人數 / 頁面瀏覽人數)
這個資料可以看出用戶在頁面上的瀏覽深度如何,有百分之多少的用戶看到了哪一屏,從這個資料中,我們可以發現一些關鍵的節點,例如,若我們的業務主推是在第二~三屏的位置,但最終發現曝光率在第二屏便暴跌,這便是存在問題的,說不定我們需要把主推內容再往上提一些,或者需要去排查首屏是否有會令用戶立即跳轉和跳出的內容……這便是曝光率這個資料指標,可以帶來的分析價值,
停留時長這個資料指標很好理解,是描述用戶在頁面上平均停留多少秒,
思考:曝光率下跌曲線越慢 / 瀏覽深度越深 / 停留時長越長,就代表我們的頁面做得越好嗎?
曝光率和停留時長的影響因素比較一致,因此可以合在一起解釋,曝光率的下降曲線、停留時長的長與短,影響因素有這些:
1)人的生理極限:人不是機器,根據研究,“人不受干擾地執行單一操作的時長為 6s ~ 30s ”[注1],超過這一常數,用戶就會走神,可想而知,用戶在單一頁面上停留的時間是有上限的,不因頁面放置入的內容多少而變化,一個反例,是通過利益點來吸參考戶在頁面上瀏覽得更深,這不但與生理極限相悖,也把用戶自然的瀏覽行為和目標,硬生生變成了為了追尋更多利益點而進行類似完成任務的操作,除了用利益點交換一個好看的資料以外,這樣的做法似乎沒能帶來更多的產出,
2)頁面定位及內容:在雙11主會場中,用戶的行為模式趨近找優惠和找目標品類,那么他可能不會在這里瀏覽太多屏數、也不會停留太久——這個時候影響曝光率和停留時長的,就是他有多快能找到感興趣的優惠,因此,并不能說瀏覽深度越深、停留時長越長就越好;在 BI(千人千面)商品瀑布流中,用戶的行為是閑逛和挑選,這時候他更可能瀏覽更多的屏數、停留更長時間——因此瀏覽的商品越多,可以說是對最終效益最好的,
3)例外情況:例如加載例外、頁面崩潰的場景,就會導致停留時長例外低、二屏后曝光例外低,
綜上,我們應該根據具體的場景、通過數次歷史資料的對比,去設定和校正目標曝光率、目標停留時長,平日看這兩個資料,可以當做一個監測例外的資料,在正常范圍內的波動不需要過度解讀,一旦發現特別例外的情況,再進行具體的分析,
自己提出的指標:對營銷、對運行都非常有價值的指標
指標1:尋找潛在的vip用戶
1.準備三個具體的指標,比較難,又有對運營,營銷又非常有價值的,幫助他們做了什么事,講講怎么做的
尋找潛在VIP:
1.上一周連續3天登錄,且上周內下過一單的
先過濾取出上周內下過一單,又是非vip的人,(從訂單明細表)
再根據他們每日的最早啟動時間,用rank視窗函式進行排序,那么排序的這個欄位就應該是以1為公差的等引數列(left join 用戶活躍表日)
然后再用date-sub去將啟動日期與rank計算,得到了日期差值,根據這個日期差值進行分組,計算這個差有幾個,
就是我們所需要的用戶,
找出來之后,給她短信,后臺訊息推送優惠券,減稅,免郵,享受會員價等活動,
2.過去一個月內下單商品大于8件,且下單次數大于2
使用用戶訂單詳情表:取出過去一個月的非vip用戶購買詳情,
計算每個用戶的下單商品數,下單次數>2 (group by userID,sum(購買件數),count(distinct 訂單號)》2)
推送訊息,給免費vip活動體驗
這部分的用戶在接下來的三個月時間里,真正轉換成vip的有35%的人,所以這個指標還挺有意義的
商品季度/半年復購率(購買過這個商品兩次以上的用戶數/這個季度購買這種商品的總人數):
3.用戶購買明細表,
把上個季度的用戶購買詳情表過濾出來,group by 用戶id 商品id分組,求出用戶對于某個商品下單的總次數,
然后用sum if(判斷訂單單數>2),訂單單數>1的人數,求比率,
然后對比率根據品類排名,求每個品類中 比率排名前十的,用row_number<11.磁區取品類,排序取復購率,
這些商品,是我們的重要維系的商品,要及時補貨,然后復購率高說明,受用戶喜歡,可以推薦,給用戶發送小樣,嘗試,增大轉化率,
4.品牌復購率:
差不多,把具體商品,改成品牌id,各類商品下的品牌復購率(每月來算)
5.每周各品類熱門商品銷量前三(取每周各熱門品類,然后取用戶行為寬表的幾個欄位,熱門品類,用戶id,商品id,然后用熱門品類過濾,得到屬于熱門品類的資料,再根據熱門品類,商品id,去聚合,去前三,)
6.各區域熱門商品銷量前五:取用戶行為寬表,然后得到里面的資料,可以轉化成樣例類的rdd,然后根據區域分組,然后求商品銷量,前五的,
7.各品類中銷量前三的品牌
8.購物車各品類占比:以品牌為key,數量為value,從購物車寬表中獲取資料,然后根據品牌分類,求總數,(說明大家想買的東西,便于后期鋪貨,
資料健康問題:
物流資訊:有的客戶物流資訊上顯示收到貨了,但是快遞可能沒有送到他手里,然后程序中有丟失的情況,那么我們的物流計算時長,如果單純按照物流資訊來就會出現偏差,所以我們物流到貨時間都是以用戶,確認識訓為準,也不會差很大,
用戶的隱私資訊,電話號碼:我們使用自己的一套脫敏技術,將每個電話號碼的4-11位,加1,然后4-7位與8-11位順序調換,后期我們需要用到他們的隱私資訊,電話進行,營銷,發送訊息是,就把他轉換過來,
資料傾斜問題:
1.用時間維度表去join過去一整年的用戶購買明細表,查看,用戶集中購買的月份和季節,分析用戶的行為,之前不是默認的,(默認開啟mapJoin嘛)
2.小表join大表的問題,后面這個優化了,但是小表不能超過512M.我們資料量沒那么大,應該是可以的,
比如說算品類銷售排名的時候,group by 品類,求銷售總量是,某一品類像面膜,可能銷售量特別大,占60%多,那么有一個任務就會執行特別久,半天出不來,設定推測執行也差不多,就應該是資料傾斜導致的問題
Map端部分聚合
這里需要修改的引數為:
hive.map.aggr=true(用于設定是否在 map 端進行聚合,默認值為真) hive.groupby.mapaggr.checkinterval=100000(用于設定 map 端進行聚合操作的條目數)
有資料傾斜時進行負載均衡
此處需要設定 hive.groupby.skewindata,當選項設定為 true 是,生成的查詢計劃有兩 個 MapReduce 任務,在第一個 MapReduce 中,map 的輸出結果集合會隨機分布到 reduce 中, 每個 reduce 做部分聚合操作,并輸出結果,這樣處理的結果是,相同的 Group By Key 有可 能分發到不同的 reduce 中,從而達到負載均衡的目的;第二個 MapReduce 任務再根據預處 理的資料結果按照 Group By Key 分布到 reduce 中(這個程序可以保證相同的 Group By Key 分布到同一個 reduce 中),最后完成最終的聚合操作,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/423866.html
標籤:其他
