MaxCompute實戰之資料儲存
MaxCompute(原名ODPS),是阿里巴巴自主研發的海量資料處理平臺。 主要服務於批量結構化資料的儲存和計算,可以提供海量資料倉儲的解決方案以及針對大資料的分析建模服務。支援PB級別資料分析,常用場景如下:大型網際網路企業的資料倉儲和BI分析、網站的日誌分析、電子商務網站的交易分析、使用者特徵和興趣挖掘等。
我們接入MaxCompute主要做兩個工作,一是網站的日誌分析,二是使用者特徵和興趣挖掘。其中網站日誌分析專案組內(就是高德開放平臺)已經玩的比較溜了,“使用者特徵和興趣挖掘”還在探索中。
無論是做資料分析還是資料探勘,都離不開資料。而MaxCompute不負責收集資料,他只負責處理資料,就好比你有臺酸奶機但是沒牛奶(MaxCompute比作酸奶機,資料比作牛奶)。所以先把海量的日誌資料收集起來是第一步要做的工作。
MaxCompute中的後設資料儲存在阿里雲端計算的另一個開放服務Table Store(表格儲存服務)中,後設資料內容主要包括使用者空間後設資料、Table/Partition Schema、ACL、Job後設資料、安全體系等。
概念清晰了,我們就可以開始動手,下面說說如何將海量的日誌收集起來。
一. 資料收集
資料來源我們並不關心,可以是來自MySQL,也可以是文字檔案。不過我們的業務場景主要是生產大量的log(文字檔案)。比如Nginx請求日誌、PHP,Java,Node的服務日誌、自建的埋點日誌等。
如果你的資料不是文字檔案,可以參考這篇文章將資料匯入MaxCompute的方法彙總
首先我們要將這些日誌收集起來,這裡我們使用Fluentd服務(類似的服務還有kafka、LogHub、DataX等,都大同小異,這裡我用Fluentd作描述只是方便),通過Fluentd我們輕鬆的建立任務去按時讀取各臺伺服器上的日誌檔案。簡單點說就是你只需要配置伺服器上日誌的路徑,Fluentd就幫你把日誌儲存到MaxCompute的Table Store中,然後你就能愉快的通過MaxCompute分析資料了。
使用Fluentd去管理資料收集方式確實能幫我們節省大量人力,而且方式相當便捷,分分鐘就能上線泡咖啡!但Fluentd帶來便利的同時就需要我們遵守它的規則。比如建立的Table Store表(這樣說好彆扭,還是叫MaxCompute表吧),必須按照Fluentd定義的欄位寫,預設四個欄位如下
- content 日誌內容
- ds 天,Fluentd自動生成
- hh 小時,Fluentd自動生成
- mm 分鐘,Fluentd自動生成
PS:如果個人使用Fluentd是可以自定義欄位的,不需要像我們一樣。我們團隊之所以規範欄位資訊,主要是為了之後的擴充套件和統一管理(上百個專案)。當然我也建議大家像我們一樣規範欄位,這樣做的好處是之後你能基於Fluentd做平臺。
如上可以看到真正能控制的欄位只有content,其他欄位Fluentd都幫你自動生成。所以在你要做資料分析時就需要用到無數的LIKE,這樣不但會導致查詢速度慢,最主要和最痛苦的是稍微複雜點的資料分析都無法實現,用LIKE去模仿等於、不等於、包含、不包含難度太高。你好不容易(其實並沒有很不容易)把平臺搭建好,並說這個服務多牛。一個月後PM要你產出一個報表你發現沒辦法,PM會覺得你做的啥玩意兒…
這個時候我們可以在埋點時對資料格式做下處理,用些小技巧。比如用各種符號做分隔符,定義一套log格式標準,總歸有很多總辦法解決問題。但是馬總不是說過嘛,解決問題的最好辦法就是不給他發生的機會……所以看下文
二. 自建MaxCompute資料來源
MaxCompute本身提供了Fluentd的所有功能介面,不過呼叫介面雖然簡單,配置環境卻很複雜。如果業務需要對資料做深入的分析和挖掘,就不得不自己配置環境。當然,這也是MaxCompute強大的體現(一般使用成本高的都讓人覺得很強大)……
-
首先,我們需要建立Table,這和MySQL基本一樣
create table if not exists sale_detail( shop_name string, customer_id string, total_price double) partitioned by (sale_date string,region string); //設定分割槽
分割槽一定要考慮到,因為MaxCompute的查詢最多隻能顯示5000條資料,limit不支援offect,所以資料量一大就無法通過開發套件(Data IDE)做線上查詢。匯出資料到本地也需要使用分割槽欄位,分割槽越大一次請求能匯出的資料就越多,合理的設定分割槽非常重要。
- 通過MaxCompute DataHub Service(DHS) 通常稱為Datahub服務,去上傳資料。
Datahub服務提供了SDK,不過是Java的,通過SDK可以實現實時上傳功能。因為Datahub服務介面不用建立MaxCompute任務(Task),所以速度非常快。可以向較高的QPS(Query Per Second)和較大的吞吐量的服務提供資料儲存支援。Datahub上的資料只會被儲存7天,之後會被刪除,被刪除之前會儲存到MaxCompute的表中。也可通過非同步的方式,呼叫介面同步Datahub中的資料到MaxCompute的表中。
如果服務本身就使用Java可以直接使用SDK,非Java服務就需要權衡成本。應該還有類似Fluentd的平臺,可以到 阿里雲MaxCompute工具查詢。
三. 流程介紹
在實際專案中使用MaxCompute有4種通用的方案,這裡貼出流程圖供大家參考;
-
最簡單也是最通用的方法,使用Fluentd上傳資料,適用於簡單的資料儲存。如果只是用來收集日誌,出問題時容易排查問題可以選擇這種方案;流程圖如下:
![使用Fluentd上傳資料](https://yqfile.alicdn.com/e5081df1919fe1c35a4a1ff6f8638696dbacb1fa.png)
-
比較進階的方法,使用PyODPS上傳資料,適用於較為複雜的資料儲存。比如我們需要對收集的日誌做轉換,例如需要將IP地址轉換成城市等;流程圖如下:
![使用PyODPS上傳資料](https://yqfile.alicdn.com/21f3115c8b15449008412847a548622a5bfa1aef.png)
-
比較複雜,易於擴充套件的方法,需要使用Fluentd和PyODPS上傳資料,適用於需要對資料做大量分析的場景。例如多個部門需要的資料埋點也不一樣,分析的方法和想得到的報表也不一樣等;流程圖如下:
![使用Fluentd和PyODPS上傳資料](https://yqfile.alicdn.com/c1a818941f5442d317bcaaf85e34c8a89ec36ea9.png)
-
最實時的方法,使用Datahub上傳資料,適用於需要實時同步資料的業務場景。例如遊戲日誌處理,電商充值、購物等要求低延的場景;流程圖如下:
![使用Datahub上傳資料](https://yqfile.alicdn.com/9864a654ee39f8a6d02618c50f90827c6c489efe.png)
四. 總結
直接在生產環境上呼叫DHS對我們的PHP環境來說成本太高,所以暫時使用的是Fluentd收集日誌資料,然後通過PyODPS將資料下載到本地,處理後再傳到MaxCompute Table中。我們的業務場景比較麻煩所以流程顯得略複雜,如果你不需要做複雜的資料分析,建議直接使用Fluentd上傳資料就行。
五. 最後
最後貼出核心程式碼,供參考,語言使用Python。
-
封裝MaxCompute的連線,這樣方便我們隨時隨地使用MaxCompute的強大功能,只需要在程式碼中呼叫一句 “odps = OdpsConnect().getIntense()” ;
#/usr/bin/python3 __author__ = `layne.fyc@gmail.com` #coding=utf-8 from odps import ODPS # 測試地址:endpoint=`http://service-corp.odps.aliyun-inc.com/api` # 正式地址:endpoint=`http://service.odps.aliyun-inc.com/api` debug = True onlineUrl = `http://service.odps.aliyun-inc.com/api` localUrl = `http://service-corp.odps.aliyun-inc.com/api` accessId = `填自己的` accessKey = `填自己的` class OdpsConnect: model = object def __init__(self): self.model = ODPS(accessId,accessKey,project=`專案名`, endpoint=(localUrl if debug else onlineUrl)) def getIntense(self): return self.model def exe(self,sql): return self.model.execute_sql(sql)
-
建立MaxCompute Table用來儲存我們的海量日誌,上萬億條資料都不在話下。
from OdpsConnect import OdpsConnect from odps.models import Schema, Column, Partition odps = OdpsConnect().getIntense() odps.delete_table(`test_amap_analys`, if_exists=True) #表存在時刪除 #各種項 columns = [ Column(name=`uid`, type=`bigint`, comment=`user id`), Column(name=`ctime`, type=`bigint`, comment=`time stamp`), Column(name=`url`, type=`string`, comment=`url`), Column(name=`param`, type=`string`, comment=`param`), Column(name=`ip`, type=`string`, comment=`ip`), Column(name=`city`, type=`string`, comment=`city`) ] #分割槽資訊 partitions = [ Partition(name=`dt`, type=`bigint`, comment=`the partition day`) ] schema = Schema(columns=columns, partitions=partitions) table = odps.create_table(`test_amap_analys`, schema,if_not_exists=True)
有幾點需要特別注意:
- MaxCompute Table只支援新增資料,不支援刪除與修改資料。如果要刪除髒資料只能先備份整張表到B,再刪除這張表A,再新建表A,最後將表B的備份資訊處理後重新匯入表A;所以,匯入資料一定要慎重。
- 分割槽資訊可以建立很多個,但是在匯入、匯出、某些特殊查詢時都要全量帶上。比如你的分割槽欄位為“a,b,c,d”,最後你在匯出資料時必須指定”a,b,c,d”的內容,只指定‘a,b’或者‘a.c’都是不行的。所以設定分割槽欄位也要慎重,儘量欄位設定少點,這裡建議通過資料量來設定,建議每個分割槽儲存2W條左右的資料。
-
通過Tunnel上傳資料到MaxCompute;
描述:我們通過程式在伺服器上埋點了大量日誌檔案,檔名為“log/20160605.log”每天通過日期定時生成。每條埋點日誌的格式為:
“name:amap|ip:19.19.19.19|uuid:110112|param:sdfsdf=123&fsdf=123|url:get-user-info|time:123123123”
使用 ‘|’和‘:’號分隔,現在我們需要將所有日誌資料儲存到我們上一步建立的“test_amap_analys” 表中。
#/usr/bin/python3 __author__ = `layne.xfl@alibaba-inc.com` #coding=utf-8 import datetime import urllib.parse #自己封裝的IP庫 import db.IP from OdpsConnect import OdpsConnect from odps.models import Schema, Column, Partition from odps.tunnel import TableTunnel odps = OdpsConnect().getIntense() t = odps.get_table(`test_amap_analys`) records = [] tunnel = TableTunnel(odps) #日誌檔名格式為 log/20160605.log #這裡預設上傳前5天資料 sz = 5 while sz > 0 : #get Yestoday last_time = (datetime.datetime.now() + datetime.timedelta(days=-sz)).strftime(`%Y%m%d`) # 分割槽不存在的時候需要建立,不然會報錯 t.create_partition(`dt=`+last_time, if_not_exists=True) #建立連線會話 upload_session = tunnel.create_upload_session(t.name, partition_spec=`dt=`+last_time) #通過日期規則構造的檔名 file = `log/%s.log` % last_time with upload_session.open_record_writer(0) as writer: for line in open(file,`r`,encoding=`utf8`): arr = {} #我們的日誌使用 ‘|’和‘:’號分隔, #例如:‘name:amap|ip:19.19.19.19|uuid:110112|param:sdfsdf=123&fsdf=123|url:get-user-info|time:123123123’ for tm in raw.split(`|`): pstm = tm.split(`:`) if(len(pstm)==2): arr[pstm[0]] = pstm[1] #nginx中的ip引數可能被偽造,我們需要做過濾 ip = arr.get(`ip`,``) if(len(ip)>15): iparr = ip.split(`,`) ip = iparr[-1].strip(" ") city = `` if ip != ``: #通過ip獲取城市資訊 city = db.IP.find(ip) writer.write(t.new_record( [ arr.get(`uid`,0), arr.get(`time`,0), arr.get(`url`,``), urllib.parse.unquote(arr.get(`param`,``)).replace("\","*").replace(`"`,"*"), #做URL_DECODE ip, city, last_time ])) upload_session.commit([0]) sz = sz - 1;
有幾點需要特別注意:
- 使用MaxCompute一定要記住,資料為重,分割槽先行。儲存資料,下載資料都要先設定好分割槽再運算元據。
- Nginx中拿到的IP引數能被偽造,不能直接使用,需要了解的話可看這篇文章 HTTP_X_FORWARDED_FOR偽造
有幫助的URL列表(不定期更新):
相關文章
- Spring Boot實戰系列(2)資料儲存之NoSQL資料庫MongoDBSpring BootSQL資料庫MongoDB
- Hive之 資料儲存Hive
- SaaS 模式雲資料倉儲 MaxCompute 資料安全最佳實踐模式
- Flutter持久化儲存之資料庫儲存Flutter持久化資料庫
- 鴻蒙HarmonyOS實戰-Web元件(Cookie及資料儲存)鴻蒙Web元件Cookie
- DataLeap資料資產實戰:如何實現儲存最佳化?
- 儲存資料之SharedPreference
- IOS資料儲存之NSUserDefaultsiOS
- k8s之資料儲存-配置儲存K8S
- IOS資料儲存之檔案沙盒儲存iOS
- 大資料儲存平臺之異構儲存實踐深度解讀大資料
- IOS資料儲存之Sqlite資料庫iOSSQLite資料庫
- IOS資料儲存之FMDB資料庫iOS資料庫
- Android中的資料儲存之檔案儲存Android
- k8s之資料儲存-高階儲存K8S
- 大資料儲存:MongoDB實戰指南——常見問題解答大資料MongoDB
- Android資料儲存之SharedPreferences及如何安全儲存Android
- 大資料挑戰下的儲存之路大資料
- 【Python3網路爬蟲開發實戰】5-資料儲存-2-關係型資料庫儲存-1 MySQL儲存Python爬蟲資料庫MySql
- 基於python的大資料分析-pandas資料儲存(程式碼實戰)Python大資料
- 資料儲存--檔案儲存
- 【Python3網路爬蟲開發實戰】5-資料儲存-3-非關係型資料庫儲存-2 Redis儲存Python爬蟲資料庫Redis
- 【Python3網路爬蟲開發實戰】5-資料儲存-3-非關係型資料庫儲存-1 MongoDB儲存Python爬蟲資料庫MongoDB
- 《資料儲存》之《分庫,分表》
- 海量資料儲存之動態SchemaOU
- greenDAO資料庫之修改儲存地址資料庫
- 安卓開發之資料儲存方式安卓
- Netflix實戰指南:規模化時序資料儲存
- Spring Boot 揭祕與實戰(二) 資料儲存篇 – MongoDBSpring BootMongoDB
- Spring Boot 揭祕與實戰(二) 資料儲存篇 – MySQLSpring BootMySql
- 分散式檔案系統HDFS,大資料儲存實戰(一)分散式大資料
- 如何使用HBase?大資料儲存的兩個實戰場景大資料
- Spring Boot 揭祕與實戰(二) 資料儲存篇 - ElasticSearchSpring BootElasticsearch
- Spring Boot 揭祕與實戰(二) 資料儲存篇 - MySQLSpring BootMySql
- Spring Boot 揭祕與實戰(二) 資料儲存篇 - RedisSpring BootRedis
- Spring Boot 揭祕與實戰(二) 資料儲存篇 - MongoDBSpring BootMongoDB
- Spring Boot 揭祕與實戰(二) 資料儲存篇 - JPASpring Boot
- Android資料儲存之SQLCipher資料庫加密AndroidSQL資料庫加密