高并发服务器架构

    设计一个稳定,高效的服务器,需要考虑很多的方面,不管是系统方面的,还是代码方面的。那么究竟有哪些?
    一: 导致服务器低效的四个罪魁祸首:数据拷贝,(用户态/内核态切换)上下文切换,内存管理,锁竞争;
    数据拷贝
        ---首先提下零拷贝。零拷贝( zero-copy ),某种程度上来说可以有效的改善数据传输的性能,在内核驱动程序(比如网络堆栈或者磁盘存储驱动程序)处理 I/O 数据的时候,零拷贝技术可以在某种程度上减少甚至完全避免不必要 CPU 数据拷贝操作。零拷贝已经是比较成熟的技术,目前有很多高性能的网络I/O框架已经实现了这一技术,如netmap.
        ---尽管所有人都知道数据拷贝是不好的,但理解上还是有些细微的差别,最重要的是,数据拷贝通常是隐藏在调用驱动或者其他的库代码的时候,你能确定没有进行数据拷贝操作?也许这比你想象的要多.
        ---避免数据拷贝的真正有用的方法是使用间接的,传递buff描述符(或者buff链表描述符)来取代大量的指针,每个描述符包含以下几个方面:
        (1)指buff针以及整个buff的长度;
        (2)指针和长度,或者指针偏移地址和长度(一般是buff已经部分被填充);
        (3)buff链表的prev,next;
        (4)引用计数;
        ---与其拷贝内存中的数据,不如在正确的描述符上简单的递增引用计数,在某些条件下,它工作的很好,如典型的网络协议栈操作,但也有可能他会令你头痛。通常来说,在buff链表的头尾添加新的buff,为整块buff添加引用计数,释放整块buff是比较容易的操作;而在中间添加新的buff,一块一块的释放buff,或者引用部分buff是很困难的;如果让你尝试切割或者组合buff能让你发疯。
        ---并不推荐你在任何地方使用这种方法,为什么呢?因为每次查找buff时,你需要从链表头部遍历,直到找到那个为止,比起数据拷贝,它的开销更大。我认为更好的方法是分配一个足够大的对象,比如说内存块,无需数据拷贝,他实现起来要容易的多(如环形缓存);
        ---不要刻意的避免数据拷贝,很多代码因刻意去避免,使得效率更低,如强制上下文切换,中断一个大的I/O操作,数据拷贝是昂贵的,你需要梳理你的代码,去除那些耗时却只涉及少量的数据拷贝的代码,这个比其他方法要好的多。
        上下文切换
        ---鉴于每个人都理所当然的任务数据拷贝是非常耗性能的,我非常奇怪有多少人会忽略上下文切换给性能带来的影响。根据以往的经验来看,相对于数据拷贝来说,在高负载的时候过多的上下文切换更是灾难性的,系统需要花费更多的时间从一个线程切换到另外一个线程,而且这个时间比实际工作的时间还要多。更疯狂的是,在某种程度上来说,导致上线问切换的原因是显而易见的。其中之一是过多的活动线程在你的处理器上,活动线程越多,上下文切换的更厉害,如果你足够幸运,上下文切换次数成直线上升,而大部分的情况是成指数上升的。这样就很容易解释为什么多线程设计成为每一个连接分配一个线程(mysql 应该算是比较典型)。现实中比较明智的选择是限制系统中活动线程的数量,通常来说,小于或者等于你处理器的数量。一种比较常用的方法是只使用一个线程,它既避免了上线文切换,而且无需加锁,但是它无法重复利用多处理器的优势,除非你的程序是非CPU密集型。
        ---首先需要解决的是:“线程节约型”程序一个线程是怎样同时处理多个连接,通常前端用 sleect/poll,asynchronous I/O, signals or completion port,这些一般都是基于事件驱动的。至于使用哪些前端的API是最好的, C10K paper 也许可以帮助到你。以我个人来说,我认为select/poll 以及singals都是些丑陋的伎俩(或许那时候还没有出现epoll吧),我比较倾向的是使用AIO,completion port。使用并不重要,如果他们喜欢使用sleect(),只要它在程序中工作的很好,都可以理解。不要太纠结于你程序前端的最外层做了什么。
        ---多线程事件驱动服务器是最简单的概念模型,中心有一个队列,所有的请求被一个或者多个监听线程(类似线程池)读取并放入队列中,然后通过一个或者多个工作线程移除,处理。概念上来说,这是一个不错的模型。但是所有人都频繁的使用这个模型实现他们的代码。为什么会错?因为在工作线程中从一个线程切换到另外一个线程会产生上线文切换。有些人甚至错上加错的将请求的回复通过原始线程发送-这样导致每个请求产生两次上下文切换。给定一个线程从监听者到工作者又回到监听者的过程中而不改变上下文,使用这种对称的方法是很重要的。是否涉及线程间分开连接或者所有线程作为监听者是否轮流工作对于整组连接就显得不是那么重要了。
        ---通常来说,即使在下一时刻很难知道当前有多少个线程将会被激活,毕竟,请求能在任一时刻,通过任一连接发过来,或者各种守护任务的后台专属线程能在某个时刻处理并唤醒它。如果你不知道当前有多少活动线程,你如何去限制活动线程个数? 以我的以经验,最有效的方法也是最简单的办法:使用老式的计数信号,每个线程都会持有它本身真正的工作。如果已经达到线程个数上限,每一个监听模式的线程当被唤醒并阻塞信号,此时会触发一次额外上下文切换,一旦所有监听模式的线程已经以这样的方式阻塞信号,它们就不会继续再竞争资源,直到其中有一个线程释放信号。它对系统的影响是微不足道的,更重要的是,这个维护线程处理的方法在大部分时间都是休眠的,对当前活动线程影响比较小。这个方法比其他的可选的方法要好的多。(按我的理解,可能是通过计数的方式才统计当前的活动线程数量吧,早期也确实这么做过,创建一个守护线程,根据CPU的负载情况来调节线程个数)。
        ---一旦请求被分解为2个阶段(监听,工作),可能会有多个线程为其服务。自然而然的,这个处理可能会进一步分解为不止两个阶段。在最简单的形式中,对请求的处理,在一个方向上持续的调用一个阶段,并且不断的重复,从而成为了一个问题。然而,更复杂的是,一个阶段可能会表现出两个处理路径,他们分别调用下一个不同的阶段,或者生成一个回复而不调用下一个阶段。因此,每个阶段需要为请求指定下一步会发生什么。以下有三种可能性,通过各个阶段的返回值来表现:
        (1)请求需要过渡到下一个阶段,返回ID或者指针;
        (2)请求已完成,返回一个指定的完成代码;
        (3)请求被阻塞,其等价于上一个情况,只是这个请求未被释放,并且发送到其他线程等待下一步处理,类似于线程间通信。
        需要注意的是,在这个模型中,查询请求是在阶段内完成的,而不是在阶段间,这样可以避免常见的诟病:不断的将请求放入到一个后续极端队列中,然后立即调用后续阶段并将请求出列,我称此为大量的活动队列-死锁。
        内存管理:
        ---内存分配和释放在大多数应用程序中是很平常的操作。因此,许多聪明的技巧已经应用到一些通用高效的内存分配器中。不管怎样,聪明的技巧可以弥补分配器的一般性必然比大多数可选的内存分配器低效这个事实。因此我有三个避免完全使用系统内存分配器的建议:
        (1)简单的预分配;我们知道在程序功能上人为的限制静态分配是不好的,但这却有许多其他的看起来不错的预分配形式。通常这归结于一个事实,通过系统内存分配也许会比少数,甚至是当一些内存‘浪费’在进程中情况要好。因此可以断言,可能只是N项会使用一次,因此在程序启动时预分配是一个可选的选择。即便不是那种情况,开始时预分配好一切也比在使用时分配要好,除非使用系统内存分配器一次连续的分配多块内存,这样大大的简化了错误恢复的代码。如果内存紧张,那么预分配不是一个很好的选择,但在大多数极端的情况下也是被证明是可行的。
        (2)针对频繁分配和释放的对象使用空闲列表,其基本的原理是把最近使用过的对象放入列表而不是释放它,如果希望再次使用的时候,可从列表中取出而不是重新从系统中分配一块内存。另外的好处是,从空闲列表中取出和放回还省去了构造/析构的调用开销。
        (3)事实上需要加锁处理,如果是在多线程程序中。我们可以为每个线程申请一个私有的空闲列表,那么这个列表只会有一个线程访问,无需加锁了。
        锁竞争:
        ---高效的锁定方案设计是出了名的难,因为我把它比作为“奥德赛”的两个怪物物后斯库拉和卡律布狄斯。斯库拉是过于简单化以及粒度比较粗的,序列化,可并行的操作,并因此牺牲性能和可扩展性;相反,卡律布狄斯是过于复杂以及粒度比较细,锁操作时间和空间再次削弱程序性能。靠近斯库拉是死锁和活锁条件的浅滩;靠近卡律布狄斯处是竞太条件的浅滩。这两者之间有一个狭窄的通道,代表既高效有正确的正确的方式,真的存在么?由于锁跟程序本身有这密切的关系,它往往不能从根本上改变程序是如何工作的,不可能设计一个良好的解决方案。这也是为何人们讨厌锁,而且试图给自己理由去使用单线程方法的原因。如果更高效?原文中给了一个方法,大概就是也是通过某种方法找到代码和性能的平衡点。
        此文只是在我现有的水平下对原文的一些翻译理解,如有误导,请见谅!
        参考: 
整理的高性能高并发服务器架构文章,内容预览:  初创网站与开源软件 6  谈谈大型高负载网站服务器的优化心得! 8  Lighttpd+Squid+Apache搭建高效率Web服务器 9  浏览量比较大的网站应该从哪几个方面入手? 17  用负载均衡技术建设高负载站点 20  大型网站的架构设计问题 25  开源平台的高并发集群思考 26  大型、高负载网站架构和应用初探 时间:30-45分钟 27  说说大型高并发高负载网站的系统架构 28  mixi技术架构 51 mixi.jp:使用开源软件搭建的可扩展SNS网站 51 总概关键点: 51 1,Mysql 切分,采用Innodb运行 52 2,动态Cache 服务器 -- 52 美国Facebok.com,中国Yeejee.com,日本mixi.jp均采用开源分布式缓存服务器Memcache 52 3,图片缓存和加 52  memcached+squid+apache deflate解决网站大访问量问题 52  FeedBurner:基于MySQL和JAVA的可扩展Web应用 53  YouTube 的架构扩展 55  了解一下 Technorati 的后台数据库架构 57  Myspace架构历程 58  eBay 的数据量 64  eBay 的应用服务器规模 67  eBay 的数据库分布扩展架构 68  从LiveJournal后台发展看大规模网站性能优化方法 70 一、LiveJournal发展历程 70 二、LiveJournal架构现状概况 70 三、从LiveJournal发展中学习 71 1、一台服务器 71 2、两台服务器 72 3、四台服务器 73 4、五台服务器 73 5、更多服务器 74 6、现在我们在哪里: 75 7、现在我们在哪里 78 8、现在我们在哪里 79 9、缓存 80 10、Web访问负载均衡 80 11、MogileFS 81  Craigslist 的数据库架构 81  Second Life 的数据拾零 82  eBay架构的思想金矿 84  一天十亿次的访问-eBay架构(一) 85  七种缓存使用武器 为网站应用和访问加速发布时间: 92  可缓存的CMS系统设计 93  开发大型高负载类网站应用的几个要点 105  Memcached和Lucene笔记 110  使用开源软件,设计高性能可扩展网站 110  面向高负载的架构Lighttpd+PHP(FastCGI)+Memcached+Squid 113  思考高并发高负载网站的系统架构 113  "我在SOHU这几年做的一些门户级别的程序系统(C/C++开发)" 115  中国顶级门户网站架构分析1 116  中国顶级门户网站架构分析 2 118  服务器的大用户量的承载方案 120  YouTube Scalability Talk 121  High Performance Web Sites by Nate Koechley 123 One dozen rules for faster pages 123 Why talk about performance? 123 Case Studies 124 Conclusion 124  Rules for High Performance Web Sites 124  对于应用高并发,DB千万级数量该如何设计系统哪? 125  高性能服务器设计 130  优势与应用:再谈CDN镜像加速技术 131  除了程序设计优化,zend+ eacc(memcached)外,有什么办法能提高服务器的负载能力呢? 135  如何规划您的大型JAVA多并发服务器程序 139  如何架构一个“Just so so”的网站? 148  最便宜的高负载网站架构 152  负载均衡技术全攻略 154  海量数据处理分析 164  一个很有意义的SQL的优化过程(一个电子化支局中的大数据量的统计SQL) 166  如何优化大数据量模糊查询(架构,数据库设置,SQL..) 168  求助:海量数据处理方法 169 # re: 求助:海量数据处理方法 回复 更多评论 169  海量数据库查询方略 169  SQL Server 2005对海量数据处理 170  分表处理设计思想和实现 174  Linux系统高负载 MySQL数据库彻底优化(1) 179  大型数据库的设计与编程技巧 本人最近开发一个访问统计系统,日志非常的大,都保存在数据库里面。 我现在按照常规的设计方法对表进行设计,已经出现了查询非常缓慢地情形。 大家对于这种情况如何来设计数据库呢?把一个表分成多个表么?那么查询和插入数据库又有什么技巧呢? 谢谢,村里面的兄弟们! 183  方案探讨,关于工程中数据库的问题. 184  web软件设计时考虑你的性能解决方案 190  大型Java Web系统服务器选型问题探讨 193  高并发高流量网站架构 210 1.1 互联网的发展 210 1.2 互联网网站建设的新趋势 210 1.3 新浪播客的简介 211 2.1 镜像网站技术 211 2.2 CDN内容分发网络 213 2.3 应用层分布式设计 214 2.4 网络层架构小结 214 3.1 第四层交换简介 214 3.2 硬件实现 215 3.3 软件实现 215  网站架构的高性能和可扩展性 233  资料收集:高并发 高性能 高扩展性 Web 2.0 站点架构设计及优化策略 243  CommunityServer性能问题浅析 250 鸡肋式的多站点支持 250 内容数据的集中式存储 250 过于依赖缓存 250 CCS的雪上加霜 250 如何解决? 251  Digg PHP's Scalability and Performance 251  YouTube Architecture 253 Information Sources 254 Platform 254 What's Inside? 254 The Stats 254 Recipe for handling rapid growth 255 Web Servers 255 Video Serving 256 Serving Video Key Points 257 Serving Thumbnails 257 Databases 258 Data Center Strategy 259 Lessons Learned 260 1. Jesse • Comments (78) • April 10th 261 Library 266 Friendster Architecture 273 Information Sources 274 Platform 274 What's Inside? 274 Lessons Learned 274  Feedblendr Architecture - Using EC2 to Scale 275 The Platform 276 The Stats 276 The Architecture 276 Lesson Learned 277 Related Articles 278 Comments 279 Re: Feedblendr Architecture - Using EC2 to Scale 279 Re: Feedblendr Architecture - Using EC2 to Scale 279 Re: Feedblendr Architecture - Using EC2 to Scale 280  PlentyOfFish Architecture 281 Information Sources 282 The Platform 282 The Stats 282 What's Inside 283 Lessons Learned 286  Wikimedia architecture 288 Information Sources 288 Platform 288 The Stats 289 The Architecture 289 Lessons Learned 291  Scaling Early Stage Startups 292 Information Sources 293 The Platform 293 The Architecture 293 Lessons Learned 294  Database parallelism choices greatly impact scalability 295  Introduction to Distributed System Design 297 Table of Contents 297 Audience and Pre-Requisites 298 The Basics 298 So How Is It Done? 301 Remote Procedure Calls 305 Some Distributed Design Principles 307 Exercises 308 References 309  Flickr Architecture 309 Information Sources 309 Platform 310 The Stats 310 The Architecture 311 Lessons Learned 316 Comments 318 How to store images? 318 RE: How to store images? 318  Amazon Architecture 319 Information Sources 319 Platform 320 The Stats 320 The Architecture 320 Lessons Learned 324 Comments 329 Jeff.. Bazos? 329 Werner Vogels, the CTO of 329 Re: Amazon Architecture 330 Re: Amazon Architecture 330 Re: Amazon Architecture 330 It's WSDL 330 Re: It's WSDL 331 Re: Amazon Architecture 331  Scaling Twitter: Making Twitter 10000 Percent Faster 331 Information Sources 332 The Platform 332 The Stats 333 The Architecture 333 L
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值