全部產品
Search
文件中心

E-MapReduce:Phoenix

更新時間:Aug 16, 2025

Apache Phoenix是構建在HBase上的SQL中介層,允許使用標準的SQL文法來查詢和管理儲存在HBase中的資料。

前提條件

已建立選擇了Phoenix和HBase服務的DataServing或Custom類型的叢集,詳情請參見建立叢集

通過命令列使用Phoenix

  1. 使用SSH方式串連叢集,詳情請參見登入叢集

  2. 執行以下命令,使用Phoenix的命令列工具。

    /opt/apps/PHOENIX/phoenix-current/bin/sqlline.py
  3. 您可以使用SQL進行資料查詢。常見操作如下:

    • 建立表

      CREATE TABLE IF NOT EXISTS example(
          my_pk bigint not null,
          m.first_name varchar(50),
          m.last_name varchar(50) 
          CONSTRAINT pk PRIMARY KEY (my_pk)
      );
    • 插入資料

      UPSERT INTO example(my_pk,m.first_name,m.last_name) VALUES(100,'Jack','Ben');
      UPSERT INTO example(my_pk,m.first_name,m.last_name) VALUES(200,'Jack3','Ben3');
    • 查詢資料

      SELECT * FROM example;

      返回資訊如下所示。

      +--------+-------------+------------+
      | MY_PK  | FIRST_NAME  | LAST_NAME  |
      +--------+-------------+------------+
      | 100    | Jack        | Ben        |
      | 200    | Jack3       | Ben3       |
      +--------+-------------+------------+
    • 刪除表

      DROP TABLE IF EXISTS example;

通過JDBC串連Phoenix

配置Maven依賴

<dependency>
     <groupId>org.apache.phoenix</groupId>
     <artifactId>phoenix-core</artifactId>
     <version>${phoenix.version}</version>
</dependency>

其中,${phoenix.version}須與叢集中的Phoenix版本保持一致。

程式碼範例

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.PreparedStatement;
import java.sql.Statement;

public class TestPhoenixJdbc {

    public static void main(String[] args) throws SQLException {
        Statement stmt = null;
        ResultSet rset = null;

        Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
        Connection con = DriverManager.getConnection("jdbc:phoenix:[zookeeper quorum hosts]");
        stmt = con.createStatement();

        stmt.executeUpdate("create table test (mykey integer not null primary key, mycolumn varchar)");
        stmt.executeUpdate("upsert into test values (1,'Hello')");
        stmt.executeUpdate("upsert into test values (2,'World!')");
        con.commit();

        PreparedStatement statement = con.prepareStatement("select * from test");
        rset = statement.executeQuery();
        while (rset.next()) {
            System.out.println(rset.getString("mycolumn"));
        }
        statement.close();
        con.close();
    }
}

通過JDBC串連開啟Kerberos的Phoenix

若您的叢集啟用了Kerberos認證,以下內容將為您介紹如何通過Java JDBC編寫用戶端程式,以安全地串連至已啟用Kerberos認證的EMR叢集中的Phoenix服務。用戶端程式將通過包含Principal和Keytab資訊的JDBC URL進行認證,並執行基本的DDL和DML操作以驗證串連。

步驟一:環境與憑證準備

在編寫和運行代碼之前,必須完成以下環境配置和Kerberos憑證建立工作。所有操作均在叢集的Master節點上執行。

  1. 使用SSH方式串連叢集Master節點,詳情請參見登入叢集

  2. 確定Kerberos網域名稱 (REALM)。

    每個啟用了Kerberos的叢集都有一個唯一的REALM。

    執行以下命令,會返回REALM資訊,您需要找到它並記錄下來,以便在後續步驟中使用。

    cat /etc/krb5.conf | grep default_realm

    返回以下類似資訊。

    default_realm = EMR.C-4FC5FDDE3759****.COM
  3. 建立用戶端Principal。

    Principal是用戶端在Kerberos系統中的唯一身份標識。我們需要為Java應用程式建立一個Principal。

    1. 在Master節點執行以下命令,使用kadmin.local工具。

      sudo kadmin.local
    2. 在kadmin.local互動介面中,執行以下命令以建立Principal。

      addprinc phoenix_client@EMR.C-4FC5FDDE3759****.COM

      執行命令後,系統將提示您為該Principal設定密碼。請務必牢記該密碼,儘管Keytab檔案允許我們實現免密登入,但在某些情況下仍可能需要使用密碼。

  4. 匯出Keytab檔案。

    1. 在kadmin.local工具中,請繼續執行以下命令以匯出Keytab檔案。

      xst -k /tmp/phoenix_client.keytab phoenix_client@EMR.C-4FC5FDDE3759****.COM
    2. 執行以下命令,退出kadmin.local。

      exit
      重要
      • 許可權: 確保運行Java程式的使用者對該Keytab檔案有讀取許可權。

      • 分發: 如果您的Java程式不在Master節點上運行,請務必將此phoenix_client.keytab檔案和/etc/krb5.conf檔案安全地分發到運行代碼的機器上,並放置在指令碼可以訪問的路徑下。

步驟二:編寫並打包Java應用程式

  • 方式一:直接使用先行編譯JAR(快速驗證)

    hbase-phoenix-kerberos-1.0-SNAPSHOT.jar

  • 方式二:手動編譯與打包(生產推薦)

    您可以參考以下程式碼範例以進行手動編譯與打包。

    核心程式碼範例PhoenixKerberosDemo.java

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    /**
     * 一個通過JDBC串連到Kerberos安全認證的Phoenix叢集的用戶端。
     * 所有的串連參數都通過一個從命令列傳入的、完整的JDBC URL來提供。
     */
    public class PhoenixKerberosDemo {
    
        /**
         * 應用程式的主進入點。
         *
         * @param args 命令列參數。程式期望接收一個參數:完整的 Phoenix JDBC URL。
         */
        public static void main(String[] args) {
            // --- 1. 驗證命令列輸入:期望接收一個參數,即JDBC URL ---
            if (args.length != 1) {
                System.err.println("ERROR: Invalid number of arguments.");
                System.err.println("Usage: java PhoenixKerberosDemo \"<full_jdbc_url>\"");
                System.err.println("Example: \"jdbc:phoenix:zk1,zk2:2181:/hbase:user@REALM.COM:/path/to/user.keytab\"");
                System.exit(1); // 以錯誤碼退出
            }
    
            String jdbcUrl = args[0];
    
            System.out.println("Attempting to connect to Phoenix...");
            System.out.println("Using JDBC URL: " + jdbcUrl);
    
            try {
                // --- 2. 載入 Phoenix 驅動 ---
                Class.forName("org.apache.phoenix.jdbc.PhoenixDriver");
            } catch (ClassNotFoundException e) {
                System.err.println("FATAL ERROR: Phoenix JDBC driver not found in the classpath.");
                e.printStackTrace();
                System.exit(1);
            }
    
            // --- 3. 使用 try-with-resources 語句建立串連並執行SQL,該文法會自動關閉資源 ---
            try (Connection con = DriverManager.getConnection(jdbcUrl);
                 Statement stmt = con.createStatement()) {
    
                System.out.println("Connection established successfully.");
    
                final String tableName = "TEST";
                System.out.println("Creating table '" + tableName + "'...");
                stmt.executeUpdate("CREATE TABLE IF NOT EXISTS " + tableName + " (mykey INTEGER NOT NULL PRIMARY KEY, mycolumn VARCHAR)");
                con.commit();
    
                System.out.println("Upserting data...");
                stmt.executeUpdate("UPSERT INTO " + tableName + " VALUES (1, 'Hello')");
                stmt.executeUpdate("UPSERT INTO " + tableName + " VALUES (2, 'World-Kerberos!')");
                con.commit();
                System.out.println("Data upserted successfully.");
    
                String sql = "SELECT * FROM " + tableName;
                System.out.println("Querying for results with: " + sql);
    
                try (PreparedStatement statement = con.prepareStatement(sql);
                     ResultSet rset = statement.executeQuery()) {
    
                    System.out.println("Query results:");
                    while (rset.next()) {
                        System.out.println(rset.getInt("mykey") + " -> " + rset.getString("mycolumn"));
                    }
                }
    
                System.out.println("Cleaning up the test table...");
                stmt.executeUpdate("DROP TABLE IF EXISTS " + tableName);
                con.commit();
    
            } catch (SQLException e) {
                // 捕獲SQL異常,並給出有協助的排查提示
                System.err.println("\n--- FAILED TO EXECUTE DATABASE OPERATION ---");
                System.err.println("Please check the following:");
                System.err.println("1. The JDBC URL is correct (format, principal, keytab path).");
                System.err.println("2. Network connectivity to ZooKeeper and HBase.");
                System.err.println("3. The keytab file exists and has correct read permissions.");
                System.err.println("4. The principal has sufficient permissions on HBase tables and namespaces.");
                e.printStackTrace();
            }
    
            System.out.println("\nExecution finished.");
        }
    }
    

    Maven配置(pom.xml)

    <?xml version="1.0" encoding="UTF-8"?>
    <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/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.aliyun.emr.doctor</groupId>
        <artifactId>hbase-phoenix-kerberos</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>Archetype - hbase-phoenix-kerberos</name>
        <url>http://maven.apache.org</url>
        <properties>
            <phoenix.version>5.2.1</phoenix.version>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.apache.phoenix</groupId>
                <artifactId>phoenix-core</artifactId>
                <version>${phoenix.version}</version>
                <scope>provided</scope>
            </dependency>
        </dependencies>
        <build>
            <plugins>
                <!--  Java Compiler  -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.1</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-shade-plugin</artifactId>
                    <version>3.2.4</version>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>shade</goal>
                            </goals>
                            <configuration>
                                <filters>
                                    <filter>
                                        <artifact>*:*</artifact>
                                        <excludes>
                                            <exclude>META-INF/*.SF</exclude>
                                            <exclude>META-INF/*.DSA</exclude>
                                            <exclude>META-INF/*.RSA</exclude>
                                        </excludes>
                                    </filter>
                                </filters>
                            </configuration>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </project>

步驟三:運行應用程式

  1. 運行環境選擇。

    在運行應用程式時,您可以選擇以下兩種運行環境:

    • 在叢集節點上運行(推薦):

      • 叢集節點已預裝所有必要的Hadoop、HBase和Phoenix依賴庫,無需額外配置。網路連通性無需額外設定,環境完整且穩定。

      • 適用情境:快速驗證和測試。開發調試階段。

    • 在叢集外運行

      如果需要在叢集外部運行程式,請確保滿足以下條件:

      • 網路互連:確保運行機器與叢集的ZooKeeper、HBase Master和RegionServer網路互連。

      • Kerberos配置: 將叢集的krb5.conf檔案和產生的keytab檔案複製到運行機器上。

      • 依賴管理: 運行命令的classpath中必須包含所有必需的Hadoop、HBase和Phoenix用戶端依賴JAR包。這通常比在叢集節點上運行複雜得多,建議使用工具(如Maven或Gradle)管理依賴。

  2. 執行指令碼。

    以下是一個整合了所有必要配置的kerberos-phoenix.sh指令碼,便於進行修改和執行。

    #!/bin/bash
    
    # ======================= 1. 使用者配置區 (請根據您的環境修改) =======================
    
    # Hadoop和HBase的設定檔所在目錄
    HADOOP_CONF_DIR="/etc/taihao-apps/hadoop-conf"
    HBASE_CONF_DIR="/etc/taihao-apps/hbase-conf"
    
    # Phoenix用戶端JAR包的路徑。使用符號連結是最佳實務,能抵抗版本變化。
    # 請先通過 `ls -l /opt/apps/PHOENIX/phoenix-current/` 確認此檔案存在。不同的版本這個位置需要修改。
    PHOENIX_JAR="/opt/apps/PHOENIX/phoenix-current/phoenix-client-lite-hbase-2.6.jar"
    
    # 您的應用程式JAR包檔案名稱。
    YOUR_JAR_FILE="hbase-phoenix-kerberos-1.0-SNAPSHOT.jar"
    
    # Kerberos設定檔路徑。
    KRB5_CONF_PATH="/etc/krb5.conf"
    
    # --- [核心] JDBC URL配置 ---
    # 格式:jdbc:phoenix:[ZK地址]:[ZK連接埠]:[HBase ZNode]:[Principal]:[Keytab絕對路徑]
    # 請將下面的ZK地址,REALM,Keytab路徑替換為您的真實資訊。
    ZK_QUORUM="master-1-1" # 如果有多個ZK,用逗號分隔,如 "zk1,zk2,zk3"
    ZK_PORT="2181"
    HBASE_ZNODE="/hbase" # 如果是安全叢集,可能是/hbase-secure
    PRINCIPAL="phoenix_client@EMR.C-4FC5FDDE3759****.COM" # 替換為您的Principal
    KEYTAB_PATH="/tmp/phoenix_client.keytab" # Keytab檔案的絕對路徑
    
    JDBC_URL="jdbc:phoenix:${ZK_QUORUM}:${ZK_PORT}:${HBASE_ZNODE}:${PRINCIPAL}:${KEYTAB_PATH}"
    # =================================================================================
    
    # ======================= 2. 執行區 (一般無需修改) =================================
    echo "================================================="
    echo "Starting Phoenix Kerberos JDBC Demo..."
    echo "Using JDBC URL: ${JDBC_URL}"
    echo "================================================="
    
    # 構建 Classpath。順序:目前的目錄 -> 配置目錄 -> 你的JAR -> 依賴JAR
    # `hbase classpath` 會自動載入Hadoop/HBase的核心依賴
    CLASS_PATH=".:${HADOOP_CONF_DIR}:${HBASE_CONF_DIR}:${YOUR_JAR_FILE}:${PHOENIX_JAR}:$(hbase classpath)"
    
    # 執行 Java 程式
    java -cp "${CLASS_PATH}" \
         -Djava.security.krb5.conf="${KRB5_CONF_PATH}" \
         PhoenixKerberosDemo "${JDBC_URL}"
    
    # 檢查退出碼
    if [ $? -eq 0 ]; then
        echo -e "\n[SUCCESS] Program finished successfully."
    else
        echo -e "\n[FAILED] Program terminated with an error."
    fi
    # =================================================================================
    1. 步驟二打包好的JAR包以及kerberos-phoenix.sh上傳至Master節點的指定目錄。

    2. 執行以下命令,賦予指令碼執行許可權。

      chmod +x kerberos-phoenix.sh
    3. 執行以下命令,運行指令碼。

      ./kerberos-phoenix.sh

      部分返回資訊如下所示。

      image

相關文檔

Phoenix更多資訊可以參見官方文檔: