Upgrade to Pro — share decks privately, control downloads, hide ads and more …

KafkaとFlink SQL on k8sで作るストリーム処理基盤 / Stream dat...

mercari
August 25, 2022

KafkaとFlink SQL on k8sで作るストリーム処理基盤 / Stream data processing platform using Apache Kafka and Flink SQL on k8s

メルペイではKafkaとFlinkを使ったストリーミング処理の基盤を構築しています。AMLやCRM、マーケティング用の広告データのニアリアルタイム連携や分析用データのデータウェアハウスへのCDC連携等で利用しています。
このセッションではDebeziumとConfluent Cloudを使ったCDC基盤とFlink SQL on k8sで構築したストリーミング処理基盤についてお話します。
------
Merpay Tech Fest 2022は3日間のオンライン技術カンファレンスです。
IT企業で働くソフトウェアエンジニアおよびメルペイの技術スタックに興味がある方々を対象に2022年8月23日(火)から8月25日(木)までの3日間、開催します。 Merpay Tech Festは事業との関わりから技術への興味を深め、プロダクトやサービスを支えるエンジニアリングを知れるお祭りです。 セッションでは事業を支える組織・技術・課題などへの試行錯誤やアプローチを紹介予定です。お楽しみに!

■イベント関連情報
- 公式ウェブサイト:https://events.merpay.com/techfest-2022/
- 申し込みページ:https://mercari.connpass.com/event/249428/
- Twitterハッシュタグ: #MerpayTechFest
■リンク集
- メルカリ・メルペイイベント一覧:https://mercari.connpass.com/
- メルカリキャリアサイト:https://careers.mercari.com/
- メルカリエンジニアリングブログ:https://engineering.mercari.com/blog/
- メルカリエンジニア向けTwitterアカウント:https://twitter.com/mercaridevjp
- 株式会社メルペイ:https://jp.merpay.com/

mercari

August 25, 2022
Tweet

More Decks by mercari

Other Decks in Technology

Transcript

  1. 中村智行 株式会社メルペイ DataPlatformチーム メルペイでPythonとScalaを使ってい い感じにデータを処理しているエンジニ ア 田中克典 株式会社メルペイ DataPlatformチーム Kafka,

    Flinkを中心に DataPlatformの開発と運用に携 わるソフトウェアエンジニア 2021年入社 趣味は開発環境のメンテナンス
  2. CDCとは Change Data Capture • データベース内のデータの変更を取得する ◦ CREATE、UPDATE、DELETE、etc ◦ データ分析やAML(Anti

    Money Laundering)、CRM等 に利用する ◦ データ収集の仕込みをサービスに実装しなくてよい • いくつかの手法がある ◦ Log-Based CDC ◦ Trigger-Based CDC ◦ Audit Columns 引用 “Change Data Capture (CDC): What it is and How it Works” https://www.striim.com/blog/change-data-capture-cdc-what-it-is-and-how-it-works/
  3. Kafka ConnectとDebeziumによるCDC環境 Kafka Connect • Kafkaと外部システムとのデータの入出力を行うフレームワーク ◦ Spannerからデータを取得 (JDBC Connector)

    ◦ BigQueryにデータを出力 (BigQuery Connector) Debezium • Log-Based CDCのOSS ◦ Kafka ConnectのConnectorとして動作する ◦ MySQL, PostgreSQLからデータを取得 詳細はエンジニアブログへ→→→ メルペイDataPlatformのCDC DataPipeline https://engineering.mercari.com/blog/entry/20220420-5d89f9d9c7/
  4. Confluent Cloud Apache KafkaのManaged Service • Kafkaの管理タスクからの解放 ◦ 障害対応 ◦

    キャパシティプランニング ◦ 監視 (各種監視ツールとの連携) • Kafka周辺のシステムのManaged Service ◦ Kafka Connect ◦ Schema Registry ◦ etc
  5. Kafka管理の自動化 Confluent CLI (※1) • Confluentの各種設定を管理できるCLIツール ◦ User、Topic、Consumer Group ◦

    権限管理 ◦ メルペイではこれをwrapしたツールを開発 ▪ 属人性の排除とヒューマンエラーの防止のため Terraform Confluent Provider (※2) • TerraformでConfluentを操作するProvider ◦ 1.0.0 released! ◦ 使用を検討中 (※1) https://docs.confluent.io/confluent-cli/current/overview.html (※2) https://registry.terraform.io/providers/confluentinc/confluent/latest/docs
  6. Kafka Connect on GKE (1) Kafka ConnectクラスタをGKE上で動かす • k8s Deployment

    • 対象DB毎に1クラスタ • 各Connector( JDBC, Debezium, Spanner)は k8s Jobの形でデプロイ • kustomizeでyamlの共通化 ◦ DBのアドレスとテーブル名だけでデプロイ可能に 監視 • jmxのメトリクスをDatadog経由でモニタリング • Connectorの死活監視
  7. Kafka Connect on GKE (2) セキュリティ周り • KafkaやDBのパスワード等はSecret Managerで管理 •

    GCPのサービスアカウントはWorkload Identity経由で使用 • DBレコード等の暗号化 ◦ Kafkaに送信する前に暗号化 ◦ Kafka ConnectのTransformationで実施 ▪ OSSで公開済み ▪ https://github.com/mercari/kafka-connect-transfo rm-kryptonite-gcp
  8. AMLのデータパイプライン • DebeziumからCDCのデータをKafkaに送信 • FlinkでKafkaからデータを取得し、SQLでデータの整形やエンリッチ化を行い PubSubに送信 • FlinkでPubSubからデータを取得し、Splunkに送信 ◦ SplunkはHECを利用

    ◦ OkHttpを使ったSinkコネクタを実装 ◦ スループットの調整が行いやすいように PubSubに集約 ◦ BigQueryにもStorageWriteAPIでリアルタイムに書き込み (JSON型を利用) •
  9. Flink on K8s • StandaloneクラスタのApplicationModeを利用 ◦ /docker-entrypoint.sh standalone-job --job-classname MAIN_CLASS_NAME

    ◦ ジョブマネージャ上でアプリケーションを起動 • ジョブマネージャとタスクマネージャのYAMLはKusomizeで管理 ◦ dev/prod環境の設定の違いを差分で管理 • デプロイはSpinnakerを利用 • モニタリングはDatadogを利用 ◦ DatadogHttpReporter ◦ アプリケーション毎にメトリックを送信 ◦ Datadogログも利用 •
  10. FlinkSQL • ストリームデータをCREATE TABLEでDynamicTableに変換 • DynamicTableに対してSQLを実行 • クエリの結果はDynamicTableにINSERTすることでストリームデータに変換 • CREATE

    TABLE clicks ( user VARCHAR, url VARCHAR, cTime TIMESTAMP(3) ) WITH (...) WITH の中に接続先の情報やデータフォーマットを記述 https://nightlies.apache.org/flink/flink-docs-release-1.15/docs/dev/table/concepts/dynamic_tables/
  11. KafkaのデータをFlinkSQLで処理 • CREATE TABLE source_table ( id BIGINT, name STRING,

    created_at BIGINT, updated_at BIGINT ) WITH ( 'connector' = 'kafka', 'topic' = 'topic', value.format = avro-confluent, … ) CREATE TABLE sink_table ( `time` BIGINT, source STRING, `index` STRING, event ROW< event_name STRING, id STRING, name STRING, created_at TIMESTAMP, updated_at TIMESTAMP >) WITH ( 'connector' = 'pubsub', 'format' = 'json', … ) INSERT INTO sink_table SELECT UNIX_TIMESTAMP(), 'mysql', 'main', ( 'cdc', CAST(id AS STRING), name, TO_TIMESTAMP(FROM_UNIXTIME(created_at)), TO_TIMESTAMP(FROM_UNIXTIME(updated_at)) ) FROM source_table
  12. PubSubのデータをFlinkSQLで処理 • FlinkSQLでSource/Sink先として使えるような実装を追加 ◦ FLINK-23501と同じような実装を自前で実装 ◦ https://github.com/apache/flink/pull/16598 ◦ そのうちマージされるかも? •

    CREATE文のWITHで connector = pubsub を指定 • Kafkaと同じようにSource/Sink先のテーブルを作成してSELECT INSERT • PubSubにAckを返すタイミングはチェックポイントのタイミング • WITH ( 'connector' = 'pubsub', 'project-name' = 'project-name', 'topic-subscription-name' = 'topic-name', 'format' = 'json', )
  13. • KafkaのデータはAvroを利用 ◦ Confluentのマネージドスキーマレジストリを利用 ◦ CREATE文で key.format/value.format = avro-confluent を指定

    • PubSubのデータはJSONもしくはProtoBufを利用 ◦ ProtoBufはFLINK-18202の実装を利用(問題なく動作) ◦ https://github.com/apache/flink/pull/14376 ◦ 1.16から正式にサポートされるはず ◦ CREATE文で format = protobuf を指定 データフォーマット • WITH ( 'connector' = 'pubsub', 'format' = 'protobuf', 'protobuf.message-class-name' = 'com.mercari.foo.bar.v1.Event', 'project-name' = 'project-name', 'topic-subscription-name' = 'topic-name' )
  14. DBデータとのJOIN ストリームデータのエンリッチ化 • DBのデータ(CDCのデータ)は正規化されている場合が多く、 JOINして足りない情報を補う必 要がある • ストリームデータとDBデータを Lookup JOIN

    • CREATE TABLE items ( id BIGINT, name STRING, price INT, user_id BIGINT, created_at TIMESTAMP, updated_at TIMESTAMP, proctime AS PROCTIME() ) WITH ( 'connector' = 'kafka', 'topic' = 'topic', value.format = avro-confluent, ...) CREATE TABLE users ( id BIGINT PRIMARY KEY NOT ENFORCED, name STRING, created_at TIMESTAMP, updated_at TIMESTAMP ) WITH ( 'connector' = 'jdbc', 'url' = 'jdbc:postgresql://', 'table-name' = 'users', ...) SELECT * FROM items AS t1 JOIN users FOR SYSTEM_TIME AS OF t1.proctime AS t2 ON t2.id = t1.user_id SELECT * FROM users WHERE id = 123 ストリームデータに proctimeフィールドを追加 JDBCコネクタでPostgreSQLのテーブルを参照 JOIN句でFOR SYSTEM_TIME OFにproctimeフィールドを指定 DBに実際に実行されるクエリ
  15. UDF • 日付フォーマッタ ◦ ソースによってフォーマットが違う場合が多い ◦ ビルトインのファンクションで対応しようとするとSQLが複雑になりや すい • JOINと同じようにDBデータをLookup

    ◦ DBにクエリを投げて結果を取得 ◦ 1対多で紐づくデータを配列として取得 ◦ SQLだと複雑になりやすい集計処理 ◦ JOINするテーブルが多くなり、SQLが複雑になるのを避ける ◦ H2 Databaseを使ったテストが書けるようにしている •
  16. HA Mode • K8sではZookeeperを使わなくてもHA構成にすることができる ◦ flink-conf.yaml に以下の設定を追加 ◦ リカバリ用のデータの管理には GCSを利用

    • HAの構成情報はConfigmapで自動的に管理される • 単一障害点のジョブマネージャを複数起動できる • ジョブマネージャが落ちても最新のチェックポイントから自動的に復旧 • ステートが重要でないアプリで多少のダウンタイムを許容 ◦ podが落ちてもK8sが上げ直してくれるので、 K8sに任せるのもあり • kubernetes.cluster-id: cluster-id high-availability: org.apache.flink.kubernetes.highavailability.KubernetesHaServicesFactory high-availability.storageDir: gs://flink/recovery flink-job-name-00000000000000000000000000000000-jobmanager-leader flink-job-name-dispatcher-leader flink-job-name-resourcemanager-leader flink-job-name-restserver-leader
  17. Auto Scaling • ReactiveMode ◦ flink-conf.yaml に scheduler-mode: reactive を追加

    • Flink 1.13から実装された機能 • StandaloneクラスタのApplicationModeのみ対応 • タスクマネージャの数に応じてジョブの並列実行数が変化 • K8sではHPAと組み合わせてオートスケーリングが可能 ◦ Datadogのメトリックを外部メトリックとして利用可能 ◦ KafkaやPubSubの未処理メッセージ数や遅延時間に応じてスケールアウト可能 ◦ kafkaの遅延時間は kafka-lag-exporter で取得 ◦ https://github.com/seglo/kafka-lag-exporter • ピーク時とオフピーク時でトラフィックに差があるアプリケーションに導入済 •