微博大數據即席查詢(OLAP)引擎實踐
- 2020 年 7 月 13 日
- 筆記
- AnalysisQL, 大數據
前言
適用於 即席查詢 場景的開源查詢引擎有很多,如:Elasticsearch、Druid、Presto、ClickHouse等;每種系統各有利弊,有的擅長檢索,有的擅長統計;實踐證明,All In One 是行不通的,最好的方式是選取若干個(考慮運維成本,建議 1 ~ 3 個),每個都對應着自身最具優勢的場景。
大多數的技術分享會從系統架構、功能擴展或性能優化角度進行討論,本文不涉及這些內容。本文以 指標多維統計查詢 為例,討論多個查詢引擎混合應用場景下的問題思考及相應的解決方案。
指標多維統計查詢
定義
什麼是 指標多維統計查詢 ?按指定的條件查詢指標值(一個或多個),條件包括:
- 時間範圍(必選)
- 時間粒度(必選)
- 維度過濾條件(可選,類似SQL中的 Where)
- 維度分組條件(可選,類似SQL中的 GroupBy)
- 維度或指標排序條件(可選,類似SQL中的 OrderBy)
注意,指標多維統計查詢 涉及4個關鍵元素:時間範圍、時間粒度、維度及 指標(詳情見後)。
示例
- 查詢微博視頻最近7天範圍內,每天的PSR1(秒開率)是多少?
- 查詢微博視頻最近1個月內,每天的移動4G場景下各個運營商的卡頓率是多少?
查詢引擎混合應用
多個查詢引擎混合應用的場景下,會遇到哪些問題呢?我們主要從 工程角度 與 業務角度 來看下。
工程角度
每個查詢引擎都有自己特有的API(也包含 SQL,雖然開源社區大多致力於提供標準的SQL支持,但實際落地情況並不盡如人意),指標查詢需要 直接連接 查詢引擎並使用相應的API進行指標值計算,開發人員和分析人員需要在多個不同的API之間來回切換,學習及維護成本較高;查詢引擎版本升級或引入新的引擎會增加這些成本,系統整體的靈活性及可擴展性較差。
業務角度
多個查詢引擎混合使用的場景下,業務指標會分散至不同的引擎中,會遇到以下問題(複雜度依次增加):
- 某個業務指標的查詢需要使用相應的查詢引擎;
- 某個業務指標的查詢需要使用相應的查詢引擎,且計算規則較為複雜;
- 某個業務指標需要依賴多個查詢引擎的聯合查詢;
- 某個業務指標需要依賴多個查詢引擎的聯合查詢,且計算規則較為複雜;
可以看出,我們需要維護指標與查詢引擎的 對應關係,以及指標的 計算規則,實際中很大程度上依賴於 文檔 (Wiki)。數據應用服務中常見的數據可視化、報表、數據接口,這些服務的實現模塊均需要直接耦合這些對應關係及計算規則,而且需要重複多次。如果某個指標的對應關係或計算規則發生變化,相應的文檔及相關的服務 必須 全部更新,才能保證數據一致性。
指標眾多的場景下,上述提及的成本及複雜度會大幅增加,有過類似服務經驗的同學應該深有體會。
補充
對應關係 與 計算規則 可能比較抽象,舉一個具體的例子。假設 MySQL 數據庫某數據表 DEFAULT.TEST_TABLE 的中有 2 列:A 和 B,指標 M 的值可以通過SQL語句查詢得出,如:
SELECT
A / B AS M
FROM
DEFAULT.TEST_TABLE
數據應用服務(數據可視化、報表或數據接口)查詢這個指標數據時,需要知道去什麼地方查詢,以及具體如何查詢;上述示例需要通過遠程方式連接MySQL,連接時使用到的協議類型(MySQL)、IP地址、端口號等信息就是 對應關係;查詢時需要使用的SQL語句就是 計算規則。
指標庫
針對指標眾多,指標計算規則及相關信息不易維護的問題,我們提出 指標庫 用於規範化指標管理。什麼是 指標庫?
對於某一個指標而言,可以從不同的時間範圍、時間粒度及維度視角進行統計查詢。換句話說,對於某一個指標而言,我們需要知道可以從哪些時間範圍、哪些時間粒度、哪些維度視角進行統計查詢,以及指標的計算規則是什麼。一般情況下,同屬於一個 業務 的指標會共享相同的時間範圍、時間粒度及維度項,我們將類似這樣的業務統稱為 主題。每一個主題對應着一個業務或業務中的某個細分場景,如:
- 移動端視頻上傳性能
- PC端視頻上傳性能
- 移動端視頻劫持性能
- CDN服務質量分析
每一個 主題 需要包含以下信息:
-
主題名稱
顧名思義,業務名稱或業務中的某個細分場景名稱。
-
時間範圍
可支持的數據查詢時間範圍([起始時間,結束時間]);相當於數據的存儲周期,過期數據會被清除。
-
時間粒度
可支持的數據查詢最小時間粒度,相當於數據的聚合程度,如:1 秒,5 分鐘,1 小時 或 1 天 之類的。
假設時間粒度是 5 分鐘,表示最小可以支持 每5分鐘 一個數據點的查詢請求,同時也可以支持 每1小時 或 每1天 之類的查詢請求,但不可以支持 每1秒 或 每1分鐘 之類的查詢請求。
-
維度
可以支持的數據查詢視角,通常會有多個,如:省份、運營商、設備 之類的。以 運營商 為例,表示可以查看指定運營商或各個運營商的數據。
-
維度值
維度可以支持的查詢值,通常會有多個。以維度 運營商 為例,維度值會有移動、聯通、電信之類的。
-
指標
可以支持查詢的指標,通常會有多個,如:秒開率、卡頓率 之類的。
-
指標計算規則
某個指標的計算公式。以指標 卡頓率 為例,計算公式:卡頓次數 / 總次數。
若干個 主題 的 集合,我們稱之為 指標庫。指標庫 的內容可以按照上述描述的格式記錄到專用的文檔中,統一更新發版,用於公司內部數據共享。
查詢語言
數據應用服務(數據可視化、報表、數據接口)的核心邏輯是查詢指標數據,並不是使用 對應關係 和 計算規則 完成指標計算,且存在重複直接耦合的問題。為此,我們在 指標庫 的基礎之上,針對 指標多維統計查詢 場景設計了一種領域特定語言(DSL)。也就是說,數據應用服務查詢指標數據時直接使用統一的查詢語言,不再存在直接耦合 對應關係 和 計算規則 的情況,後續 對應關係(查詢引擎升級或遷移)或 計算規則 的 變更 對於數據應用服務也是 透明 的。
查詢語言是基於 JSON 實現的。
getTopics
查詢指標庫中有哪些主題(多個)。
{
"type": "getTopics"
}
getDimentions
查詢指定主題中有哪些維度項(多個)。
{
"type": "getDimentions",
"topic": "..."
}
其中,topic 為主題名稱。
getDimentionValues
查詢指定主題、指定維度中有哪些維度值(多個)。
{
"type": "getDimentionValues",
"topic": "...",
"dimension": "..."
}
其中,topic 用於指定主題名稱, dimension 用於指定維度名稱。
getMetrics
查詢指定主題中有哪些指標項(多個)。
{
"type": "getMetrics",
"topic": "..."
}
其中,topic 用於指定主題名稱。
query
查詢(指標數據),是查詢語言中最為複雜的類型。
{
"type": "query",
"topic": "...",
"interval": {...},
"granularity": {...},
"metric": "...",
"where": {...},
"groups": [...],
"having": {...},
"orders": [...],
"limit": ...
}
topic
主題名稱(必填項)。
interval
時間範圍(必填項)。
{
"start": "...",
"end": "..."
}
其中,start/end 均為閉區間,格式:yyyy-MM-dd HH:mm:ss。
granularity
時間粒度,默認為無窮大。
{
"data": ...,
"unit": "..."
}
其中,data 為數值(整型),unit 為單位,如:s(秒)、m(分鐘)、h(小時)、d(天)、w(周)、M(月)、y(年)。
metric
指標名稱(必填項)。
where
維度過濾,對應於SQL語句中的 Where,默認為空,支持比較表達式與邏輯表達式。
比較表達式
比較表達式用於表示數值比較、包含或不包含,以及正則匹配。
eq/ne/gt/lt/ge/le
{
"operator": "...",
"name": "...",
"value": "..."
}
其中,operator 為 eq(等於)、ne(不等於)、gt(大於)、lt(小於)、ge(大於或等於)或 le(小於或等於),name 為維度名稱,value 為維度值。
in
{
"operator": "in",
"name": "...",
"values": [...]
}
其中,operator 為 in(包含),name 為維度名稱,values 為維度值列表(JSON數組)。
regex
{
"operator": "regex",
"name": "...",
"pattern": "..."
}
其中,operator 為 regex(正則匹配),name 為維度名稱,pattern 為正則表達式。
邏輯表達式
邏輯表達式用於表示一個或多個表達式之間的 與(And)、或(Or)、非(Not)關係。
and
{
"operator": "and",
"filters": [...]
}
其中,operator 為 and(與),filters 為兩個或兩個以上的比較表達式或邏輯表達式。
or
{
"operator": "or",
"filters": [...]
}
其中,operator 為 or(或),filters 為兩個或兩個以上的比較表達式或邏輯表達式。
not
{
"operator": "not",
"filter": {...}
}
其中,operator 為 not(非),filter 為一個比較表達式或邏輯表達式。
groups
維度分組,類似於SQL語句中的 GroupBy,默認為空,可以指定多個維度項(JSON數組)。
[
"...",
...
]
having
分組過濾,類似於SQL語句中的 Having,默認為空,語法同 where。分組過濾表達式中的 name 可以是維度名稱,也可以是指標名稱。
orders
排序,類似於SQL語句中的 OrderBy,默認為空,可以指定多個排序項。
[
{
"name": "...",
"sort": "..."
},
...
]
其中,name 為維度名稱或指標名稱,sort 為 asc(升序)或 desc(降序)。
limit
限制結果集行數,類似於SQL語句中的 Limit,默認為空。
示例參考
查詢指標
主題:CDN服務質量分析;
時間範圍:[“2020-03-16 00:00:00”, “2020-03-16 23:59:59”];
時間粒度:1小時;
指標:下載速度(download_speed_avg);
維度過濾:域名(domain)包含有字符串「weibo」;
維度分組:運營商(isp);
分組過濾:下載速度(download_speed_avg)大於2000 Kb/s;
排序:下載速度降序(download_speed_avg);
結果集:最多100行;
查詢語言
{
"type": "query",
"topic": "CDN服務質量分析",
"interval": {
"start": "2020-03-16 00:00:00",
"end": "2020-03-16 23:59:59"
},
"granularity": {
"data": 1,
"unit": "h"
},
"metric": "download_speed_avg",
"where": {
"operator": "regex",
"name": "domain",
"pattern": "^.*weibo.*$"
},
"groups": [
"isp"
],
"having": {
"operator": "gt",
"name": "download_speed_avg",
"value": 2000
},
"orders": [
{
"name": "download_speed_avg",
"sort": "desc"
}
],
"limit": 100
}
查詢代理
查詢語言只是一種描述性的協議規範,並不能完成實際的查詢過程。我們需要一種 服務,可以接收並執行這種查詢語言,過程如下:
- 解析查詢語言,獲取需要查詢的指標;
- 查找指標對應的查詢引擎及計算規則;
- 使用查詢語言設定的查詢條件,連接查詢引擎,根據計算規則調用API,執行指標的實際計算過程;
- 返回結果。
這就是我們即將要重點介紹的 查詢代理。
客戶端
AnalysisQl 本質是一套Java API,需要嵌入到Web或RPC容器中使用。
DefaultConnector connector = new DefaultConnector();
...
AnalysisQl analysisQl = new AnalysisQl(connector);
AnalysisQl 的實現是線程安全的,一個Web或RPC容器進程中創建一個 AnalysisQl 實例即可,實例創建完成即表示查詢代理服務啟動完成。
查詢語言的執行都需要通過 AnalysisQl.request 來完成,如下:
Response response = analysisQl.request(dsl);
相當於,AnalysisQl 是查詢代理的客戶端。
代碼參考
解析器
查詢語言是基於 JSON 實現的,不方便直接在Java語言中使用,需要將其 解析 成相應的 JavaBean,如下:
Parser parser = new Parser(connector);
Request request = parser.parse(dsl);
Parser 是解析器,Request 是查詢類型的頂層抽象類,查詢語言中的每一種查詢類型都有其對應的實現類:
- GetTopicsRequest(getTopics)
- GetDimensionsRequest(getDimentions)
- GetDimensionValuesRequest(getDimentionValues)
- GetMetricsRequest(getMetrics)
- QueryRequest(query)
代碼參考
//github.com/weibodip/analysisql/blob/master/core/src/main/java/com/weibo/dip/analysisql/dsl/request/GetTopicsRequest.java
//github.com/weibodip/analysisql/blob/master/core/src/main/java/com/weibo/dip/analysisql/dsl/request/GetDimensionsRequest.java
//github.com/weibodip/analysisql/blob/master/core/src/main/java/com/weibo/dip/analysisql/dsl/request/GetDimensionValuesRequest.java
//github.com/weibodip/analysisql/blob/master/core/src/main/java/com/weibo/dip/analysisql/dsl/request/GetMetricsRequest.java
//github.com/weibodip/analysisql/blob/master/core/src/main/java/com/weibo/dip/analysisql/dsl/request/QueryRequest.java
其中,QueryRequest 關於 Filter(過濾)的實現較為有意思,有興趣的同學可以參考 //github.com/weibodip/analysisql/tree/master/core/src/main/java/com/weibo/dip/analysisql/dsl/filter。
連接器
連接器用於定義查詢代理支持的接口協議,對應着查詢語言的查詢類型:
public interface Connector {
Response getTopics(GetTopicsRequest request);
Response getDimensions(GetDimensionsRequest request);
Response getDimensionValues(GetDimensionValuesRequest request);
Response getMetrics(GetMetricsRequest request);
Response query(QueryRequest request);
}
為什麼需要設計連接器?
理論上,查詢語言是標準的,但查詢代理的實現可以是多種多樣的。類似於 Java JDBC,統一抽象數據庫的操作接口,連接數據庫時需要使用相應類型的驅動。我們使用連接器,用於橋接查詢客戶端與查詢代理的具體實現,保證系統的可擴展性;同時提供系統默認的連接器 DefaultConnector,滿足大部分場景的使用需求。
每一種查詢類型應調用連接器的哪一個接口,是通過 Request.type 判斷的,如下:
switch (request.getType()) {
case Request.GET_TOPICS:
return connector.getTopics((GetTopicsRequest) request);
case Request.GET_DIMENSIONS:
return connector.getDimensions((GetDimensionsRequest) request);
case Request.GET_DIMENSION_VALUES:
return connector.getDimensionValues((GetDimensionValuesRequest) request);
case Request.GET_METRICS:
return connector.getMetrics((GetMetricsRequest) request);
case Request.QUERY:
return connector.query((QueryRequest) request);
default:
throw new UnsupportedOperationException();
}
代碼參考
//github.com/weibodip/analysisql/blob/master/core/src/main/java/com/weibo/dip/analysisql/connector/Connector.java
//github.com/weibodip/analysisql/blob/master/view/src/main/java/com/weibo/dip/analysis/view/DefaultConnector.java
數據視圖
數據視圖 View 是一個抽象類,對應於指標庫中的主題,每一個主題均需要提供相應的數據視圖實現類,並於查詢代理初始化之前註冊到連接器中。實現時需要設置以下信息:
protected String topic;
protected List<Dimension> dimensions;
protected List<Metric> metrics;
protected List<Table> tables;
protected PolicyRouter router;
topic:主題名稱;
dimensions:維度項,每一個 Dimension 表示一個維度;
metrics:指標項,每一個 Metric 表示一個維度;
tables:數據表,每一個 Table 表示一張數據表,詳細見後;
router:策略路由,詳情見後;
以 CDN服務質量分析 為例,數據視圖實現類如下:
public class CdnServiceQualityView extends DefaultView {
/** Initialize a instance. */
public CdnServiceQualityView() {
super(
"CDN服務質量分析", // 主題名稱
...);
addDimension("country", "國家"); // 添加維度項
addDimension("business", "業務");
addDimension("city", "城市");
addMetric("error_num", "錯誤量(萬)"); // 添加指標項
addMetric("request_num", "訪問量(億)");
addMetric("download_time_avg", "下載時間(s)");
addTable(new CdnServiceQualityTable(this)); // 添加數據表
addTable(new CdnNetflowBillingTable(this));
}
}
注:DefaultView 是 View 的默認實現類。
CdnServiceQualityView 構建函數中直接完成主題、維度項、指標項及數據表的設置,也可以在 CdnServiceQualityView 實例創建完成之後,通過相應的實例方法(addDimension/addMetric/addTable)設置。
然後,註冊到連接器:
connector.register(new CdnServiceQualityView());
連接器中保存着所有已註冊的數據主題:
protected Map<String, Metadata> metadatas = new HashMap<>();
public void register(Metadata metadata) {
metadatas.put(metadata.getTopic(), metadata);
}
注:Metadata 是 View 的抽象父類。
連接器中多數協議方法的實現本質就是根據主題名稱(topic)查找到相應的數據主題實例,調用其實例方法完成查詢請求。
為什麼需要設計數據視圖?
假設數據表 A 以 5分鐘 的時間粒度,存儲着 m 個維度、n 個指標的數據,每5分鐘的數據量(即:數據行數)的最大值理論上取決於各個維度的維度值數目;如果 m 個維度的維度值數目依次為 N1、N2、…、Nm,那麼每5分鐘數據量為 N1 * N2 * … * Nm(即多個維度的維度值數目的笛卡爾乘積);每日的數據最為 288 * N1 * N2 * … * Nm。
我們列舉幾個常用的查詢:
- 查詢最近 1小時內,以 5分鐘 為時間粒度,某個維度或某幾個維度組合的指標數據;
- 查詢最近 7天內,以 1小時 為時間粒度,某個維度或某幾個維度組合的指標數據;
- 查詢最近 1月內,以 1天 為時間粒度,某個維度或某幾個維度組合的指標數據;
可以看出,數據表 A 是可以完全支撐上述查詢需求的。那麼,問題在於哪裡?問題在於查詢的 響應時間,響應時間很大程度上取決於查詢時需要掃描的 數據量。在我們的場景中,很多業務按數據表 A 的方式存儲數據,每天的數據量會達到數百億級別,較長時間範圍內(跨天/跨周/跨月)的指標數據查詢,響應是比較緩慢的。
我們經常使用的優化方案:
-
創建數據表 B,以 5分鐘 為時間粒度,存儲數據表 A 中部分維度的指標數據;
維度數目的減少,表示着數據表 B 相對於 數據表 A 的數據是減少的。以上述 查詢1 為例,如果需要查詢的維度正好存在於數據表 B,那麼使用數據表 B 相比於 數據表 A,需要掃描的數據量更少,響應時間更快。
-
創建數據表 C,以 1天 為時間粒度,存儲數據表 A 聚合之合的指標數據;
時間粒度的增大,表示着數據表 C 相對於 數據表 A 的數據量是減少的。以上述 查詢3 為例,使用數據表 C 相比於 數據表 A,需要掃描的數據量更少,響應時間更快。
擴展一下思路:可以根據實際的業務場景,在基礎數據表(如:數據表A)之上,有效組合不同的時間粒度、不同的維度組合額外創建出若干張數據表,用於優化查詢的響應時間。
也就是說,指標庫中的某一個主題可以對應着多張數據表,這些數據表可以有不同的時間粒度、不同的維度組合,甚至不同的指標項,存儲於不同的查詢引擎,或者被多個主題所共享。這樣的 自由組合 從工程角度看是非常靈活的;但從數據服務角度看,會帶來2個問題:
- 多張數據表之間的信息是 混亂 的,缺乏一致的數據口徑;
- 查詢指標數據時應該使用哪張數據表?
因此,我們設計 數據視圖,顯示聲明包含的維度、指標信息,以及相關的數據表(參考數據視圖定義)。數據視圖 如何解決查詢指標時使用的數據表問題,參見後文。
代碼參考
數據表
如前文所述,同一個主題(數據視圖)中可以包含多張數據表,且這些數據表之間可能會有不同的時間粒度、維度項、指標項等,數據表(Table)的設計需要能夠明確顯示聲明這些信息。
protected String topic;
protected List<Dimension> dimensions;
protected List<Metric> metrics;
protected Map<String, MetricCalculator> calculators;
private Granularity granularity;
private int period;
private int delay;
topic:數據表屬於的主題名稱;
dimensions:數據表支持的維度項;
metrics:數據表支持的指標項;
calculators:數據表支持的指標項對應的 指標計算器 (參見後文);
granularity:數據表存儲數據的時間粒度;
period:數據表存儲數據的周期,也就是數據表可以查詢的時間範圍;
delay:數據表數據的延遲時間,也就是說相對於當前時間,這個延遲範圍內的數據是查詢不到的;
以 CDN服務質量分析 的數據表為例,數據表實現類如下:
public class CdnServiceQualityTable extends Table {
public CdnServiceQualityTable(View view) {
super(view, "clickhouse-cdn-all_cdn_staging", new Granularity(5, Unit.m), 103680, 36); // 設置時間粒度、存儲周期及延遲時間
addDimension("country"); // 聲明支持的維度項
addDimension("business");
addDimension("city");
addCalculator("error_num", new HubbleClickHouseCalculator("analysisql/cdn/cdn-error_num.sql")); // 聲明支持的指標項的同時,提供指標相應的指標計算器
addCalculator(
"request_num", new HubbleClickHouseCalculator("analysisql/cdn/cdn-request_num.sql"));
addCalculator(
"download_time_avg",
new HubbleClickHouseCalculator("analysisql/cdn/cdn-download_time_avg.sql"));
}
}
代碼參考
策略路由
數據視圖(View)中包含多張數據表(Table),查詢指標數據時,我們需要根據一定的 規則 從這些數據表中選取出 查詢代價最小(響應時間最快) 的數據表用於指標計算,規則 的具體實現就是 策略路由。
過濾
過濾就是 排除 不能支持查詢的數據表,考慮以下4個因素:
-
指標
數據表必須包含查詢的指標項;
-
維度
數據表必須包含查詢涉及的維度項(多個);
-
時間粒度
數據表數據存儲的時間粒度必須小於或等於查詢指定的時間粒度,否則無法聚合數據;
-
時間範圍
數據表在查詢指定的時間範圍內存在數據(根據數據表存儲周期及延遲時間計算);
滿足上述4個條件的數據表即可以進入下一階段。
排序
排序規則:
- 數據表的時間粒度越大,查詢代價越小;
- 數據表的維度數目越少,查詢代價越小;
經過過濾、排序之後,位於第1個位置的數據表即是 最優 的數據表。目前,策略路由(PolicyRouter)的實現是直接內置於數據視圖,尚不支持自定義擴展。
代碼參考
指標計算器
指標計算器(MetricCalculator)用於根據查詢請求完成指標的計算。也就是說,前文中提及的 對應關係 和 計算規則 均包含在指標計算器中,指標計算器需要連接查詢引擎,使用相應的API或SQL,根據計算規則完成指標的計算過程,並返回結果。數據表的各個指標均需要提供相應的指標計算器實現器,並註冊到數據表中。
public interface MetricCalculator {
List<Row> calculate(QueryRequest request) throws Exception;
}
考慮到常用的查詢引擎(如:MySQL、Presto、ClickHouse)大多支持以 SQL 的方式查詢數據,為加速指標計算器的實現效率,系統支持以 SQL模板 的方式定義指標的計算規則,並提供多種 模板引擎, 可將 查詢條件 與 SQL模板 整合轉換特定查詢引擎的SQL語句(不同查詢引擎的SQL實現存在一定差異)。
以 ClickHouse 為例,某指標計算規則可以這樣定義:
SELECT
$COLUMNS, SUM(netflow) * 8 / 1000 / 1000 / 1000 AS $METRIC
FROM
cdn.edge_scheduler_bandwith
WHERE
$WHERE
GROUP BY
$GROUPS
HAVING
$HAVING
AND isNaN($METRIC) == 0
AND isInfinite($METRIC) == 0
AND $METRIC >= 0.0
ORDER BY
$ORDERS
LIMIT
$LIMIT
$COLUMNS、$WHERE、$GROUPBY、$HAVING、$ORDERBY、$LIMIT 均是 模板引擎 支持的自定義變量(不同的模板引擎支持的變量種類存在一定差異)。模板引擎 會將查詢語言中的過濾表達式、維度分組、分組過濾、排序及結果集行數轉換為這些自定義變更對應的值,並輸出完整的SQL語句。
指標計算器直接使用轉換之後的SQL語句,連接查詢引擎查詢數據即可。
綜上所述,查詢代理核心工作流程如下:
- 解析查詢語言;
- 使用主題名稱查找數據視圖;
- 使用策略路由選取最優數據表;
- 使用指標名稱查找最優數據表的指標計算器;
- 計算指標並返回結果;
數據應用服務僅需要知道查詢代理服務地址(域名)、端口號,使用查詢語言查詢需要的指標數據即可。
結語
本文介紹的指標庫、查詢語言(DSL)、查詢代理是我們團隊自主研發的OLAP服務,在微博視頻性能數據分析中取得很好地應用效果。通過技術優化的方式,在有限的計算資源範圍內得到不錯的性能表現,大幅降低數據接口、可視化及監控服務的開發成本。 同時,我們團隊也在準備項目開源(//github.com/weibodip/analysisql )的準備工作,有興趣的同學可關注交流。