客戶端埋點實時OLAP指標計算方案
背景
產品經理想要實時查詢一些指標資料,在新版本的APP上線之後,我們APP的一些質量指標,比如課堂連線掉線率,課堂內崩潰率,APP崩潰率等指標,以此來看APP升級之後上課的體驗是否有所提升,上課質量是否有所提高,為下一步的APP升級做準備。
客戶端埋點
1.0版本設計
流程
按照需求打點,如果想知道某一指標如進入教室成功率,點選進入教室這一動作上報資料,進入教室結果上報資料,同時上報課程id,使用者id等屬性。
缺點
埋點規範全靠Excel,產品經理編寫Excel埋點文件,開發按照文件埋點,測試按照文件測試。出現如下幾類問題,
- 產品經理埋點文件編寫失誤,漏埋點,埋點關鍵字錯誤,上報欄位值不明確等;
- 埋點開發者打錯上報關鍵字,如device打錯成devcie,上報值使用全形輸入法,時間戳未按照規範上報成毫秒。
- 測試人員,不重視測試環節,只是粗略看下埋點是否存在,並未進行埋點質量的測試。
- 大資料開發進行資料清洗落地時,遇到未按照json格式上報的髒資料,由於上報值不規範,很多資料增加了清洗的難度和不確定性。
優點
整個流程跑起來了,有些計算指標具有參考意義。
2.0版本設計
規範埋點上報
經過調研,我們2.0採用Protobuf資料格式上報,並封裝成統一埋點SDK,一方面可以定義列舉值,解決上報值和關鍵字不規範的問題。上報的資訊進行歸類,簡潔明瞭。 我們定義了三種資料結構:
- 基礎資訊
message BaseInfo { //系統上報時間戳-毫秒(由銀河服務端生成) int64 sysTime = 1; //客戶端上報時間戳-毫秒 int64 time = 2; //會話Id,一段會話的唯一標識(客戶端每次啟動APP到下一次啟動APP之間生成一個會話id) //生成規則:16位隨機數+13位時間戳+3位(端表示pc:001 android:002 ios:003 web:004 server:005) string sessionId = 3; //裝置唯一標識 string uuid = 4; //公司標識 Company company = 5; //sdk版本 SDKVersion sdkVersion = 6; //使用者ID string userId = 7; //使用者型別 UserType userType = 8; //日誌型別 LogType type = 9; string eventId = 10;//事件ID (產品經理提供) NetType netType = 11;//網路型別 OperatorType operatorType = 12;//網路運營商型別 int32 requestCnt = 13;//介面請求次數,預設為1 string business = 14;//業務型別 (產品經理提供) //來源:安卓、iOS、pc、web、server Os os = 15; string channel = 16; // 渠道來源(針對前端的落地頁url編碼,H5商城的來源渠道) //APP版本號 string appVersion = 17; //APP型別:yimi/bubugao/yuxuepai string appType = 18; //裝置型號,標示手機品牌+型號 string deviceInfo = 19; //裝置作業系統版本號 string osVersion = 20; AppAction appAction = 21; //資訊,崩潰資訊 string info = 22; int64 stayTime = 23; //頁面停留時間 }
- 教室內資訊
message LiveInfo {
//課程id
string lessonId = 1;
//課程型別
LessonType lessonType = 2;
//伺服器IP
string serverIp = 3;
//使用者ip
string userIp = 4;
}
- 其他資訊
message ExtraInfo { //額外欄位key string key = 1; //額外欄位value string value = 2; }
埋點元資料介面
基於1.0的一些缺點,我們進行了改造,開發了一個埋點元資料錄入的介面,產品經理只需要在上面錄入想要的埋點,規範上報值。開發者和測試者都可以在這個介面檢視埋點的資訊。
埋點測試流程規範
重新規劃了埋點的測試流程,粗略流程如下
後端架構設計
CarbonDataApache CarbonData是一種新的融合儲存解決方案,利用先進的列式儲存,索引,壓縮和編碼技術提高計算效率,從而加快查詢速度。其與Spark緊密結合,而我們公司的技術棧也包含Spark,經過測試查詢效能確實優秀,遂決定使用此元件。
社群BUG
在測試的過程中,由於想使用新版的Spark,所以使用了Spark2.3+CarbonData1.5的組合,但是在入庫的時候,發現了一個bug,Spark Streaming無法實時寫入表,社群對此bug至今也沒有解決。所以只能決定使用Spark 2.2+CarbonData1.5。
實時入庫
CarbonData表結構設計
CREATE TABLE IF NOT EXISTS carbon.dw_flow_disc_analyze_daily (
pt string,
lesson_id string,
app_version string,
user_type string,
app_device_type string,
server_ip string,
event_type string,
err_msg string,
msg_type string,
galaxy_type string,
sys_time string,
app_type string,
lesson_type string,
result string,
crash_type string,
crash_msg string,
down_load_result string
)
STORED AS carbondata
TBLPROPERTIES (
'DICTIONARY_INCLUDE'='pt,lesson_id,server_ip,app_version,app_device_type,user_type,event_type,err_msg,msg_type,galaxy_type,app_type,lesson_type,result,crash_type,down_load_result,crash_msg',
'BAD_RECORD_PATH'='hdfs://bd-tst/apps/carbon/badrecords',
'INVERTED_INDEX' = 'lesson_id',
'sort_columns'='pt,lesson_id',
'SORT_SCOPE'='GLOBAL_SORT',
'RANGE_COLUMN'='pt',
'streaming'='true');
參照CarbonData的官方文件和例子,開發Spark Streaming程式,消費日誌資料實時入庫。
OLAP
啟動Spark ThriftServer
nohup /opt/spark/spark-2.2.3/bin/spark-submit --master spark://bd-prod-master01:7077,bd-prod-master02:7077 --conf spark.sql.hive.thriftServer.singleSession=true --deploy-mode client --num-executors 4 --executor-memory 2g --executor-cores 2 --total-executor-cores 8 --class org.apache.carbondata.spark.thriftserver.CarbonThriftServer /opt/spark/spark-2.2.3/carbonlib/apache-carbondata-1.5.2-bin-spark2.2.1-hadoop2.7.2.jar hdfs://bd-prod/apps/carbon/warehouse >/dev/null 2>&1 &
JDBC連線查詢
明細資料入庫之後,使用jdbc連線Spark ThriftServer,對指標進行實時聚合。
總結
優點
- 實時入庫,新版本APP上線後可以立刻看到買點資料;
- SQL靈活性高,可進行JOIN,條件可隨意定製;
- 查詢速度快,一個月之內的報表資料可在30s之內返回。
缺點
- 耗費資源比較嚴重,需要建立索引,需要的spark記憶體比較大,資源充足可忽略;
- 與Spark強耦合,不能使用Flink入庫;
- 社群不活躍。