$30 off During Our Annual Pro Sale. View Details »

Apache Kafka and the World of Streams

hashi
May 24, 2022

Apache Kafka and the World of Streams

# GCPUG Tokyo Queue Day 2022 May 登壇資料

Apache Kafkaはイベント駆動の領域で広く活用されています。一つの大きな特徴は、イベントが連なる『ストリーム』をコア概念としている点であり、概念だけでなく構造自体もストリームを扱う少し変わった設計がなされています。この為一般的なイベント駆動アーキテクチャの様に見えて、他のアプローチでは難しいユースケースで利用されたり、より複雑なエコシステムを形成することが出来ます。 本セッションでは、ストリームを支えるKafkaの内部構造と、その特徴を活用した「広がるストリーミング・エコシステム」のアプローチと事例についてお話しします。

hashi

May 24, 2022
Tweet

More Decks by hashi

Other Decks in Technology

Transcript

  1. GCPUG Tokyo Queue Day Apache Kafka® and the World of

    Streams Shinichi Hashitani, Solutions Engineering Lead, May. 2022. #gcpug
  2. 3
 Merpay - Data Platform CDC Pipeline 各マイクロサービスが運用するデータベースから 更新情報を抽出し、加工後にBigQueryに転送。 Kafka

    Connectを利用したSouce/Sinkとの接続 SourceからSinkに到達する過程でのデータ処理 「メルペイDataPlatformのCDC DataPipeline」 - mercari engineering
  3. @ShinHashitani | developer.confluent.io Microservice Challenges - Orchestration Independent Scalability コンポーネント単位でデプロイ&ス

    ケール可能。アプリケーションの 成長に応じて個々が独自のライフ サイクルによってサービスを管 理。個々のスケールが可能 - ボト ルネックとなる局所のみの増強に より全体スループットを向上。 Cascading Failure (連鎖障害) あるサービスが応答出来なくなると、その サービスにリクエストするサービスが応答不 能となる。1サービスの障害、高負荷による反 応速度低下が全体的な停止/パフォーマンス低 下に繋がる。 Data Consistency サービス毎に独立したデータストアを持つ - 異なるサービス間でデータ整合性を保つ必要 がある。2PCやSagaの様なパターンではデー タ同期コストが高く処理も複雑になる。ス ケールしにくい。
  4. @ShinHashitani | developer.confluent.io Kafka-Based Durable Event Driven Architecture Pull Model

    Pushモデルである為バックプレッシャーが不要 - Consumerをスケールする事により、他に影響を与え ず個別に対応。また一般的なMessage Brokerとは異 なり、同じストリームのConsumerが増えてもBroker の負荷にほとんど影響を与えない。 Durable Streams Brokerが任意の期間ストリームを保持できる為、 Consumeによる遅延は発生してもデータの欠損を起 こさない。Consumerが追いつく為の時間的バッ ファーが生まれる。
  5. @ShinHashitani | developer.confluent.io CQRS and Change Data Capture CQRS Command

    Query Responsibility Segregation - CRUD (Command) と検索 (Query) の役割とデータストアを分離するア プローチ。既存システムへの影響を抑えつ つ、ボトルネックになりがちな検索機能を別 のサービスとして切り離す。 Change Data Capture データベースの更新を抽出/イベント化し連携 することで、別データストア間のデータ整合 性を非同期に保つ手法。更新イベントは漏れ なく、順序通り連携する必要がある。 Command Query
  6. @ShinHashitani | developer.confluent.io final Properties settings = new Properties(); settings.put(ProducerConfig.CLIENT_ID_CONFIG,

    driverId); settings.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "kafka:9092"); settings.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); settings.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, KafkaAvroSerializer.class); settings.put(KafkaAvroSerializerConfig.SCHEMA_REGISTRY_URL_CONFIG, "http://schema-registry:8081"); final KafkaProducer<String, PositionValue> producer = new KafkaProducer<>(settings); ... final ProducerRecord<String, PositionValue> record = new ProducerRecord<>(“store-order”, key, value); producer.send(record); どこにどう送るか? 何を送るか? How to Send an Event to Kafka?
  7. @ShinHashitani | developer.confluent.io final ProducerRecord<String, PositionValue> record = new ProducerRecord<>(“store-order”,

    key, value); 何のイベントか? イベント自体 “store-order” is a Topic Kafkaにイベントを送る上で指定する唯一の「何のイベントか」に関わる情報。 KafkaはこのTopic毎にイベントをまとめて保存する。
  8. @ShinHashitani | developer.confluent.io Stream = Grouped Events customer login: abc

    order confirmed: #001 order updated: #002 customer login: efg order canceled: #003 package received: #a01 at dist center: #b02 left dist center: #a02 delivered: #a01 customer C: 0001 order U: 0003 payment U: 0002 payment C: 0003 customer U: 0002 store-order order confirmed: #001 order updated: #002 order canceled: #003 store-customer customer login: abc customer login: efg logistic package received: #a01 left dist center: #a02 delivered: #a01 at dist center: #b02 orderdb-c customer C: 0001 customer U: 0002 orderdb-o order U: 0003 orderdb-p payment C: 0003 payment U: 0002
  9. @ShinHashitani | developer.confluent.io Why Kafka? - Kafka Keeps Data Consistent

    イベントはトランザクションログとして保存 イベントはログとして永続化され、同じイベン トを何度でも読み込み処理する事が可能。Pullモ デルでもある為、イベントを漏れなく順序通り 高速に連携出来る仕組みとなっている。 customer login order confirmed order updated customer logout order canceled Append-Only Immutable 1 2 3 4 5 6 8 7 10 9 11 12 1 2 3 4 5 6 8 7 Old New
  10. @ShinHashitani | developer.confluent.io Event, Total Order, and Data Consistency 13

    “Streams and Tables in Apache Kafka: A Primer”, Michael Noll, Confluent Blog. チェスの一手一手とチェス盤の状態は 同じデータの異なる表現方法。 • チェス盤はある特定時点での完全な状 態 (State) を表現できる。 • チェスの一手一手を漏れなく、順序通 り適用すればチェス盤の状態を再現で きる。
  11. @ShinHashitani | developer.confluent.io Kafka is a Durable Storage Broker 1

    Broker 2 Broker 3 Broker 4 Topic1 partition1 Topic1 partition2 Topic1 partition3 Topic1 partition4 Topic1 partition1 Topic1 partition1 Topic1 partition2 Topic1 partition2 Topic1 partition3 Topic1 partition3 Topic1 partition4 Topic1 partition4 Concurrent Access Data Replication
  12. @ShinHashitani | developer.confluent.io What Did We Just See in the

    Demo? 18 API Google Cloud - asia-northeast-1b - e2-standard-4
  13. @yourtwitterhandle | developer.confluent.io Easily Build Real-Time Apps Joins Aggregates Push

    & Pull Queries Filters User-Defined Functions Connectors Compute Storage ksqlDB Kafka CREATE TABLE activePromotions AS SELECT rideId, qualifyPromotion(distanceToDst) AS promotion FROM locations GROUP BY rideId EMIT CHANGES 複雑なリアルタイム処理アプリを 数行のSQLで表現 ksqlDB at a glance ksqlDB is a database for building real-time applications that leverage stream processing
  14. @ShinHashitani | developer.confluent.io Event and State - Pull Query and

    Push Query Seven Eleven payment: 500 JPY CREATE STREAM payments AS SELECT Account_id, store, amount FROM transactions EMIT CHANGES; CREATE TABLE payment_sum AS SELECT account_id, SUM (amount) FROM transactions GROUP BY account_id TUMBLING WINDOW (1 DAY) EMIT CHANGES; Yoshinoya payment: 800 JPY AEON payment: 2,400 JPY hashi: 3700 JPY PULL hashi: Seven Eleven, 500 JPY hashi: Yoshinoya, 800 JPY hashi: AEON, 2400 JPY PUSH hashi: 500 JPY hashi: 1300 JPY hashi: 3700 JPY PUSH
  15. @ShinHashitani | developer.confluent.io Analyzing Site Access stream table process pageviews

    KSQL Female View Site users Admin female_per_region female_views KSQL Per Region KSQL Top Viewer KSQL Region 8&9 female_top_viewer female_region_89 CREATE STREAM female_views AS SELECT USERS.ID USERID, PAGEVIEWS.PAGEID PAGEID, USERS.REGIONID REGIONID, USERS.GENDER GENDER FROM pageviews LEFT OUTER JOIN USERS users ON ((pageviews.USERID = users.ID)) WHERE (users.GENDER = 'FEMALE') EMIT CHANGES; CREATE TABLE female_per_region AS SELECT views.GENDER GENDER, views.REGIONID REGIONID, COUNT(*) NUMUSERS FROM FEMALE_VIEWS views WINDOW TUMBLING ( SIZE 30 SECONDS ) GROUP BY views.GENDER, views.REGIONID HAVING (COUNT(*) > 1) ; CREATE STREAM female_top_viewer AS SELECT * FROM female_views views WHERE (CAST(SPLIT(views.PAGEID, '_')[2] AS INTEGER) >= 50) EMIT CHANGES; CREATE STREAM female_region_89 AS SELECT * FROM female_views views WHERE ((views.REGIONID LIKE '%_8') OR (views.REGIONID LIKE '%_9')) EMIT CHANGES; リアルタイムアクセス解析 • サイトから2種類のストリーム - ユーザー情報はログイン時にイベ ント化。JOIN対象ユーザーを 絞って解析。 • 一次処理した結果ストリームを異 なるダッシュボード毎に処理。 • ニーズによってストリームとテー ブルの混在。
  16. @ShinHashitani | developer.confluent.io ksqlDB - JSON Struct SHARES CUST_ID SYMBOL

    5000 1234567 ACMC 3000 2345678 IMPC 20000 3456789 HECH { "id": "STBCKS289803838HHDHD", "transaction": { "num_shares": 50000, "amount": 50044568.89, "txn_ts": "2020-11-18 02:31:43", "customer": { "first_name": "Jill", "last_name": "Smith", "id": 1234567, "email": "[email protected]" }, "company": { "name": "ACME Corp", "ticker": "ACMC", "id": "ACME837275222752952", "address": "Anytown USA, 333333" } } } CREATE STREAM TRANSACTION_STREAM ( id VARCHAR, trans STRUCT< num_shares INT, amount DOUBLE, txn_ts VARCHAR, customer STRUCT< first_name VARCHAR, last_name VARCHAR, id INT, email VARCHAR>, company STRUCT< name VARCHAR, ticker VARCHAR, id VARCHAR, address VARCHAR> >); SELECT TRANS->num_shares AS SHARES, TRANS->CUSTOMER->ID AS CUST_ID, TRANS->COMPANY->TICKER AS SYMBOL FROM TRANSACTION_STREAM EMIT CHANGES;
  17. @ShinHashitani | developer.confluent.io ksqlDB - Functions CAST CAST(COL0 AS BIGINT)

    GREATEST GREATEST(col1, col2, …) LEAST LEAST(col1, col2, …) LN LN(col1) ROUND ROUND(col1, scale) ARRAY_CONCAT ARRAY_CONCAT(array1, array2) ARRAY_DISTINCT ARRAY_DISTINCT([1, 1, 2, 2, 3]) ARRAY_MAX ARRAY_MAX(['foo', 'bar', 'baz']) ARRAY_SORT ARRAY_SORT(['foo', 'bar', 'baz'], 'ASC|DESC') Scalar Functionの一覧 JSON_ARRAY_CONTAI NS JSON_ARRAY_CONTAINS('[1, 2, 3]', 3) SLICE SLICE(col1, from, to) CONCAT CONCAT(col1, col2, 'hello', …, col-n) INSTR INSTR(string, substring, [position], [occurrence]) ENCODE ENCODE(col1, input_encoding, output_encoding) EXTRACTJSONFIELD EXTRACTJSONFIELD(message, '$.log.cloud') REGEXP_EXTRACT REGEXP_EXTRACT('(([AEIOU]).)', col1, 2)
  18. cnfl.io/ask-the-community Ask questions, share knowledge and chat with your fellow

    community members! Join your local Kafka User Group! Learn Apache Kafka® with Confluent Intrigued by Confluent Cloud? cnfl.io/mu-try-cloud Promo code for new + existing users: CC60COMM kafka-apache-jp.connpass.com