IoTマスデバイスのハートビート登録、オフラインクリア、マルチスレッドの高度な同時mutexロックランディング

 

1.アプリケーションの背景

モノのインターネットアプリケーションシナリオでは、デバイスによって収集された情報を取得し、デバイスのデジタルスイッチまたはアナログを逆に制御するために、TCPソケット通信に基づく長い接続など、多くのデバイスの接続を維持する必要があります。これらの長いTCP接続を、IPアドレスをキー、デバイスボックスドメインモデルを値として、スレッドセーフティに基づいてConcurrentDictionaryアクティベーションディクショナリテーブルに入れます。アクティブ化されたデバイスボックスのディクショナリテーブルを維持する必要があり、タイムアウトになったときにハートビートのないデバイスを呼び出す必要があります。これをオフラインデバイスと呼び、アクティブ化されたディクショナリテーブルをクリーンアップして、オフラインディクショナリテーブルに書き込むことができます。次回ネットワーク外のデバイスにハートビートがある場合、デバイスを再度アクティベーションディクショナリテーブルに移動して、回復アラームを生成し、他の一連のアクションを実行できます。

2.全体的なフレームワーク

2.1。ハートビート登録フレームワーク

2.1.1。大規模な機器

大規模デバイスのTCPシナリオをシミュレートするため、シミュレータを使用して12,000のシミュレートされたデバイスを生成しました。8つの実デバイス。

2.1.2。ハートビートを報告するためのハンドラープロセス

詳細なハートビートレポートプロセスの詳細は、上のフレームダイアグラムにあります。

突然、一連のモノのインターネットコレクションシステムを作成し、ディレクトリを整理できることがわかりました。頑張りたいです。

2.2。オフラインクリーニングフレームワーク

2.2.1。辞書テーブルをアクティブにしてオフライン機器を掃除する

原理は非常にシンプルで、ディクショナリテーブルに設定された検出期間を反復処理し、ディクショナリのIEnumerableにフィルターをかけ、アクティブ化されたディクショナリテーブルの対応するタイムアウトキー(この場合はIPアドレス)を削除します。もちろん、ここでの_internalサイクルは* Nにすることができます。構成ファイルで複数のサイクルを設定できます。構成ファイルは次のとおりです。

 "ipboxNumStaticInternal": 12
    public static void DeleteDeadBoxFromActiveBox(in _internal) { { var outTime = DateTime.Now.AddSeconds(-_internal); var iboxTimeOutList = iboxActiveDictionary.Where(q => (outTime > q.Value.UpdateTime));//.Select(x=> iboxActiveDictionary[x.Key]) ; foreach (var item in iboxTimeOutList) { iboxActiveDictionary.Remove(item.Key); } } } 

2.2.2。オフラインクリーニングのフローチャート

ここでは、主にシステムタイマーが開始され、ネットワーク外のデバイスをクリーニングするメソッドがアクティブに呼び出され、呼び出し間隔はipboxNumStaticInternalです。コードは次のとおりです。

    public void systemTimerStart() { var interval = ReadTheInternalFromSetting(); _systemTimer = new Timer(state => { IBoxActiveDicManager.DeleteDeadBoxFromActiveBo(_internal); Console.WriteLine("{1},激活设备数量:{0}\n",IBoxActiveDicManager.iboxActiveDictionary.Count,DateTime.Now); }, null, interval, interval); Console.WriteLine("PemsCom采集系统时钟已经开启"); LoggerHelper.Info("PemsCom采集系统时钟已经开启"); } /// <summary> /// 配置文件读入时间间隔方法 /// </summary> /// <returns></returns> private int ReadTheInternalFromSetting() { _internal = int.Parse(Appsettings.app(new string[] {"ipboxNumStaticInternal" })); Console.WriteLine("PemsCom采集系统时钟配置参数已经读"); LoggerHelper.Info("PemsCom采集系统时钟配置参数已经读"); return Convert.ToInt32(TimeSpan.FromSecond(_internal).TotalMilliseconds); } 

3.マルチスレッドおよび高並行性命令

3.1。マルチスレッド命令

次のように、CPUがラウンドで実行するスレッドは多数あります。

  • 12008受信イベントはスレッドをトリガーします。
  • オフラインのデバイススレッドを定期的にクリアします。
  • メインスレッド、コマンドライン入力の監視、対応するコマンドの実行。

実用的な例を示すために、写真を証明として撮ります

12008デバイスの場合、1秒あたりの受信ネットワークパケットのピークツーピーク値は9218パケットです。つまり、特定の1秒で、CPUは合計で9218スレッドを実行しました。たとえば、デュアルコア4スレッドの場合、9218/4 = 2304.5です。つまり、CPUは1秒間に2305ラウンドを実行します。つまり、0.43ミリ秒が1回実行されます。

3.2。高並行性の説明

実際、3.1は高い並行性を説明しています。一定の時間内に、処理される受信イベントが約10,000あります。この時点での実行順序は順不同であり、9218には非常に多くのスレッドがあるため、どちらを最初に実行し、どれを後で実行するかはわかりません。今日紹介するミューテックスロックなどのロジック制御を追加することを考えないと、異常な現象が発生します。

4.高いマルチスレッド同時実行によって引き起こされる異常な現象

ここでは現象のみを説明し、その理由を以下に説明します。5.異常の原因を分析する。

4.1。ヌル参照

例外の場所:ハートビート処理クラスは次のとおりです。

    public class HeartHandler
    {
        static string _deviceIndex = Appsettings.app(new string[] { "DeviceIndex" }); private static IBoxActive iboxActive; public static void Register(TcpHeartPacket heartPacket,int sessId) { UInt32 IP; UInt64 mac; if (_deviceIndex == "IP") { IP =(UInt32)BitConverter.ToUInt32(heartPacket.IP, 0); if (IBoxActiveDicManager.GetBoxActive(IP, out iboxActive) != true) { IBoxActiveDicManager.iboxActiveDictionary.TryAdd(IP, iboxActive); iboxActive.SessID = sessId; } } else { mac = (UInt64)BitConverter.ToUInt64(heartPacket.Mac, 0); if (IBoxActiveDicManager.GetBoxActive(mac, out iboxActive) != true) { IBoxActiveDicManager.iboxActiveDictionary.TryAdd(mac, iboxActive); iboxActive.SessID = sessId; } } //引用类型,智能指针,使用方便 iboxActive.UpdateTime = DateTime.Now; } } 

4.2。辞書テーブルでの要素の割り当ての失敗

        /// <summary>
        /// 查询激活设备箱字典中是否有存在上报的设备箱, /// 存在返回true,不存在返回false,并且新建好设备箱模型 /// </summary> /// <param name="mac"></param> /// <param name="iboxActive"></param> /// <returns></returns> public static bool GetBoxActive(UInt32 IP, out IBoxActive iboxActive) { if (iboxActiveDictionary.TryGetValue(IP, outiboxActive)) { return true; } iboxActive = new IBoxActive(); iboxActive.IP = IP; if (iboxActive.IP != IP) { LoggerHelper.Error(string.Format("实例化赋值不成功.iboxActive.IP:{0};IP{1}", iboxActive.IP, IP)); } return false; } 

変に感じますか?前の文はすべて割り当てられており、次の文は等しくありません。ただし、これはマルチスレッド同時実行で可能であり、以下で詳しく分析します。

4.3。統計デバイスの総数が正しくない

12008国立台湾大学の同時実行中に間違いを起こしやすかったため、1,000に変更されました。次の統計はエラーを引き起こしますが、これもマルチスレッドの同時実行性が高いために発生するエラーが原因です。

5.異常原因の分析

5.1。null参照の原因

実際、4番目のポイントの3つの理由はすべて同じ理由が原因です。そのため、5.1と5.2で詳しく説明し、5.3については簡単に説明します。ここで黒板をたたいて、マルチスレッドの高い同時実行性の異常な問題を分析します。プログラム操作の特徴は、シームに挿入することです。これは、古いドライバーと同じように、スレッド間の不規則性として要約されます。たとえば、デバイスのハートビートスレッドがデバイスのハートビート時間を更新している場合です。オフラインクリーニングスレッドはデバイスをクリーンアップします。その結果、(オフラインスレッドによってクリーンアップされた)空のオブジェクトに時間を割り当てることはできません。したがって、報告できるのはnull参照例外のみです。これは非常に単純なので、デバッグしてこの例外について考えるのに長い時間がかかりました。

5.2。デバイスのIP割り当てが失敗した理由

同様に、デバイスインスタンスが作成された後、IP割り当てが完了し、デバイススレッドがネットワークのすぐ外でクリアされてデバイスがクリアされます。比較するときは、元のアドレスが参照されます。辞書の元のアドレスは他のデバイスボックスのIPを格納しているため、IPアドレス等しくない。

5.3。機器の総数の不正確な統計の理由

その理由は、実際には5.2です。登録に失敗した場合、もちろん番号は間違っています。

6.ソリューション

つまり、アクティブ化されたデバイスインスタンス(最初のハートビート登録)を作成するとき、または(最初の登録ではなく)ハートビート時間を更新するときに、順序付けされていないオフライン削除スレッドを実行させないでください。黒板をたたく:ハートビート処理の登録プロセスの原子性を確保するためです。はい、実際、これはリレーショナルデータベースのトランザクションである原子性と非常によく似ています。原子性は、プログラムの混乱によって引き起こされる異常に対する強力な武器です。登録されたハートビート処理メソッドに相互排他ロックを追加して、コンパイラーがランタイムでより合理的な実行順序を調整できるようにします。

7.コードの実装

コードは簡単です。

    //定义一把锁
    public static Mutex activeIpboxDicMutex = new Mutex();
    //设备箱注册加锁。异常全部消除 IBoxActiveDicManager.activeIpboxDicMWaitOne(); HeartHandler.Register(tcpHeartPacsessionId); IBoxActiveDicManager.activeIpboxDicMReleaseMutex(); 

ここにトランザクションの使用法を挿入するのとよく似ていますが、メインのビジネスを真ん中に追加すると、このアナロジーは誰もが理解して覚えるのに便利です。サンドイッチクッキーみたいです。

            unitOfWork.BeginTransaction();

            // Adds new device
            unitOfWork.DeviceRepository.Add(device); // Commit transaction unitOfWork.Commit(); 

もちろん、デバイスボックスのオフライン取り外しスレッドをロックすることも可能です。

     IBoxActiveDicManager.activeIpboxDicMutex.WaitOne();
     IBoxActiveDicManager.DeleteDeadBoxFromActiveBox(_internal); IBoxActiveDicManager.activeIpboxDicMutex.ReleaseMutex(); 

オフラインのクリアスレッドがパフォーマンスの一部を消費することを考慮して、ロックを削除する状況もテストしました。4番目の3番目の例外はなく、これまでのところすべての問題は解決されています。

8.まとめ

  • 少数のアナログデバイスはこの問題を検出できないため、上記の3つの問題が実際に確実に発生し、それらはすべて非常に深刻で致命的な問題であるため、大量デバイスの重要性が明らかになります。優れたテスト方法は、クレードルの問題を解消することができます。

  • マルチスレッド化と高い同時実行性があらゆる種類の異常の傾向がある場合、私たちは畏敬の念を抱いて問題を解決する必要があります。

おすすめ

転載: www.cnblogs.com/guoguo251/p/12709946.html