開源的Spark SQL并不支持高可用,但實際應(yīng)用中高可用對于用戶意義重大。中興大數(shù)據(jù)平臺DAP在對應(yīng)的ZDH中實現(xiàn)了Spark SQL的高可用。
Spark SQL的高可用,是兩個Spark SQL服務(wù)上線的時候向SQL進行注冊,用戶連接的JDBC URL指定為Zookeeper的列表,連接的時候會通過Zookeeper集群獲取Spark SQL節(jié)點信息,然后連接到Spark SQL服務(wù)節(jié)點。
Spark SQL元數(shù)據(jù)雙主主要是用MySQL實現(xiàn),MySQL支持單向、異步復(fù)制,復(fù)制過程中一個服務(wù)器充當主服務(wù)器,而一個或多個其它服務(wù)器充當從服務(wù)器。主服務(wù)器將更新寫入二進制日志文件,并維護日志文件的索引以跟蹤日志循環(huán)。從服務(wù)器接收從那時起發(fā)生的任何更新,然后封鎖并等待主服務(wù)器通知下一次更新。
在實際項目中,兩臺分布于異地的主機上安裝有MySQL數(shù)據(jù)庫,兩臺服務(wù)器互為主備,當其中一臺機器出現(xiàn)故障時,另外一臺能夠接管服務(wù)器上的應(yīng)用,這就需要兩臺數(shù)據(jù)庫的數(shù)據(jù)要實時保持一致,在這里使用MySQL的同步功能實現(xiàn)雙機的同步復(fù)制。
實現(xiàn)方案
目前SparkSQL節(jié)點訪問雙主的元數(shù)據(jù)庫主要考慮兩種方案:
SparkSQL節(jié)點直接連接MySQL節(jié)點:
下圖中SparkSQL節(jié)點分別連接單個MySQL節(jié)點,不同SparkSQL節(jié)點對元數(shù)據(jù)庫的更改會在MySQL節(jié)點之間進行同步。
?
?
?
SparkSQL節(jié)點通過MetaStore節(jié)點連接元數(shù)據(jù)庫:
?
下圖中SparkSQL節(jié)點分別連接多個MetaStore節(jié)點,每個MetaStore節(jié)點連接對應(yīng)的MySQL節(jié)點,不同SparkSQL節(jié)點對元數(shù)據(jù)庫的更改會在MySQL節(jié)點之間進行同步。
?
?
上面兩種SparkSQL節(jié)點訪問雙主的元數(shù)據(jù)庫方案下,客戶端獲取SparkSQL服務(wù)的方式是相同的,主要通過如下方式:
?
Beeline連接
?
?
程序通過JDBC端口訪問
?
Beeline方式首先通過Zookeeper集群獲取SparkSQL節(jié)點信息,然后連接到SparkSQL服務(wù)節(jié)點。當連接的SparkSQL節(jié)點異常時,可以通過重試幾次獲取SparkSQL服務(wù)。
程序通過JDBC端口連接到對應(yīng)的SparkSQL節(jié)點的方式下,如果正在連接的SparkSQL節(jié)點出現(xiàn)異常,可以通過在代碼中進行異常捕獲的方式重新獲取SparkSQL服務(wù)。
下面主要對兩種方案的功能可行性以及異常情況進行驗證。
?
測試環(huán)境
?
MySQL:10.43.183.121和10.43.183.122兩臺主機
SparkSQL: 10.43.183.121和10.43.183.122兩臺主機
Hive MetaStoreServer: 10.43.183.121和10.43.183.122兩臺主機
?
測試場景
?
場景一:SparkSQL節(jié)點直接連接MySQL高可用驗證
每個SparkSQL節(jié)點直接連接一個MySQL節(jié)點。驗證元數(shù)據(jù)能否成功同步以及MySQL節(jié)點失效能否自動切換。
測試步驟如下:
1.?修改配置
SparkSQL配置修改如下:
?
?
10.43.183.121對應(yīng)的JDBC連接配置為10.43.183.121上的MySQL
10.43.183.122對應(yīng)的JDBC連接配置為10.43.183.122上的MySQL
2.?Beeline連接10.43.183.121節(jié)點的SparkSQL。
3.?創(chuàng)建表test,分別查找兩個MySQL的hiveomm數(shù)據(jù)庫的tbls表,可以看到test記錄。表明元數(shù)據(jù)同步成功。
4.?將SparkSQL當前連接的MySQL停掉。
5. Beeline 界面執(zhí)行“show tables”命令,查詢異常。
6.?斷開Beeline連接并多次重新連接10.43.183.121節(jié)點的SparkSQL,連接異常。
7.?用SQL URL連接SparkSQL服務(wù)!connectjdbc:hive2://10.43.183.121:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=sparkThriftServer重試若干次可以連接上SparkSQL服務(wù),通過“show tables”命令可以查到test表。
8.?啟動MySQL節(jié)點,Beeline重新連接10.43.183.121節(jié)點,可以連接到SparkSQL節(jié)點。執(zhí)行“show tables”命令,可以查詢到test表信息。
測試結(jié)論:
?
MySQL之間的元數(shù)據(jù)可以同步。
?
?
MySQL節(jié)點掛掉會導(dǎo)致Beeline無法查詢。
?
?
Beeline重新連接無法連接到對應(yīng)的SparkSQL節(jié)點。
?
?
Beeline通過SQL URL連接SparkSQL服務(wù),可以在嘗試一定次數(shù)之后連接到可用的SparkSQL節(jié)點。
?
?
場景二: SparkSQL節(jié)點通過HiveMetaStoreServer節(jié)點連接MySQL高可用驗證
?
MetaStoreServer節(jié)點主要用于MySQL節(jié)點失效時的容錯,每個MetaStoreServer節(jié)點對應(yīng)一個MySQL節(jié)點,每個SparkSQL節(jié)點配置多個MetaStoreServer節(jié)點。驗證元數(shù)據(jù)能否成功同步以及MySQL節(jié)點失效能否自動切換。
測試步驟如下:
1.?修改配置
MetaStoreServer節(jié)點配置修改如下:
?
?
10.43.183.121節(jié)點的MetaStoreServer配置10.43.183.121節(jié)點上的MySQL
10.43.183.122節(jié)點的MetaStoreServer配置10.43.183.122節(jié)點上的MySQL
SparkSQL添加對應(yīng)配置:
?
?
2.?Beeline連接10.43.183.121節(jié)點的SparkSQL。
3.?創(chuàng)建表test,分別查找兩個MySQL的hiveomm數(shù)據(jù)庫的tbls表,可以看到test記錄,表明元數(shù)據(jù)同步成功。
4.?將SparkSQL當前連接的MetaStoreServer(通過日志看到)對應(yīng)的MySQL停掉。
5.?Beeline 界面執(zhí)行“show tables”命令,查詢異常。
6.?斷開Beeline連接并多次重新連接10.43.183.121節(jié)點的SparkSQL,連接出現(xiàn)異常。
7.?用SQL url連接SparkSQL服務(wù)!connectjdbc:hive2://10.43.183.121:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=sparkThriftServer始終無法連接上SparkSQL服務(wù),通過“show tables”命令可以查到test表。
8.?重新啟動MySQL節(jié)點,Beeline重新連接10.43.183.121節(jié)點,可以連接到SparkSQL節(jié)點。執(zhí)行“show tables”命令,可以查詢到test表信息。
測試結(jié)論:
?
MySQL之間的元數(shù)據(jù)可以同步。
?
?
MySQL節(jié)點掛掉會導(dǎo)致Beeline無法查詢。
?
?
MySQL節(jié)點掛掉的情況下,Beeline重新連接SparkSQL節(jié)點,無法連接到對應(yīng)的SparkSQL節(jié)點。
?
?
MySQL節(jié)點掛掉的情況下,Beeline通過SQL URL連接SparkSQL服務(wù)無法連接到對應(yīng)的SparkSQL服務(wù)。
?
?
場景三: 代碼的JDBC接口連接到SparkSQL服務(wù)
?
服務(wù)配置同場景一中的方式,通過JDBC連接到SparkSQL節(jié)點,示例代碼如下:
?
public static void main(String[] args)
{
??? int num = 0;
??? Connection conn = null;
??? ResultSet rs = null;
??? PreparedStatement pstat = null;
??? while (num < 3)
??? {
??????? num = num + 1;
??????? try
??????? {
??????????? Class.forName("org.apache.hive.jdbc.HiveDriver");
??????????? if (conn == null)
??????????? {
??????????????? if (args.length > 0)
????? ??????????????conn = DriverManager.getConnection(args[0], "mr", "mr");
??????????????? else
??????????????????? conn = DriverManager
??????????????????????? .getConnection("jdbc:hive2://10.43.183.121:18000", "mr", "mr");
??????????? }
??????????? pstat = conn.prepareStatement("select * from test");
??????????? rs = pstat.executeQuery();
?
??????????? while (rs.next())
??????????? {
??????????????? System.out.println(rs.getString("name"));
??????????? }
??????????? break;
??????? } catch (Exception e)
??????? {
??????????? e.printStackTrace();
??????????? try
??????????? {
??????????????? conn = DriverManager
??????????????????? .getConnection("jdbc:hive2://10.43.183.122:18000", "mr", "mr");
??????????? } catch (SQLException e1)
??????????? {
??????????????? e1.printStackTrace();
??????????? }
??????? } finally
??????? {
??????????? try
??????????? {
??????????????? rs.close();
??????????????? pstat.close();
??????????????? conn.close();
??????????? } catch (SQLException e)
????? ??????{
??????????????? e.printStackTrace();
??????????? }
??????? }
?
??? }
}
?
測試結(jié)論:
?
通過JDBC連接到SparkSQL節(jié)點可以通過異常捕獲的方式實現(xiàn)實現(xiàn)MySQL節(jié)點故障之后獲取SparkSQL服務(wù)。
?
?
測試結(jié)論
?
SparkSQL訪問元數(shù)據(jù)服務(wù)的兩種方案都可以正常訪問元數(shù)據(jù)庫并且實現(xiàn)元數(shù)據(jù)庫的同步,而且元數(shù)據(jù)庫異常的情況下,兩種方案的處理是一樣的。
但是SparkSQL連接MetaStore節(jié)點需要連接到Hive的MetaStore節(jié)點,對比直接連接MySQL會有多余的MetaStore進程需要維護、更加復(fù)雜的元數(shù)據(jù)庫管理方式以及版本問題。
因此,建議用MySQL雙主的方式實現(xiàn)SparkSQL的雙主高可用,不同的SparkSQL節(jié)點直接連接到不同的MySQL。
訪問SparkSQL服務(wù)的方式可以采用兩種方式:
?
Beeline連接SQL URL的方式,對于MySQL異常的情況,可以重新連接繼續(xù)獲取SparkSQL服務(wù)。
?
?
調(diào)用JDBC接口訪問SparkSQL,捕獲異常并對異常情況作處理,重新連接到其他SparkSQL節(jié)點。
?
?
配置方式
?
SparkSQL節(jié)點直接連接MySQL的配置如下:
在服務(wù)配置界面將javax.jdo.option.ConnectionURL項配置任一MySQL節(jié)點作為默認MySQL節(jié)點,如下圖所示:
?
?
SparkSQL節(jié)點可以在自定義HIVE_SITE_CUSTOM_CONFIG中配置其他MySQL節(jié)點作為其對應(yīng)的MySQL節(jié)點,配置格式為:
?
?
javax.jdo.option.ConnectionURL
${{mysql_url}}
?
?
${{mysql_url}}為MySQL服務(wù)的URL。
如下圖所示:
?
?
評論
查看更多