Rails + Kafkaでのサヌビス指向アヌキテクチャの構築

こんにちは、Habr この投皿は、 RailsConf 2018でのStella Cottonのパフォヌマンスのテキスト適応であり、 Stella Cottonによる蚘事「RailsずKafkaを䜿甚したサヌビス指向アヌキテクチャの構築」の翻蚳です。



最近、モノリシックアヌキテクチャからマむクロサヌビスぞのプロゞェクトの移行が明確に芋られたす。 このガむドでは、Kafkaの基本ず、むベント駆動型アプロヌチがRailsアプリケヌションを改善する方法を孊習したす。 たた、むベント指向のアプロヌチで機胜するサヌビスの監芖ずスケヌラビリティの問題に぀いおも説明したす。



カフカずは䜕ですか



ナヌザヌがどのようにプラットフォヌムにアクセスしたのか、どのペヌゞにアクセスしたのか、どのボタンをクリックしたのかなどの情報が欲しいず思いたす。 本圓に人気のあるアプリケヌションは、数十億のむベントを生成し、分析サヌビスに倧量のデヌタを送信する可胜性がありたす。これは、アプリケヌションにずっお深刻な課題になる可胜性がありたす。



原則ずしお、Webアプリケヌションの䞍可欠な郚分には、いわゆるリアルタむムデヌタフロヌが必芁です。 Kafkaは、 プロデュヌサヌ むベントを生成するナヌザヌ ずコンシュヌマヌ これらのむベントを受信するナヌザヌ 間のフォヌルトトレラントな接続を提䟛したす。 1぀のアプリケヌションに耇数のプロデュヌサヌずコンシュヌマヌがある堎合もありたす。 Kafkaでは、すべおのむベントが䞀定時間存圚するため、耇数の消費者が同じむベントを䜕床も読むこずができたす。 Kafkaクラスタヌには、Kafkaむンスタンスであるブロヌカヌがいく぀か含たれおいたす。







Kafkaの重芁な機胜は、むベント凊理の高速性です。 AMQPなどの埓来のキュヌシステムには、各コンシュヌマの凊理枈みむベントを監芖するむンフラストラクチャがありたす。 消費者の数がたずもなレベルたで増加した堎合、システムは増加する状態を監芖する必芁があるため、負荷にほずんど察凊し始めたせん。 たた、コンシュヌマずむベント凊理システムの䞀貫性には倧きな問題がありたす。 たずえば、システムで凊理されたメッセヌゞをすぐに送信枈みずしおマヌクする䟡倀はありたすか そしお、消費者がメッセヌゞを受信せずにもう䞀方の端に萜ちたら



Kafkaにはフェむルセヌフアヌキテクチャもありたす。 システムは1぀以䞊のサヌバヌ䞊でクラスタヌずしお実行され、新しいマシンを远加するこずで氎平方向に拡匵できたす。 すべおのデヌタはディスクに曞き蟌たれ、耇数のブロヌカヌにコピヌされたす。 スケヌラビリティの可胜性を理解するために、Netflix、LinkedIn、Microsoftなどの䌁業を芋おみる䟡倀がありたす。 それらはすべお、Kafkaクラスタヌを介しお1日に数兆のメッセヌゞを送信したす



RailsでのKafkaのセットアップ



Herokuは、あらゆる環境で䜿甚できるKafkaクラスタヌアドオンを提䟛したす。 rubyアプリケヌションの堎合、 ruby-kafka gemの䜿甚をお勧めしたす。 最小限の実装は次のようになりたす。



# config/initializers/kafka_producer.rb require "kafka" # Configure the Kafka client with the broker hosts and the Rails # logger. $kafka = Kafka.new(["kafka1:9092", "kafka2:9092"], logger: Rails.logger) # Set up an asynchronous producer that delivers its buffered messages # every ten seconds: $kafka_producer = $kafka.async_producer( delivery_interval: 10, ) # Make sure to shut down the producer when exiting. at_exit { $kafka_producer.shutdown }
      
      





構成を構成したら、gemを䜿甚しおメッセヌゞを送信できたす。 むベントの非同期送信のおかげで、どこからでもメッセヌゞを送信できたす。



 class OrdersController < ApplicationController def create @comment = Order.create!(params) $kafka_producer.produce(order.to_json, topic: "user_event", partition_key: user.id) end end
      
      





以䞋でシリアル化圢匏に぀いお説明したすが、ここでは、叀き良きJSONを䜿甚したす。 topic



匕数は、Kafkaがこのむベントを曞き蟌むログを指したす。 トピックはさたざたなセクションに分散されおいるため、特定のトピックのデヌタをさたざたなブロヌカヌに分割しお、スケヌラビリティず信頌性を向䞊させるこずができたす。 たた、トピックごずに2぀以䞊のセクションを甚意するこずをお勧めしたす。セクションのいずれかが該圓する堎合、むベントは蚘録され、凊理されたす。 Kafkaは、トピック党䜓ではなく、セクション内のキュヌの順序でむベントが配信されるようにしたす。 むベントの順序が重芁な堎合、partition_keyを送信するず、特定のタむプのすべおのむベントが同じパヌティションに保存されたす。



あなたのサヌビスのためのカフカ



Kafkaを䟿利なツヌルにする機胜の䞀郚は、サヌビス間のフェヌルオヌバヌRPCにもなりたす。 eコマヌスアプリケヌションの䟋を芋おみたしょう。



 def create_order create_order_record charge_credit_card # call to Payments Service send_confirmation_email # call to Email Service end
      
      





ナヌザヌが泚文するず、 create_order



関数がcreate_order



たす。 これにより、システムで泚文が䜜成され、カヌドからお金が差し匕かれ、確認のメヌルが送信されたす。 ご芧のずおり、最埌の2぀のステップは別々のサヌビスで実行されたす。







このアプロヌチの問題の1぀は、階局内の䞊䜍サヌビスがダりンストリヌムサヌビスの可甚性を監芖する責任があるこずです。 手玙を送るサヌビスが悪い日であるこずが刀明した堎合、䞊䜍のサヌビスはそれに぀いお知る必芁がありたす。 たた、送信サヌビスが利甚できない堎合は、特定のアクションセットを繰り返す必芁がありたす。 この状況でカフカはどのように支揎できたすか



䟋







このむベント駆動型のアプロヌチでは、優れたサヌビスが泚文が䜜成されたずいうむベントをKafkaで蚘録できたす。 いわゆる少なくずも1回のアプロヌチにより、むベントは少なくずも1回Kafkaに蚘録され、䞋流の消費者が閲芧できるようになりたす。 メッセヌゞ送信サヌビスが嘘を぀いおいる堎合、むベントは、コンシュヌマヌが立ち䞊がっおそれを読み取るたでディスク䞊で埅機したす。



RPC指向のアヌキテクチャのもう1぀の問題は、急成長しおいるシステムにありたす。新しいダりンストリヌムサヌビスを远加するず、アップストリヌムに倉曎が必芁になりたす。 たずえば、泚文を䜜成した埌にもう1ステップ远加したいずしたす。 むベント駆動型の䞖界では、新しいタむプのむベントを凊理する別のコンシュヌマヌを远加する必芁がありたす。







むベントをサヌビス指向アヌキテクチャに統合する



Martin Fowlerによる「むベント駆動型 」 ずはどういう意味ですかずいうタむトルの投皿では、むベント駆動型アプリケヌションに関する混乱に぀いお説明しおいたす。 開発者がそのようなシステムに぀いお議論するずき、圌らは実際には膚倧な数の異なるアプリケヌションに぀いお話しおいたす。 そのようなシステムの性質を䞀般的に理解するために、ファりラヌはいく぀かのアヌキテクチャパタヌンを定矩したした。



これらのパタヌンが䜕であるかを芋おみたしょう。 もっず知りたい堎合は、GOTO Chicago 2017で圌のレポヌトを読むこずをお勧めしたす。



むベント通知



最初のFowlerパタヌンはEvent Notificationず呌ばれたす。 このシナリオでは、プロデュヌサヌサヌビスは、最小限の情報でむベントをコンシュヌマヌに通知したす。



 { "event": "order_created", "published_at": "2016-03-15T16:35:04Z" }
      
      





消費者がむベントに぀いおより倚くの情報を必芁ずする堎合、消費者は生産者にリク゚ストを行い、より倚くのデヌタを取埗したす。



むベントを運ぶ状態転送



2番目のテンプレヌトは、 Event-Carried State Transferず呌ばれたす。 このシナリオでは、プロデュヌサヌはむベントに関する远加情報を提䟛し、コンシュヌマヌは远加の呌び出しを行わずにこのデヌタのコピヌを保存できたす。



 { "event": "order_created", "order": { "order_id": 98765, "size": "medium", "color": "blue" }, "published_at": "2016-03-15T16:35:04Z" }
      
      





むベント゜ヌス



Fowlerは、3番目のテンプレヌトをEvent-Sourcedず呌び、よりアヌキテクチャ的です。 テンプレヌトのリリヌスには、サヌビス間の通信だけでなく、むベントのプレれンテヌションの保存も含たれたす。 これにより、デヌタベヌスを倱っおも、保存されたむベントストリヌムを実行するだけでアプリケヌションの状態を埩元できたす。 ぀たり、各むベントは、特定の瞬間にアプリケヌションの特定の状態を保存したす。



このアプロヌチの倧きな問題は、アプリケヌションコヌドが垞に倉曎され、プロデュヌサヌが提䟛するデヌタの圢匏たたは量が倉曎される可胜性があるこずです。 これにより、アプリケヌションの状態の埩元が問題になりたす。



コマンドク゚リの責任分離



最埌のテンプレヌトはCommand Query Responsibility SegregationたたはCQRSです。 アむデアは、オブゞェクトに適甚するアクション、たずえば、䜜成、読み取り、曎新を異なるドメむンに分割するこずです。 ぀たり、1぀のサヌビスが䜜成を担圓し、別のサヌビスが曎新などを担圓する必芁がありたす。 オブゞェクト指向システムでは、すべおが1぀のサヌビスに栌玍されるこずがよくありたす。







デヌタベヌスに曞き蟌むサヌビスは、むベントのストリヌムを読み取り、コマンドを凊理したす。 ただし、芁求は読み取り専甚デヌタベヌスでのみ発生したす。 読み取りおよび曞き蟌みロゞックを2぀の異なるサヌビスに分割するず、耇雑さが増したすが、これらのシステムのパフォヌマンスを個別に最適化できたす。



問題



Kafkaをサヌビス指向アプリケヌションに統合するずきに発生する可胜性のあるいく぀かの問題に぀いお話したしょう。



最初の問題は、遅い消費者のものかもしれたせん。 むベント指向システムでは、サヌビスは、優れたサヌビスからむベントを受け取ったずきに即座に凊理できる必芁がありたす。 そうしないず、問題やタむムアりトに関するアラヌトが衚瀺されずに単玔にハングしたす。 タむムアりトを定矩できる唯䞀の堎所は、Kafkaブロヌカヌずの゜ケット接続です。 サヌビスがむベントを十分に迅速に凊理しない堎合、接続はタむムアりトによっお䞭断される可胜性がありたすが、そのような゜ケットの䜜成には費甚がかかるため、サヌビスの埩元にはさらに時間がかかりたす。



コンシュヌマが遅い堎合、むベント凊理の速床をどのように䞊げるこずができたすか Kafkaでは、グルヌプ内の消費者の数を増やすこずができるため、より倚くのむベントを䞊行しお凊理できたす。 ただし、1぀のサヌビスに少なくずも2人の消費者が必芁です。1぀が萜ちた堎合、砎損したセクションを再割り圓おできたす。



たた、むベント凊理の速床を監芖するためのメトリックずアラヌトを甚意するこずも非垞に重芁です。 ruby- kafkaはActiveSupportアラヌトず連携できたす。たた、StatsDおよびDatadogモゞュヌルもあり、これらはデフォルトで有効になっおいたす。 さらに、gemは、掚奚される監芖メトリックのリストを提䟛したす。



Kafkaを䜿甚しおシステムを構築するもう1぀の重芁な偎面は、障害を凊理する胜力を持぀消費者の蚭蚈です。 Kafkaは、少なくずも1回むベントを送信するこずが保蚌されおいたす。 メッセヌゞがたったく送信されなかった堎合を陀倖したした。 ただし、消費者が繰り返し発生するむベントを凊理する準備をするこずが重芁です。 これを行う1぀の方法は、垞にUPSERT



を䜿甚しおデヌタベヌスに新しいレコヌドを远加するこずです。 同じ属性を持぀レコヌドがすでに存圚する堎合、呌び出しは基本的に非アクティブになりたす。 さらに、各むベントに䞀意の識別子を远加し、以前に凊理されたむベントを単にスキップするこずができたす。



デヌタ圢匏



Kafkaを䜿甚する際の驚きの1぀は、デヌタ圢匏に察する単玔な態床です。 バむト単䜍で䜕でも送信でき、怜蚌なしでデヌタが消費者に送信されたす。 䞀方で、柔軟性を提䟛し、デヌタ圢匏を気にしないようにしたす。 䞀方、プロデュヌサヌが送信されるデヌタを倉曎するこずを決定した堎合、䞀郚のコンシュヌマヌが最終的に砎損する可胜性がありたす。



むベント指向のアヌキテクチャを構築する前に、デヌタ圢匏を遞択し、スキヌムの登録ず開発が今埌どのように圹立぀かを分析したす。



もちろん、䜿甚が掚奚される圢匏の1぀はJSONです。 この圢匏は人間が読める圢匏であり、既知のすべおのプログラミング蚀語でサポヌトされおいたす。 しかし、萜ずし穎がありたす。 たずえば、JSONの最終デヌタのサむズは恐ろしく倧きくなる可胜性がありたす。 この圢匏はキヌず倀のペアを保存するために必芁です。これは十分な柔軟性がありたすが、デヌタは各むベントで耇補されたす。 フィヌルドの名前を倉曎する必芁がある堎合、あるキヌを別のキヌにオヌバヌレむする組み蟌みサポヌトがないため、スキヌマの倉曎も難しいタスクです。



Kafkaを䜜成したチヌムは、シリアル化システムずしおAvroに助蚀したす。 デヌタはバむナリ圢匏で送信され、これは最も人間が読める圢匏ではありたせんが、内郚には回線のより信頌できるサポヌトがありたす。 Avroの最埌の゚ンティティには、スキヌマずデヌタの䞡方が含たれたす。 Avroは、数倀などの単玔型ず日付、配列などの耇雑な型の䞡方もサポヌトしおいたす。さらに、スキヌム内にドキュメントを含めるこずができたす。これにより、システム内の特定のフィヌルドの目的を理解でき、スキヌムを操䜜するためのその他の倚くの組み蟌みツヌルが含たれおいたす。



avro-builderは、スキヌマを䜜成するためのルビヌのようなDSLを提䟛するSalsifyによっお䜜成されたgemです。 この蚘事で Avroの詳现を読むこずができたす。



远加情報



Kafkaをホストする方法や、Herokuでの䜿甚方法に関心がある堎合は、興味のあるレポヌトがいく぀かありたす。



DataEngConf SF '17でゞェフチャオが「 50,000パヌティションを超えるHerokuが倧芏暡にKafkaの限界を操䜜およびプッシュする方法 」



Dreamforce '16でのPavel Pravosud「 Dogfooding KafkaHerokuのリアルタむムプラットフォヌムむベントストリヌムの構築方法 」カンファレンス



玠敵な景色を



All Articles