阿里云 E-MapReduce ClickHouse 操作指南 04期 — 数据导入

阿里云 E-MapReduce(简称EMR)是运行在阿里云平台上的一种大数据处理的系统解决方案。

ClickHouse 作为开源的列式存储数据库,主要用于在线分析处理查询(OLAP),能够使用 SQL 查询实时生成分析数据报告。而阿里云 EMR ClickHouse 则提供了开源 OLAP 分析引擎 ClickHouse 的云上托管服务。

本系列文章将从以下几个方面详细介绍 EMR ClickHouse 的操作指南:

EMR ClickHouse 操作指南 — 数据导入

一、从 Spark 导入数据至 ClickHouse

介绍如何将 Spark 中的数据导入至 ClickHouse 集群

前提条件

  • 开发工具

    • 本地安装了 Java JDK 8。

    • 本地安装了 Maven 3.x。

    • 本地安装了用于 Java 或 Scala 开发的 IDE,推荐 IntelliJ IDEA,且已配置完成 JDK 和 Maven 环境。

  • 已创建 Spark 集群,详情请参见创建集群:
    https://help.aliyun.com/document_detail/28088.htm

  • 已创建 ClickHouse 集群,详情请参见创建集群:
    https://help.aliyun.com/document_detail/213395.htm

背景信息

关于 Spark 的更多介绍,请参见简介:
https://help.aliyun.com/document_detail/206291.htm


代码示例

代码示例如下:

package com.company.packageName


import java.util.Properties
import java.util.concurrent.ThreadLocalRandom


import scala.annotation.tailrec


import com.google.common.collect.ImmutableMap
import org.apache.spark.internal.Logging
import org.apache.spark.sql.{SaveMode, SparkSession}


case class Test(id: Int, key1: String, value1: Boolean, key2: Long, value2: Double)


object CKDataImporter extends Logging {


  private var dbName: String = "default"
  private var tableName: String = ""
  private var ckHost: String = ""
  private var ckPort: String = "8123"
  private var user: String = "default"
  private var password: String = ""
  private var local: Boolean = false


  def main(args: Array[String]): Unit = {
    parse(args.toList)
    checkArguments()


    val jdbcUrl = s"jdbc:clickhouse://$ckHost:$ckPort/$dbName"


    logInfo(s"Use jdbc: $jdbcUrl")
    logInfo(s"Use table: $tableName")


    val spark = getSparkSession


    // generate test data
    val rdd = spark.sparkContext.parallelize(1 to 1000).map(i => {
      val rand = ThreadLocalRandom.current()
      val randString = (0 until rand.nextInt(10, 20))
        .map(_ => rand.nextLong())
        .mkString("")


      Test(i, randString, rand.nextBoolean(), rand.nextLong(), rand.nextGaussian())
    })


    val df = spark.createDataFrame(rdd)


    df.write
      .mode(SaveMode.Append)
      .jdbc(jdbcUrl, tableName, getCKJdbcProperties(user, password))
  }


  private def printUsageAndExit(exitCode: Int = 0): Unit = {
    logError("Usage: java -jar /path/to/CKDataImporter.jar [options]")
    logError("  --dbName      设置ClickHouse数据库的名称,默认为default")
    logError("  --tableName   设置ClickHouse库中表的名称")
    logError("  --ckHost      设置ClickHouse地址")
    logError("  --ckPort      设置ClickHouse端口,默认为8123")
    logError("  --user        设置ClickHouse所使用的用户名")
    logError("  --password    设置ClickHouse用户的密码,默认为空")
    logError("  --local       设置此程序使用Spark Local模式运行")
    System.exit(exitCode)
  }


  @tailrec
  private def parse(args: List[String]): Unit = args match {
    case ("--help" | "-h") :: _ =>
      printUsageAndExit()
    case "--dbName" :: value :: tail =>
      dbName = value
      parse(tail)
    case "--tableName" :: value :: tail =>
      tableName = value
      parse(tail)
    case "--ckHost" :: value :: tail =>
      ckHost = value
      parse(tail)
    case "--ckPort" :: value :: tail =>
      ckPort = value
      parse(tail)
    case "--user" :: value :: tail =>
      user = value
      parse(tail)
    case "--password" :: value :: tail =>
      password = value
      parse(tail)
    case "--local" :: tail =>
      local = true
      parse(tail)
    case Nil =>
    case _ =>
      printUsageAndExit(1)
  }


  private def checkArguments(): Unit = {
    if ("".equals(tableName) || "".equals(ckHost)) {
      printUsageAndExit(2)
    }
  }


  private def getCKJdbcProperties(
      user: String,
      password: String,
      batchSize: String = "1000",
      socketTimeout: String = "300000",
      numPartitions: String = "8",
      rewriteBatchedStatements: String = "true"): Properties = {
    val kvMap = ImmutableMap.builder()
      .put("driver", "ru.yandex.clickhouse.ClickHouseDriver")
      .put("user", user)
      .put("password", password)
      .put("batchsize", batchSize)
      .put("socket_timeout", socketTimeout)
      .put("numPartitions", numPartitions)
      .put("rewriteBatchedStatements", rewriteBatchedStatements)
      .build()
    val properties = new Properties
    properties.putAll(kvMap)
    properties
  }


  private def getSparkSession: SparkSession = {
    val builder = SparkSession.builder()
    if (local) {
      builder.master("local[*]")
    }
    builder.appName("ClickHouse-Data-Importer")
    builder.getOrCreate()
  }
}

操作流程

步骤一:创建 ClickHouse 表
  • 使用 SSH 方式登录 ClickHouse 集群,详情请参见使用SSH连接主节点:
    https://help.aliyun.com/document_detail/169150.htm

  • 执行如下命令,进入 ClickHouse 客户端。

clickhouse-client
  • 创建ClickHouse信息。

i. 执行如下命令,创建数据库clickhouse_database_name

CREATE DATABASE clickhouse_database_name ON CLUSTER cluster_emr;

阿里云EMR会为 ClickHouse 集群自动生成一个名为 cluster_emr 的集群。数据库名您可以自定义。

ii. 执行如下命令,创建表clickhouse_table_name_local。

CREATE TABLE clickhouse_database_name.clickhouse_table_name_local ON CLUSTER cluster_emr (
  id            UInt32,
  key1            String,
  value1        UInt8,
  key2            Int64,
  value2        Float64
) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{layer}-{shard}/clickhouse_database_name/clickhouse_table_name_local', '{replica}')
ORDER BY id

说明:表名您可以自定义,但请确保表名是以 _local 结尾。layer、shard 和 replica 是阿里云 EMR 为 ClickHouse 集群自动生成的宏定义,可以直接使用。

iii. 执行如下命令,创建与表 clickhouse_table_name_local 字段定义一致的表 clickhouse_table_name_all。

说明: 表名您可以自定义,但请确保表名是以 _all 结尾。

CREATE TABLE clickhouse_database_name.clickhouse_table_name_all ON CLUSTER cluster_emr (
  id                    UInt32,
  key1                  String,
  value1                UInt8,
  key2                  Int64,
  value2                Float64
) ENGINE = Distributed(cluster_emr, clickhouse_database_name, clickhouse_table_name_local, rand());
步骤二:编译并打包
  • 下载并解压 CKDataImporter 示例到本地:
    https://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/206129/cn_zh/1618215359208/CKDataImporter.tgz
  • 在 CMD 命令行中,进入到下载文件中 pom.xml 所在的目录下,执行如下命令打包文件。
mvn clean package

根据您 pom.xml 文件中artifactId的信息,下载文件中的target目录下会出现 CKDataImporter-1.0.0.jar 的 JAR 包。

步骤三:提交作业
  • 使用 SSH 方式登录 Spark 集群,详情请参见使用SSH连接主节点:
    https://help.aliyun.com/document_detail/169150.htm

  • 执行如下命令提交作业。

spark-submit --master yarn \
             --class com.aliyun.emr.CKDataImporter \
             /CKDataImporter-1.0.0.jar \
             --dbName clickhouse_database_name \
             --tableName clickhouse_table_name_all \
             --ckHost ${clickhouse_host}

参数 说明
dbName ClickHouse集群数据库的名称,默认为default。本文示例为clickhouse_database_name。
tableName ClickHouse集群数据库中表的名称。本文示例为clickhouse_table_name_all。
ckHost ClickHouse集群的Master节点的内网IP地址或公网IP地址。ip地址获取方式,请参见下文获取主节点的IP地址。
获取主节点的 IP 地址
  • 进入详情页面。

  • i. 登录 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值