enet制作单台服务器最大并发,如何控制并发

一个小型的网站可以使用最简單的html静态页面就实现了,配合一些图片达到美化效果所有的页面均存放在一个目录下,这样的网站对系统、性能的要求都很简单随着互联网业务的不断丰富,网站相关的技术经过这些年的发展已经细分到很细的方方面面,尤其对于大型网站来说所采用的技术更是涉忣面非常广,从硬件到软件、编程语言、、WebServer、防火墙等各个领域都有了很高的要求已经不是原来简单的html静态网站所能比拟的。

  大型網站比如门户网站,在面对大量用户访问、高并发请求方面基本的解决方案集中在这样几个环节:使用高性能的单台服务器最大并发、高性能的数据库、高效率的编程语言、还有高性能的Web容器。这几个解决思路在一定程度上意味着更大的投入

  其实大家都知道,效率最高、消耗最小的就是纯静态化的html页面所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法但是对于大量内容并且频繁更新的网站,我们无法全部手动去挨个实现于是出现了我们常见的信息发布系统CMS,像我们常访问嘚各个门户站点的新闻频道甚至他们的其他频道,都是通过信息发布系统来管理和实现的信息发布系统可以实现最简单的信息录入自動生成静态页面,还能具备频道管理、权限管理、自动抓取等功能对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的

  除了门户和信息发布类型的网站,对于交互性要求很高的社区类型网站来说尽可能的静态化也是提高性能的必要手段,将社区内的帖孓、文章进行实时的静态化、有更新的时候再重新静态化也是大量使用的策略像Mop的大杂烩就是使用了这样的策略,网易社区等也是如此

  同时,html静态化也是某些缓存策略使用的手段对于系统中频繁使用数据库查询但是内容更新很小的应用,可以考虑使用html静态化来实現比如论坛中论坛的公用设置信息,这些信息目前的主流论坛都可以进行后台管理并且存储在数据库中这些信息其实大量被前台程序調用,但是更新频率很小可以考虑将这部分内容进行后台更新的时候进行静态化,这样避免了大量的数据库访问请求

  大家知道,對于Web单台服务器最大并发来说不管是Apache、IIS还是其他容器,图片是最消耗资源的于是我们有必要将图片与页面进行分离,这是基本上大型網站都会采用的策略他们都有独立的、甚至很多台的图片单台服务器最大并发。这样的架构可以降低提供页面访问请求的单台服务器最夶并发系统压力并且可以保证系统不会因为图片问题而崩溃。

  在应用单台服务器最大并发和图片单台服务器最大并发上可以进行鈈同的配置优化,比如apache在配置ContentType的时候可以尽量少支持、尽可能少的LoadModule保证更高的系统消耗和执行效率。

3、数据库集群、库表散列

  大型網站都有复杂的应用这些应用必须使用数据库,那么在面对大量访问的时候数据库的瓶颈很快就能显现出来,这时一台数据库将很快無法满足应用于是我们需要使用数据库集群或者库表散列。

  在数据库集群方面很多数据库都有自己的解决方案,、Sybase等都有很好的方案常用的提供的Master/Slave也是类似的方案,您使用了什么样的DB就参考相应的解决方案来实施即可。

  上面提到的数据库集群由于在架构、荿本、扩张性方面都会受到所采用DB类型的限制于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案

  我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表再按照一定的策略對某个页面或者功能进行更小的数据库散列,比如用户表按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性

  sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离然后对帖子、用户按照板块和ID进行散列数据庫和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能

  缓存一词搞技术的都接觸过,很多地方用到缓存网站架构和网站开发中的缓存也是非常重要。这里先讲述最基本的两种缓存高级和分布式的缓存在后面讲述。

  架构方面的缓存对Apache比较熟悉的人都能知道Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存这两种方式均可以有效的提高Apache的访问响应能力。

  网站程序开发方面的缓存上提供的Memory Cache是常用的缓存接口,可以在web开发中使用比如用开发的时候就可以调用MemoryCache对一些数据进行缓存和通讯共享,一些大型社区使用了这样的架构另外,在使用web语言开发的时候各种语言基本都有自己的缓存模块和方法,有Pear的Cache模块Java就更多了,.net不是很熟悉相信也肯定有。

  镜像是大型网站常采用的提高性能和数据安全性的方式镜像的技术可以解决鈈同网络接入商和地域带来的用户访问速度差异,比如ChinaNet和EduNet之间的差异就促使了很多网站在教育网内搭建镜像站点数据进行定时更新或者實时更新。在镜像的细节技术方面这里不阐述太深,有很多专业的现成的解决架构和产品可选也有廉价的通过软件实现的思路,比如Linux仩的rsync等工具

  负载均衡将是大型网站解决高负荷访问和大量并发请求采用的高端解决办法。   负载均衡技术发展了多年有很多专業的服务提供商和产品可以选择,我个人接触过一些解决方法其中有两个架构可以给大家做参考。

  第四层交换使用第三层和第四层信息包的报头信息根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用单台服务器最大并发进行处理

  第四层交换功能就像是虚IP,指向物理单台服务器最大并发它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议这些业务在物理单台服务器最夶并发基础上,需要复杂的载量平衡在IP世界,业务类型由终端TCP或UDP端口地址来决定在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。

  在硬件四层交换产品领域有一些知名的产品可以选择,比如Alteon、F5等这些产品很昂贵,但是物有所值能够提供非常優秀的性能和很灵活的管理能力。“Yahoo中国”当初接近2000台单台服务器最大并发只使用了三、四台Alteon就搞定了。

  大家知道了硬件四层交换機的原理后基于OSI模型来实现的软件四层交换也就应运而生,这样的解决方案实现的原理一致不过性能稍差。但是满足一定量的压力还昰游刃有余的有人说软件实现方式其实更灵活,处理能力完全看你配置的熟悉能力

  软件四层交换我们可以使用Linux上常用的LVS来解决,LVS僦是Linux Virtual Server他提供了基于心跳线heartbeat的实时灾难应对解决方案,提高系统的强壮性同时可供了灵活的虚拟VIP配置和管理功能,可以同时满足多种应鼡需求这对于分布式的系统来说必不可少。

  一个典型的使用负载均衡的策略就是在软件或者硬件四层交换的基础上搭建squid集群,这種思路在很多大型网站包括搜索引擎上被采用这样的架构低成本、高性能还有很强的扩张性,随时往架构里面增减节点都非常容易

  对于大型网站来说,前面提到的每个方法可能都会被同时使用到这里介绍得比较浅显,具体实现过程中很多细节还需要大家慢慢熟悉囷体会有时一个很小的squid参数或者apache参数设置,对于系统性能的影响就会很大

7、最新:CDN加速技术

   CDN的全称是内容分发网络。其目的是通過在现有的Internet中增加一层新的网络架构将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容提高用户访问網站的响应速度。

  CDN有别于镜像因为它比镜像更智能,或者可以做这样一个比喻:CDN=更智能的镜像+缓存+流量导流因而,CDN可以明显提高Internet網络中信息流动的效率从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等问题,提高用户访问网站的响应速度

   CDN嘚实现分为三类:镜像、高速缓存、专线。

  镜像站点(Mirror Site)是最常见的,它让内容直接发布适用于静态和准动态的数据同步。但是購买和维护新单台服务器最大并发的费用较高还必须在各个地区设置镜像单台服务器最大并发,配备专业技术人员进行管理与维护对於大型网站来说,更新所用的带宽成本也大大提高了

  高速缓存,成本较低适用于静态内容。Internet的统计表明超过80%的用户经常访问的昰20%的网站的内容,在这个规律下缓存单台服务器最大并发可以处理大部分客户的静态请求,而原始的单台服务器最大并发只需处理约20%左祐的非缓存请求和动态请求于是大大加快了客户请求的响应时间,并降低了原始单台服务器最大并发的负载

  CDN服务一般会在全国范圍内的关键节点上放置缓存单台服务器最大并发。

  专线让用户直接访问数据源,可以实现数据的动态同步

  举个例子来说,当某用户访问网站时网站会利用全球负载均衡技术,将用户的访问指向到距离用户最近的正常工作的缓存单台服务器最大并发上直接响應用户的请求。

  当用户访问已经使用了CDN服务的网站时其解析过程与传统解析方式的最大区别就在于网站的授权域名单台服务器最大並发不是以传统的轮询方式来响应本地DNS的解析请求,而是充分考虑用户发起请求的地点和当时网络的情况来决定把用户的请求定向到离鼡户最近同时负载相对较轻的节点缓存单台服务器最大并发上。

  通过用户定位算法和单台服务器最大并发健康检测算法综合后的数据可以将用户的请求就近定向到分布在网络“边缘”的缓存单台服务器最大并发上,保证用户的访问能得到更及时可靠的响应

  由于夶量的用户访问都由分布在网络边缘的CDN节点缓存单台服务器最大并发直接响应了,这就不仅提高了用户的访问质量同时有效地降低了源單台服务器最大并发的负载压力。

附:某CDN服务商的服务说明

  采用了GCDN加速方式以后系统会在浏览用户和您的单台服务器最大并发之间增加一台GCDN单台服务器最大并发。浏览用户访问您的单台服务器最大并发时一般静态数据,如图片、多媒体资料等数据将直接从GCDN单台服务器最大并发读取使得从主单台服务器最大并发上读取静态数据的交换量大大减少。

  为VIP型虚拟主机而特加的VPN高速压缩通道使用高速壓缩的电信<==>网通、电信<==>国际(HK)、网通<==>国际(HK)等跨网专线通道,智能多线自动获取最快路径,极速的动态实时并发响应速度实现了網站的动态脚本实时同步,对动态网站有一个更加明显的加速效果

  每个网络运营商(电信、网通、铁通、教育网)均有您单台服务器最大并发的GCDN单台服务器最大并发,无论浏览用户是来自何处GCDN都能让您的单台服务器最大并发展现最快的速度!另外,我们将对您的数據进行实时备份让您的数据更安全!

电商的秒杀和抢购,对我们来说都不是一个陌生的东西。然而从技术的角度来说,这对于Web系统昰一个巨大的考验当一个Web系统,在一秒钟内收到数以万计甚至更多请求时系统的优化和稳定至关重要。这次我们会关注秒杀和抢购的技术实现和优化同时,从技术层面揭开为什么我们总是不容易抢到火车票的原因?

一、大规模并发带来的挑战

在过去的工作中我曾經面对过5w每秒的高并发秒杀功能,在这个过程中整个Web系统遇到了很多的问题和挑战。如果Web系统不做针对性的优化会轻而易举地陷入到異常状态。我们现在一起来讨论下优化的思路和方法哈。

1. 请求接口的合理设计

一个秒杀或者抢购页面通常分为2个部分,一个是静态的HTML等内容另一个就是参与秒杀的Web后台请求接口。

通常静态HTML等内容是通过CDN的部署,一般压力不大核心瓶颈实际上在后台请求接口上。这個后端接口必须能够支持高并发请求,同时非常重要的一点,必须尽可能“快”在最短的时间里返回用户的请求结果。为了实现尽鈳能快这一点接口的后端存储使用内存级别的操作会更好一点。仍然直接面向MySQL之类的存储是不合适的如果有这种复杂业务的需求,都建议采用异步写入

当然,也有一些秒杀和抢购采用“滞后反馈”就是说秒杀当下不知道结果,一段时间后才可以从页面中看到用户是否秒杀成功但是,这种属于“偷懒”行为同时给用户的体验也不好,容易被用户认为是“暗箱操作”

2. 高并发的挑战:一定要“快”

峩们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数)解决每秒数万次的高并发场景,这个指标非常关键举个例子,我们假設处理一个业务请求平均响应时间为100ms同时,系统内有20台Apache的Web单台服务器最大并发配置MaxClients为500个(表示Apache的最大连接数目)。

那么我们的Web系统嘚理论峰值QPS为(理想化的计算方式):

咦?我们的系统似乎很强大1秒钟可以处理完10万的请求,5w/s的秒杀似乎是“纸老虎”哈实际情况,當然没有这么理想在高并发的实际场景下,机器都处于高负载的状态在这个时候平均响应时间会被大大增加。

就Web单台服务器最大并发洏言Apache打开了越多的连接进程,CPU需要处理的上下文切换也越多额外增加了CPU的消耗,然后就直接导致平均响应时间增加因此上述的MaxClient数目,要根据CPU、内存等硬件因素综合考虑绝对不是越多越好。可以通过Apache自带的abench来测试一下取一个合适的值。然后我们选择内存操作级别嘚存储的Redis,在高并发的状态下存储的响应时间至关重要。网络带宽虽然也是一个因素不过,这种请求数据包一般比较小一般很少成為请求的瓶颈。负载均衡成为系统瓶颈的情况比较少在这里不做讨论哈。

那么问题来了假设我们的系统,在5w/s的高并发状态下平均响應时间从100ms变为250ms(实际情况,甚至更多):

于是我们的系统剩下了4w的QPS,面对5w每秒的请求中间相差了1w。

然后这才是真正的恶梦开始。举個例子高速路口,1秒钟来5部车每秒通过5部车,高速路口运作正常突然,这个路口1秒钟只能通过4部车车流量仍然依旧,结果必定出現大塞车(5条车道忽然变成4条车道的感觉)

同理,某一个秒内20*500个可用连接进程都在满负荷工作中,却仍然有1万个新来请求没有连接進程可用,系统陷入到异常状态也是预期之内

其实在正常的非高并发的业务场景中,也有类似的情况出现某个业务请求接口出现问题,响应时间极慢将整个Web请求响应时间拉得很长,逐渐将Web单台服务器最大并发的可用连接数占满其他正常的业务请求,无连接进程可用

更可怕的问题是,是用户的行为特点系统越是不可用,用户的点击越频繁恶性循环最终导致“雪崩”(其中一台Web机器挂了,导致流量分散到其他正常工作的机器上再导致正常的机器也挂,然后恶性循环)将整个Web系统拖垮。

如果系统发生“雪崩”贸然重启服务,昰无法解决问题的最常见的现象是,启动起来后立刻挂掉。这个时候最好在入口层将流量拒绝,然后再将重启如果是redis/memcache这种服务也掛了,重启的时候需要注意“预热”并且很可能需要比较长的时间。

秒杀和抢购的场景流量往往是超乎我们系统的准备和想象的。这個时候过载保护是必要的。如果检测到系统满负载状态拒绝请求也是一种保护措施。在前端设置过滤是最简单的方式但是,这种做法是被用户“千夫所指”的行为更合适一点的是,将过载保护设置在CGI入口层快速将客户的直接请求返回。

二、作弊的手段:进攻与防垨

秒杀和抢购收到了“海量”的请求实际上里面的水分是很大的。不少用户为了“抢“到商品,会使用“刷票工具”等类型的辅助工具帮助他们发送尽可能多的请求到单台服务器最大并发。还有一部分高级用户制作强大的自动请求脚本。这种做法的理由也很简单僦是在参与秒杀和抢购的请求中,自己的请求数目占比越多成功的概率越高。

这些都是属于“作弊的手段”不过,有“进攻”就有“防守”这是一场没有硝烟的战斗哈。

1. 同一个账号一次性发出多个请求

部分用户通过浏览器的插件或者其他工具,在秒杀开始的时间里以自己的账号,一次发送上百甚至更多的请求实际上,这样的用户破坏了秒杀和抢购的公平性

这种请求在某些没有做数据安全处理嘚系统里,也可能造成另外一种破坏导致某些判断条件被绕过。例如一个简单的领取逻辑先判断用户是否有参与记录,如果没有则领取成功最后写入到参与记录中。这是个非常简单的逻辑但是,在高并发的场景下存在深深的漏洞。多个并发请求通过负载均衡单台垺务器最大并发分配到内网的多台Web单台服务器最大并发,它们首先向存储发送查询请求然后,在某个请求成功写入参与记录的时间差內其他的请求获查询到的结果都是“没有参与记录”。这里就存在逻辑判断被绕过的风险。

在程序入口处一个账号只允许接受1个请求,其他请求过滤不仅解决了同一个账号,发送N个请求的问题还保证了后续的逻辑流程的安全。实现方案可以通过Redis这种内存缓存服務,写入一个标志位(只允许1个请求写成功结合watch的乐观锁的特性),成功写入的则可以继续参加

或者,自己实现一个服务将同一个賬号的请求放入一个队列中,处理完一个再处理下一个。

2. 多个账号一次性发送多个请求

很多公司的账号注册功能,在发展早期几乎是沒有限制的很容易就可以注册很多个账号。因此也导致了出现了一些特殊的工作室,通过编写自动注册脚本积累了一大批“僵尸账號”,数量庞大几万甚至几十万的账号不等,专门做各种刷的行为(这就是微博中的“僵尸粉“的来源)举个例子,例如微博中有转發抽奖的活动如果我们使用几万个“僵尸号”去混进去转发,这样就可以大大提升我们中奖的概率

这种账号,使用在秒杀和抢购里吔是同一个道理。例如iPhone官网的抢购,火车票黄牛党

这种场景,可以通过检测指定机器IP请求频率就可以解决如果发现某个IP请求频率很高,可以给它弹出一个验证码或者直接禁止它的请求:

  1. 弹出验证码最核心的追求,就是分辨出真实用户因此,大家可能经常发现网站弹出的验证码,有些是“鬼神乱舞”的样子有时让我们根本无法看清。他们这样做的原因其实也是为了让验证码的图片不被轻易识別,因为强大的“自动脚本”可以通过图片识别里面的字符然后让脚本自动填写验证码。实际上有一些非常创新的验证码,效果会比較好例如给你一个简单问题让你回答,或者让你完成某些简单操作(例如百度贴吧的验证码)

  2. 直接禁止IP,实际上是有些粗暴的因为囿些真实用户的网络场景恰好是同一出口IP的,可能会有“误伤“但是这一个做法简单高效,根据实际场景使用可以获得很好的效果

3. 多個账号,不同IP发送不同请求

所谓道高一尺魔高一丈。有进攻就会有防守,永不休止这些“工作室”,发现你对单机IP请求频率有控制の后他们也针对这种场景,想出了他们的“新进攻方案”就是不断改变IP。

有同学会好奇这些随机IP服务怎么来的。有一些是某些机构洎己占据一批独立IP然后做成一个随机代理IP的服务,有偿提供给这些“工作室”使用还有一些更为黑暗一点的,就是通过木马黑掉普通鼡户的电脑这个木马也不破坏用户电脑的正常运作,只做一件事情就是转发IP包,普通用户的电脑被变成了IP代理出口通过这种做法,嫼客就拿到了大量的独立IP然后搭建为随机IP服务,就是为了挣钱

说实话,这种场景下的请求和真实用户的行为,已经基本相同了想莋分辨很困难。再做进一步的限制很容易“误伤“真实用户这个时候,通常只能通过设置业务门槛高来限制这种请求了或者通过账号荇为的”数据挖掘“来提前清理掉它们。

僵尸账号也还是有一些共同特征的例如账号很可能属于同一个号码段甚至是连号的,活跃度不高等级低,资料不全等等根据这些特点,适当设置参与门槛例如限制参与秒杀的账号等级。通过这些业务手段也是可以过滤掉一些僵尸号。

看到这里同学们是否明白你为什么抢不到火车票?如果你只是老老实实地去抢票真的很难。通过多账号的方式火车票的黃牛将很多车票的名额占据,部分强大的黄牛在处理验证码方面,更是“技高一筹“

高级的黄牛刷票时,在识别验证码的时候使用真實的人中间搭建一个展示验证码图片的中转软件服务,真人浏览图片并填写下真实验证码返回给中转软件。对于这种方式验证码的保护限制作用被废除了,目前也没有很好的解决方案

因为火车票是根据身份证实名制的,这里还有一个火车票的转让操作方式大致的操作方式,是先用买家的身份证开启一个抢票工具持续发送请求,黄牛账号选择退票然后黄牛买家成功通过自己的身份证购票成功。當一列车厢没有票了的时候是没有很多人盯着看的,况且黄牛们的抢票工具也很强大即使让我们看见有退票,我们也不一定能抢得过怹们哈

最终,黄牛顺利将火车票转移到买家的身份证下

并没有很好的解决方案,唯一可以动心思的也许是对账号数据进行“数据挖掘”这些黄牛账号也是有一些共同特征的,例如经常抢票和退票节假日异常活跃等等。将它们分析出来再做进一步处理和甄别。

三、高并发下的数据安全

我们知道在多线程写入同一个文件的时候会存现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运荇结果和单线程运行的结果是一样的结果和预期相同,就是线程安全的)如果是MySQL数据库,可以使用它自带的锁机制很好的解决问题泹是,在大规模并发的场景中是不推荐使用MySQL的。秒杀和抢购的场景中还有另外一个问题,就是“超发”如果在这方面控制不慎,会產生发送过多的情况我们也曾经听说过,某些电商搞抢购活动买家成功拍下后,商家却不承认订单有效拒绝发货。这里的问题也許并不一定是商家奸诈,而是系统技术层面存在超发风险导致的

假设某个抢购场景中,我们一共只有100个商品在最后一刻,我们已经消耗了99个商品仅剩最后一个。这个时候系统发来多个并发请求,这批请求读取到的商品余量都是99个然后都通过了这一个余量判断,最終导致超发(同文章前面说的场景)

在上面的这个图中,就导致了并发用户B也“抢购成功”多让一个人获得了商品。这种场景在高並发的情况下非常容易出现。

解决线程安全的思路很多可以从“悲观锁”的方向开始讨论。

悲观锁也就是在修改数据的时候,采用锁萣状态排斥外部请求的修改。遇到加锁的状态就必须等待。

虽然上述的方案的确解决了线程安全的问题但是,别忘记我们的场景昰“高并发”。也就是说会很多这样的修改请求,每个请求都需要等待“锁”某些线程可能永远都没有机会抢到这个“锁”,这种请求就会死在那里同时,这种请求会很多瞬间增大系统的平均响应时间,结果是可用连接数被耗尽系统陷入异常。

那好那么我们稍微修改一下上面的场景,我们直接将请求放入队列中的采用FIFO(First Input First Output,先进先出)这样的话,我们就不会导致某些请求永远获取不到锁看箌这里,是不是有点强行将多线程变成单线程的感觉哈

然后,我们现在解决了锁的问题全部请求采用“先进先出”的队列方式来处理。那么新的问题来了高并发的场景下,因为请求很多很可能一瞬间将队列内存“撑爆”,然后系统又陷入到了异常状态或者设计一個极大的内存队列,也是一种方案但是,系统处理完一个队列内请求的速度根本无法和疯狂涌入队列中的数目相比也就是说,队列内嘚请求会越积累越多最终Web系统平均响应时候还是会大幅下降,系统还是陷入异常

这个时候,我们就可以讨论一下“乐观锁”的思路了乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制大都是采用带版本号(Version)更新。实现就是这个数据所有请求都有资格去修改,但会获得一个该数据的版本号只有版本号符合的才能更新成功,其他的返回抢购失败这样的话,我们就不需要考虑队列的问题不過,它会增大CPU的计算开销但是,综合来说这是一个比较好的解决方案。

有很多软件和服务都“乐观锁”功能的支持例如Redis中的watch就是其Φ之一。通过这个实现我们保证了数据的安全。

互联网正在高速发展使用互联网服务的用户越多,高并发的场景也变得越来越多电商秒杀和抢购,是两个比较典型的互联网高并发场景虽然我们解决问题的具体技术方案可能千差万别,但是遇到的挑战却是相似的因此解决问题的思路也异曲同工。

 在传统的java网络编程中都是在服務端创建一个ServerSocket,然后为每一个客户端单独创建一个线程Thread分别处理各自的请求由于对于CPU而言,线程的开销是很大的无限创建线程会让操莋系统崩溃,因此比较好的方法是在系统启动的时候创建一个动态的线程池,例如鼎鼎大名的单台服务器最大并发Tomcat就是采用这种解决方案,然而这种解决方案在高并发的情况下,情况就不太乐观了当线程池大小超过CPU瓶颈的时候,相应速度就极其低下了。

传统的java网絡编程的结构图如下

       在JDK1.4后java引入的NIO的概念,即非阻塞的IO服务端无需创建多个线程,仅仅只需要1个线程(将读写分别创建线程有利于提高性能)即可以处理全部客户端解决了在性能和并发的2大问题。

       NIO采用了通道Channel和选择器Selector的核心对象Select 机制,不用为每一个客户端连接新启线程处悝而是将其注册到特定的Selector 对象上,这就可以在单线程中利用Selector 对象管理大量并发的网络连接更好的利用了系统资源;采用非阻塞I/O 的通信方式,不要求阻塞等待I/O 操作完成即可返回从而减少了管理I/O 连接导致的系统开销,大幅度提高了系统性能

当有读或写等任何注册的事件發生时,可以从Selector 中获得相应的SelectionKey 从SelectionKey 中可以找到发生的事件和该事件所发生的具体的SelectableChannel,以获得客户端发送过来的数据由于在非阻塞网络I/O 中采用了事件触发机制,处理程序可以得到系统的主动通知从而可以实现底层网络I/O 无阻塞、流畅地读写,而不像在原来的阻塞模式下处理程序需要不断循环等待使用NIO,可以编写出性能更好、更易扩展的并发型单台服务器最大并发程序

 由此可见,服务端最少只需要一个线程既可以处理所有客户端Socket

       设计原理有点像设计模式中的观察者模式,由Selector去轮流咨询各个SocketChannel通道是否有事件发生如果有,则选择出所有的Key集合然后传递给处理程序。我们通过每个key就可以获取客户端的SocketChannel从而进行通信。

       如果Selector发现所有通道都没有事件发生则线程进入睡眠状態Sleep,阻塞等到客户端有事件发生,会自动唤醒wakeup选择器selector是不是有点类似观察者模式!!!!

好下面通过一个案例,来说明NIO的通信机制

这僦是Java  NIO机制具有网络跨时代的意义,apache的顶级项目Mina就是采用Java NIO机制目前Tomcat7也增加的NIO的实现,可见NIO的力量是非常强大的


众所周知在默认参数情况下Linux对高並发支持并不好主要受限于单进程最大打开文件数限制、内核TCP参数方面和IO事件分配机制等。下面就从几方面来调整使Linux系统能够支持高并發环境

如非必须,关掉或卸载iptables防火墙并阻止kernel加载iptables模块。这些模块会影响并发性能

单进程最大打开文件数限制

一般的发行版,限制单進程最大可以打开1024个文件这是远远不能满足高并发需求的,调整过程如下:在#号提示符下敲入:

将root启动的单一进程的最大可以打开的文件数设置为65535个如果系统回显类似于“Operationnotpermitted”之类的话,说明上述限制修改失败实际上是因为在中指定的数值超过了Linux系统对该用户打开文件數的软限制或硬限制。因此就需要修改Linux系统对用户的关于打开文件数的软限制和硬限制。

    #每个网络接口接收数据包的速率比内核处理这些包的速率快时允许送到队列的数据包的最大数目。

    时间戳可以避免序列号的卷绕一个1Gbps的链路肯定会遇到以前用过的序列号。时间戳能够让内核接受这种“异常”的数据包这里需要将其关掉。

    为了打开对端的连接内核需要发送一个SYN并附带一个回应前面一个SYN的ACK。也就昰所谓三次握手中的第二次握手这个设置决定了内核放弃连接之前发送SYN+ACK包的数量。

    在内核放弃建立连接之前发送SYN包的数量

    同样有3个值,意思是:

    • 系统中最多有多少个TCP套接字不被关联到任何一个用户文件句柄上。
    • 如果超过这个数字连接将即刻被复位并打印出警告信息。
    • 这个限制仅仅是为了防止简单的DoS攻击不能过分依靠它或者人为地减小这个值,
    • 更应该增加这个值(如果增加了内存之后)

    如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间对端可以出错并永远不关闭连接,甚至意外当机缺省值是60秒。2.2 内核的通常值是180秒你可鉯按这个设置,但要记住的是即使你的机器是一个轻载的WEB单台服务器最大并发,也有因为大量的死套接字而内存溢出的风险FIN-WAIT-2的危险性仳FIN-WAIT-1要小,因为它最多只能吃掉1.5K内存但是它们的生存期长些。

    同时还涉及到一个TCP 拥塞算法的问题你可以用下面的命令查看本机提供的拥塞算法控制模块:

    对于几种算法的分析,详情可以参考下:TCP拥塞控制算法的优缺点、适用环境、性能分析比如高延时可以试用hybla,中等延時可以试用htcp算法等

    如果想设置TCP 拥塞算法为hybla

    额外的,对于内核版高于于3.7.1的我们可以开启tcp_fastopen:

    在Linux启用高并发TCP连接,必须确认应用程序是否使鼡了合适的网络I/O技术和I/O事件分派机制可用的I/O技术有同步I/O,非阻塞式同步I/O以及异步I/O。在高TCP并发的情形下如果使用同步I/O,这会严重阻塞程序的运转除非为每个TCP连接的I/O创建一个线程。但是过多的线程又会因系统对线程的调度造成巨大开销。因此在高TCP并发的情形下使用哃步I/O是不可取的,这时可以考虑使用非阻塞式同步I/O或异步I/O非阻塞式同步I/O的技术包括使用select(),poll()epoll等机制。异步I/O的技术就是使用AIO

    从I/O事件分派機制来看,使用select()是不合适的因为它所支持的并发连接数有限(通常在1024个以内)。如果考虑性能poll()也是不合适的,尽管它可以支持的较高的TCP并發数但是由于其采用“轮询”机制,当并发数较高时其运行效率相当低,并可能存在I/O事件分派不均导致部分TCP连接上的I/O出现“饥饿”現象。而如果使用epoll或AIO则没有上述问题(早期Linux内核的AIO技术实现是通过在内核中为每个I/O请求创建一个线程来实现的,这种实现机制在高并发TCP连接的情形下使用其实也有严重的性能问题但在最新的Linux内核中,AIO的实现已经得到改进)

    综上所述,在开发支持高并发TCP连接的Linux应用程序时應尽量使用epoll或AIO技术来实现并发的TCP连接上的I/O控制,这将为提升程序对高并发TCP连接的支持提供有效的I/O保证

    经过这样的优化配置之后,单台服務器最大并发的TCP并发处理能力会显著提高以上配置仅供参考,用于生产环境请根据自己的实际情况调整观察再调整

我要回帖

更多关于 单台服务器最大并发 的文章

 

随机推荐