2017-01-06 3 views
1

私たちはいくつかのマイクロサービスで構成されたWebアプリケーションを実行しており、リクエストごとに最終的にサードパーティサービス時間がかかり、通常は数秒かかる。 リクエストtraceIdを使用して、各リクエストのすべてのサービス間ですべての処理ログをトレースする必要があります。NIOやNettyのようなイベントドリブンフレームワークを使用する場合のリクエストプロセスのトレース方法

現在の実装では、スレッドベースの同時実行モデルを使用しています。スレッドは、各サービスで最初から最後まで要求を処理するように割り当てられ、リモートサービスの応答を待つときにブロックされます。 traceIdThreadLocalに入れて、いつでもどこでも必要なときにいつでも戻すことができます。

しかし、スレッドベースの並行性モデルは拡張性がよくないため、NIO /イベント駆動型モデルに変更する傾向があり、パフォーマンスが非常に向上してNettyを試用しました。しかし、リクエスト処理ごとに異なる段階がNettyの異なるスレッドによって処理され、ログのトレースが非常に難しくなる可能性があります。

我々の現在の考慮事項は、次のとおりです

  • パスTRACEIDメソッドのパラメータとして、それはとにかく、要求にすでにだが、深いネストされた方法は、それを必要とする場合、それは非常に非便利です。
  • セットtraceIdスレッドローカルすべてのコールバックの冒頭に。しかし、個人的に私はこのアプローチがエラーを起こしやすく、競合状態のバグが見つからない可能性があると考えています。

NIO /イベント駆動モデルでこのようなトレースの問題を解決するには、洗練された方法がありますか。

+0

スレッドの代わりにチャンネルIDを使用できますか? – Nicholas

答えて

1

これは、非同期の世界に適応しようとしているすべてのJava EEフレームワークのアキレス腱で、何十年にもわたってThreadLocalsに状態を格納しています。

基本的には、渡したい状態をチャンネルに結びつけたり、処理していることを要求して、次に取得するコードがあればそれを利用できるようにする必要があります。それを解決するために

二つの方法:

  1. Channel.attr() - 状態は静的AttributeKeyとパスを作成し、その後、一度に一つのことに使用されるコネクションに接続することができた場合Channel.attr() - 最初はnullのAttributeを取得します。最初のハンドラで何かに割り当てます。それ以降のすべてがそこから取り出せます(あなたが知っているときにクリアしてくださいHTTPキープアライブ接続のように、その接続が閉じられずに再利用される場合には完了です)。
  2. これをデコードするオブジェクトにアタッチします.HTTPリクエストのデコーダをサブクラス化し(HTTPが実行している場合)、IDを持つ独自のサブクラスを作成します。

我々の業界は、コンピュータが実際に何をしているかとは関係のない方法でプログラムモデルI/Oを行うことに10年か20年回り道をしたので、このようなもののためにThreadLocalsを使用するだけで自然に感じ - それは多くを売却しても(asyncは私が1983年頃に書いた割り込みハンドラのようなものです):

+0

ありがとう@Tim Boudreau、最後に、traceIdをリクエスト/応答オブジェクトに結びつけるために2番目の方法を使用しました。私たちのユースケースのすべてに合って、私たちのアプリケーションのいくつかはJava 8のCompletableFutureフレームワークによって実装されています。だから私は関連オブジェクトを持つタイトレースIDはこの問題を解決する最も自然な方法だと思います。 – shizhz

2

2セント:NIO /イベントドリブンモデルを使用している場合は、呼び出し元から呼び出し元に「要求ID」を渡してから、呼び出し元に戻す必要があります(async/even-driven方法)。これはスレッドやチャンネルIDとは関係ありません(1つのチャンネルは何度も何度も "connect"を支払わないように、さまざまなクエリで再利用できます)。

呼び出し元側では、コンテキストを復元して実行する必要があるように、マップなどを使用できます(永続化ツールを使用してマテリアライズされたものさえも)。

+0

ありがとう@Fredericので、複数のネストされたメソッドの中で「要求ID」が必要な場合は、そのメソッドにすべて渡すか、呼び出し先のコンテキストを準備しますか? – shizhz

+0

私はあなたがおそらくidを渡す必要があると考えています(コンテキストを取得するためにはコンテキストや外部の永続性、paramのidなど)。どんな深さであれ、誰でも、呼び出し元/呼び出し先は、どのクエリ/アクション/コンテキストが参加しているのか知るでしょう。 –

関連する問題