[转]How to support 10,000 or more concurrent TCP connections

本文探讨了如何利用现代Windows操作系统及正确API实现支持数万并发TCP连接的服务器系统。通过减少上下文切换、数据复制、内存分配及锁竞争等手段提高服务器性能。

http://www.serverframework.com/asynchronousevents/2010/10/how-to-support-10000-concurrent-tcp-connections.html

 

Using a modern Windows operating system it's pretty easy to build a server system that can support many thousands of connections if you design the system to use the correct Windows APIs. The key to server scalability is to always keep in mind the Four Horsemen of Poor Performance as described by Jeff Darcy in his document on   High Performance Server Architecture. These are:

  • Data copies
  • Context switches
  • Memory allocation
  • Lock contention
I'll look at context switches first, as IMHO this is where outdated designs often rear their head first. On Windows systems you MUST be using I/O Completion Ports and overlapped I/O if you want the best scalability. Using the IOCP API correctly can mean that you can service thousands of concurrent connections with a handful of threads.

So, we'll assume we're using a modern overlapped I/O, IO Completion Port based design; something similar to what   The Server Framework  provides, perhaps. Using an IOCP allows you to limit the number of threads that are eligible to run at the same time and the IOCP uses a last in, first out mechanism to ensure that the thread that was last active and processing is always the next one to be given new work, thus preventing a new thread's memory needing to be paged in. 

The latest versions of Windows allow you to reduce context switching even further by enabling various options on each socket. I've spoken in detail about how FILE_SKIP_COMPLETION_PORT_ON_SUCCESS  can help to reduce context switching on my blog,   here. The gist is that with this option enabled you can process overlapped operation completions on the same thread that issued the operation if the operation can complete at the time it's issued. This removes unnecessary context switching. The Server Framework supports this mode of operation on operating systems that support it.

Next on to data copies, as Jeff says in his document, one of the best ways to avoid data copies is to use reference counted buffers and to manage them in terms of the amount of data present in them, building buffer chains where necessary. The Server Framework has always worked in terms of flexible, reference counted buffers. Many server designs can benefit from accumulating inbound data into a single buffer with no buffer copying required simply by reissuing a read on a connection with the buffer that was passed to you when the previous read completed. In this way it's easy to accumulate 'complete messages' and process them without needing to copy data. 

Since the buffers are reference counted you can easily pass them off to other threads for processing, or keep them hanging around until you're done with them. The CMultiBufferHandle  class allows you to use scatter/gather I/O so that you can transmit common blocks of data without needing to copy the common data and the CBufferHandle  class allows you to broadcast data buffers to multiple connections without needing to copy the data for each connection.

Memory allocation during connection processing is minimal and custom buffer allocators can reduce this even further. The Server Framework ships with several different allocators and it's easy to implement your own if you need to and simply plug it in to the framework code. By default the buffer and socket allocators pool memory for reuse which helps reduce contention and improve performance.

Once you're processing your messages several tricks can be employed to optimise your memory allocation use, a favourite of mine is to use custom memory allocators that use scratch space in the buffer that the message was initially read into. This can then be used to provide all of the dynamic memory needed during message processing and avoids the need for traditional memory management and its potential lock contention.  

Lock contention within the framework itself is limited. The design of the socket object is such that you can design a server where there's never any need to access a common collection of connection objects simply to obtain per connection data from it. Each connection can have as much user data as you like associated with it and this can all be accessed from the connection without the need for any locks. The locks in the buffer allocators are probably the most likely locks to result in contention but here you can select from several different strategies, including a lock free allocator. 

Of course once you've our of the framework code and into your own code you still have to be careful not to fall foul of the Four Horsemen of Poor Performance, but you can rest assured that The Server Framework is designed very much with these issues in mind. I believe that the only way to make sure that you maintain scalability and performance is to test for it at all stages of development, it's important to set up scalability tests from day 1 and to run them regularly using real world usage scenarios. I'll talk about how to go about setting up these kinds of tests in a later blog post.

 

Performance Endpoint for Linux (32-bit and 64-bit) File README Version 7.30 SP1 Copyright (C) 2003-2013 Ixia. All rights reserved. Ixia 26601 W. Agoura Road Calabasas, CA 91302 U.S.A. Web: www.ixiacom.com Phone: +1 818 871-1800 or + 1 877 FOR IXIA Fax: +1 818 871 1805 General information: Email: info@ixiacom.com Technical support: Email: support@ixiacom.com Thanks! We appreciate your interest in our software. We keep seeking ways to improve it; we welcome your feedback and suggestions. We continue to enhance and expand our Web site -- come and visit us. The latest versions of the endpoints are always available for free at http://www.ixiacom.com/support/endpoint_library/ Note that the Ixia Performance Endpoints have not been tested with NetIQ applications and may not function properly with NetIQ applications. Linux kernel 2.4.20 We've tested with packages that implement Linux kernel 2.4.20. We have not tested this version of Performance Endpoint with earlier versions of the Linux kernel. Only TCP and UDP/RTP support The Performance Endpoint for Linux uses the Sockets interface to the TCP/IP support shipped with Linux. IPX, SPX, or other network protocols are not supported in this version. For IPv6 support, kernel 2.4.18-3 or better is required. Here's what you need to run the endpoint program with Linux: - A computer capable of running Linux well. We recommend a CPU such as Intel Pentium III or better. For the 64-bit (x64) version of the endpoint you will need an AMD64/EM64T compatible CPU, such as AMD Opteron or an Intel Xeon with support for EM64T technology. For the 64-bit versions of the endpoint the corresponding 64-bit version of Linux is also required. - 64 MBytes of RAM. The total RAM requirement depends on RAM usage of the underlying protocol stack and the number of concurrent endpoint pairs. For tests involving over one hundred connections through a single endpoint, additional memory may be required. - A hard disk with at least 8 MBytes of space available. - Linux kernel 2.4.20 or better. Older versions of the Linux kernel may not support IPv6 properly. TAR-Based Endpoint Installation for Linux ------------------------------------------------------------------- Use the TAR-based installation if you are installing the endpoint on any Linux platform other than Red Hat (32-bit) or SuSE (64-bit). First, make sure that you are logged in as a "root" user. Also remember all commands and parameters discussed here are case-sensitive. Use the combination of uppercase and lowercase letters as shown below (for all the file names, "M" represents the major version and "m" represents the minor version). The following instructions describe how to install the endpoint on a computer with a CD-ROM drive. Put the CD-ROM in your CD-ROM drive. If you want to install the 64-bit version of the endpoint, replace the name of the archives (pelnx_Mm.tar.gz and pelnx_Mm.tar) from the following instructions with pelinux_amd64_Mm.tar.gz Enter the following commands, assuming your CD-ROM drive device name is /dev/cdrom and you are able to create a temporary directory named cdrom: mkdir /cdrom mount /dev/cdrom /cdrom The CD-ROM contains an archive of the endpoint package. First use the RM command to ensure a clean temporary install directory. Then use the TAR command to extract the archive contents from the CD-ROM: cd /tmp rm -fr temp tar -zxvf ./pelnx_Mm.tar.gz Next, run the endpoint's installation script to install the endpoint: ./endpoint.install The license agreement is shown, presented with the "more" command. Press the space bar until the end of the agreement is displayed. You are asked whether you accept the terms and conditions of the agreement. If you do, enter "accept_license" and press return. After the installation is complete, use the UMOUNT command to unmount the file system from the CD-ROM: umount /cdrom During installation, you will see several status messages. Pay close attention to the output. When the installation is successful, you see the message "Installation of endpoint was successful." The installation script and temporary directory are not removed automatically if the installation is successful. If you need the disk space after installing the endpoint, you may delete the temporary directory and installation script. Unattended Installation for TAR-Based Linux You can install the endpoint silently, that is, without providing any additional user input. Complete the steps, as described above, through the TAR command. Next, run the endpoint's installation, adding the "accept_license" parameter: ./endpoint.install accept_license Removing the TAR-Based Endpoint Package (Uninstall) You must be logged in as the root user to remove the endpoint package. If you need to remove the endpoint package from your hard disk, first stop the endpoint program (if running). Enter the following command: /usr/local/Ixia/endpoint -k Use the following command to remove the endpoint: /usr/local/Ixia/endpoint.remove If the removal is successful, you will see the following: "Removal of endpoint was successful." This removes the files from /usr/local/Ixia, except for any files added to this directory that were not present at install, such as the endpoint.ini file, but does not delete the directory. The remove program does not automatically delete files added to the directory that you may need if you reinstall the product. RPM-Based Endpoint Installation for Linux ------------------------------------------------------------------- Use the RPM-based installation if you are installing the endpoint on Red Hat (32-bit) or SuSE (64-bit). For installation, first make sure that you are logged in as a "root" user. Also remember all commands and parameters discussed here are case-sensitive. Use the combination of uppercase and lowercase letters as shown below (for all the file names, "M" represents the major version and "m" represents the minor version). The following instructions describe how to install the endpoint on a computer with a CD-ROM drive. Put the CD-ROM in your CD-ROM drive. If you want to install the 64-bit version of the endpoint, replace the name of the RPM file (pelnx_Mm.rpm) from the following instructions with pelinux_amd64_Mm.rpm Enter the following commands, assuming your CD-ROM drive device name is /dev/cdrom and you are able to create a temporary directory named cdrom: mkdir /cdrom mount /dev/cdrom /cdrom Copy the pelnx_Mm.rpm file from the CD-ROM drive to a local directory (for example, tmp). cp /cdrom/endpoint/linux/pelnx_Mm.rpm /tmp For RPM, use the RPM command to install the endpoint: rpm -Uvh /tmp/pelnx_Mm.rpm After the installation is complete, use the UMOUNT command to unmount the file system from the CD-ROM: umount /cdrom During installation, you will see several status messages. Pay close attention to the output. When the installation is successful, you see the message "Installation of endpoint was successful." Removing the RPM-Based Endpoint Package (Uninstall) You must be logged in as the root user to remove the endpoint package. If you need to remove the endpoint package from your hard disk, first stop the endpoint program (if running). Enter the following command: /usr/local/Ixia/endpoint -k Use the following command to remove the endpoint (you must be logged in as root to run this program): rpm -e endpoint If the removal is successful, you will see the following: "Removal of endpoint was successful." This removes the files from /usr/local/Ixia, except for any files that were added to this directory that were not present at install, such as the endpoint.ini file, and does not delete the directory. The remove program does not automatically delete files added to the directory that you may need if you reinstall the product. What We Do During Installation Here is what happens during the installation steps. The endpoint is installed into the directory /usr/local/Ixia. A directory is created with the following contents: - the executable programs. - the README file. - various install and uninstall programs. - the directory cmpfiles. This directory contains files with the .cmp file extension. These are files containing data of different types, such as typical text or binary data. These files are used by the endpoint as data on SEND commands. The different data types can be used to vary the data compression performance of your network hardware and software. - the file endpoint.ini. Our software ends any copy of the endpoint program currently running and starts a copy of the newly-installed endpoint. You can run tests immediately, without a reboot. Our software displays information on how to update your system to have the endpoint start automatically upon reboot. No changes are made to the PATH environment variable of the root user. *IxChariot is a registered trademark of Ixia. United States Patent Numbers 5,838,919, 5,881,237, 5,937,165, and 6,061,725. Other patents pending.啥意思
10-16
# Other default tuning values # MySQL Server Instance Configuration File # ---------------------------------------------------------------------- # Generated by the MySQL Server Instance Configuration Wizard # # # Installation Instructions # ---------------------------------------------------------------------- # # On Linux you can copy this file to /etc/my.cnf to set global options, # mysql-data-dir/my.cnf to set server-specific options # (@localstatedir@ for this installation) or to # ~/.my.cnf to set user-specific options. # # On Windows, when MySQL has been installed using MySQL Installer you # should keep this file in the ProgramData directory of your server # (e.g. C:\ProgramData\MySQL\MySQL Server X.Y). To make sure the server # reads the config file, use the startup option "--defaults-file". # # To run the server from the command line, execute this in a # command line shell, e.g. # mysqld --defaults-file="C:\Program Files\MySQL\MySQL Server X.Y\my.ini" # # To install the server as a Windows service manually, execute this in a # command line shell, e.g. # mysqld --install MySQLXY --defaults-file="C:\Program Files\MySQL\MySQL Server X.Y\my.ini" # # And then execute this in a command line shell to start the server, e.g. # net start MySQLXY # # # Guidelines for editing this file # ---------------------------------------------------------------------- # # In this file, you can use all long options that the program supports. # If you want to know the options a program supports, start the program # with the "--help" option. # # More detailed information about the individual options can also be # found in the manual. # # For advice on how to change settings please see # https://dev.mysql.com/doc/refman/8.0/en/server-configuration-defaults.html # # # CLIENT SECTION # ---------------------------------------------------------------------- # # The following options will be read by MySQL client applications. # Note that only client applications shipped by MySQL are guaranteed # to read this section. If you want your own MySQL client program to # honor these values, you need to specify it as an option during the # MySQL client library initialization. # [client] # pipe= # socket=MYSQL port=3306 [mysql] no-beep # default-character-set= # SERVER SECTION # ---------------------------------------------------------------------- # # The following options will be read by the MySQL Server. Make sure that # you have installed the server correctly (see above) so it reads this # file. # [mysqld] port = 3306 bind-address = 0.0.0.0 # The next three options are mutually exclusive to SERVER_PORT below. # skip-networking # enable-named-pipe # shared-memory # shared-memory-base-name=MYSQL # The Pipe the MySQL Server will use. # socket=MYSQL # The access control granted to clients on the named pipe created by the MySQL Server. # named-pipe-full-access-group= # The TCP/IP Port the MySQL Server will listen on port=3306 # Path to installation directory. All paths are usually resolved relative to this. # basedir="D:/mysql" # Path to the database root datadir=D:/mysql\Data # The default character set that will be used when a new schema or table is # created and no character set is defined # character-set-server= # The default storage engine that will be used when create new tables when default-storage-engine=INNODB # The current server SQL mode, which can be set dynamically. # Modes affect the SQL syntax MySQL supports and the data validation checks it performs. This # makes it easier to use MySQL in different environments and to use MySQL together with other # database servers. sql-mode="ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION" # General and Slow logging. log-output=FILE general-log=0 general_log_file="WIN-20240617SLP.log" slow-query-log=1 slow_query_log_file="WIN-20240617SLP-slow.log" long_query_time=10 # Error Logging. log-error="WIN-20240617SLP.err" # ***** Group Replication Related ***** # Specifies the base name to use for binary log files. With binary logging # enabled, the server logs all statements that change data to the binary # log, which is used for backup and replication. log-bin="WIN-20240617SLP-bin" # ***** Group Replication Related ***** # Specifies the server ID. For servers that are used in a replication topology, # you must specify a unique server ID for each replication server, in the # range from 1 to 2^32 − 1. "Unique" means that each ID must be different # from every other ID in use by any other source or replica. server-id=1 # Indicates how table and database names are stored on disk and used in MySQL. # Value 0 = Table and database names are stored on disk using the lettercase specified in the CREATE # TABLE or CREATE DATABASE statement. Name comparisons are case-sensitive. You should not # set this variable to 0 if you are running MySQL on a system that has case-insensitive file # names (such as Windows or macOS). If you force this variable to 0 with # --lower-case-table-names=0 on a case-insensitive file system and access MyISAM tablenames # using different lettercases, index corruption may result. # Value 1 = Table names are stored in lowercase on disk and name comparisons are not case-sensitive. # MySQL converts all table names to lowercase on storage and lookup. This behavior also applies # to database names and table aliases. # Value 2 = Table and database names are stored on disk using the lettercase specified in the CREATE TABLE # or CREATE DATABASE statement, but MySQL converts them to lowercase on lookup. Name comparisons # are not case-sensitive. This works only on file systems that are not case-sensitive! InnoDB # table names and view names are stored in lowercase, as for lower_case_table_names=1. lower_case_table_names=1 # This variable is used to limit the effect of data import and export operations, such as # those performed by the LOAD DATA and SELECT ... INTO OUTFILE statements and the # LOAD_FILE() function. These operations are permitted only to users who have the FILE privilege. secure-file-priv="D:/mysql/Uploads" # The maximum amount of concurrent sessions the MySQL server will # allow. One of these connections will be reserved for a user with # SUPER privileges to allow the administrator to login even if the # connection limit has been reached. max_connections=151 # The number of open tables for all threads. Increasing this value increases the number # of file descriptors that mysqld requires. table_open_cache=4000 # Defines the maximum amount of memory that can be occupied by the TempTable # storage engine before it starts storing data on disk. temptable_max_ram=1G # Defines the maximum size of internal in-memory temporary tables created # by the MEMORY storage engine and, as of MySQL 8.0.28, the TempTable storage # engine. If an internal in-memory temporary table exceeds this size, it is # automatically converted to an on-disk internal temporary table. tmp_table_size=128M # The storage engine for in-memory internal temporary tables (see Section 8.4.4, "Internal # Temporary Table Use in MySQL"). Permitted values are TempTable (the default) and MEMORY. internal_tmp_mem_storage_engine=TempTable #*** MyISAM Specific options # The maximum size of the temporary file that MySQL is permitted to use while re-creating a # MyISAM index (during REPAIR TABLE, ALTER TABLE, or LOAD DATA). If the file size would be # larger than this value, the index is created using the key cache instead, which is slower. # The value is given in bytes. myisam_max_sort_file_size=2146435072 # The size of the buffer that is allocated when sorting MyISAM indexes during a REPAIR TABLE # or when creating indexes with CREATE INDEX or ALTER TABLE. myisam_sort_buffer_size=245M # Size of the Key Buffer, used to cache index blocks for MyISAM tables. # Do not set it larger than 30% of your available memory, as some memory # is also required by the OS to cache rows. Even if you're not using # MyISAM tables, you should still set it to 8-64M as it will also be # used for internal temporary disk tables. key_buffer_size=8M # Each thread that does a sequential scan for a MyISAM table allocates a buffer # of this size (in bytes) for each table it scans. If you do many sequential # scans, you might want to increase this value, which defaults to 131072. The # value of this variable should be a multiple of 4KB. If it is set to a value # that is not a multiple of 4KB, its value is rounded down to the nearest multiple # of 4KB. read_buffer_size=128K # This variable is used for reads from MyISAM tables, and, for any storage engine, # for Multi-Range Read optimization. read_rnd_buffer_size=256K #*** INNODB Specific options *** # innodb_data_home_dir= # Use this option if you have a MySQL server with InnoDB support enabled # but you do not plan to use it. This will save memory and disk space # and speed up some things. # skip-innodb # If set to 1, InnoDB will flush (fsync) the transaction logs to the # disk at each commit, which offers full ACID behavior. If you are # willing to compromise this safety, and you are running small # transactions, you may set this to 0 or 2 to reduce disk I/O to the # logs. Value 0 means that the log is only written to the log file and # the log file flushed to disk approximately once per second. Value 2 # means the log is written to the log file at each commit, but the log # file is only flushed to disk approximately once per second. innodb_flush_log_at_trx_commit=1 # The size in bytes of the buffer that InnoDB uses to write to the log files on # disk. The default value changed from 8MB to 16MB with the introduction of 32KB # and 64KB innodb_page_size values. A large log buffer enables large transactions # to run without the need to write the log to disk before the transactions commit. # Thus, if you have transactions that update, insert, or delete many rows, making # the log buffer larger saves disk I/O. innodb_log_buffer_size=16M # The size in bytes of the buffer pool, the memory area where InnoDB caches table # and index data. The default value is 134217728 bytes (128MB). The maximum value # depends on the CPU architecture; the maximum is 4294967295 (232-1) on 32-bit systems # and 18446744073709551615 (264-1) on 64-bit systems. On 32-bit systems, the CPU # architecture and operating system may impose a lower practical maximum size than the # stated maximum. When the size of the buffer pool is greater than 1GB, setting # innodb_buffer_pool_instances to a value greater than 1 can improve the scalability on # a busy server. innodb_buffer_pool_size=128M # Defines the amount of disk space occupied by redo log files. This variable supersedes the # innodb_log_files_in_group and innodb_log_file_size variables. innodb_redo_log_capacity=100M # Defines the maximum number of threads permitted inside of InnoDB. A value # of 0 (the default) is interpreted as infinite concurrency (no limit). This # variable is intended for performance tuning on high concurrency systems. # InnoDB tries to keep the number of threads inside InnoDB less than or equal to # the innodb_thread_concurrency limit. Once the limit is reached, additional threads # are placed into a "First In, First Out" (FIFO) queue for waiting threads. Threads # waiting for locks are not counted in the number of concurrently executing threads. innodb_thread_concurrency=25 # The increment size (in MB) for extending the size of an auto-extend InnoDB system tablespace file when it becomes full. innodb_autoextend_increment=64 # The number of regions that the InnoDB buffer pool is divided into. # For systems with buffer pools in the multi-gigabyte range, dividing the buffer pool into separate instances can improve concurrency, # by reducing contention as different threads read and write to cached pages. innodb_buffer_pool_instances=8 # Determines the number of threads that can enter InnoDB concurrently. innodb_concurrency_tickets=5000 # Specifies how long in milliseconds (ms) a block inserted into the old sublist must stay there after its first access before # it can be moved to the new sublist. innodb_old_blocks_time=1000 # When this variable is enabled, InnoDB updates statistics during metadata statements. innodb_stats_on_metadata=0 # When innodb_file_per_table is enabled (the default in 5.6.6 and higher), InnoDB stores the data and indexes for each newly created table # in a separate .ibd file, rather than in the system tablespace. innodb_file_per_table=1 # Use the following list of values: 0 for crc32, 1 for strict_crc32, 2 for innodb, 3 for strict_innodb, 4 for none, 5 for strict_none. innodb_checksum_algorithm=0 # If this is set to a nonzero value, all tables are closed every flush_time seconds to free up resources and # synchronize unflushed data to disk. # This option is best used only on systems with minimal resources. flush_time=0 # The minimum size of the buffer that is used for plain index scans, range index scans, and joins that do not use # indexes and thus perform full table scans. join_buffer_size=256K # The maximum size of one packet or any generated or intermediate string, or any parameter sent by the # mysql_stmt_send_long_data() C API function. max_allowed_packet=64M # If more than this many successive connection requests from a host are interrupted without a successful connection, # the server blocks that host from performing further connections. max_connect_errors=100 # The number of file descriptors available to mysqld from the operating system # Try increasing the value of this option if mysqld gives the error "Too many open files". open_files_limit=8161 # If you see many sort_merge_passes per second in SHOW GLOBAL STATUS output, you can consider increasing the # sort_buffer_size value to speed up ORDER BY or GROUP BY operations that cannot be improved with query optimization # or improved indexing. sort_buffer_size=256K # Specify the maximum size of a row-based binary log event, in bytes. # Rows are grouped into events smaller than this size if possible. The value should be a multiple of 256. binlog_row_event_max_size=8K # If the value of this variable is greater than 0, a replica synchronizes its master.info file to disk. # (using fdatasync()) after every sync_source_info events. sync_source_info=10000 # If the value of this variable is greater than 0, the MySQL server synchronizes its relay log to disk. # (using fdatasync()) after every sync_relay_log writes to the relay log. sync_relay_log=10000 # Load mysql plugins at start."plugin_x ; plugin_y". # plugin_load # The TCP/IP Port the MySQL Server X Protocol will listen on. 这就是配置文件内容
10-03
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值