有這樣的一個業(yè)務場景-客戶端通過接口訪問impala Daemon叨吮,impala做查詢并返回數(shù)據(jù)給到客戶端锋玲;
下面通過impala jdbc訪問服務方式來介紹客戶端調(diào)用接口訪問impala場景
訪問實例前惭蹂,會做kerberos認證; 通過后就允許訪問相關(guān)服務
在實施方案前盾碗,假設讀者已經(jīng)基本熟悉以下技術(shù) (不細說)
- Java廷雅,maven
- impala榜轿, hdfs谬盐,kerberos
方案實施
- 把kdc服務端krb5.conf拷貝到本地工程目錄
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = WONHIGH.COM
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
[realms]
WONHIGH.COM = {
#注意這里最好改成IP飞傀,因為你部署工程的機器有可能并不知道host對應的ip
kdc = 172.17.194.20
admin_server = 172.17.194.20
}
- 生成的keytab文件并拷貝都工程目錄下
kadmin.local: xst -norandkey -k wms_dev.keytab wms_dev@WONHIGH.COM
-
工程目錄
keytab_krb5.png - 然后就是代碼了,不多說幢痘,直接上 (頭暈的直接拉到最下面看效果即可)
- pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>deng.yb</groupId>
<artifactId>impalaJdbc</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>impalaJdbc</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hive.version>2.5.42</hive.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.cloudera</groupId>
<artifactId>impala-jdbc41</artifactId>
<version>${hive.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.6.5</version>
</dependency>
<dependency>
<groupId>org.apache.hive</groupId>
<artifactId>hive-jdbc</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
</project>\
- 主類
package impala.kerberos;
import impala.conf.KbsConfiguration;
import impala.kerberos.callback.CallBack;
import impala.utils.Tools;
import java.io.IOException;
import java.security.PrivilegedAction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import org.apache.hadoop.security.UserGroupInformation;
public class KBImpalaJBDC {
private static String JDBC_DRIVER = "com.cloudera.impala.jdbc41.Driver";
private static String CONNECTION_URL = "jdbc:impala://{0}:21050/;AuthMech=1;KrbRealm={1};KrbHostFQDN={0};KrbServiceName=impala";
private static String SECURITY_KRB5_CONF = "java.security.krb5.conf";
private static String HADOOP_SECURITY_AUTH = "hadoop.security.authentication";
private static String DEFAULT_REALM = "WONHIGH.COM";
private String user;
private String realm;
private String krb5ConfDest = "krb5.conf";
private String keytabDest;
static {
try {
Class.forName(JDBC_DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public KBImpalaJBDC(String deamonHost, String realm) {
this.realm = realm;
CONNECTION_URL = MessageFormat
.format(CONNECTION_URL, deamonHost, realm);
}
public KBImpalaJBDC(String deamonHost) {
this(deamonHost, DEFAULT_REALM);
}
public KBImpalaJBDC user(String user) {
this.user = user;
return self();
}
public KBImpalaJBDC krb5Dest(String krb5ConfDest) {
this.krb5ConfDest = krb5ConfDest;
return self();
}
public KBImpalaJBDC keytabDest(String keytabDest) {
this.keytabDest = keytabDest;
return self();
}
public Object runWithKrbs(final String sql,final CallBack func) {
if (null == user || user.length() == 0) {
throw new RuntimeException("用戶不能為空!");
}
System.out.println("通過JDBC連接訪問Kerberos環(huán)境下的Impala");
// 登錄Kerberos賬號
try {
System.setProperty(SECURITY_KRB5_CONF,
Tools.getPath(krb5ConfDest));
UserGroupInformation.setConfiguration(KbsConfiguration
.newInstance().setPro(HADOOP_SECURITY_AUTH,
"Kerberos"));
UserGroupInformation.loginUserFromKeytab(
user,
Tools.getPath(keytabDest == null?(user.replace(realm, "") + ".keytab"):keytabDest));
UserGroupInformation logUser = UserGroupInformation.getLoginUser();
if (null == logUser) {
throw new RuntimeException("登錄用戶為空!");
}
System.out.println(UserGroupInformation.getCurrentUser() + "------"
+ logUser );
return logUser.doAs(new PrivilegedAction<Object>() {
public Object run() {
Connection connection = null;
ResultSet rs = null;
PreparedStatement ps = null;
try {
//Class.forName(JDBC_DRIVER);
connection = DriverManager
.getConnection(CONNECTION_URL);
ps = connection.prepareStatement(sql);
rs = ps.executeQuery();
if (null == func) {
return null;
} else {
return func.deal(rs);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.close();
}
if (ps != null) {
ps.close();
}
if (rs != null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
});
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
private KBImpalaJBDC self() {
return this;
}
}
- 工具類
package impala.utils;
public class Tools {
public static String getPath(String fileName) {
if (null == fileName || fileName.length() == 0) {
throw null;
}
return currentLoader().getResource(fileName).getPath();
}
public static ClassLoader currentLoader() {
return Thread.currentThread().getContextClassLoader();
}
}
- 輔助類和接口
package impala.conf;
import org.apache.hadoop.conf.Configuration;
public class KbsConfiguration extends Configuration {
public static KbsConfiguration newInstance() {
return new KbsConfiguration();
}
public Configuration setPro(String name, String value) {
super.set(name, value);
return this;
}
}
package impala.kerberos.callback;
public interface CallBack {
Object deal (Object obj);
}
方案驗證
- 測試類
package impalaJdbc.testCase;
import impala.kerberos.KBImpalaJBDC;
import impala.kerberos.callback.CallBack;
import java.sql.ResultSet;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args )
{
KBImpalaJBDC jdbc = new KBImpalaJBDC("bi-slave1");
Object obj = jdbc.user("wms_dev@WONHIGH.COM")
.krb5Dest("krb5.conf")
.keytabDest("wms_dev.keytab")
.runWithKrbs("select count(1) from gtp.ods_item;",new CallBack(){
public Object deal(Object obj) {
try {
if (obj instanceof ResultSet) {
ResultSet result = (ResultSet) obj;
StringBuilder builder = new StringBuilder();
while (result.next()) {
builder.append(result.getString(1)+"\n");
}
return builder.toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
System.out.println((obj!=null && obj instanceof java.lang.String)?obj.toString():"");
}
}
-
代碼結(jié)果
代碼結(jié)果.png -
直接登陸服務查詢結(jié)果
impala_服務結(jié)果.png 結(jié)果一致!
遺留問題
- 有經(jīng)驗的開發(fā)會發(fā)現(xiàn)一個問題绎签;就是代碼里面寫死訪問同一個impala實例酝锅,并發(fā)量一大會不會導致impala Daemon服務罷工屈张。答案是肯定的阁谆!
- 解決思路:實現(xiàn)軟均衡負載场绿,
- 具體方案;在客戶端與服務端直接搭建 HAProxy服務璧尸, 監(jiān)聽相應接口爷光,分發(fā)請求蛀序;以下是通過HAProxy實現(xiàn)impala均衡負載方案
均衡方案實施前徐裸,假設滿足以下條件
- impala服務正常
- 集成kerberos正常
HAProxy安裝和配置
yum -y install haproxy
- 啟動與停止HAProxy服務
service haproxy start
service haproxy stop
chkconfig haproxy on
- 配置Impala負載均衡
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak
vi /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
# http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
#option http-server-close
#option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen stats
bind 0.0.0.0:1080
mode http
option httplog
maxconn 5000
stats refresh 30s
stats uri /stats
listen impalashell
bind 0.0.0.0:25003
mode tcp
option tcplog
balance leastconn
server bi-slave1 bi-slave1:21000 check
server bi-slave2 bi-slave2:21000 check
server bi-slave3 bi-slave3:21000 check
listen impalajdbc
bind 0.0.0.0:25004
mode tcp
option tcplog
balance leastconn
server bi-slave1 bi-slave1:21050 check
server bi-slave2 bi-slave2:21050 check
server bi-slave3 bi-slave3:21050 check
- 啟動HAProxy服務
service haproxy restart
-
查看是否啟動正常
haproxy_stats.png
impala 配置
load_balance.png
- 保存重啟
Impala Shell測試
-
打開兩個窗口气笙,同時訪問impala-shell -i bi-master:25003
企業(yè)微信截圖_15284393253991.png
企業(yè)微信截圖_15284393378471.png - 發(fā)現(xiàn)請求會分發(fā)到不同impala daemon上健民,證明均衡負載配置成功
-
同理:java jdbc連接把Connect url的節(jié)點改為bi-master:25004即可
hue配置
-
impala均衡負載配置后,進入impala查詢會有可能報以下錯
企業(yè)微信截圖_15284412421912.png -
解決辦法稚晚,在hue配置中修改
hue_safety_value.png - 重啟hue服務即可