简历项目描述过程详解
簡歷項目描述過程詳解
- 一、項目分點
- 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所有的數據遍歷完成后,
將數據寫出
②過濾數據:保留沒有點擊過商品的用戶
③轉換,只要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層獲取
指標的作用:漏斗分析,統計瀏覽頁面 -> 進入詳情的頁面 -> 加入購物車 -> 下單 -> 支付,
步驟
客單價(客單價 = 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 中),最后完成最終的聚合操作。
總結
以上是生活随笔為你收集整理的简历项目描述过程详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 苹果手机打字换行怎么换_苹果id怎么换
- 下一篇: 学习笔记21--高精地图技术概述