oynix

于无声处听惊雷,于无色处见繁花

在Spark中加载Redshift数据问题汇总

1. java.sql.SQLException: No suitable driver

这个错误是因为,连接Redshift时需要一个driver,而程序执行时找不到能用的driver,所以报错。AWS提供了多个版本连接Redshift的driver,点击查看

2. java.lang.NoClassDefFoundError: com/amazonaws/services/kinesis/model/Record

经过几次尝试发现,直接使用AWS提供的驱动可以连上Redshift,打印出表结构,但是不能加载数据,一加载数据会报这个奇怪的错误,表结构都可以打印出来,为什么不能加载数据呢?我想不通。几番查询,找到了一个包装库,github地址

3. java.lang.IllegalArgumentException: AWS Access Key ID and Secret Access Key must be specified as the username or password (respectively) of a s3n URL, or by setting the fs.s3n.awsAccessKeyId or fs.s3n.awsSecretAccessKey properties (respectively).

按照2里面的github库里的文档说明配置好后,可能会报这个错。因为spark-redshift用到了S3,所以要配置key和secret才可以。文档里也提供了几种方式,i、ii和iii,开始我选择的是第三种方式,直接写在了URI里面。

4. java.lang.NoClassDefFoundError: com/eclipsesource/json/Json

紧接着,配置好aws的key和secret,可能会遇到这个错误。这个错误一眼看上去感觉奇怪,为什么会报json的错误呢?在spark-redshift的issue里面找到了遇到同样问题的人,最下面arvindkanda提供了解决方案,启动时提供一个额外的jar包就可以了。

5. java.sql.SQLException: Amazon Invalid operation: S3ServiceException:The S3 bucket addressed by the query is in a different region from this cluster.

这个问题是说,S3和EMR必须在同一个region,不然Spark是读不到Redshift的数据的。我这里用的都是us-west-2,Oregon,俄勒冈。

6. com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.services.s3.model.AmazonS3Exception: Bad Request (Service: Amazon S3; Status Code: 400; Error Code: 400 Bad Request;

这个问题,就比较厉害了,卡了我好几个小时。网上各种方案都在说,因为签名版本的问题,所以访问S3时,必须指定S3的endpoint,查来的都是s3a的,比如这个。但是因为spark-redshift里用的是s3n,我就将a替换成了n,但是这个问题还是在。各种方案不断尝试,可能是运气好,莫名的就试对了一种方式:将3里面的方式替换成ii,然后再配置sc.hadoopConfiguration.set("fs.s3a.endpoint", "s3.us-west-2.amazonaws.com"),就可以了。

最终代码如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spark = SparkSession.builder.getOrCreate()
spark._jsc.hadoopConfiguration().set('fs.s3n.awsAccessKeyId', aws_access_key_id)
spark._jsc.hadoopConfiguration().set('fs.s3n.awsSecretAccessKey', aws_secret_access_key)
spark._jsc.hadoopConfiguration().set("fs.s3n.endpoint", "s3.us-west-2.amazonaws.com")

rsdf = spark.read\
.format('com.databricks.spark.redshift')\
.option('url', 'jdbc:redshift://host:port/schema')\
.option('dbtable', 'table_name')\
.option('user', 'username')\
.option('password', 'password')\
.option('tempdir', 's3n://bucket/dir')\
.load()
# 打印表结构
rsdf.printSchema()
# 打印表内容
rsdf.show()
关于spark启动命令参数,这篇文章已经说明过,这里就不再赘述。
------------- (完) -------------
  • 本文作者: oynix
  • 本文链接: https://oynix.com/2019/09/0858075fe9aa/
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

欢迎关注我的其它发布渠道