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にエクスポートする方法

推薦する

Linux/Mac に MySQL をインストールするときにパスワードを忘れた場合の解決策

序文この記事では主に、Linux/Mac に MySQL をインストールするときにパスワードを忘れた...

Vueプロジェクトでのトークン検証ログイン(フロントエンド部分)

この記事の例では、Vueプロジェクトでのトークン検証ログインの具体的なコードを参考までに共有していま...

mysql 5.7.5 m15 winx64.zip インストール チュートリアル

win7 64 ビットで mysql-5.7.5-m15-winx64 をインストールして構成する方...

画像マーキー効果を実現するネイティブJS

今日は、ネイティブ JS で実装された画像マーキー効果を紹介します。効果は次のとおりです。 実装され...

Docker 環境での Jmeter の分散操作に関する詳細なチュートリアル

1. jmeterの基本イメージを構築するDockerfile は次のとおりです。 # Java 8...

XshellがvirtualBox仮想マシンに接続できない問題の解決策

まず、VirtualBox仮想マシンのネットワーク設定モードについて説明します。NAT+ホストオンリ...

Youku 動画から 30 秒の広告コードを削除する 2 つの方法

誰もがこんな気持ちになったことがあると思います。30 秒の広告が入った動画を見ると、とても不快に感じ...

MySQL 5.7 でルートパスワードを忘れた後に変更する方法の詳細なチュートリアル

序文長い間、MySQL のアプリケーションおよび学習環境は MySQL 5.6 以前のバージョンであ...

mysql8.0.23 msi インストールの超詳細なチュートリアル

1.MySqlをダウンロードしてインストールする公式ウェブサイトからMySqlデータベースをダウンロ...

Ubuntu で VIM を C++ 開発エディタとして設定する

1. 設定ファイルをユーザー環境にコピーし、新しい.vimフォルダを作成し、バンドルサブフォルダを作...

Linux でディスクをマウントし、起動時に自動的にマウントするように設定する方法

皆さんの時間は貴重だと承知しているので、プロセス コマンドを直接書き留めておきます。設定できます。原...

Mysqlは実行中のトランザクションを照会し、ロックを待機する方法

navicatを使用してテストと学習を行います。まず、 set autocommit = 0;を使用...

Mysql 8.0 のインストールとパスワードのリセットの問題

Mysql 8.0 のインストールの問題とパスワードのリセット1: MySqlをダウンロードする公式...

nginxでイメージサーバーを構築する手順の詳しい説明(ルートとエイリアスの違い)

インストール手順は省略します( yum -y install nginx;を使用して直接インストール...

HTML CSS を使用して div またはテーブルを指定した位置に固定する方法

CSSコードコンテンツをクリップボードにコピー.bottomTable{背景色: rgb (249,...