Slide 1

Slide 1 text

KafkaとFlink SQL on K8sで作る ストリーム処理基盤 田中克典 中村智行 株式会社メルペイ DataPlatformチーム

Slide 2

Slide 2 text

中村智行 株式会社メルペイ DataPlatformチーム メルペイでPythonとScalaを使ってい い感じにデータを処理しているエンジニ ア 田中克典 株式会社メルペイ DataPlatformチーム Kafka, Flinkを中心に DataPlatformの開発と運用に携 わるソフトウェアエンジニア 2021年入社 趣味は開発環境のメンテナンス

Slide 3

Slide 3 text

本セッションのテーマ 01 メルカリ/メルペイのCDC基盤 02 Flink SQL on Kubernetesによるストリーム処理基盤

Slide 4

Slide 4 text

メルカリ/メルペイのCDC基盤

Slide 5

Slide 5 text

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/

Slide 6

Slide 6 text

メルカリ/メルペイにおけるCDCの活用 ● ほぼリアルタイムに近い鮮度のデータが必要な分析 ○ AML (アンチマネーロンダリング)対策など ■ セッション後半で紹介 ● データ変遷の履歴が必要な分析 ○ ユーザステータス遷移の履歴 ○ イベントログ的な使い方 ○ CRM等

Slide 7

Slide 7 text

メルカリ/メルペイのCDC基盤

Slide 8

Slide 8 text

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/

Slide 9

Slide 9 text

Confluent Cloud Apache KafkaのManaged Service ● Kafkaの管理タスクからの解放 ○ 障害対応 ○ キャパシティプランニング ○ 監視 (各種監視ツールとの連携) ● Kafka周辺のシステムのManaged Service ○ Kafka Connect ○ Schema Registry ○ etc

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

Kafka Connect on GKE (1) Kafka ConnectクラスタをGKE上で動かす ● k8s Deployment ● 対象DB毎に1クラスタ ● 各Connector( JDBC, Debezium, Spanner)は k8s Jobの形でデプロイ ● kustomizeでyamlの共通化 ○ DBのアドレスとテーブル名だけでデプロイ可能に 監視 ● jmxのメトリクスをDatadog経由でモニタリング ● Connectorの死活監視

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

まとめ Kafkaを中心としたCDC環境を構築した ● Kafka ConnectとDebeziumでデータを取得 ● Confluent CloudでKafka運用の省力化 ● Kafka Connect on k8s

Slide 14

Slide 14 text

Flink SQL on Kubernetesによる ストリーム処理基盤

Slide 15

Slide 15 text

AMLのデータパイプライン ● DebeziumからCDCのデータをKafkaに送信 ● FlinkでKafkaからデータを取得し、SQLでデータの整形やエンリッチ化を行い PubSubに送信 ● FlinkでPubSubからデータを取得し、Splunkに送信 ○ SplunkはHECを利用 ○ OkHttpを使ったSinkコネクタを実装 ○ スループットの調整が行いやすいように PubSubに集約 ○ BigQueryにもStorageWriteAPIでリアルタイムに書き込み (JSON型を利用) ●

Slide 16

Slide 16 text

Flink on K8s ● StandaloneクラスタのApplicationModeを利用 ○ /docker-entrypoint.sh standalone-job --job-classname MAIN_CLASS_NAME ○ ジョブマネージャ上でアプリケーションを起動 ● ジョブマネージャとタスクマネージャのYAMLはKusomizeで管理 ○ dev/prod環境の設定の違いを差分で管理 ● デプロイはSpinnakerを利用 ● モニタリングはDatadogを利用 ○ DatadogHttpReporter ○ アプリケーション毎にメトリックを送信 ○ Datadogログも利用 ●

Slide 17

Slide 17 text

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/

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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', )

Slide 20

Slide 20 text

● 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' )

Slide 21

Slide 21 text

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に実際に実行されるクエリ

Slide 22

Slide 22 text

UDF ● 日付フォーマッタ ○ ソースによってフォーマットが違う場合が多い ○ ビルトインのファンクションで対応しようとするとSQLが複雑になりや すい ● JOINと同じようにDBデータをLookup ○ DBにクエリを投げて結果を取得 ○ 1対多で紐づくデータを配列として取得 ○ SQLだと複雑になりやすい集計処理 ○ JOINするテーブルが多くなり、SQLが複雑になるのを避ける ○ H2 Databaseを使ったテストが書けるようにしている ●

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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 ● ピーク時とオフピーク時でトラフィックに差があるアプリケーションに導入済 ●

Slide 25

Slide 25 text

まとめ K8s上にFlinkを使ってストリーム処理基盤を構築 ● ストリーミングデータに対して、SQLで簡単に整形処理やデータのエンリッチ化が行 える ● K8s上で動かしているので、他のアプリケーション (Go)とCI/CDやモニタリング、 オートスケーリングの仕組みを共通化できる ● K8s上で簡単にHA構成にすることができ、チェックポイント /セーブポイントの仕組み と合わせてより安全にデータを配送できる ●

Slide 26

Slide 26 text

No content