私のIoTプロジェクトの初期のオンライン事故

1つのMQTT接続番号アラーム

プロジェクトは約1か月間オンラインで行われ、クレードルの出庫数は約200で、1日あたりの平均オンライン数です(一部の企業は慎重で、プラグを差し込む前に車に乗る必要がある子供がいると聞きました。通常はプラグが差し込まれておらず、一部はまだ接続されていません。コーナーのレイジーチューブ)は約100に維持されています。当時、Alibaba Cloudで購入したMQTT構成は最大接続数2000でした(MQTTは接続数に応じて購入しました)。現在のロッカー数と同様に、当時の構成で十分でした。 、1か月間、正規化されています(今考えてみると、元のプロモーション戦略は未成熟で、毎日配置されるクレードルの数は1日3または4ユニット、または3または4ユニットが数日間プロモーションされました)ので、問題はありません。公開されていませんが、遅かれ早かれ返済される予定です。

ある日の午後、仕事を辞めようとすると、突然MQTTが警告を発し続け、5秒ごとに電話で、MQTT接続の数が制限を超えたことを示す警告メッセージを受け取りました(Alibaba Cloud製品を使用すると、この警告機能は非常にタイムリーであると感じます)。テスト用のロッカーもいくつかあり、MQTTを頻繁に使用するため、当時はあまり気にせず、テスターに​​停止してテストを実行するように依頼しました(これは非常に恥ずかしいことです。テスト環境と、ロッカースキャンコードが開始するために使用する行上記の環境は同じMQTTです。理由は後で詳しく説明します)しばらくすると接続数が解放されると思いましたが、携帯電話はますます激しくアラームメッセージを受信しました。最初に全体的な事故ポイントを考えたのはMQTTビジネスアプリケーションレイヤーです。この時点で(携帯電話のスキャンコードはMQTTアプリケーションレイヤーへのhttpリクエストを介して行われ、MQTTアプリケーションレイヤーはAlibaba Cloud MQTTサーバーにメッセージをスローします)。最初は、2つのMQTTアプリケーションレイヤーが負荷分散クラスターを実行していました。2つのサーバーにログインし、それぞれtopを使用しました。 2台のサーバーを表示するコマンド。一方のCPUは約80%、もう一方のCPUは約60%です。突然、非常に驚​​きました。このようなちょっとしたデータ要求によって、アプリケーションサーバーがそれに耐えられなくなることはありません。最初に考えたのは、監視することでした。 TCP接続の現在の数を見ると、結果はショックを受けました(コマンド:netstat -natp | awk '{print $ 7}' | sort | uniq -c | sort -rnを使用)。2つのサーバーの現在の接続数は近いです。 1Wよりも高速で、まだ上昇しています(その時点でリリースされたクレードルがまだ使用および消費されているため)、現時点での基本的な位置決めの問題:携帯電話がコードをスキャンしてhttp要求をMQTTアプリケーションレイヤーに送信し、MQTTアプリケーションレイヤーは毎回メッセージを送信しますAlibaba Cloud MQTTサーバーへの接続は、確立する必要があります。コードロジックが最初は比較的単純だったので、このコードを書いた開発者を直接見つけて一緒に調べました。確かに、コードを変更してパッケージを再送信すると、すべてが正常になり、携帯電話はすぐにSMSに警告します。停止。

	public void sendMsgMqtt(String productId, String deviceId, String scontent, String topic){
		String subTopic = getSubTopic(productId, deviceId, topic);
		String clientId = getClientId();
		MemoryPersistence persistence = new MemoryPersistence();
		try {
			 final MqttClient sampleClient = new MqttClient(GlobalConstant.BROKER, clientId, persistence);
             final MqttConnectOptions connOpts = getConnOpts(clientId);
             log.info("Coin Connecting to broker: " + GlobalConstant.BROKER);
             sampleClient.setCallback(new MqttCallback() {
             public void connectionLost(Throwable throwable) {
                 log.info("mqtt connection lost");
                 throwable.printStackTrace();
                 while(!sampleClient.isConnected()){
                     try {
                         sampleClient.connect(connOpts);
                     } catch (MqttException e) {
                         e.printStackTrace();
                     }
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
                         e.printStackTrace();
                     }
                 }
             }
             public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
                 log.info("coin messageArrived:" + topic + "------" + new String(mqttMessage.getPayload()));
             }
             public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                 log.info("coin deliveryComplete:" + iMqttDeliveryToken.getMessageId());
             }
          });
             sampleClient.connect(connOpts);
             try{
            	 scontent = scontent.replace("[", "").replace("]", "");
            	 final MqttMessage message = new MqttMessage(scontent.getBytes());
                 message.setQos(1);
                 log.info("pushed at "+new Date()+" "+ scontent);
                 sampleClient.publish(subTopic, message);
                 log.info("-------send end---------");
             }catch(Exception ex){
            	 ex.printStackTrace();
             }finally{
               	 sampleClient.disconnect();
                 log.info("-------client disConnect()---------"); 
             }
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

2つのデータベースCPU100%

スタートアッププロジェクトの開始当初のビジネスは非常に不明確でした。基本的には、石を感じて一歩一歩進んで考えたり、市場の反応を見て変更を加えたりすることで、川を渡るようなものです。したがって、この段階では、モデルのテストとビジネスの最適化について説明します。もちろん、資金も限られており、迅速な開発と反復の要件が必要です。したがって、データベースは最初はクラスター化されておらず、1台のマシンを再生するだけでした。これは、1台のマシンを再生するためであり、一部はクラスター内にあります。環境内でそれほど迅速に発生しない問題は、1台のマシンで簡単に発生する可能性があります。

夕方の7時頃(夕方の7時から9時がクレードルの使用のピークであり、通常、日中の注文データは少なく、夕方にはデータが2倍になります)、プラットフォームシステムが非常に遅く、開くのが遅いというフィードバックを受け取りました。さらに、携帯電話は、未消費の注文が多数あるというMQTT SMS警告を引き続き受信しました。最初の応答は、クラウドデータベース管理プラットフォームにすばやくログインして、データベースCPUインジケーターが真っ赤になり、使用率が100%に達したことを確認しました。当初、データベースは汎用の4コア8Gを使用し、注文テーブルのデータは40W近くでした。データベースのパフォーマンス管理インターフェイスを開いて表示します(そのような管理インターフェイスがない場合は、実行中のSQLを表示し、コマンドshowprocesslistで説明て実行計画を分析することもできます。遅いSQLを確認してください)、遅いSQLが大量に蓄積されていることがわかりました。一部のSQLの平均実行時間は1分近くを超えています。明らかに、データベースのグローバルスキャンが実行されています。さらに、この時間のピーク時に、遅いSQLが蓄積され、CPUリソースが発生します。注文は消費されます。

当時はビジネス利用のピークでもあり、お客様からの苦情や上記の多くの方々に加えて、データベースを短期間で通常の状態に戻したいと考えていました。当初は、迅速に復旧するための選択肢がいくつかありました。データベースをスタンバイデータベースに切り替える(データベースの可用性が高い)か、低速のSQLを強制終了します(状態がshow processlistを介してデータを送信している列を確認してから、idを強制終了します)。これらは、最後の手段として、現在使用中のビジネスに影響を与える可能性があります。状況はすぐには起こりません。最初のいくつかの遅いSQLを調べましたが、そのうちのいくつかは、インデックスの最適化など、すばやく処理できます。いくつかのインデックスを再最適化しようとしました(後で詳しく説明します)。数分後、CPU使用率はゆっくりと低下し(インデックスが最適化される前に1つのレコードが約3秒で実行され、インデックスが最適化された後1秒で数千のレコードが実行されました)、ビジネスは正常で、後でデータベースが使用されました最適化について考える時間はたくさんあるので、この事件の最大の感想は、頭を悩ませる必要がなく、落ち着いて問題を最小限に抑える必要があるということです。

このSQL最適化では、いくつかの経験を要約し、関連する最適化を次のように行いました。

1.インデックスを追加し、インデックスを最適化します。特に、インデックスの暗黙的な変換には注意してください。

テーブルに主キーのみが設定されている場合、他のインデックスは作成されません。主キーによるクエリのみを含むビジネスなどの単純なビジネスは問題ありませんが、他のフィールドへのクエリの設計により、データ量とビジネスのピークが増加します。期間中、テーブルのグローバルクエリにつながるこの種のSQLは、間違いなく多くの低速SQLを蓄積し、最終的にCPUを上昇させ続けます。条件がある場合は、大量のデータを使用してストレステストを実行してテストし、さらにインデックスを確立することをお勧めします。 、インデックスが無効であることに注意してください。例:select * from order where phone = 13772556391;通常は不注意にコードを記述し、注意深くチェックせず、ストレステストが適切に テストされていないため、同時データ量がわずかに多いビジネスシナリオで問題が発生する可能性があります。データベーステーブルのphoneフィールドで使用される文字列タイプですが、このSQLには引用符がないため、この場合、インデックスは無効です。

2.ページングクエリの最適化

select * from orderwhere oid = 100 limit 100000、5000、この一般的な制限M、Nページめくり書き込み方法、ページめくりプロセスが遅い、MySQLがテーブルの最初のM + Nエントリを読み取る理由データ、Mが大きいほど、パフォーマンスは低下します。この種のSQLがレコードを見る通常のクエリである場合、異常を感じなければ、少し遅くても耐えることができますが、先ほど述べたビジネスシナリオでは、遅いSQLクエリの蓄積にもつながります。最適化された書き込み:次数t1からt1。*を選択します(次数oid = 100制限100000、5000からIDを選択します)t2ここで、t1.id = t2.idの場合、この種の効率は高く、非常に優れています。

3.サブテーブル

上記の最適化が行われていますが、実行効率は以前よりもはるかに高くなっていますが、単一式のプレッシャーは依然として存在します。当時、注文表はテーブルに分割されていませんでした。現在の状況ではシャーディングクラスターを使用していませんでしたが、燃焼のニーズを解決するために物理的な分散テーブルも必要でした(クレードルがますます出されるにつれて、注文は約1でした) 10,000〜20,000)。

 

SQLの最適化は長期的なプロセスであり、特定のビジネスシナリオと組み合わせて効率を最適化することをお勧めします。後で、このプロジェクトの実際の戦闘で出現したSQLの落とし穴と関連する最適化をいくつかリストします。

おすすめ

転載: blog.csdn.net/u010460625/article/details/108848862