但凡有些规模和积累的公司一定不会对基于 Hadoop 集群的 Hive 表陌生,毕竟廉价,稳定且成熟。但 Hive 表不适合存放频繁变化的数据,而这却是 TiDB 的强项,这就导致了很多业务公司可能既有 Hadoop 集群又有 TiDB 集群。要实现完美的混和访问,我们希望达到以下三个核心目标:

    1. 对业务 SQL 来讲,不能有 Hive/TiDB 表的区分,都按库名+表名进行访问,不要有多余操作。
    2. 由于访问 Hive 表可能需要消耗巨大资源,因此最好可以使用与之配套的计算集群资源。
    3. 确保 hive-site.xml 能够被 Spark 访问到,例如 hive-site.xml 复制到 SPARK_HOME/conf 下。hive-site.xml 中包含了 Hive Metastore 相关信息,只有 Spark 可以读取它,才能访问 Hive 中的数据。 下节将用一个具体的例子进行阐述。
    1. 软件环境清单:

      • Livy 服务,版本:基于 0.6 版本的改动版,作用:提交原始任务到 Spark 客户端;
      • beeline 客户端,版本:3.1.1,作用:连接 Livy 服务的客户端;
      • Spark 客户端,版本:2.4.0,作用:向 yarn 集群提交 Spark 作业;
      • Tispark Jar 包,版本:2.1.8,作用:提供与 TiKV 交互的能力;
      • YARN 集群,作用:提供计算资源。
    2. 函数封装代码:

    3. 封装函数说明:

      • 上述函数为封装的 shell 脚本函数,接收 2 个参数,$1 是 SQL 代码,$2 是可选的参数用以进行任务标识,本身使用了 $RANDOM 保证 session 名称不重复;
      • beeline 本身支持多种用户认证的方式,因此可以根据环境的具体情况变化,详情不在这里讲述。这里使用的是使用 hdfs 用户来认证;
      • TiDB 相关参数: a) spark.sql.extensions=org.apache.spark.sql.TiExtensions
        b) spark.tispark.pd.addresses=10.10.10.11:2379,10.10.10.12:2379,10.10.13.10:2379
        c) spark.jars=hdfs://com-hdfs/user/spark/tispark-core-2.1.4-spark_2.4-jar-with-dependencies.jar
      • livy.session.name 需要保证唯一,因此加了随机数及$2;
      • livy.session.queue 是 YARN 的队列名称;
      • 如果不加 -e “$1” 即可以实现交互查询。
      1. +----------------------------------------------------+
      2. | databaseName |
      3. +----------------------------------------------------+
      4. | sales_db |
      5. | db_em |
      6. | db_test |
      7. | db_shr |
      8. +----------------------------------------------------+

      上面 sales_db 是 Hive 库,db_em 及以下是 TiDB 库。
      (2) 单独查询 TiDB 库表:

      (3) 单独查 Hive 表:

      1. 0: jdbc:Hive2://bj0000,bj0001,bj0002:2222/> select count(1) from sales_db.mdms_tsqa_syyt;
      2. [Stage 2:> (0 + 1) / 151]
      3. ...
      4. [Stage 3:> (0 + 0) / 1]
      5. | count(1) |
      6. +------------+
      7. | 142380109 |
      8. +------------+
      9. 1 row selected (25.169 seconds)

      (4) 混和查询并写入 Hive 表:

      (5) 检查结果:

      1. RSC client is executing SQL query: select cnt from dc_tmp.test_for_mix, statementId = 18247b15-d9fb-4b97-87a1-6fa9cc3afad8, session = SessionHandle [b6933d96-8ec0-47b9-a767-ff2da5c5b2b2]
      2. [Stage 11:> (0 + 1) / 1]
      3. ......
      4. [Stage 11:> (0 + 1) / 1]
      5. +------------+
      6. | cnt |
      7. +------------+
      8. | 142380109 |
      9. | 224 |
      10. 2 rows selected (2.977 seconds)

    1. 写回TiDB

    TiDB 4.0 实现大事务支持之前,TiSpark 没有理想的方案支持向 TiDB 原生写入数据的方案。用户可以选择的是:

    • 使用 Spark 原生的 JDBC 方案,将 TiDB 当做 MySQL 写入数据,具体方案请参考。这个方案的缺陷是,数据必须被拆分为小批次插入,而这些批次之间无法维持事务原子性。换句话说,如果插入在中途失败,那么已经写入的数据并不会自动回滚,而需要人工干预。
    • 第二个方案是使用 TiSpark 的大批写入,这个方案可以导入大量数据且维持事务的原子性,但是由于缺少锁表和大事务支持,并不推荐在生产环境使用。

    在 TiSpark 完成对应 TiDB 4.0 大事务对应的支持后,用户就可以使用 TiSpark 作为一种主要的 TiDB 跑批方案,无论是向 TiDB 写入还是由 TiDB 向其他系统写出。在本文写作的时间点,此功能尚未完成,如有相关需要,请关注官方 更新 TiSpark 版本。

    2. 库重名问题

    TiDB 和 Hive 重名的情况,需要为 TiSpark 开启表名前缀模式,该模式会为所有 TiDB 表在 TiSpark 中加入前缀(而并不会改变 TiDB 内实际的表名)。例如,希望 TiDB 表在 TiSpark 中以 tidb_ 作为前缀使用,则增加如下配置(这并不会实际改变 TiDB 的表名):

    由于 TiSpark 没有直接修改 Apache Spark 代码,因此 Spark 原生兼容的大多数功能仍可正常运行。可以参考 Apache Spark 如何访问各个系统的文档正常使用,这里不做赘述。