读 www.52im.net/thread-561-… 笔记。html
一个tcp链接都要占一个文件描述符,一旦这个文件描述符使用完了,新的链接到来返回给咱们的错误是“Socket/File:Can't open so many files”
。linux
进程限制shell
执行 ulimit -n 输出 1024,说明对于一个进程而言最多只能打开1024个文件,因此你要采用此默认配置最多也就能够并发上千个TCP链接。临时修改:ulimit -n 1000000,可是这种临时修改只对当前登陆用户目前的使用环境有效,系统重启或用户退出后就会失效。编程
重启后失效的修改(不过我在CentOS 6.5下测试,重启后未发现失效),编辑 /etc/security/limits.conf 文件, 修改后内容为:数组
soft nofile 1000000
hard nofile 1000000
复制代码
永久修改:编辑/etc/rc.local,在其后添加以下内容:缓存
ulimit -SHn 1000000
复制代码
全局限制服务器
执行 cat /proc/sys/fs/file-nr
输出 9344 0 592026,分别为:网络
但在kernel 2.6版本中第二项的值总为0,这并非一个错误,它实际上意味着已经分配的文件描述符无一浪费的都已经被使用了 。多线程
咱们能够把这个数值改大些,用 root 权限修改 /etc/sysctl.conf
文件:架构
fs.file-max = 1000000
net.ipv4.ip_conntrack_max = 1000000
net.ipv4.netfilter.ip_conntrack_max = 1000000
复制代码
最初的服务器都是基于进程/线程模型的,新到来一个TCP链接,就须要分配1个进程(或者线程)。而进程又是操做系统最昂贵的资源,一台机器没法建立不少进程。若是是C10K就要建立1万个进程,那么单机而言操做系统是没法承受的(每每出现效率低下甚至彻底瘫痪)。
建立的进程线程多了,数据拷贝频繁(缓存I/O、内核将数据拷贝到用户进程空间、阻塞), 进程/线程上下文切换消耗大, 致使操做系统崩溃,这就是C10K问题的本质!
可见,解决C10K问题的关键就是尽量减小这些CPU等核心计算资源消耗,从而榨干单台服务器的性能,突破C10K问题所描述的瓶颈。
思路:每一个进程/线程同时处理多个链接(IO多路复用)
该思路的实现存在如下历程:
截至目前,40gpbs、32-cores、256G RAM
的X86服务器在Newegg网站上的报价是几千美圆。实际上以这样的硬件配置来看,它彻底能够处理1000万个以上的并发链接,若是它们不能,那是由于你选择了错误的软件,而不是底层硬件的问题。
能够预见在接下来的10年里,由于IPv6协议下每一个服务器的潜在链接数都是数以百万级的,单机服务器处理数百万的并发链接(甚至千万)并不是不可能,但咱们须要从新审视目前主流OS针对网络编程这一块的具体技术实现。
Unix的设计初衷并非通常的服务器操做系统,而是电话网络的控制系统。因为是实际传送数据的电话网络,因此在控制层和数据层之间有明确的界限。问题是咱们如今根本不该该使用Unix服务器做为数据层的一部分。
不要让OS内核执行全部繁重的任务:将数据包处理、内存管理、处理器调度等任务从内核转移到应用程序高效地完成,让诸如Linux这样的OS只处理控制层,数据层彻底交给应用程序来处理。
综上所述,解决C10M问题的关键主要是从下面几个方面入手:
**网卡问题:**经过内核工做效率不高 **解决方案:**使用本身的驱动程序并管理它们,使适配器远离操做系统。
**CPU问题:**使用传统的内核方法来协调你的应用程序是行不通的。 **解决方案:**Linux管理前两个CPU,你的应用程序管理其他的CPU,中断只发生在你容许的CPU上。
**内存问题:**内存须要特别关注,以求高效。 **解决方案:**在系统启动时就分配大部份内存给你管理的大内存页。
以Linux为例,解决的思路就是将控制层交给Linux,应用程序管理数据。应用程序与内核之间没有交互、没有线程调度、没有系统调用、没有中断,什么都没有。
不管是多进程模型仍是多线程模型,都要把全部的调度任务交给操做系统,让操做系统帮咱们分配硬件资源。咱们经常使用的服务器操做系统都属于分时操做系统,调度模型都尽量的追求公平,并无为某一类任务作特别的优化,若是当前系统仅仅运行某一特定任务的时候,默认的调度策略可能会致使必定程度上的性能损失。我运行一个A任务,第一个调度周期在0号核心上运行,第二个调度周期可能就跑到1号核心上去了,这样频繁的调度可能会形成大量的上下文切换,从而影响到必定的性能。
数据局域性是一样相似的问题。当前x86服务器以NUMA架构为主,这种平台架构下,每一个CPU有属于本身的内存,若是当前CPU须要的数据须要到另一颗CPU管理的内存获取,必然增长一些延时。因此咱们尽量的尝试让咱们的任务和数据在始终在相同的CPU核心和相同的内存节点上,Linux提供了sched_set_affinity
函数,咱们能够在代码中,将咱们的任务绑定在指定的CPU核心上。一些Linux发行版也在用户态中提供了numactl
和taskset
工具,经过它们也很容易让咱们的程序运行在指定的节点上。
这些技术都是近些年来为了优化Linux网络方面的性能而添加的特性,RPS、RFS、XPS都是Google贡献给社区,RSS须要硬件的支持,目前主流的网卡都已支持,即俗称的多队列网卡,充分利用多个CPU核心,让数据处理的压力分布到多个CPU核心上去。
RPS和RFS在linux2.6.35的版本被加入,通常是成对使用的,在不支持RSS特性的网卡上,用软件来模拟相似的功能,而且将相同的数据流绑定到指定的核心上,尽量提高网络方面处理的性能。XPS特性在linux2.6.38的版本中被加入,主要针对多队列网卡在发送数据时的优化,当你发送数据包时,能够根据CPU MAP来选择对应的网卡队列,低于指定的kernel版本可能没法使用相关的特性,可是发行版已经backport这些特性。
关于IRQ的优化,这里主要有两点,第一点是关于中断合并。在比较早期的时候,网卡每收到一个数据包就会触发一个中断,若是小包的数据量特别大的时候,中断被触发的数量也变的十分可怕。大部分的计算资源都被用于处理中断,致使性能降低。后来引入了NAPI和Newernewer NAPI特性,在系统较为繁忙的时候,一次中断触发后,接下来用轮循的方式读取后续的数据包,以下降中断产生的数量,进而也提高了处理的效率。第二点是IRQ亲和性,和咱们前面提到了CPU亲和性较为相似,是将不一样的网卡队列中断处理绑定到指定的CPU核心上去,适用于拥有RSS特性的网卡。
这里再说说关于网络卸载的优化,目前主要有TSO、GSO、LRO、GRO这几个特性,先说说TSO,以太网MTU通常为1500,减掉TCP/IP的包头,TCP的MaxSegment Size为1460,一般状况下协议栈会对超过1460的TCP Payload进行分段,保证最后生成的IP包不超过MTU的大小,对于支持TSO/GSO的网卡来讲,协议栈就再也不须要这样了,能够将更大的TCPPayload发送给网卡驱动,而后由网卡进行封包操做。经过这个手段,将须要在CPU上的计算offload到网卡上,进一步提高总体的性能。GSO为TSO的升级版,不在局限于TCP协议。LRO和TSO的工做路径正好相反,在频繁收到小包时,每次一个小包都要向协议栈传递,对多个TCPPayload包进行合并,而后再传递给协议栈,以此来提高协议栈处理的效率。GRO为LRO的升级版本,解决了LRO存在的一些问题。这些特性都是在必定的场景下才能够发挥其性能效率,在不明确本身的需求的时候,开启这些特性反而可能形成性能降低。
关于Kernel的网络相关优化咱们就不过多的介绍了,主要的内核网络参数的调整在如下两处:net.ipv4.*参数和net.core.*参数。
主要用于调节一些超时控制及缓存等,经过搜索引擎咱们能很容易找到关于这些参数调优的文章,可是修改这些参数是否能带来性能的提高,或者会有什么弊端,建议详细的阅读kernel文档,而且多作一些测试来验证。