BI 系統的常見結構是:前端是 BI 應用,負責多維分析的用戶操做和結果呈現;後臺是數據庫 / 數據倉庫,負責數據計算和存儲。前端和後臺之間用 SQL 做爲接口。前端
實際應用中,經常出現後臺數據倉庫壓力太重的問題。問題表現爲前端響應時間過長,數據倉庫反應速度變慢。java
常見的解決方案是在數據倉庫和應用之間再增長一個前置數據庫。可是前置數據庫和後臺數據倉庫之間很難實現數據的路由和混合計算,例如:訪問頻次很高的熱點數據放在前置數據庫,大量冷數據放在數據倉庫中,查詢時按照必定規則來決定訪問前置數據庫仍是後臺數據倉庫。而若是前置數據庫和後臺數據倉庫是不一樣的產品,還要考慮 SQL 的翻譯問題。linux
做爲數據計算中間件(DCM),構建獨立的數據前置層是集算器的重要應用模式。數據前置層將 BI 系統重構爲三層結構:數據存儲及批量數據計算層由數據庫承擔;數據前置及緩存層由集算器承擔;數據分析展示層由多維分析工具或者報表工具承擔。web
集算器能夠脫離數據庫進行數據緩存和獨立的複雜計算,同時具有可編程網關機制,能夠在緩存計算和 SQL 透傳之間自由切換。利用集算器完成前置層數據計算,能夠與數據庫承擔的批量數據計算任務分離,而且沒必要再建設另一個數據庫。sql
集算器能夠將熱點數據、近期數據放在數據前置層,從而起到數據緩存的做用,能夠有效提升數據計算的速度,減小用戶等待時間。數據庫
系統架構圖以下:編程
前臺 BI 系統,要針對訂單數據作自助查詢。查詢的必選條件是訂購日期。爲了簡化起見,前臺 BI 系統用 tomcat 服務器中的 jdbc.jsp 來模擬。windows
集算器 JDBC 和智能網關集成在應用系統中。jdbc.jsp 模仿 BI 應用系統,產生符合集算器簡單查詢規範的 SQL,經過集算器 JDBC 提交給集算器智能網關處理。瀏覽器
數據來自於 ORACLE 數據庫 demo 中的 ORDERS 表。ORDERS 訂單表是全量數據,集算器只存儲最近三年的數據,好比:2015 年 -2018 年。日期以訂購日期爲準。緩存
用下面的 orders.sql 文件在 ORACLE 數據庫中完成 ORDERS 表的建表和數據初始化。
在集算器中,新建一個數據源 orcl,鏈接 ORACLE 數據庫。用 SPL 語言腳本 etl1.dfx 將最近三年的數據預先讀取到集算器集文件 orders.btx 中。SPL 腳本以下:
A | B | |
---|---|---|
1 | =year(now())-3 | |
2 | =connect(「orcl」) | =A2.cursor@d(「select * from orders where to_char(orderdate,‘yyyy’)>=?」,A1) |
3 | =file(「C:/tomcat6/webapps/gateway/WEB-INF/data/orders.btx」) | |
4 | =A3.export@z(B2) | >A2.close() |
從 SPL 腳本能夠看出,只要在 A4 單元格中用一句 export 就能夠將數據庫中的數據導出到文件中。集文件是集算器內置的二進制文件格式,採用了簡單壓縮機制,相同數據量比數據庫的佔用空間會更小。@z 選項表示寫出能夠分段的文件,很適合經常須要並行的多維分析類運算。
B2 單元格中數據庫遊標的 @d 選項,表示從 ORACLE 數據庫中取數的時候將 numeric 型數據轉換成 double 型,精度對於金額這樣的常見數值徹底足夠了。若是沒有這個選項就會默認轉換成 big decimal 型數據,計算性能會受到較大影響。
腳本能夠用 windows 或者 linux 命令行的方式執行,結合定時任務,能夠定時執行批量任務。windows 命令行的調用方式是:
C:\Program Files\raqsoft\esProc\bin>esprocx.exe C: \etl1.dfx
linux 命令是:
/raqsoft/esProc/bin/esprocx.sh /gateway/etl1.dfx
集算器 JDBC 智能網關接收到 SQL 後,轉給 gateway1.dfx 程序處理。gateway1.dfx 判斷是否三年內的查詢,若是是,就把表名換成文件名,查本地文件 orders.btx 返回結果。若是不是,把 SQL 轉換成 ORACLE 格式,提交數據庫處理。
一、下面的 gateway 目錄複製到 tomcat 的應用目錄。
目錄結構以下圖:
注意:配置文件在 classes 中,在官網上獲取的受權文件也要放在 classes 目錄中。集算器的 Jar 包要放在 lib 目錄中(須要哪些 jar 請參照集算器教程)。另外,還須要檢查和修改 raqsoftConfig.xml 中的以下配置:
<mainPath>C:\\\\\tomcat6\\\\\webapps\\\\\gateway\\\\\WEB-INF\\\\\dfx\\\</mainPath> <JDBC> <load>Runtime,Server\\\</load> <gateway>gateway1.dfx\\\</gateway> </JDBC> <mainPath>C:\\\tomcat6\\\webapps\\\gateway\\\WEB-INF\\\dfx\\</mainPath> <JDBC> <load>Runtime,Server\\</load> <gateway>gateway1.dfx\\</gateway> </JDBC> <mainPath>C:\\\tomcat6\\\webapps\\\gateway\\\WEB-INF\\\dfx\\</mainPath> <JDBC> <load>Runtime,Server\\</load> <gateway>gateway1.dfx\\</gateway> </JDBC> <mainPath>C:\\tomcat6\\webapps\\gateway\\WEB-INF\\dfx\</mainPath> <JDBC> <load>Runtime,Server\</load> <gateway>gateway1.dfx\</gateway> </JDBC>
這裏標籤的內容就是網關 dfx 文件。在 BI 系統中調用集算器 JDBC 時,所執行的 SQL 都將交由網關文件處理。若是不配置這個標籤,JDBC 提交的語句都被集算器看成腳本直接解析運算,而沒法實現但願的路由規則。
二、編輯 gateway 目錄中的 jdbc.jsp,模擬前臺界面提交 sql 展示結果。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ page import="java.sql.*" %> <body> <% String driver = "com.esproc.jdbc.InternalDriver"; String url = "jdbc:esproc:local\\\://"; try { Class.forName(driver); Connection conn = DriverManager.getConnection(url); Statement statement = conn.createStatement(); String sql ="select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date('2015-07-18') and AMOUNT>100"; out.println("Data gateway test page v1 <br><br><br><pre>"); out.println("訂單ID"+"\\\\\t"+"客戶ID"+"\\\\\t"+"僱員ID"+"\\\\\t"+"訂購日期"+"\\\\\t"+"訂單金額"+"<br>"); ResultSet rs = statement.executeQuery(sql); int f1,f6; String f2,f3,f4; float f5; while (rs.next()) { f1 = rs.getInt("ORDERID"); f2 = rs.getString("CUSTOMERID"); f3 = rs.getString("EMPLOYEEID"); f4 = rs.getString("ORDERDATE"); f5 = rs.getFloat("AMOUNT"); out.println(f1+"\\\\\t"+f2+"\\\\\t"+f3+"\\\\\t"+f4+"\\\\\t"+f5+"\\\\\t"+"<br>"); } out.println("</pre>"); rs.close(); conn.close(); } catch (ClassNotFoundException e) { System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } %> </body> <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ page import="java.sql.*" %> <body> <% String driver = "com.esproc.jdbc.InternalDriver"; String url = "jdbc:esproc:local\\://"; try { Class.forName(driver); Connection conn = DriverManager.getConnection(url); Statement statement = conn.createStatement(); String sql ="select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date('2015-07-18') and AMOUNT>100"; out.println("Data gateway test page v1 <br><br><br><pre>"); out.println("訂單ID"+"\\\t"+"客戶ID"+"\\\t"+"僱員ID"+"\\\t"+"訂購日期"+"\\\t"+"訂單金額"+"<br>"); ResultSet rs = statement.executeQuery(sql); int f1,f6; String f2,f3,f4; float f5; while (rs.next()) { f1 = rs.getInt("ORDERID"); f2 = rs.getString("CUSTOMERID"); f3 = rs.getString("EMPLOYEEID"); f4 = rs.getString("ORDERDATE"); f5 = rs.getFloat("AMOUNT"); out.println(f1+"\\\t"+f2+"\\\t"+f3+"\\\t"+f4+"\\\t"+f5+"\\\t"+"<br>"); } out.println("</pre>"); rs.close(); conn.close(); } catch (ClassNotFoundException e) { System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } %> </body> <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ page import="java.sql.*" %> <body> <% String driver = "com.esproc.jdbc.InternalDriver"; String url = "jdbc:esproc:local\\://"; try { Class.forName(driver); Connection conn = DriverManager.getConnection(url); Statement statement = conn.createStatement(); String sql ="select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date('2015-07-18') and AMOUNT>100"; out.println("Data gateway test page v1 <br><br><br><pre>"); out.println("訂單ID"+"\\\t"+"客戶ID"+"\\\t"+"僱員ID"+"\\\t"+"訂購日期"+"\\\t"+"訂單金額"+"<br>"); ResultSet rs = statement.executeQuery(sql); int f1,f6; String f2,f3,f4; float f5; while (rs.next()) { f1 = rs.getInt("ORDERID"); f2 = rs.getString("CUSTOMERID"); f3 = rs.getString("EMPLOYEEID"); f4 = rs.getString("ORDERDATE"); f5 = rs.getFloat("AMOUNT"); out.println(f1+"\\\t"+f2+"\\\t"+f3+"\\\t"+f4+"\\\t"+f5+"\\\t"+"<br>"); } out.println("</pre>"); rs.close(); conn.close(); } catch (ClassNotFoundException e) { System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } %> </body> <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <%@ page import="java.sql.*" %> <body> <% String driver = "com.esproc.jdbc.InternalDriver"; String url = "jdbc:esproc:local\://"; try { Class.forName(driver); Connection conn = DriverManager.getConnection(url); Statement statement = conn.createStatement(); String sql ="select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date('2015-07-18') and AMOUNT>100"; out.println("Data gateway test page v1 <br><br><br><pre>"); out.println("訂單ID"+"\\t"+"客戶ID"+"\\t"+"僱員ID"+"\\t"+"訂購日期"+"\\t"+"訂單金額"+"<br>"); ResultSet rs = statement.executeQuery(sql); int f1,f6; String f2,f3,f4; float f5; while (rs.next()) { f1 = rs.getInt("ORDERID"); f2 = rs.getString("CUSTOMERID"); f3 = rs.getString("EMPLOYEEID"); f4 = rs.getString("ORDERDATE"); f5 = rs.getFloat("AMOUNT"); out.println(f1+"\\t"+f2+"\\t"+f3+"\\t"+f4+"\\t"+f5+"\\t"+"<br>"); } out.println("</pre>"); rs.close(); conn.close(); } catch (ClassNotFoundException e) { System.out.println("Sorry,can`t find the Driver!"); e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } %> </body>
能夠看到,jsp 中先鏈接集算器的 JDBC,而後提交執行 SQL。步驟和通常的數據庫徹底同樣,具備很高的兼容性和通用性。對於 BI 工具來講,雖然是界面操做來鏈接 JDBC 和提交 SQL,可是基本原理和 jsp 徹底同樣。
三、打開 dfx 目錄中的 gateway1.dfx,觀察理解 SPL 代碼。
首先,能夠看到 gateway1.dfx 傳入參數是 sql 和 args,例如傳入 SQL:
select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date(‘2015-07-18’) and AMOUNT>100。
接下來,能夠看到 SPL 腳本以下:
A | B | C | |
---|---|---|---|
1 | =filename=「C:/tomcat6/webapps/gateway/WEB-INF/data/orders.btx」 | ||
2 | =sql.sqlparse@w().split(" ") | =A2.select@1(like(~,「ORDERDATE=date(‘????-??-??’)」)) | |
3 | =mid(right(B2,14),3,10) | =year(now())-year(date(A3)) | |
4 | if B3<=3 | =connect() | =sql=replace(sql,「from ORDERS」,"from "+filename) |
5 | =B4.cursor@x(sql) | return B5 | |
6 | else | =connect(「orcl」) | =sql=sql.sqltranslate(「ORACLE」) |
7 | =B6.cursor@x(sql) | return B7 |
說明:
A1:定義集算器集文件的絕對路徑。
A2:解析 SQL,獲取 where 子句,並用空格來拆分紅序列。
B二、A3:在 A2 序列找到必選條件訂購日期,獲取日期值。
B3:計算訂購日期的年份和當前日期年份相差幾年。
A4:判斷相差的年份是否超過 3 年。
B4-C5:若是不超過 3 年,就鏈接文件系統。將 SQL 中的 from 訂單,替換成 from 文件名。執行 SQL 獲得遊標並返回。
B6-C7:若是超過 3 年,就鏈接數據庫。將 SQL 翻譯成符合 ORACLE 數據庫規範的 SQL, 執行 SQL 獲得遊標並返回。
四、啓動 tomcat,在瀏覽器中訪問 http://localhost:8080/gateway/jdbc.jsp,查看結果。
還能夠繼續測試以下狀況:
(1) 超出三年的查詢
sql =「select top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date(‘2014-07-18’) and AMOUNT>100」;
因爲日期 2014 年已經超出三年的限制,因此在 C6 中 SQL 會被翻譯成 ORACLE 規範以下:
SELECT * FROM (select ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=TO_DATE(‘2014-07-18’,‘YYYY-MM-DD’) and AMOUNT>100)t WHERE ROWNUM<=10
(2) 分組彙總
sql =「select CUSTOMERID,EMPLOYEEID,sum(AMOUNT) 訂單總額,count(1) 訂單數量 from ORDERS where ORDERDATE=date(‘2015-07-18’) group by CUSTOMERID,EMPLOYEEID」;
(3) 並行查詢
sql="select /+ parallel (4) /
top 10 ORDERID,CUSTOMERID,EMPLOYEEID,ORDERDATE,AMOUNT from ORDERS where ORDERDATE=date(‘2015-07-18’) and AMOUNT>100"
和 ORACLE 相似,集算器簡單 SQL 也支持 /+ parallel (4) / 這樣的並行查詢。
第一種解決辦法是利用應用服務器的資源。在併發量很大,或者數據量很大的狀況下,應用服務器會出現較大壓力。這種狀況下,推薦用獨立的節點服務器進行數據計算。節點服務器能夠進行橫向擴展,應對大併發或大數據量計算的壓力。
集算器 JDBC 智能網關接受到 SQL 後,轉給 gateway2.dfx 程序處理。gateway2.dfx 調用節點服務器上的 gatewayServer2.dfx 進行計算。gatewayServer2.dfx 判斷是否三年內的查詢,若是是,就把表名換成文件名,查本地文件 orders.btx 返回結果。若是不是三年內的查詢,把 sql 轉換成 ORACLE 格式,提交數據庫處理。
一、下面的 gatewayServer 目錄複製到須要的目錄。集算器的節點服務器具有跨平臺的特性,能夠運行在任何支持 Java 的操做系統上,部署方法參見集算器教程。這裏假設放到 windows 操做系統的 C 盤根目錄。
二、修改前面的 dfx,將 A3 改成 =file(「C:/gatewayServer/data/orders.btx」),另存爲 etl2.dfx。修改好的 etl2.dfx 在 c:\gatewayServer 目錄。
三、打開應用服務器中的 C:\tomcat6\webapps\gateway\WEB-INF\dfx\gateway2.dfx,觀察理解 SPL 代碼。參數不變,仍是傳入的 sql 和 args。
A | B | |
---|---|---|
1 | =callx(「gatewayServer2.dfx」,[sql];[「127.0.0.1:8281」]) | |
2 | return A1.ifn() |
A1:調用節點機上的 gatewayServer2.dfx。參數是 [sql],中括號表示序列,此時是隻有一個成員的序列。[「127.0.0.1:8281」] 是節點機的序列,採用 IP: 端口號的方式。節點機是集羣的時候,能夠有多個 IP 地址,例如:["IP1:PORT1″,"IP2:PORT2″,「IP3:PORT3」]。
A2:返回 A1 調用的結果。由於調用結果能夠是序列,因此要用 ifn 函數找到序列中第一個不爲空的成員,就是 SQL 對應的返回結果。
修改 C:\tomcat6\webapps\gateway\WEB-INF\classes\raqsoftConfig.xml 中的以下配置 gateway1.dfx 改成 gateway2.dfx。
<JDBC> <load>Runtime,Server\\\</load> <gateway>gateway2.dfx\\\</gateway> </JDBC> <JDBC> <load>Runtime,Server\\</load> <gateway>gateway2.dfx\\</gateway> </JDBC> <JDBC> <load>Runtime,Server\\</load> <gateway>gateway2.dfx\\</gateway> </JDBC> <JDBC> <load>Runtime,Server\</load> <gateway>gateway2.dfx\</gateway> </JDBC>
四、啓動節點服務器。
運行 esprocs.exe, 以下圖:
點擊配置按鈕,配置相關參數:
點擊肯定後,返回主界面,點擊啓動按鈕。
五、打開 C:\gatewayServer\dfx\gatewayServer2.dfx,觀察理解 SPL 代碼。
A | B | C | |
---|---|---|---|
1 | =filename=「C:/gatewayServer/data/orders.btx」 | ||
2 | =sql.sqlparse@w().split(" ") | =A2.select@1(like(~,「ORDERDATE=date(‘????-??-??’)」)) | |
3 | =mid(right(B2,14),3,10) | =year(now())-year(date(A3)) | |
4 | if B3<=3 | =connect() | =sql=replace(sql,「from ORDERS」,"from "+filename) |
5 | =B4.cursor@x(sql) | return B5 | |
6 | else | =connect(「orcl」) | =sql=sql.sqltranslate(「ORACLE」) |
7 | =B6.cursor@x(sql) | return B7 |
代碼基本和前面的 gateway1.dfx 一致。區別是這個 dfx 是在節點服務器 unitServer 上執行的,數據是存在節點服務器上。
五、重啓 tomcat,在瀏覽器中訪問 http://localhost:8080/gateway/jdbc.jsp,查看結果。
當數據量很大同時又須要秒級的查詢速度時,咱們建議採用集算器組表來存儲數據。組表適用的場合包括:數據表字段有幾十個甚至更多;數據量幾千萬行,存成集文件在 1G 以上;查詢要求秒級響應。
對於簡單 SQL 來講,組表文件的用法和集文件沒有什麼不一樣, 只是文件名不同。gatewayServer2.dfx 中只須要把 A1 改成 =filename=「C:/gatewayServer/data/orders.ctx」,另存爲 gatewayServer3.dfx。相應的 gateway2.dfx 中的 A1 改成 =callx(「gatewayServer3.dfx」,[sql];[「127.0.0.1:8281」]),另存爲 gateway3.dfx。
修改 C:\tomcat6\webapps\gateway\WEB-INF\classes\raqsoftConfig.xml 中的以下配置 gateway2.dfx 改成 gateway3.dfx。
<JDBC> <load>Runtime,Server\\\</load> <gateway>gateway3.dfx\\\</gateway> </JDBC> <JDBC> <load>Runtime,Server\\</load> <gateway>gateway3.dfx\\</gateway> </JDBC> <JDBC> <load>Runtime,Server\\</load> <gateway>gateway3.dfx\\</gateway> </JDBC> <JDBC> <load>Runtime,Server\</load> <gateway>gateway3.dfx\</gateway> </JDBC>
咱們重點理解如何改寫 etl 過程,修改前面的 etl2.dfx,另存爲 etl3.dfx。
A | |
---|---|
1 | =year(now())-3 |
2 | =connect(「orcl」) |
3 | =A2.cursor@d(「select CUSTOMERID,EMPLOYEEID,ORDERDATE,ORDERID,AMOUNT from ORDERS where to_char(ORDERDATE,‘yyyy’)>=? order by CUSTOMERID,EMPLOYEEID,ORDERDATE,ORDERID",A1) |
4 | =file(「C:/gatewayServer/data/orders.ctx」) |
5 | =A4.create(#CUSTOMERID,#EMPLOYEEID,#ORDERDATE,#ORDERID,AMOUNT) |
6 | =A5.append(A3) |
7 | >A2.close() |
組表與集文件不一樣,默認是採用列式存儲的,支持任意分段的並行計算,能夠有效提高查詢速度。同時,生成組表的時候,要注意數據預先排序和合理定義維字段。本例中,按照常常過濾、分組的字段,將維字段肯定爲:CUSTOMERID,EMPLOYEEID,ORDERDATE,ORDERID。
A3 取得數據的時候,要按照維字段排序。由於 CUSTOMERID,EMPLOYEEID,ORDERDATE 對應的重複數據多,因此放在前面排序;ORDERID 對應的重複數據少,因此放在後面排序。
A4 中定義組表的時候用 #來表示維字段。
須要說明的是,組表也支持並行查詢 /*+ parallel (n) */。
BI 應用的特色是:
一、響應時間要求高,通常不超過 5-10 秒。
二、查詢對應數據量在幾百兆到幾 G 範圍,字段有幾十個甚至上百個。
三、併發量較大,幾十到幾百個併發。
性能優化的方法是:
一、採用組表,提升單任務查詢的響應速度。
◇ 根據需求,合理定義維字段。
組表定義的時候,要按照業務的須要肯定維字段。要選擇常常做爲過濾條件或者用來分組的字段做爲維字段,維字段前用 #標識。
◇ 按照維字段,預先排序。
要按照維字段作好數據的排序,重複記錄數多的字段在前面,例如:按照 order by 省,市,縣的字段順序來排序,而不是反過來。
◇ 根據併發量,選擇是否用並行查詢。
併發量比較大的時候,單個 SQL 查詢就不建議用並行查詢了 /+ parallel (n) /。並行查詢會消耗更多的線程數,反而會影響大的併發性能。
二、合理配置節點服務器的參數,發揮每一個節點的性能。
每臺服務器(實體機或者虛擬機)要啓動一個節點服務器,每一個節點服務器啓動分機的配置界面以下:
◇ 根據硬件資源,配置進程數
進程列表中的進程數(也就是適合做業數)建議是不要超過 CPU 總核數 *2/3。例如:服務器有 8 個 CPU 每一個兩核,總核數是 8*2=16,那麼進程數量就不要超過 16*2/3=10 個。最大做業數推薦是適合做業數 *2,也就是 10*2=20 個。
◇ 儘可能多分配內存,但要避免超量
節點服務器每一個進程的最大內存要儘可能多分配,可是總數加起來要比實際的物理內存小,避免操做系統用硬盤來補充內存的不足。例如,總內存是 32G,進程數量是 8 個,那麼每一個進程的最大內存就不要大於 4G。配置進程的最大最小內存是在 C:\Program Files\raqsoft\esProc\bin\config.txt 中,例如:
jvm_args=-Xms128m -Xmx4845m 最小內存是 128M,最大是 4G。
三、橫向擴展節點服務器,多機應對大併發訪問。
◇ 橫向擴展,應對大併發。
隨着併發量的增大,當性能不能知足要求的時候,要增長節點服務器的數量,經過橫向擴展來知足需求。
◇ 增長服務器列表配置項。
這時候要修改 gateway3.dfx 中的 callx 函數的服務器序列參數。能夠將服務器序列參數寫到配置文件中,這樣就能夠沒必要每次都修改 dfx 文件了。
四、使用本機硬盤數據進行計算,避免跨網絡訪問。
硬盤的 IO 速度是比較有保證的。
節點服務器經過網絡去取其餘服務器上的數據,或者經過訪問共享存儲上的數據,常常會出現網絡阻塞的狀況,下降查詢響應速度。所以,儘量每臺節點服務器僅僅執行本機上的數據,不要跨網絡訪問。
可編程數據路由是數據計算中間件(DCM)的重要應用場景。
在前述的例子中,數據路由的策略是:最近三年的數據做爲熱數據放路由到集算器中計算,其餘數據做爲冷數據,路由到數據庫中計算。
相似的路由規則還有:最近三天和最近十二個月的最後一天的數據做爲熱數據,路由到集算器中計算,其餘數據路由到數據庫彙總計算。
對於冷熱數據計算路由規則,本篇只介紹了一次查詢只涉及冷或熱數據的狀況,若是在一次查詢中可能同時涉及冷熱兩種數據,咱們將在後續文章中進行介紹。
實際應用中,數據路由的規則可能會很複雜和多變,經過配置來實現會很是困難,用編程的方式實現是最佳方案。採用集算器的編程語言 SPL 來實現複雜的數據路由規則是最簡單和最高效的。集算器支持多樣性異構數據源的混合計算,能夠編程實現涉及到各類異構數據源的複雜數據路由規則。
用做多維分析後臺時,數據計算中間件(DCM)要提供必要的 SQL 解析與翻譯功能。
數據路由的實現離不開集算器對 SQL 語句的解析和翻譯。首先要用集算器的 SQL 解析能力,找到 where 條件中的日期字段,而後根據規則來決定路由到文件仍是數據庫。若是是路由到數據庫,那麼要把集算器的標準 SQL 翻譯成數據庫的 SQL,就要用到集算器的 SQL 翻譯能力。
集算器的 SQL 解析用 sqlparse()函數實現,SQL 翻譯用 sqltranslate() 函數實現。
SQL 性能優化也是數據計算中間件(DCM)必不可少的能力。
BI 應用容許用戶拖拽生成 SQL,就會出現不少性能不高的 SQL。好比直接在明細查詢的 SQL 外面加上一層 count 來統計結果總條數:select count(1) from (select f1,f2,f3,f4…f30 from table1 where f1=1 and 1=1)。此時子查詢中的 f1 到 f30 若是所有取出,就會下降查詢的性能。1=1 這樣的過濾條件也會形成沒有意義的時間消耗。
集算器簡單 SQL 引擎,能夠完成自動查詢優化。去掉 1=1 這樣沒必要要的條件,也不會取出全部字段來完成 count。從而實現 SQL 解析和優化,有效的提升查詢性能。
相似的,還有 select top 10 f1,f2 from table1 order by f1。集算器會採用小結果集比較的方式實現。能夠作到無須大排序,只遍歷一邊數據便可獲得須要的結果,有效提高查詢速度。
先進的數據存儲方式,是數據計算中間件(DCM)成功實施的重要保障。
集算器組表採用列存方式存儲數據,對於字段特別多的寬表查詢,性能提高特別明顯。組表採用的列存機制和常規列存是不一樣的。常規列存(好比 parquet 格式),只能分塊以後,再在塊內列存,在作並行計算的時候是受限的。組表的可並行壓縮列存機制,採用倍增分段技術,容許任意分段的並行計算,能夠利用多 CPU 核的計算能力把硬盤的 IO 發揮到極致。
組表生成的時候,要指定維字段,數據自己是按照維字段有序存放的,經常使用的條件過濾計算不依賴索引也能保證高性能。文件採用壓縮存儲,減少在硬盤上佔用的空間,讀取更快。因爲採用了合適的壓縮比,解壓縮佔用的 CPU 時間能夠忽略不計。
組表也能夠採起行存和全內存存儲數據,支持內存數據庫方式運行。
敏捷的集羣能力能夠保證數據計算中間件(DCM)的高性能和高可用性。
集算器節點服務器是獨立進程,能夠接受集算器網關程序的計算請求並返回結果。對於併發訪問的狀況,能夠發給多個服務器同時計算,提升併發容量。對於單個大計算任務的狀況,能夠分紅多個小任務,發給多個服務器同時計算,起到大數據並行計算的做用。
集算器集羣計算方案,具有敏捷的橫向擴展能力,併發量或者數據量大時能夠經過快速增長節點來解決。集算器集羣也具有容錯能力,即有個別節點失效時還能確保整個集羣能工做,計算任務能繼續執行完畢,起到多機熱備和保證高可用性的做用。
做爲數據計算中間件(DCM),集算器實現的數據計算網關和路由,能夠解決數據倉庫沒法知足性能要求,冷熱數據分開又要混合計算的場景,不只僅限於前端是 BI 的狀況。例如:大屏展現、管理駕駛艙、實時報表、大數據量清單報表、報表批量訂閱等等。