7

現在、会社で実行されているWindowsサービスをスケールアウトする方法についての情報を探しています。.NET 4.0を使用しており(将来的には4.5にアップグレードできます)、これをWindowsServer2012で実行しています。

サービスについて
サービスの仕事は、ログテーブル(Oracleデータベースを使用)の新しい行のクエリ、情報の処理、他の5つのテーブル(トラッキングテーブルと呼びましょう)の一連の行の作成および/または更新です。 )、ログテーブルを更新して繰り返します。

ロギングテーブルには大量のXMLがあり(1行あたり最大20 MBになる可能性があります)、他の5つのトラッキングテーブルで選択して保存する必要があります。新しい行は、1時間あたり最大500,000行の割合で常に追加されます。
トラッキングテーブルのトラフィックははるかに高く、最小のテーブルの90,000の新しい行から、最大のテーブルの潜在的に数百万の行まで、1時間ごとに発生します。これらのテーブルにも更新操作があることは言うまでもありません。

処理中のデータについて、
これらのオブジェクトがどのようにグループ化および処理されているかに基づいて解決策を見つけるには、このビットが重要だと思います。データ構造は次のようになります。

public class Report
{
    public long Id { get; set; }
    public DateTime CreateTime { get; set; }
    public Guid MessageId { get; set; }
    public string XmlData { get; set; }
}

public class Message
{
    public Guid Id { get; set; }
}
  • レポートは、選択して処理する必要のあるログデータです
  • メッセージごとに、平均5つのレポートがあります。これは、場合によっては1から数百の間で変化する可能性があります。
  • メッセージには他のコレクションや他の関係がたくさんありますが、それらは質問とは無関係です。

現在、16コアサーバーの負荷をほとんど管理していないWindowsサービス(完全な仕様は覚えていませんが、このマシンは獣だと言っても過言ではありません)。私は、このすべてのデータを処理し、他のインスタンスに干渉しないマシンをスケールアウトして追加する方法を見つけるという任務を負っています。

現在、各メッセージは独自のスレッドを取得し、関連するレポートを処理します。データを処理するときにDBクエリの数を最小限に抑えるために、MessageIdでグループ化されたレポートをバッチで処理します。

制限事項

  • この段階で、適切と思われるアーキテクチャを使用して、このサービスを最初から書き直すことができます。
  • インスタンスがクラッシュした場合、他のインスタンスは、クラッシュしたインスタンスが残った場所をピックアップできる必要があります。データが失われることはありません。
  • この処理は、データベースに挿入されるレポートから可能な限りリアルタイムに近い必要があります。

そのようなプロジェクトを構築する方法についての意見やアドバイスを探しています。サービスはステートレスである必要があると思いますか、それともすべてのインスタンスのキャッシュを何らかの方法で同期する方法はありますか?すべてのインスタンス間で調整し、それらが同じデータを処理していないことを確認するにはどうすればよいですか?どうすればそれらの間で負荷を均等に分散できますか?そしてもちろん、インスタンスがクラッシュして完了しないのを処理するにはどうすればよいですか?

編集
無関係な情報を削除しました

4

2 に答える 2

6

作業項目の場合、Windowsワークフローはおそらくサービスをリファクタリングするための最も迅速な手段です。

Windows Workflow Foundation @ MSDN

WFから得られる最も便利なことは、ワークフローの永続性です。ワークフローが最後に保存された時点からワークフローに何かが起こった場合に、適切に設計されたワークフローが永続化ポイントから再開される可能性があります。

ワークフローの永続性@MSDN

これには、ワークフローの処理中に他のプロセスがクラッシュした場合に、ワークフローを別のプロセスから回復する機能が含まれます。共有ワークフローストアを使用する場合、再開プロセスは同じマシン上にある必要はありません。すべての回復可能なワークフローでは、ワークフローストアを使用する必要があることに注意してください。

仕事の分配については、いくつかのオプションがあります。

  1. WorkflowServiceクラスを介したWCFエンドポイントを使用したワークフロー呼び出しを介して、ホストベースの負荷分散と組み合わせてメッセージを生成するサービス。Receive手動でセットアップして対応するSendReplyハンドラー(これらはWCFメソッドにマップされます)ではなく、ここでデザインモードエディターを使用してエントリメソッドを作成することをお勧めします。メッセージごとにサービスを呼び出す可能性があり、レポートごとにサービスを呼び出す可能性もあります。ここではCanCreateInstanceプロパティが重要であることに注意してください。それに関連付けられたすべての呼び出しは、独立して実行される実行中のインスタンスを作成します。
    〜WorkflowService
    クラス(System.ServiceModel.Activities)@ MSDN
    受信クラス(System.ServiceModel.Activities)@ MSDN
    Receive.CanCreateInstanceプロパティ(System.ServiceModel.Activities)@ MSDN
    SendReplyクラス(System.ServiceModel.Activities)@ MSDN

  2. キューをサポートするサービスバスを使用します。少なくとも、任意の数のクライアントからの入力を受け入れる可能性があり、その出力を一意に識別して1回だけ処理できるものが必要です。頭に浮かぶのは、NServiceBus、MSMQ、RabbitMQ、およびZeroMQです。ここに記載されている項目のうち、NServiceBusは.NETにすぐに対応しています。クラウドのコンテキストでは、オプションには、AzureServiceBusやAmazonSQSなどのプラットフォーム固有のオファリングも含まれます。
    〜NServiceBus MSMQ @ MSDN RabbitMQZeroMQAzureサービスバス
    @MSDNAmazon SQS @ Amazon AWS〜






    サービスバスは、メッセージを開始するプロデューサーと、キューから読み取るために任意の数のマシンに存在できるコンシューマーの間の単なる接着剤であることに注意してください。同様に、この間接参照をレポート生成に使用できます。コンシューマーは、ワークフローの永続性を使用できるワークフローインスタンスを作成します。

  3. Windows AppFabricを使用してワークフローをホストできるため、IIS負荷分散に適用される多くの手法を使用して作業を分散できます。私は個人的にそれを使った経験がないので、それがすぐに使える優れた監視サポートを持っていることを除いて、私がそれについて言うことができることはあまりありません。

    方法:Windows App Fabric@MSDNでワークフローサービスをホストする
于 2013-02-04T21:55:22.963 に答える
2

このスケーラビリティと冗長性をすべて自分でコーディングすることで、これを解決しました。誰かがこれを必要とした場合に備えて、私が何をしたか、どのようにしたかを説明します。

他のインスタンスを追跡し、特定のインスタンスが処理できるレコードを知るために、各インスタンスにいくつかのプロセスを作成しました。起動時に、インスタンスはデータベースの(まだ登録されていない場合)というテーブルに登録されますInstances。このテーブルには次の列があります。

Id                 Number
MachineName        Varchar2
LastActive         Timestamp
IsMaster           Number(1)

インスタンスが見つからなかった場合にこのテーブルに行を登録して作成した後、MachineNameインスタンスは別のスレッドでこのテーブルに毎秒pingを開始し、そのLastActive列を更新します。次に、このテーブルからすべての行を選択し、Master Instance(後で詳しく説明します)がまだ生きていることを確認します。つまり、LastActive時間は最後の10秒です。マスターインスタンスが応答を停止した場合、マスターインスタンスは制御を引き継ぎ、自分自身をマスターとして設定します。次の反復では、マスターが1つだけであることを確認し(別のインスタンスが同時に制御を引き継ぐことを決定した場合)、そうでない場合は、が最も低いインスタンスに譲りますId

マスターインスタンスとは何ですか?
このサービスの仕事は、ロギングテーブルをスキャンしてそのデータを処理し、人々が簡単にフィルタリングして読み取ることができるようにすることです。私は私の質問でこれを述べませんでした、しかしそれはここで関連があるかもしれません。リクエストごとにロギングテーブルに複数のレコードを書き込むESBサーバーがたくさんあります。私のサービスの仕事は、ほぼリアルタイムでそれらを追跡することです。彼らは非同期でログを書き込んでいるので、ログにfinished processing request Abeforestarted processing request Aエントリを取得する可能性があります。したがって、これらのレコードを並べ替えて、サービスがデータを正しい順序で処理することを確認するコードがあります。このサービスをスケールアウトする必要があったため、このロジックを実行できるのは1つのインスタンスだけで、多くの不要なDBクエリや場合によっては非常識なバグを回避できます。
これは、Master Instanceこのソートロジックを実行し、ログレコードIDをと呼ばれる別のテーブルに一時的に保存するだけReportAssignmentです。このテーブルの仕事は、どのレコードが誰によって処理されたかを追跡することです。処理が完了すると、レコードは削除されます。テーブルは次のようになります。

RecordId        Number
InstanceId      Number    Nullable

マスターインスタンスはログエントリを並べ替え、IDをここに挿入します。すべてのサービスインスタンスは、このテーブルを1秒間隔でチェックして、誰も処理していない、または非アクティブなインスタンスによって処理されている新しいレコードと、[record's Id] % [number of isnstances] == [index of current instance in a sorted array of all the active instances](Pingingプロセス中に取得された)新しいレコードを確認します。クエリは次のようになります。

SELECT * FROM ReportAssignment 
WHERE (InstanceId IS NULL OR InstanceId NOT IN (1, 2, 3))   // 1,2,3 are the active instances
AND RecordId % 3 == 0    // 0 is the index of the current instance in the list of active instances

なぜこれを行う必要があるのですか?

  • RecordId % 3 == 1他の2つのインスタンスは、とをクエリしますRecordId % 3 == 2
  • RecordId % [instanceCount] == [indexOfCurrentInstance]レコードがすべてのインスタンスに均等に分散されるようにします。
  • InstanceId NOT IN (1,2,3)クラッシュしたインスタンスによって処理されていたレコードをインスタンスが引き継ぐことを許可し、新しいインスタンスが追加されたときにすでにアクティブなインスタンスのレコードを処理しないようにします。

インスタンスがこれらのレコードをクエリすると、更新コマンドを実行し、InstanceIdを独自に設定して、ログテーブルでこれらのIDを持つレコードをクエリします。処理が完了すると、からレコードが削除されReportAssignmentます。

全体的に、私はこれに非常に満足しています。うまくスケーリングし、インスタンスがダウンしてもデータが失われないようにし、既存のコードにほとんど変更がないことを保証します。

于 2013-03-11T18:16:07.237 に答える