Linux で TCP 接続の最大数をテストする方法

Linux で TCP 接続の最大数をテストする方法

序文

TCP サーバの最大同時接続数に関して、「ポート番号の上限が 65535 であるため、TCP サーバが理論上処理できる最大同時接続数も 65535 である」という誤解があります。

まず結論を述べます。TCP サーバー プロセスの場合、同時に接続できるクライアントの数は、使用可能なポート番号によって制限されません。同時接続数は、Linux で開くことができるファイルの数によって制限されます。この数は設定可能で、非常に大きくなる可能性があるため、実際にはシステム パフォーマンスによって制限されます。

昨今、高並列性でないとサーバ開発をすると外に出るのが恥ずかしくなります。そこで、将来「日々並列性を向上させていますが、これまで達成した最高の並列性はどれくらいですか?」と聞かれたときに、きちんと答えられるように、お正月に家で何もせずにいる間に自分でデモを書くことにしました。

このテストの主な目的は、Linux のどのパラメータ設定が最大接続数を制限し、その上限はいくらであるかを調べることです。

1.まずデモのアイデアについてお話しします。

サーバーは、接続を受信するだけの epoll で実装されており、クライアントは go の goroutine を使用します。各 goroutine は、接続を確立するだけで、その後は何も行いません。

上記のコード:

サーバ:

/*
 * g++ -o test_epoll ./test_epoll.c
 */
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <stdio.h>
#include <stdlib.h>
#include <文字列.h>
#include <errno.h>

int SetReuseAddr(int fd)
{
 整数 最適値 = 1;
 socklen_t optlen = sizeof(optval);
 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen) を返します。
}

int メイン()
{
 int fd = socket(AF_INET, SOCK_STREAM, 0);
 int iRet = SetReuseAddr(fd);
 (iRet != 0) の場合
 {
 printf("SO_REUSEADDR の setsockopt が失敗しました。エラー:%s\n", strerror(iRet));
 iRet を返します。
 }

 構造体 sockaddr_in アドレス;
 memset(&addr, 0, sizeof(addr));
 アドレス.sin_family = AF_INET;
 addr.sin_port = htons(8080);
 addr.sin_addr.s_addr = INADDR_ANY;
 (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1 の場合)
 {
 printf("バインドに失敗しました。エラー:%s\n", strerror(errno));
 errno を返します。
 }

 (listen(fd, 5) == -1)の場合
 {
 printf("listen に失敗しました。エラー:%s\n", strerror(errno));
 errno を返します。
 }
 printf("8080 でリッスンしています...\n");

 epfd = epoll_create(102400);
 構造体 epoll_event イベント;
 イベント.イベント = EPOLLIN;
 イベントデータfd = fd;
 epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);

 構造体epoll_eventイベント[102400];
 int iOnline = 0;
 (1)
 {
 int num = epoll_wait(epfd, revents, 102400, 60 * 1000);
 printf("epoll_wait 戻り値 %d\n", num);
 (数値>0)の場合
 {
  (int i = 0; i < num; i++) の場合
  {
  (revents[i].data.fd == fd)の場合
  {
   整数クライアント;
   構造体 sockaddr_in cli_addr;
   socklen_t cli_addr_len = sizeof(cli_addr);
   クライアント = accept(fd, (struct sockaddr*)&cli_addr, &cli_addr_len);
   (クライアント == -1)の場合
   {
   printf("受け入れに失敗しました、エラー:%s\n", strerror(errno));
   (errno == EMFILE)の場合
   {
    printf("プロセスごとの制限に達しました\n");
    終了(エラー番号);
   }
   (errno == ENFILE)の場合
   {
    printf("システム全体の制限に達しました\n");
    終了(エラー番号);
   }
   続く;
   }

   iOnline++;
   printf("%s:%d から新しい接続を受信しました\n", inet_ntoa(cli_addr.sin_addr), cli_addr.sin_port);
   イベント.イベント = EPOLLIN;
   イベントデータfd = クライアント;
   epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
  }
  }
 }
 printf("オンライン番号:%d\n", iOnline);
 }

 0を返します。
}

クライアント:

パッケージメイン

輸入 (
 "ネット"
 「fmt」
 "時間"
 「strconv」
 "ランタイム"
)

func Connect(ホスト文字列、ポート整数) {
 _, err := net.Dial("tcp", host+":"+strconv.Itoa(port))
 err != nil の場合 {
 fmt.Printf("%s:%d へのダイヤルに失敗しました\n", ホスト, ポート)
 戻る
 }

 のために {
 時間.スリープ(30 * 1000 * 時間.ミリ秒)
 }
}

関数main() {
 カウント:= 0
 のために {
 接続します("192.168.63.128", 8080)
 カウント++;
 fmt.Printf("Goroutie num:%d\n",runtime.NumGoroutine())
 時間.スリープ(100 * 時間.ミリ秒)
 }
}

2. テストを開始する

初め:

まずは結果からお話しします。接続数が 1031 に達した時点で accept が失敗しました。このとき errno は判定されていなかったため、accept 失敗のみが出力されました。

すると、最初に思い浮かぶのは ulimit -n 制限です。確認してみると、デフォルト値は 1024 であることがわかりました。次に、この値を変更し、/etc/security/limits.conf に次の内容を追加しました。

1 * ソフトノーファイル 102400
2 * ハードノーファイル 102400

次に、現在の xshell 接続を閉じて再接続し、有効にします。これで、ulimit -n は 102400 になります。

これら 2 行は、各プロセスが開くことができるファイル記述子の数に対するソフト制限とハード制限を 102400 に調整することを意味します。

注意: ulimit -n 102400 も有効になりますが、この変更は一時的です。

次に2回目のテストを実行します。

2回目:

面白いことに、実際には接続数は 2000 以上しかありません。Windows のデフォルトの接続数がなぜこんなに高いのか疑問に思っていました。一部の接続が切断されていることが判明しましたが、何もしていないため、まだ残っていると思っていました。別の仮想マシンをインストールする必要があるようです [Erha]

つづく。 。 。

仮想マシンをインストールします。

時間: 2017-12-31 00:09:00

仮想マシンがインストールされたら、続行します。

今回は本当に10Kを超えました。

まだまだ接続数が増え続けています。最終的には10万まで行けるかな。楽しみです。

時間: 2017-12-31 00:41:00、最終的な上限は 28232 で止まっています。golang はダイヤル失敗を報告し続けています。具体的なエラー メッセージを出力し忘れたため、ダイヤルが失敗した理由がわかりません。そのため、もう一度実行するしかありません T_T

時間: 2017-12-31 01:01:00、ダイヤル失敗のエラー メッセージを追加し、再度実行しましたが、28232 でダイヤル失敗が引き続き発生し、次のエラー メッセージが表示されました:

golangの標準ライブラリのドキュメントにはエラーメッセージの説明がありません。エラーメッセージからするとアドレスの割り当てに失敗しているようなので、ポートアドレスの範囲が制限されているのかなと思います。

ポートアドレス範囲を確認し、これが制限であることを確認しました。ポートアドレスは16ビットなので、ポートアドレス範囲を1024〜65535に変更しても、最大64521の接続しか開けません。クライアントとして仮想マシンを1台しか持っていないので、10万接続を実現することは不可能です。ただし、このテストを通じて、どのパラメータが接続の上限を制限するのかについても把握できました。これが私が望んでいることです。

最後に、epoll のような素晴らしいメカニズムを立ち上げてくれた Linux カーネル チームの素晴らしい人々に感謝したいと思います。epoll のおかげで、高い並行性を簡単に実現できるようになりました。いつか私も彼らと同じくらい素晴らしい人になれたらいいなと思います。

要約する

上記はこの記事の全内容です。この記事の内容が皆さんの勉強や仕事に一定の参考学習価値を持つことを願っています。ご質問があれば、メッセージを残してコミュニケーションしてください。123WORDPRESS.COM を応援していただきありがとうございます。

以下もご興味があるかもしれません:
  • Linux での TCP 接続タイムアウト問題の解決方法
  • Linux で TCP 接続を確認する 2 つのコマンド
  • Linux で TCP フラッド攻撃を防ぐ方法

<<:  Windows プラットフォームでの MySQL のインストールと設定方法と注意事項

>>:  MySQLクエリ結果をCSVにエクスポートする方法

推薦する

Bootstrap 3.0 の特殊効果の学習ノート(表示と非表示、フローティングの除去、閉じるボタンなど)

この記事の主な内容は次のとおりです。 1. 閉じるボタン2.キャレット3. フローティングを素早く設...

Reactは二次連結(左右連結)を実現する

この記事では、二次リンクを実現するためのReactの具体的なコードを参考までに共有します。具体的な内...

js を使用して年カルーセル選択効果をネイティブに実装する例

序文js を使用して、年の回転選択効果を実現します。では早速、写真を見てみましょう。 1. アイデア...

MySQL マルチインスタンス構成ソリューション

1.1 MySQL マルチインスタンスとは何ですか?簡単に言うと、MySQL マルチインスタンスとは...

MySQL データの集約とグループ化

多くの場合、データを実際に取得せずに要約する必要があり、 MySQLこの目的のために特別な関数を提供...

JavaScriptにおけるこのポインティング問題の詳細な説明

序文JS の this ポインターは、初心者にとって常に頭痛の種でした。今日は、これが地面に落ちたと...

MySQL でのログインを取り消す

コンセプト紹介: MySQL の redo ログにはトランザクションの動作が記録されることはご存じの...

JavaScript 円グラフの例

描画効果実装コードJavaScript var キャンバス = document.getElemen...

MySQL ビューの原理と使用法の詳細な分析

序文: MySQL では、ビューはおそらく最も一般的に使用されるデータベース オブジェクトの 1 つ...

CSS 背景画像を設定するための 6 つの興味深いヒント

background-image は、おそらくすべてのフロントエンド開発者がキャリアの中で少なくとも...

WeChatアプレットキャンバスが署名機能を実装

WeChatアプレットプロジェクトでは、開発モジュールに手書き署名機能が含まれ、WeChatアプレッ...

JavaScript Canvas は動的なワイヤーフレーム効果を描画します

この記事では、JavaScript Canvasの動的なワイヤーフレーム効果を描画する具体的なコード...

MybatisはSQLクエリのインターセプションと変更の詳細を実装します

序文インターセプターの機能の 1 つは、特定のメソッドの呼び出しをインターセプトできることです。イン...

HTML で複数のフォームのテキスト ボックスを揃える方法

フォームのコードは図の通りです。スタイルシートがまだ追加されていないため、フォームが整列されておらず...

Reactマウスの複数選択機能の設定方法

一般的に、リストには選択機能があり、単一選択、二重選択、複数選択が非常に一般的です。カスタム ループ...