8

私は認証メカニズムを備えたプロジェクトに取り組んでいます。認証メカニズムでは、以下の手順に従います。

  1. ユーザーはブラウザを開き、テキストボックスに自分の電子メールを入力して、ログインボタンをクリックします。
  2. リクエストはサーバーに送信されます。ランダムな文字列(たとえば、123456)を生成し、ユーザーのAndroid / iPhoneに通知を送信し、メソッドを使用して現在のスレッドを待機させますwait()
  3. ユーザーは自分の電話でパスワードを入力し、自分の電話の送信ボタンをクリックします。
  4. ユーザーが送信ボタンをクリックすると、Webサービスがサーバーにヒットし、以前に生成された文字列(たとえば、123456)とパスワードが渡されます。
  5. 以前に入力した電子メールに対してパスワードが正しい場合、notify()以前に待機していたスレッドにメソッドを呼び出し、応答として成功を送信し、ユーザーがシステムに入力されます。
  6. 以前に入力した電子メールに対してパスワードが正しくない場合、notify()以前に待機していたスレッドに対してメソッドを呼び出し、応答として失敗を送信し、ユーザーに無効な資格情報メッセージを表示します。

すべてが正常に機能していますが、最近、クラスター環境に移行しました。一部のスレッドは、ユーザーが返信した後でも、無制限の待機時間の間、通知されないことがわかりました。

サーバーにはTomcat5.5を使用しており、Tomcatクラスター環境を作成するためにApacheTomcat5.5サーブレット/JSPコンテナーを使用しています。

回答::考えられる問題と解決策

考えられる問題は、クラスター環境内の複数のJVMです。現在、クラスター化されたTomcat URLを、生成された文字列とともにユーザーのAndroidアプリケーションに送信しています。

また、ユーザーが返信ボタンをクリックすると、生成された文字列がクラスター化されたTomcat URLとともに送信されるため、この場合、両方のリクエストが同じJVMに送信され、正常に機能します。

しかし、私は上記の問題に対する単一の解決策があるかどうか疑問に思っています。

このソリューションには問題があります。クラスタ化されたTomcatがクラッシュした場合はどうなりますか? ロードバランサーは2番目のクラスター化されたTomcatに要求を送信し、同じ問題が発生します。

4

10 に答える 10

9

問題の根本的な理由は、Java EE が別の方法で動作するように設計されていることです。サービス スレッドをブロック/待機しようとすることは、重要な禁止事項の 1 つです。最初にその理由を説明し、その後で問題を解決する方法を説明します。

Java EE (Web 層と EJB 層の両方) は、非常に大きなサイズ (クラスター内の数百台のコンピューター) に拡張できるように設計されています。ただし、それを行うために、設計者は次の仮定を行う必要がありました。これは、コーディング方法に関する特定の制限です。

  • トランザクションは次のとおりです。

    1. 短命 (たとえば、ブロックしたり、1 秒以上待機したりしないでください)
    2. 互いに独立 (例: スレッド間の通信なし)
    3. コンテナーによって管理される EJB の場合
  • すべてのユーザー状態は、次のような特定のデータ ストレージ コンテナーに保持されます。

    1. JDBC などを介してアクセスされるデータ ストア。従来の SQL データベースまたは NoSQL バックエンドを使用できます
    2. EJB を使用する場合は、ステートフル セッション Bean。これらは、フィールドをデータベースに永続化する Java Bean と考えてください。ステートフル セッション Bean はコンテナーによって管理されます
    3. Web セッションこれはキーと値のストア (NoSQL データベースに似ていますが、スケーリング機能や検索機能はありません) であり、特定のユーザーのデータをセッション全体にわたって保持します。Java EE コンテナーによって管理され、次のプロパティがあります。

      1. ノードがクラスターでクラッシュした場合、自動的に再配置されます
      2. ユーザーは複数の現在の Web セッションを持つことができます (つまり、2 つの異なるブラウザーで)
      3. Web セッションは、ユーザーがログアウトしてセッションを終了するか、セッションが構成可能なタイムアウトより長く非アクティブである場合に終了します。
      4. 格納されるすべての値は、クラスター内のノード間で永続化または転送されるように、シリアル化可能である必要があります。

これらのルールに従えば、Java EE コンテナーは、ノードのシャットダウン、新しいノードの開始、ユーザー セッションの移行など、特定の開発者コードなしでクラスターを正常に管理できます。開発者は、グラフィカル インターフェイスとビジネス ロジックを記述します。すべての「配管」は、構成可能なコンテナ機能によって管理されます。

また、実行時に Java EE コンテナーを監視および管理することもできます。このソフトウェアは、稼働中のシステムでアプリケーションのパフォーマンスと動作の問題を追跡できます。

<スナーク>まあ、それが理論でした。実際には、AOSP やコード インジェクション手法につながる重要な制限が見逃されていることが示唆されていますが、それは別の話です < /snark >

[これについては、ネット上で多くの議論があります。EJB に焦点を当てたものは次のとおりです: Java EE コンテナーでのスレッドの生成はなぜ推奨されないのですか? Tomcat などの Web コンテナーについてもまったく同じことが言えます]

エッセイで申し訳ありませんが、これはあなたの問題にとって重要です。スレッドの制限により、別の後のリクエストを待機している Web リクエストをブロックしないでください。

現在の設計のもう 1 つの問題は、ユーザーがネットワークから切断された場合、電力が不足した場合、または単にあきらめることを決定した場合にどうなるかということです。おそらくタイムアウトしますが、どれくらい後ですか?おそらく、一部の顧客にとっては早すぎて、満足度の問題が発生する可能性があります。タイムアウトが長すぎると、Tomcat のすべてのワーカー スレッドがブロックされ、サーバーがフリーズする可能性があります。これにより、組織はサービス拒否攻撃を受けやすくなります。

編集:アルゴリズムのより詳細な説明が公開された後、改善された提案。

Web ワーカー スレッドをブロックすることの悪い習慣とサービス拒否の可能性に関する上記の説明にもかかわらず、Android フォンの通知に対応するための短い時間枠がユーザーに提示されることは明らかです。セキュリティを強化するために、適度に小さく保ってください。この時間枠は、応答に対する Tomcat のタイムアウトよりも低く抑えることもできます。そのため、スレッド ブロッキング アプローチを使用できます。

この問題を解決するには、次の 2 つの方法があります。

  1. ソリューションの焦点をクライアント エンドに変更する- ブラウザで Javascript を使用してサーバーをポーリングする
  2. クラスター内のノード間の通信により、Android アプリから承認応答を受信するノードが、サーブレットの応答をブロックしているノードのブロックを解除できるようになります。

アプローチ 1 の場合、ブラウザーは Javascript を介してサーバーをポーリングし、Tomcat 上の Web サービスへの AJAX 呼び出しを行います。TrueAndroid アプリが認証されると、AJAX 呼び出しが返されます。利点: クライアント側、サーバーでの最小限の実装、サーバーでのスレッドのブロックなし。短所: 待機中は、頻繁に呼び出しを行う必要があります (おそらく 1 秒に 1 回 - ユーザーはこの待ち時間に気付かないでしょう)。これにより、大量の呼び出しが発生し、サーバーに追加の負荷がかかります。

アプローチ 2 の場合も、選択肢があります。

  1. Object.wait()オプションでノード ID、IP、またはその他の識別子を共有データ ストアに保存してスレッドをブロックします。その場合、Android アプリの承認を受け取るノードは次のことを行う必要があります。

    1. 現在ブロックしているノードを見つけるか、クラスタ内のすべてのノードにブロードキャストします
    2. 上記の 1. のノードごとに、ブロックを解除するユーザー セッションを識別するメッセージを送信します。メッセージは次の方法で送信できます。

      1. 各ノードに内部専用のサーブレットを配置します。これは、Android アプリの承認を実行するサーブレットによって呼び出されます。内部サーブレットはObject.notify正しいスレッドで呼び出します
      2. JMS pub-sub メッセージ キューを使用して、クラスターのすべてのメンバーにブロードキャストします。各ノードはサブスクライバーであり、通知を受信するとObject.notify()正しいスレッドを呼び出します。
  2. スレッドの続行が承認されるまでデータ ストアをポーリングする: この場合、Android アプリが行う必要があるのは、状態を SQL DB に保存することだけです。

于 2012-12-27T09:16:54.670 に答える
1

The exact problem is because of the cluster environment. Both requests are not going to the same JVM. But we know that a normal/simple notify works on the same JVM when the previous thread is waiting.

You should try to execute both requests (first request, second request when the user replies from an Android application).

于 2012-12-23T13:17:38.427 に答える
1

申し訳ありませんが、スレッドは従来のJava EEクラスターに移行できません。

アーキテクチャを再考して、待機/通知を別の方法で実装する必要があります (コネクションレス)。

または、 terracotta.orgで試してみることもできます。これにより、JVMプロセス全体を複数のマシンにクラスター化できるようです。多分それはあなたの唯一の解決策です。

Introduction to OpenTerracottaの簡単な紹介を読んでください。

于 2012-12-28T01:12:37.530 に答える
1

クラスター内のインスタンスが状態を共有できるように、メモリー内グリッドの使用を検討してください。インスタンス間でデータを共有するためにHazelcastを使用したため、応答が別のインスタンスに到達した場合でも処理できます。

たとえば、値が 1 の分散カウントダウン ラッチを使用して、メッセージの送信後に待機するスレッドを設定できます。応答がクライアントから別のインスタンスに到着すると、応答が減少し、そのインスタンスはラッチを 0 に減少させて、最初のインスタンスを実行させることができます。スレッド。

于 2012-12-27T05:38:11.527 に答える
1

Web サービス環境で使用Thread.waitするのは大きな間違いです。代わりに、ユーザーとトークンのペアのデータベースを維持し、定期的に期限切れにします。

クラスタが必要な場合は、クラスタ化可能なデータベースを使用してください。memcached のようなものをお勧めします。これはメモリ内 (かつ高速) であり、オーバーヘッドが少ないためです (キーと値のペアは単純なので、RDBMS などは必要ありません)。memcached はすでにトークンの有効期限を処理しているため、完璧に適合するように思えます。

特に、同じ 2 要素認証の責任を共有する 2 つの異なるコンポーネントがあるため、ユーザー名 -> トークン -> パスワード戦略は不要だと思います。複雑さをさらに軽減し、ユーザーの混乱を減らし、SMS 送信料金をいくらか節約できると思います。

Web サービスとのやり取りは簡単です。

  1. ユーザーは、ユーザー名とパスワードを使用して Web サイトにログインします
  2. 一次認証 (ユーザー名/パスワード) が成功した場合は、トークンを生成し、userid=tokenを memcachedに挿入します。
  3. トークンをユーザーの電話に送信する
  4. 「トークンの入力」ページをユーザーに提示する
  5. ユーザーは電話でトークンを受け取り、それをフォームに入力します
  6. ユーザーの ID に基づいて memcached からトークン値を取得します。一致する場合は、memcached でトークンを期限切れにし、第 2 要素が成功したと見なします
  7. トークンは、memcached で設定したい時間が経過すると自動的に期限切れになります

上記のソリューションにはスレッド化の問題はなく、独自のソフトウェアをサポートするために必要な数の JVM に拡張できます。

于 2012-12-27T21:16:01.967 に答える
0

解決:

待機中のすべてのスレッドに対して単一の連絡先を作成します。したがって、クラスター化された環境では、すべてのスレッドが 3 番目の JVM (単一の連絡先) で待機するため、このようにして、すべての要求 (クラスター化されたTomcatのいずれか) が同じ JVM に接続して待機し、ロジックに通知するため、待機するスレッドはありません。無制限の時間。応答がある場合、同じオブジェクトが待機しており、2 回目に通知されているかどうかがスレッドに通知されます。

于 2012-12-23T13:29:06.570 に答える
0

問題は、最初のスレッドが JVM 1 のユーザーの Android アプリケーションに通知を送信し、ユーザーが返信すると、制御が JVM 2 に移動することだと思います。それが主な問題です。

どういうわけか、両方のスレッドが同じ JVM にアクセスして、待機ロジックと通知ロジックを適用できます。

于 2012-12-23T12:18:10.767 に答える