序文 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 を応援していただきありがとうございます。 以下もご興味があるかもしれません:
|
<<: Windows プラットフォームでの MySQL のインストールと設定方法と注意事項
この記事では、MySQL 8.0.12解凍版のインストールチュートリアルを参考までに紹介します。具体...
昨日は写真をアップロードしてリンクを返す機能を実装していました。プロジェクトが Tomcat に再デ...
これは、ネイティブJSを使用してページングクリックコントロールを実装する必要がある面接の質問です。参...
Canal は、Java を使用して開発された Alibaba のオープンソース プロジェクトです...
必要最近、Node オンライン サービスを移行する必要があったため、2 つの新しいオンライン サーバ...
まず、VirtualBox仮想マシンのネットワーク設定モードについて説明します。NAT+ホストオンリ...
ツール型ウェブサイトについて、まず疑問に思うのは、無数のオンラインウェブサイトの中で、どのようなウェ...
Linuxでyumを入力すると、プロンプトが表示されます: -bash: /usr/bin/yum:...
この記事では、参考までにMySQL 8.0に接続できないJavaの問題をまとめて紹介します。具体的な...
Apache Tika は、さまざまな形式のファイルからファイル タイプを検出し、コンテンツを抽出す...
MySQL サーバーをシャットダウンする場合、シャットダウン方法に応じてさまざまな問題が発生する可能...
最近、Microsoft は Docker をネイティブにサポートする Windows Server...
目次序文1. リクエストをキャンセルする方法2. 重複リクエストの判定方法3. 繰り返しリクエストを...
この記事では、虫眼鏡効果を実現するためのJavaScriptの具体的なコードを参考までに紹介します。...
js のイベント ループJavaScript はシングルスレッドなので、同じイベントで実行できるメソ...