弹性网卡ENI(Elastic Network Interface)是一种可以绑定到专有网络VPC类型ECS实例上的虚拟网卡。通过弹性网卡,您可以实现高可用集群搭建、低成本故障转移和精细化的网络管理。本文主要介绍如何使用Serverless Spark通过ENI访问用户VPC中的HADOOP集群(开启kerberos认证的集群暂不支持)。

前提条件

保证Serverless Spark能够访问您的VPC,详情请参见访问用户VPC
注意 ENI交换机和安全组可以使用用户集群已有的ENI交换机和安全组。

操作步骤

  1. 将ENI交换机网段添加到HDFS服务的白名单/安全组中。
    • 当您需要访问EMR中的HDFS时,需要在EMR集群的安全组入方向中添加ENI交换机所在网段,暴露HDFS相关端口8020,50010,50020(如用户修改了HDFS的默认端口,请进行相应修改),EMR集群的安全组如下图所示,详细操作请参见安全组图片
    • 当您需要访问Xpack-Spark中的HDFS时,可在Xpack-Spark集群的访问控制中,将ENI交换机所在网段添加到网络白名单。详细操作请参见设置白名单和安全组图片
      注意 对于Xpack-Spark用户首先联系云X-Pack Spark答疑(钉钉号:dgw-jk1ia6xzp)开通HDFS, 由于HDFS的开放可能造成用户的恶意攻击,引起集群不稳定甚至造成破坏。因此XPack-Spark的HDFS功能暂时不直接开放给用户。
    • 当您访问自建的HADOOP集群时,您可以同样修改集群所在的安全组,添加ENI交换机所在网段,暴露HDFS相关端口8020,50010,50020(如用户修改了默认端口,请进行相应修改)。
  2. 获取需要在Severless Spark配置的参数。
    说明 如果您无法执行spark作业,可以跳过这步。
    由于Severless Spark无法自动获取用户HDOOP集群上HDOOP_CONF_DIR中的配置,所以需要您自行配置读取HDOOP相关的参数。您可以通过我们提供的工具来读取HDOOP集群下的配置。您也可以按照下面的地址自行下载spark-examples-0.0.1-SNAPSHOT-shaded.jar并上传至OSS。然后提交Spark作业到用户集群上执行,即可在作业输出中获得访问HDOOP所需的配置。
    wget https://dla003.oss-cn-hangzhou.aliyuncs.com/GetSparkConf/spark-examples-0.0.1-SNAPSHOT-shaded.jar
    • ERM用户将Jar包上传至OSS后,可以通过以下命令提交获取配置作业:
      --class com.aliyun.spark.util.GetConfForServerlessSpark
      --deploy-mode client
      ossref://{path/to}/spark-examples-0.0.1-SNAPSHOT-shaded.jar
      get hadoop
      作业运行完毕后,可以通过SparkUI查看driver的stdout输出或者从作业详情中的提交日志中查看输出的配置。图片
    • Xpack-Hdoop用户将Jar包上传至资源管理目录后,以用以下命令提交获取配置作业:
      --class com.aliyun.spark.util.GetConfForServerlessSpark
      /{path/to}/spark-examples-0.0.1-SNAPSHOT-shaded.jar
      get hadoop
      等待作业完成后,通过SparkUI的driver中的stdout查看输出配置tp
    • 其他HDOOP集群,如果您在集群上未设置HADOOP_CONF_DIR环境变量,则需要手动输入HADOOP_CONF_DIR路径。
      --class com.aliyun.spark.util.GetConfForServerlessSpark
      /{path/to}/spark-examples-0.0.1-SNAPSHOT-shaded.jar
      get --hadoop-conf-dir </path/to/your/hadoop/conf/dir> hadoop
  3. 编写访问HDFS的SparkApplication
    以下示例代码可以根据传入的HDFS目录信息,来读写HDFS目录,然后把内容展示出来:
    package com.aliyun.spark
    
    import org.apache.spark.sql.SparkSession
    
    object SparkHDFS {
      def main(args: Array[String]): Unit = {
        val sparkSession = SparkSession
          .builder()
          .appName("Spark HDFS TEST")
          .getOrCreate()
    
        val welcome = "hello, dla-spark"
    
        //hdfs目录用于存放内容
        val hdfsPath = args(0)
        //将welcome字符串存入指定的hdfs目录
        sparkSession.sparkContext.parallelize(Seq(welcome)).saveAsTextFile(hdfsPath)
        //从指定的hdfs目录中读取内容,并打印
        sparkSession.sparkContext.textFile(hdfsPath).collect.foreach(println)
      }
    }
  4. 将SparkApplication jar包和依赖上传至OSS中
    详情请参见上传文件
    说明 OSS所在的region和Serverless Spark所在的region需要保持一致。
  5. 在Serverless Spark中提交作业并进行计算。
    • HDFS 以非高可用的模式部署,详情请参见创建和执行Spark作业
      {
          "args": [
              "${fs.defaultFS}/tmp/dla_spark_test"
          ],
          "name": "spark-on-hdfs",
          "className": "com.aliyun.spark.SparkHDFS",
          "conf": {
          "spark.dla.eni.enable": "true",
          "spark.dla.eni.vswitch.id": "{您的交换机id}",
          "spark.dla.eni.security.group.id": "{您的安全组id}",
          "spark.driver.resourceSpec": "medium",
          "spark.executor.instances": 1,
          "spark.executor.resourceSpec": "medium"
          },
          "file": "oss://{您的jar包所属的oss路径}"
      }
      参数说明如下:
      参数 说明 备注
      fs.defaultFS 您的hdfs配置文件中core-site.xml 中的配置,注意如果fs.defaultFS配置的是机器的域名,需要转换成域名所对应的的ip。 典型格式 hdfs://${域名对应的ip}:9000/path/to/dir 用户可以通过登录集群master节点,通过/etc/hosts文件查看域名和ip的对应关系,或者直接采取ping域名的方式获取,或者通过步骤2获取相应配置。
      spark.dla.eni.vswitch.id 您的交换机id
      spark.dla.eni.security.group.id 您的安全组id
      spark.dla.eni.enable 控制开启或关闭ENI
      作业运行成功后,单击操作 > 日志,查看作业日志。图片
    • HDFS以高可用模式部署。
      {
          "args": [
              "${fs.defaultFS}/tmp/test"
          ],
          "name": "spark-on-hdfs",
          "className": "com.aliyun.spark.SparkHDFS",
          "conf": {
              "spark.dla.eni.enable": "true",
              "spark.dla.eni.vswitch.id": "{您的交换机id}",
              "spark.dla.eni.security.group.id": "{您的安全组id}",
              "spark.driver.resourceSpec": "medium",  
              "spark.executor.instances": 1,
              "spark.executor.resourceSpec": "medium",
              "spark.hadoop.dfs.nameservices":"{您的nameservices名称}",
              "spark.hadoop.dfs.client.failover.proxy.provider.${nameservices}":"{您的failover proxy provider实现类全路径名称}",
              "spark.hadoop.dfs.ha.namenodes.${nameservices}":"{您的nameservices所属namenode列表}",
              "spark.hadoop.dfs.namenode.rpc-address.${nameservices}.${nn1}":"namenode0所属的ip:port",
              "spark.hadoop.dfs.namenode.rpc-address.${nameservices}.${nn2}":"namenode1所属的ip:port"
          },
          "file": "oss://{{您的jar包所属的oss路径}"
      }
      参数 说明 备注
      spark.hadoop.dfs.nameservices 对应hdfs-site.xml中的dfs.nameservices
      spark.hadoop.dfs.client.failover.proxy.provider.${nameservices} 对应hdfs-site.xml中的dfs.client.failover.proxy.provider.${nameservices}
      spark.hadoop.dfs.ha.namenodes.${nameservices} 对应hdfs-site.xml中的dfs.ha.namenodes.${nameservices}
      spark.hadoop.dfs.namenode.rpc-address.${nameservices}.${nn1/nn2} 对用hdfs-site.xml中的dfs.namenode.rpc-address.${nameservices}.${nn1/nn2} 注意这里应该填写namenode域名对应的ip:port,用户可以通过用户集群master节点中的/etc/hosts文件查看域名和ip的对应关系,或者通过步骤2获取相应的配置。
    说明 Servless Spark 无法读取到用户集群上的HADOOP_CONF_DIR目录,因此在高可用模式下对比非高可用模式,需要用户额外传入5个参数,这五个参数均可以在hdfs-site.xml中找到。