Redshift Serverlessと他のサーバーレス集計サービス、Glue Data Catalogのテーブルへのクエリ実行

awslogsparkpresto

Redshift Serverless

Redshift Serverlessは今年のre:Inventで発表された、インスタンスを立てることなく従量課金でペタバイトスケールのDWHであるRedshiftを使える機能。 S3のデータを直接参照できるRedshift SpectrumやRDSへのFederated Query、機械学習のRedshift MLも使える。 分析のような不定期に発生する需要のためにインスタンスを立てておくのはコストの上でハードルが高かったのでこのアップデートは嬉しい。

料金は最低1分のオートスケールするRPU (2vCPU, 16GiBメモリ)時間とストレージに対してかかり、オレゴンリージョンなどが$0.45/RPU hourなのに対して東京はなぜか$0.70/RPU hourと少し割高な設定になっている。2vCPU, 15 GiBメモリのインスタンスdc2.largeがオンデマンドで$0.314/hourなので、利用頻度が少なかったり不定期なために平均40%以上リソースが使えていない場合のコストは抑えられそうだ。RIが最大まで効いている場合は$0.110/hourとなり15%まで閾値が下がるが、スケールを気にしなくて良いのは運用の上でもメリットがある。また、Redshift Spectrumのロード量に対する課金は発生しない。

他のサーバーレス集計サービス

サーバーレスで集計を行える他のサービスとしてはPrestoのマネージドサービスであるAthenaやSparkのマネージドサービスであるGlueがあって、前者は手軽にクエリを実行できロード量による課金も分かりやすいが、実行時間や同時実行数などの制約があり、後者は時間のかかる集計も行うことができるがジョブを作る必要があってアドホックな実行にはあまり向かない。

これらはHive Metastoreに対応しており、その互換サービスであるGlue Data Catalogでスキーマを共有できるので用途に応じて使い分けることもできるが、使える文法に差があったり、同じクエリを実行しても異なる結果を返すことがあったりと、移植する際には注意する必要がある。

Athena(Presto)とGlue(Spark)で同じクエリを実行した際に異なる値が返る原因 - sambaiz-net

また、いずれもRDSに加えてDynamoDBやMongoDBなどのコネクタが用意されており、カスタムコネクタを用いることで他のデータソースにも接続することができる。

AthenaのFederated QueryでTPC-DS Connectorを用いてデータを生成する - sambaiz-net

GlueのカスタムコネクタでBigQueryに接続する - sambaiz-net

同じく今年のre:Inventで発表されたEMR Serverlessもある。 巨大なデータに対して重い集計やrepartition()を行ったりするとOOMやNo space left on deviceになることがあるが、Glueだとスケールアップできないため物理的に解決が難しいことがあり、そのような場合はEMRを検討することになる。

サードパーティにも目を向ければ各クラウドにホストされるSnowflakeがある。コストやスケールの容易さのためにRedshiftからSnowflakeに移行した事例もあり良い評判を目にするが、立ち位置が近いRedshift Serverlessが発表されたことでこれからの技術選定に影響があるかもしれない。料金はプランによって単価が異なるSnowflake Creditとストレージに対してかかる。

他にはAnthosを用いてマルチクラウドでクエリエンジンを動かすBigQuery Omniもある。今年の10月にGAになったばかりで、対応リージョンがまだ少なく、料金も従量課金でないので他と同様に使うイメージではないが、データを転送することなくAWS上でBigQueryのクエリを実行できるのは待望の機能なので今後の動きが気になる。

Glue Data Catalogのテーブルにクエリを実行する

CDKでData CatalogのDatabaseとTable、それらにアクセスできるRoleを作成する。

CDKでGlue Data CatalogのDatabase,Table,Partition,Crawlerを作成する - sambaiz-net

これも今年のre:Inventで発表があったが、ついにCDKのv2がstableになったのでv2で書く。 各サービスのパッケージ @aws-cdk/aws-xxxaws-cdk-lib に統合され、alphaのものだけ旧パッケージ名に-alphaを付けたものになった。

$ npx [email protected] init app --language typescript
$ npm install --save aws-cdk-lib
$ npm install --save @aws-cdk/aws-glue-alpha

Redshift Serverlessで用いるRoleはPrincipalに redshift.amazonaws.comredshift-serverless.amazonaws.comを入れる必要がある

const db = new Database(this, 'Database', {
  databaseName: "test_db",
})

const bucket = new Bucket(this, 'Bucket', {
  bucketName: `redshift-serverless-test-${this.account}-${this.region}`
})

new BucketDeployment(this, 'DeployWebsite', {
  sources: [Source.asset('./data')],
  destinationBucket: bucket,
  destinationKeyPrefix: 'test_table/',
});

const table = new Table(this, 'TestTable', {
  tableName: "test_table",
  database: db,
  columns: [{
    name: "id",
    type: Schema.BIG_INT,
  }],
  dataFormat: DataFormat.JSON,
  bucket: bucket,
  s3Prefix: "test_table/",
  compressed: false,
})

const role = new Role(this, 'SchemaRole', {
    assumedBy: new CompositePrincipal(
      new ServicePrincipal('redshift.amazonaws.com'),
      new ServicePrincipal('redshift-serverless.amazonaws.com')
    )
  })
  role.addToPolicy(new PolicyStatement({
    resources: [
      db.databaseArn,
      db.catalogArn,
      table.tableArn
    ],
    actions: ['glue:Get*'],
  }))
  role.addToPolicy(new PolicyStatement({
    resources: [
      bucket.bucketArn,
      `${bucket.bucketArn}/*`,
    ],
    actions: ['s3:Get*', 's3:List*'],
  }))
})

作ったRoleをエンドポイントに関連付けてSchema作成時に選べるようにする。

リソース一覧のServerlessをクリックして接続した後、Data CatalogのDatabaseとRoleを指定してRedshiftのExternal Schemaを作成する。

これでData CatalogのTableに対してクエリを実行できる。 リソース一覧にTableが表示されない場合はRoleにTableを取得する権限がついているかを確認する。

Data Catalogを参照するAthenaからも同様のクエリが実行できる。こちらはSchemaを作成したりする必要がない。

参考

Redshift から Snowflake に移行しました | CyberAgent Developers Blog

Amazon Redshift の 進化の歴史とこれから/redshift-evolution-2021 - Speaker Deck