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")
,就可以了。
最終代碼如下,
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()