ライブクリックストリームデータを毎秒約1000メッセージの速度で取得し、AmazonRedshiftに書き込むことを目的とした概念実証アプリを作成しています。
他の人が主張するパフォーマンスのようなものを手に入れるのに苦労しています(たとえば、 ここ )。
2 x dw.hs1.xlargeノード(+リーダー)でクラスターを実行しています。ロードを実行しているマシンは、64ビットUbuntu12.04.1を実行しているRedshiftクラスターと同じVPC上のEC2m1.xlargeインスタンスです。
Java 1.7(Ubuntuリポジトリのopenjdk-7-jdk)とPostgresql 9.2-1002ドライバーを使用しています(主に、Maven Centralでビルドが簡単になる唯一のドライバーだからです!)。
最後のテクニックを除いて、示されているすべてのテクニックを試しました ここ 。
「リアルタイム」でデータをロードしたいのでCOPY FROM
を使用できません。そのため、S3またはDynamoDBを介してデータをステージングすることは実際にはオプションではなく、Redshiftは何らかの理由でCOPY FROM stdin
をサポートしていません。
これは私のログからの抜粋で、個々の行が約15 /秒の速度で挿入されていることを示しています。
2013-05-10 15:05:06,937 [pool-1-thread-2] INFO uk.co...redshift.DatabaseWriter - Beginning batch of 170
2013-05-10 15:05:18,707 [pool-1-thread-2] INFO uk.co...redshift.DatabaseWriter - Done
2013-05-10 15:05:18,708 [pool-1-thread-2] INFO uk.co...redshift.DatabaseWriter - Beginning batch of 712
2013-05-10 15:06:03,078 [pool-1-thread-2] INFO uk.co...redshift.DatabaseWriter - Done
2013-05-10 15:06:03,078 [pool-1-thread-2] INFO uk.co...redshift.DatabaseWriter - Beginning batch of 167
2013-05-10 15:06:14,381 [pool-1-thread-2] INFO uk.co...redshift.DatabaseWriter - Done
私は何が間違っているのですか?他にどのようなアプローチを取ることができますか?
Redshift(別名ParAccel)は分析データベースです。目標は、非常に大量のデータに対して分析クエリに迅速に回答できるようにすることです。そのために、Redshiftはデータを列形式で保存します。各列は個別に保持され、列の前の値に対して圧縮されます。特定の列は通常、多くの反復的で類似したデータを保持するため、この圧縮は非常に効果的である傾向があります。
このストレージアプローチは、要求された列のみを読み取る必要があり、読み取るデータが非常に圧縮されているため、クエリ時に多くの利点があります。ただし、このコストは、インサートが遅くなる傾向があり、はるかに多くの労力を必要とすることです。また、完全に順序付けされていない挿入は、テーブルがVACUUMされるまでクエリのパフォーマンスが低下する可能性があります。
したがって、一度に1つの行を挿入することで、Redshiftの動作方法に完全に反することになります。データベースは、データを各列に連続して追加し、圧縮を計算する必要があります。これは、多数のZipアーカイブに単一の値を追加するのと少し似ています(正確ではありません)。さらに、データが挿入された後でも、VACUUMを実行してテーブルを再編成するまで、最適なパフォーマンスは得られません。
データを「リアルタイム」で分析したい場合は、すべての実用的な目的で、おそらく別のデータベースやアプローチを選択する必要があります。ここに私の頭のてっぺんから3があります:
同じINSERTステートメントで複数のリクエストをまとめてバッチ処理することで、Redshiftに1000行/秒を挿入することができました(この場合、各INSERTで最大200個の値タプルをバッチ処理する必要がありました)。 HibernateのようなORMレイヤーを使用する場合は、バッチ処理用に構成できます(たとえば、 http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html を参照してください)。 )
単一の挿入が遅い理由は、Redshiftがコミットを処理する方法です。 Redshiftには、コミット用の単一のキューがあります。
行1を挿入してからコミットするとします。これは、redshiftコミットキューに移動してコミットを終了します。
次の行、行2、次にコミット-再びコミットキューに移動します。この間に、行1のコミットが完了していない場合、行2は1のコミットが完了するのを待ってから、行2のコミットの作業を開始します。
したがって、挿入をバッチ処理すると、単一のコミットが実行され、Redshiftシステムへの単一のコミットよりも高速になります。
以下のリンクの問題#8からコミットキュー情報を取得できます。 https://aws.Amazon.com/blogs/big-data/top-10-performance-tuning-techniques-for-Amazon-redshift/
トランザクションあたり75,000レコードのトランザクションに書き込みをバッチ処理することで、2,400回/秒の挿入を達成することができました。ご想像のとおり、各レコードは小さく、レコードあたり約300バイトです。
EC2インスタンスにインストールされているMariaDBにクエリを実行し、Mariaがインストールされているのと同じEC2インスタンスからRedShiftにレコードを挿入しています。
[〜#〜]更新[〜#〜]
5つの並列スレッドでMariaDBからデータをロードし、各スレッドからRedShiftに書き込むように、書き込みの方法を変更しました。これにより、パフォーマンスが12,000回以上の書き込み/秒に向上しました。
そうですね、正しく計画すれば、RedShiftの書き込みから優れたパフォーマンスを得ることができます。