Интеграция Kyuubi и Spark Connect

Обзор

Spark Connect — это протокол, позволяющий клиентским приложениям взаимодействовать с удаленным сервером Spark через gRPC без необходимости размещать на клиенте драйвер Spark.

Kyuubi — это многопользовательский шлюз, позволяющий запускать задачи Spark и исполнять SQL-запросы в вычислительных движках по типу Spark, Hive и Flink.

Стандартный сервер Spark Connect не предоставляет возможностей изоляции пользователей и аутентификации. gRPC-канал между клиентским приложением Spark и Spark Connect остается незащищенным. В то же время эти функции предоставляет Kyuubi, поэтому для него была введена поддержка протокола Spark Connect.

Spark Connect поддерживает следующие способы аутентификации: KERBEROS, LDAP и NONE. Клиент отправляет запрос с заголовком аутентификации Authorization: Negotiate …​ для Kerberos/SPNEGO или Authorization: Basic …​ для LDAP. Если аутентификация проходит корректно, сервер выдает токен, действующий столько, сколько указано в параметре kyuubi.frontend.spark.connect.token.ttl компонента Kyuubi Server (по умолчанию — 24 часа).

Затем, клиент может отправлять различные запросы к Spark с выданным токеном (клиент указывает его в заголовке аутентификации Bearer при каждом запросе). Время жизни этого токена обновляется каждый раз при отправке запроса. Когда пользователь завершает сессию Spark (вызывая spark.stop()), клиент Spark вызывает RPC-метод ReleaseSession, и сервер автоматически инвалидирует токен.

Ограничения
  • Spark Connect не поддерживает режим высокой доступности (High Availability). В строке подключения указывается только один сервер Kyuubi.

  • Между Kyuubi и движком Spark отсутствует шифрование и процесс аутентификации.

  • Kyuubi поддерживает только Spark3 (Spark 3.5 и выше).

Данные ограничения будут сняты в последующих релизах.

Клиентские библиотеки

Для Python и Java/Scala доступны клиентские библиотеки.

Пакет Python содержит модуль, реализующий аутентификацию для Spark Connect. Также доступен соответствующий пакет PySpark. Эти библиотеки уже имеются на всех хостах ADH (в директориях /usr/lib/spark3/python и /opt/pyspark3-python), но перед запуском программ Python необходимо активировать нужную среду:

$ source /opt/pyspark3-python/bin/activate

Если вы используете стандартный пакет PySpark, RPC-метод ReleaseSession не будет вызван при исполнении spark.stop(). Таким образом, после завершения сессии Spark, токен аутентификации не будет отозван. Если уровень изоляции Kyuubi имеет значение CONNECTION, то сессия YARN останется активной даже после вызова spark.stop().

Также доступен пакет для Java/Scala.

Настройка

В ADCM добавьте в значение конфигурационного параметра kyuubi.frontend.protocols компонента Kyuubi Server значение SPARK_CONNECT и перезапустите сервис Kyuubi. Таким образом, итоговое значение параметра будет иметь вид, например, THRIFT_BINARY,SPARK_CONNECT.

Примеры

Python

Данный пример демонстрирует подключение к Kyuubi через Spark Connect из Python. В кластере ADH активирован SSL и Kerberos.

  1. Подготовьте shell-скрипт, устанавливающий необходимую среду:

    prepare_env.sh
    source /opt/pyspark3-python/bin/activate
    export GRPC_DEFAULT_SSL_ROOTS_FILE_PATH=/etc/ssl/certs/ca-certificates.crt
  2. Подготовьте программу Python:

    spark_connect_client_kerberos.py
    from kyuubi.spark_connect import KyuubiSessionBuilder
    
    HOST = "tsn-adh3-3.ru-central1.internal"
    PORT = 10199
    
    spark = KyuubiSessionBuilder(f"sc://{HOST}:{PORT}/;use_ssl=true",
        auth="kerberos").getOrCreate()
    
    spark.sql("SELECT current_user()").show()
    
    spark.stop()

    Код для LDAP-аутентификации похож на представленный выше за исключением параметров, передаваемых для создания сессии:

    spark = KyuubiSessionBuilder(f"sc://{HOST}:{PORT}/;use_ssl=true",
        auth="ldap",
        username="<ldap_username>",
        password="<ldap_password>").getOrCreate()

    где <ldap_username> и <ldap_password> — имя пользователя и пароль пользователя в LDAP.

    Если вы не используете ни LDAP, ни Kerberos, опустите параметр auth.

  3. Запустите программу Python:

    $ python3 spark_connect_client_kerberos.py

    Ожидаемый вывод должен быть похож на следующий:

    +--------------+
    |current_user()|
    +--------------+
    |   stikhomirov|
    +--------------+

Java/Scala

  1. Подготовьте программу Java:

    SparkConnectClientKerberos.java
    import org.apache.spark.sql.SparkSession;
    import org.apache.spark.sql.kyuubi.KyuubiAuthType;
    import org.apache.spark.sql.kyuubi.KyuubiSessionBuilder;
    
    public class SparkConnectClientKerberos {
    
      public static void main(String[] args) {
        String url = System.getenv("KYUUBI_URL");
        if (url == null || url.isEmpty()) {
          throw new IllegalArgumentException("KYUUBI_URL environment variable is required");
        }
    
       String authStr = System.getenv().getOrDefault("KYUUBI_AUTH", "NONE");
        KyuubiAuthType authType = KyuubiAuthType.valueOf(authStr.toUpperCase());
    
        System.out.println("connection string: " + url);
        System.out.println("auth type: " + authType);
    
        SparkSession spark = new KyuubiSessionBuilder(url, authType).getOrCreate();
        try {
          spark.sql("SELECT current_user()").show();
        } finally {
          spark.stop();
        }
      }
    }
  2. В файле pom.xml добавьте следующую зависимость:

    <dependency>
      <groupId>org.apache.kyuubi</groupId>
      <artifactId>kyuubi-spark-connect-client-standalone_2.13</artifactId>
      <version>1.11.1.1-4.3.0-4</version>
    </dependency>
    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/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>org.apache.kyuubi.examples</groupId>
      <artifactId>kyuubi-spark-connect-client-jvm-examples</artifactId>
      <version>1.0-SNAPSHOT</version>
    
      <properties>
        <maven.compiler.release>17</maven.compiler.release>
        <kyuubi.version>1.11.1.1-4.3.0-0</kyuubi.version>
        <spark.version>3.5.4</spark.version>
      </properties>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.11.0</version>
          </plugin>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.5.0</version>
            <executions>
              <execution>
                <phase>package</phase>
                <goals><goal>shade</goal></goals>
                <configuration>
                  <filters>
                    <filter>
                      <artifact>*:*</artifact>
                      <excludes>
                        <exclude>META-INF/versions/*/module-info.class</exclude>
                        <exclude>META-INF/*.SF</exclude>
                        <exclude>META-INF/*.DSA</exclude>
                        <exclude>META-INF/*.RSA</exclude>
                      </excludes>
                    </filter>
                  </filters>
                  <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                      <mainClass>SparkConnectClientKerberos</mainClass>
                      <manifestEntries>
                        <Multi-Release>true</Multi-Release>
                      </manifestEntries>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                  </transformers>
                </configuration>
              </execution>
            </executions>
          </plugin>
        </plugins>
      </build>
    
      <dependencies>
        <dependency>
          <groupId>org.apache.kyuubi</groupId>
          <artifactId>kyuubi-spark-connect-client-standalone_2.13</artifactId>
          <version>${kyuubi.version}</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-simple</artifactId>
          <version>1.7.36</version>
        </dependency>
      </dependencies>
    
    </project>

    С подготовленным POM-файлом сгенерируйте JAR-файл.

  3. Подготовьте shell-скрипт, устанавливающий необходимые переменные среды и запускающий программу:

    run.sh
    export KYUUBI_AUTH=kerberos
    export KYUUBI_URL = "sc://tsn-adh3-3.ru-central1.internal:10199/;use_ssl=true"
    java --add-opens=java.base/java.nio=ALL-UNNAMED -jar target/kyuubi-spark-connect-client-jvm-examples-1.0-SNAPSHOT.jar
  4. Запустите подготовленный скрипт:

    $ source run.sh
Нашли ошибку? Выделите текст и нажмите Ctrl+Enter чтобы сообщить о ней