近期易觀公司舉辦了一個OLAP大賽,咱們隊伍很是榮幸地得到了第一名,成爲本次比賽最大黑馬。此篇文章主要分享一下咱們是如何解決有序漏斗秒查問題的html
比賽地址:2017易觀OLAP算法大賽mysql
參賽狀況: https://www.analysys.cn/media/detail/20018458/git
在以上示例場景下,咱們在易觀提供的6億測試數據集上,在4臺UCloud雲主機(16core,16G ram)機器下從24s優化到了0.5s。而在正式比賽的26億數據集上,使用相同硬件環境,耗時1.6s。github
題目描述的有序漏斗問題能夠歸結爲 帶滑動時間窗口的最左子序列問題, 好比咱們須要尋找,2017年7月份中,在3小時的時間窗口下, [A,B,C,D] 漏斗路徑下的轉化狀況, 單個用戶只能有 NULL , [a], [A,B], [A,B,C], [A,B,C,D] 五種轉化結果,對應的漏斗深度咱們稱之爲level,在[A,B,C,D]漏斗路徑下,level的取值能夠有[0,1,2,3,4] 四個值,題目的要求即算出全部用戶的知足條件下最大level彙總結果。算法
理解問題以後,咱們梳理了一下流程圖:sql
咱們將問題解決分爲5個步驟:數據庫
根據以上分析,須要filter,group,sort,aggregate等操做,數據庫是必備的核心,而在OLAP領域,開源的數據庫選型有不少,好比:mysql, druid, kylin hdfs + (hive,spark,presto),imapla, kudu etc。數組
但在這個場景下,結合以往對其餘數據的深刻研究分析對比經驗,咱們幾乎堅決果斷就選擇了 ClickHouse (縱然它不支持udaf),,咱們相信ClickHouse是目前cpu領域最快的olap開源數據庫,它最突出的優勢就是快,若是你是第一次用,相信ClickHouse會讓你感到很是驚豔。數據結構
ClickHouse 由俄羅斯Yandex開發,09年原型,12年生產可用,16年開源,目前最大的線上部署實例是 Yandex.Metrica: 472個節點,每秒處理2T數據,實時在線分析。ClickHouse 在OLAP上的查詢性能很是彪悍,平均查詢性能幾乎是vertica的三倍。架構
ClickHouse不只速度快,它系統架構靈活,性能優越,代碼優雅, 很是適合大數據下須要極致性能的應用場景。ClickHouse目前暫不支持UDAF,但不要緊,咱們能夠經過修改源代碼並從新編譯來實現自定義AggregateFunction。
以上就是針對漏斗場景的代碼修改狀況,能夠看出咱們只用了不到300行代碼就爲ClickHouse加入了漏斗計算(aggregate function path)的功能。
對比官方的presto + hdfs 方案實現的24s速度,使用ClickHouse以後,咱們在測試環境下跑的速度達到了8s。
下面開始咱們的正式優化過程
咱們注意到,漏斗的計算中,每一個用戶都是相互獨立的,因此咱們能夠將數據按照uid來分區,這樣就將數據分散到了四臺機器上,咱們能夠分別向每一個數據庫節點發送請求,而後將數據進行彙總,獲得最終結果。
經過此次優化,咱們在測試環境下跑的速度達到了1.6s。
ClickHouse中primary key表明了數據的組織排序方式
左邊的以(timestamp,uid)爲主鍵,時間是有序的,方便作時間精準過濾,但uid壓縮率低;右邊的以(uid,timestamp) 爲主鍵,uid壓縮率高,方便作uid group, 但對時間過濾支持不夠好。
經過測試對比,咱們發現以 (uid,timestamp) 做爲主鍵性能略快,查詢時間達到了 1.4s。
當咱們以 (uid,timestamp) 做爲primary key後, 分組內的數據其實已經有序了, 咱們能夠去掉代碼中的sort方法,來提升性能,通過這個優化,查詢時間達到了 0.9s。
這裏主要是用了一些 剪枝的策略,當咱們從左往右去搜索 a,b,c,d 漏斗的時候,咱們須要找到最大的深度,必須一直去搜索以a開頭的子序列;但咱們從右往左搜索時, 咱們只要考慮比當前結尾更大的子串便可, 好比咱們找到了 a,b,c, 後面咱們只須要考慮以d結尾的串,這樣減少了搜索的複雜度,查詢時間達到了0.8s。
事件ID到數組下標Index的映射,咱們直接遍歷了數組搜索,而不使用std::unordered_map, 由於在events數據量不大的狀況下, 數組搜索O(1)比O(n)慢。
使用純C++數組存儲事件序列,不使用std::vector,去掉了vector的開銷,靈活控制內存分配。
經此優化,查詢時間達到了0.6s。
數據庫一般會對字段進行壓縮,這樣作節省了硬盤空間,但卻浪費了cpu計算,爲了提供性能,咱們對字段進行了部分壓縮,經此優化,查詢時間達到了最終的0.5s。
總結:
咱們已經將代碼和PPT開源:
https://github.com/analysys/olap
0.5s固然不會是極限,現在GPU數據庫大道橫行,技術變革也愈演愈烈, 前路漫長,預測將來最好的方法就是本身創造將來。
[1] 如何實現海量數據下有序漏斗秒查
https://zhuanlan.zhihu.com/p/30823204
[2] analysys/olap
https://github.com/analysys/olap
[3] 易觀olap大賽
http://ds.analysys.cn/OLAP.html
[4] 易觀OLAP算法大賽結果揭曉,開源組黑馬放大招!