sql >> データベース >  >> NoSQL >> HBase

サンタンデールのほぼリアルタイムのデータ取り込みアーキテクチャの内部(パート2)

    SantanderUKが革新的なSpendlyticsアプリを強化するためのほぼリアルタイムのサービングエンジンとしてApacheHBaseをどのように使用しているかについて、この投稿に協力してくれたSantanderのエンジニアリングチームのPedroBoadoとAbelFernandezAlfonsoに感謝します。

    Spendlytics iOSアプリは、Santanderの個人的なデビットカードとクレジットカードの顧客が、Apple Payを介した支払いを含め、支出を上手く維持できるように設計されています。リアルタイムのトランザクションデータを使用して、顧客が期間全体(毎週、毎月、毎年)、カテゴリ(旅行、スーパーマーケット、現金など)、および小売業者ごとにカードの支出を分析できるようにします。

    前回の投稿では、ApacheFlumeとApacheKafkaを使用して、トランザクションをApache HBaseに変換、強化、ストリーミングする方法について説明しました。この投稿では、パフォーマンスを最適化するためにApache HBaseでトランザクションをどのように配置するか、およびコプロセッサーを使用して購入傾向の顧客ごとの集計を提供する方法について説明します。 SantanderとClouderaは、Spendlyticsを使用してHBaseの旅を続けました。これは、スキーマ設計とコプロセッサーの実装の多くの反復と最適化を経験したものです。これらの教訓が、この投稿からの重要なポイントになることを願っています。

    スキーマ1.0

    優れたHBaseスキーマ設計とは、意図されたアクセスパターンを理解することです。正しく理解すれば、HBaseが飛ぶでしょう。誤解すると、リージョンのホットスポットなどの設計上のトレードオフや、複数のリージョンにわたって大規模なスキャンを実行する必要があるため、パフォーマンスが最適化されなくなる可能性があります。 (ホットスポット HBaseテーブルでは、行キーの分散が不均一であると、リクエストの大部分が単一のリージョンにルーティングされ、RegionServerが圧倒され、応答時間が遅くなる可能性があります。)

    Spendlyticsが意図したアクセスパターンと、それが初期のスキーマ設計にどのように影響したかについて私たちが知っていたこと:

    • 顧客は自分のアカウントのトランザクションのみを分析します:
      • 高速の線形スキャンパフォーマンスを実現するには、すべての顧客トランザクションを順番に保存する必要があります。
    • 顧客IDは単調に増加しています:
      • シーケンシャルな顧客IDは、新しい顧客が同じ地域内に同じ場所に配置される可能性を高め、地域のホットスポットを作成する可能性があります。この問題を回避するには、ローキーの先頭で使用する場合、顧客IDをソルト化(プレフィックス)するか、リージョン間で均等に分散するように逆にする必要があります。
    • 顧客は複数のカードを持っています
      • スキャンを最適化するには、顧客のトランザクションをカード契約ごとにさらにグループ化して並べ替える必要があります。つまり、契約IDが行キーの一部を形成する必要があります。
    • トランザクション全体にアクセスします。つまり、小売業者、販売者、場所、通貨、金額などの属性を個別に読み取る必要はありません
      • トランザクション属性を別々のセルに保存すると、テーブルが広くなり、シーク時間が長くなります。属性は一緒にアクセスされるため、ApacheAvroレコードでそれらを一緒にシリアル化することは理にかなっています。 Avroはコンパクトで、スキーマの進化性を備えた効率的な表現を提供します。
    • トランザクションには、個別に、バッチで(時間、カテゴリ、および小売業者ごとに)、および集計ごとに(時間、カテゴリ、および小売業者ごとに)アクセスされます。
      • 列修飾子として一意のトランザクションIDを追加すると、行キーを複雑にすることなく、個々のトランザクションを取得できます。
      • 可変期間にわたるトランザクションの高速スキャンを有効にするには、トランザクションのタイムスタンプが行キーの一部を形成する必要があります。
      • 行キーにカテゴリと小売業者を追加すると、きめ細かくなりすぎて、複雑な行キーを持つ非常に高くて狭いテーブルになる可能性があります。アトミック性が問題にならないことを考えると、背が高くて狭いことは問題ありませんが、列修飾子としてそれらを使用すると、二次集計をサポートしながらテーブルを広げることができます。
    • 読み取りパフォーマンスを最適化するために、トレンドデータは可能な限り事前に計算する必要があります。
      • これについては後で詳しく説明しますが、今のところ、トレンドを保存するために2番目の列ファミリーを追加したことを知っています。

      上記に基づいて、初期のスキーマ設計は次のように示されます。

      コンピューティングトレンド

      私たちが最も学んだ初期設計の側面は、コンピューティングの傾向でした。要件は、顧客がカテゴリおよび小売業者ごとに1時間までの支出を分析できるようにすることでした。データポイントには、最小および最大のトランザクション値、合計トランザクション値、およびトランザクション数が含まれていました。応答時間は200ミリ秒以下である必要がありました。

      トレンドを事前に計算すると応答時間が最も速くなるため、これが最初のアプローチでした。トレンドはトランザクションに遅れをとることができなかったため、書き込みパスで計算する必要がありました。これは読み取りパフォーマンスには最適ですが、いくつかの課題がありました。HBaseでトレンドを整理する最善の方法と、書き込みパフォーマンスに深刻な影響を与えることなくトレンドを迅速かつ確実に計算する方法です。

      さまざまなスキーマ設計を試し、可能な場合はいくつかのよく知られた設計(OpenTSDBのスキーマなど)を活用しようとしました。数回繰り返した後、上記のスキーマ設計に落ち着きました。トランザクションテーブルの別の列ファミリーに格納されているトレンド値は、顧客ごとに1つのトレンド行を含む単一の行にまとめられています。行キーに顧客のトランザクションと同じプレフィックスを付けることによって(たとえば、<reverse_customer_id>::<contract_id> )トレンド行が対応する顧客のトランザクションレコードと一緒に並べ替えられるようにしました。定義されたリージョン境界とカスタムリージョン分割ポリシーを設定すると、トレンド行が常に顧客のトランザクションレコードと同じ場所に配置され、トレンド集約がコプロセッサーで完全にサーバー側にとどまることが可能になります。

      傾向を事前に計算するために、カスタムのオブザーバーコプロセッサーを実装しました。 書き込みパスにフックします。 (オブザーバーコプロセッサーは、特定のイベントが発生する前または後にユーザーコードを実行するという点で、RDBMSのトリガーに似ています。たとえば、Putの前または後に またはGet 。)

      postPutについて コプロセッサーは以下のアクションを実行します:

      1. Putをチェックします トレンド属性(フラグ)の場合。この属性は、トレンドレコードを更新するときに再帰的な呼び出しを回避するためにのみ、新しいトランザクションレコードに設定されます。また、Putでコプロセッサーをスキップすることもできます。 トレンドを更新する必要がないもの(例:決済
      2. 顧客のトレンドレコードを取得します。顧客のトレンドレコードは、(行キープレフィックスに基づいて)トランザクションと同じ場所に配置されるため、コプロセッサーは現在のリージョンから直接取得できます。複数のRegionServerハンドラースレッドがトレンドを並行して更新しようとするのを防ぐために、トレンド行をロックする必要があります。
      3. データポイントを更新します:
      4. トレンド行を更新してロックを解除します。

      このソリューションはテスト中に正確であることが証明され、予想どおり、読み取りパフォーマンスは要件を上回りました。ただし、このアプローチにはいくつかの懸念がありました。 1つ目は、障害の処理方法でした。傾向は別の行に格納されるため、原子性は保証されません。 2つ目は、時間の経過に伴う傾向の正確さを検証する方法でした。つまり、トレンドの不正確さを特定して修正するメカニズムを実装する必要があります。 HA要件と、異なるデータセンターでHBaseの2つのアクティブ-アクティブインスタンスを実行する必要があるという事実も考慮すると、これはより大きな問題になる可能性があります。トレンドの精度は時間の経過とともに低下する可能性があるだけでなく、2つのクラスターもドリフトする可能性があり、それらを同期するために使用した方法によっては調整する必要があります。最後に、バグの修正や新しいデータポイントの追加は、すべての傾向をさかのぼって再計算する必要がある可能性があるため、困難です。

      その後、書き込みパフォーマンスがありました。新しいトランザクションごとに、オブザーバーはトレンドレコードをフェッチし、32個のデータポイントを更新し、トレンドレコードを元に戻す必要がありました。これらすべてが単一のリージョンの範囲内で発生しているにもかかわらず、スループットが1秒あたり20,000回を超える書き込みから1秒あたり1,000回の書き込み(RegionServerあたり)に低下することがわかりました。このパフォーマンスは短期的には許容範囲内でしたが、予測される長期的な負荷をサポートするように拡張することはできませんでした。

      書き込みパフォーマンスがリスクであることがわかっていたため、バックアップ計画を立てました。これはエンドポイントコプロセッサーでした。 。エンドポイントコプロセッサーは、クライアントではなく、データが配置されているRegionServerでサーバー側の計算を実行できるという点で、RDBMSのストアドプロシージャに似ています。エンドポイントはHBaseAPIを効果的に拡張します。

      エンドポイントは、トレンドを事前に計算する代わりに、サーバー側でその場でトレンドを計算します。その結果、トレンド列ファミリーをスキーマから削除することができ、不正確さと相違のリスクがそれに伴いました。オブザーバーから離れると、書き込みパフォーマンスは向上しましたが、読み取りは十分に高速でしょうか?要するに、はい。顧客のトランザクションが単一の地域に限定され、カードとタイムスタンプで並べ替えられているため、エンドポイントは、Spendlyticsの200ミリ秒の目標の範囲内で、すばやくスキャンして集約できます。これは、クライアントリクエスト(この場合はSpendlytics APIから)が単一のエンドポイントインスタンス(単一のRegionServer)にのみルーティングされ、クライアントが単一の応答を返し、完全な結果を返すことを意味します。つまり、クライアント側はありません。複数のエンドポイントからの部分的な結果を集約するには、処理が必要です。これは、顧客のトランザクションが複数のリージョンにまたがっている場合に当てはまります。

      学んだ教訓

      Spendlyticsは2015年7月から稼働しています。それ以来、アクセスパターンを綿密に監視し、パフォーマンスを最適化する方法を検討してきました。私たちは、ユーザーエクスペリエンスを継続的に改善し、カードの支出についてより多くの洞察を顧客に提供したいと考えています。この投稿の残りの部分では、Spendlyticsを本番環境で実行することから学んだ教訓と、実施された最適化のいくつかについて説明します。

      最初のリリース後、改善に焦点を当てたいいくつかの問題点を特定しました。 1つ目は、トランザクション属性で結果をフィルタリングする方法でした。前述のように、トランザクション属性はAvroレコードにエンコードされますが、属性でフィルタリングする必要のあるアクセスパターンが増えており、ユーザーはこのクライアント側での実行を余儀なくされていることがわかりました。最初の解決策は、カスタムHBase ValueFilterを実装することでした。 独自の複雑なフィルター式を受け入れました。例:

      category='SUPERMARKETS' AND amount > 100 AND 
      (brand LIKE 'foo%' OR brand = 'bar')

      式はAvroレコードごとに評価されるため、サーバー側で結果をフィルタリングし、クライアントに返されるデータの量を減らすことができます(ネットワーク帯域幅とクライアント側の処理を節約できます)。フィルタはスキャンパフォーマンスに影響を与えますが、応答時間は200ミリ秒の目標内に十分収まりました。

      書き込みを最適化するためにさらに変更が必要だったため、これは一時的な解決策になりました。クレジットカード決済プロセスの仕組みにより、最初に承認済みを受け取ります 販売時から(ほぼリアルタイムで)取引を行い、しばらくしてから決済済み クレジットカードネットワークからのトランザクション(バッチ)。これらのトランザクションは、基本的に決済済みをマージすることにより、調整する必要があります。 承認済みとの取引 トランザクションはすでにHBaseにあり、トランザクションIDで参加しています。このプロセスの一環として、トランザクション属性を変更したり、新しい属性を追加したりできます。これは、単一の属性を更新する場合でも、Avroレコード全体を書き直さなければならないというオーバーヘッドのために苦痛であることが判明しました。そのため、更新のために属性にアクセスしやすくするために、Avroシリアル化を置き換えて、属性を列に編成しました。

      また、トランザクションレベルのアトミック性のみを考慮しているため、トランザクションを時間単位でバケット化してもメリットはありません。さらに、解決済み 現在バッチで到着するトランザクションは、日レベルの粒度しかないため、既存の承認済みとの調整が困難(コストがかかる)になりました。 時間単位で保存されたトランザクション。この問題を解決するために、トランザクションIDを行キーに移動し、タイムスタンプの粒度を時間ではなく日数に減らしました。変更をHBaseに一括ロードして、決済できるようになったため、調整プロセスがはるかに簡単になりました。 値が優先されます。

      要約:

      • オブザーバーコプロセッサーは価値のあるツールですが、賢明に使用してください。
      • 一部のユースケースでは、エンドポイントを使用してHBaseAPIを拡張することをお勧めします。
      • カスタムフィルターを使用して、サーバー側で結果をトリミングすることでパフォーマンスを向上させます。
      • シリアル化された値は適切なユースケースには意味がありますが、フィールドと列のネイティブサポートを優先することでHBaseの長所を発揮します。
      • 事前に計算された結果を管理することは困難です。オンザフライでのコンピューティングによる追加のレイテンシは価値があります。
      • アクセスパターンは変更されるため、アジャイルでオープンにHBaseスキーマに変更を加えて、ゲームに適応し、先を行くようにしてください。

      ロードマップ

      現在評価している最適化は、ハイブリッドコプロセッサーです。これが意味するのは、傾向を事前計算するためのオブザーバーとエンドポイントの両方のコプロセッサーの組み合わせです。ただし、以前とは異なり、これは書き込みパスではなく、バックグラウンドでHBaseのフラッシュおよび圧縮操作にフックすることで実行します。オブザーバーは、 settled に基づいて、フラッシュおよび圧縮イベント中の傾向を計算します。 その時点で利用可能なトランザクション。次に、エンドポイントを使用して、事前に計算された傾向をトランザクションのデルタのオンザフライ集計と組み合わせます。このようにトレンドを事前計算することで、書き込みパフォーマンスに影響を与えることなく、読み取りのパフォーマンスを向上させたいと考えています。

      トレンドアグリゲーションおよび一般的なHBaseアクセスについて評価しているもう1つのアプローチは、ApachePhoenixです。 PhoenixはHBa​​seのSQLスキンであり、標準のJDBCAPIを使用したアクセスを可能にします。 SQLとJDBCを使用することで、HBaseアクセスが簡素化され、作成する必要のあるコードの量が削減されることを願っています。また、Phoenixのインテリジェントな実行パターンと組み込みのコプロセッサーおよびフィルターを活用して、高速な集計を行うこともできます。フェニックスは、Spendlyticsの当初は本番環境での使用には未熟であると考えられていましたが、eBayやSalesforceなどから同様のユースケースが報告されているため、今が再評価の時期です。 (CDH用のPhoenixパッケージは、インストールと評価に利用できますが、Cloudera Labsを介してサポートされていません。)

      サンタンデールは最近、顧客がSmartBankアプリに話しかけ、カードの支出について質問できるようにするボイスバンキングテクノロジーを立ち上げた最初の銀行であると発表しました。このテクノロジーの背後にあるプラットフォームはClouderaであり、Spendlyticsのアーキテクチャは、この一連の投稿で説明されているように、青写真の設計として機能しました。

      James Kinleyは、Clouderaのプリンシパルソリューションアーキテクトです。

      Ian Bussは、Clouderaのシニアソリューションアーキテクトです。

      Pedro Boadoは、英国サンタンデール(Isban)のHadoopエンジニアです。

      アベルフェルナンデスアルフォンソ は、英国サンタンデール(Isban)のHadoopエンジニアです。


    1. ClusterControlを使用したMongoDB4.0の監視と運用管理

    2. 次のストップ–エッジからインサイトへのデータパイプラインの構築

    3. 原因:java.lang.IllegalArgumentException:CONTAINING(1):[IsContaining、Containing、Contains]はredisクエリの派生ではサポートされていません-Redis

    4. MongoDBデータベースに画像を保存する