转:高并发高负载系统架构

本文作者在Cernet做过拨号接入平台的搭建,而后在Yahoo3721负载搜索引擎前端平台开发,又在猫扑处理过大型社区猫扑大杂烩的架构升级等工作,同时自己接触和开发过不少大中型网站的模块,因此在大型网站应对高负载和并发的解决方案上有一些积累和经验,可以和大家一起探讨一下。

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

  大型网站,比如门户网站。在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节:使用高性能的服务器、高性能的数据库、高效率的编程语言、还有高性能的Web容器。但是除了这几个方面,还没法根本解决大型网站面临的高负载和高并发问题。

  上面提供的几个解决思路在一定程度上也意味着更大的投入,并且这样的解决思路具备瓶颈,没有很好的扩展性,下面我从低成本、高性能和高扩张性的角度来说说我的一些经验。

  1、HTML静态化

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

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

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

  2、图片服务器分离

  大家知道,对于Web服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以进行不同的配置优化,比如apache在配置ContentType的时候可以尽量少支持,尽可能少的LoadModule,保证更高的系统消耗和执行效率。

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

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

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

  上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用DB类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,库表散列是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。sohu的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。

  4、缓存

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

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

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

  5、镜像

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

  6、负载均衡

  负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。

  负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择,我个人接触过一些解决方法,其中有两个架构可以给大家做参考。

  硬件四层交换

  第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。 第四层交换功能就象是虚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参数设置,对于系统性能的影响就会很大,希望大家一起讨论,达到抛砖引玉之效。

随着中国大型IT企业信息化速度的加快,大部分应用的数据量和访问量都急剧增加,大型企业网站正面临性能和高数据访问量的压力,而且对存储、安全以及信息检索等等方面都提出了更高的要求……


    本文中,我想通过几个国外大型IT企业及网站的成功案例,从Web技术人员角度探讨如何积极地应对国内大型网站即将面临的扩展(主要是技术方面,而较少涉及管理及营销等方面)矛盾。 

一、 国外大型IT网站的成功之道 
(一) MySpace 
    今天,MySpace已经成为全球众口皆碑的社区网站之王。尽管一流和营销和管理经验自然是每个IT企业取得成功的首要因素,但是本节中我们却抛弃这一点,而主要着眼于探讨在数次面临系统扩张的紧急关头MySpace是如何从技术方面采取应对策略的。 
第一代架构—添置更多的Web服务器 
    MySpace最初的系统很小,只有两台Web服务器(分担处理用户请求的工作量)和一个数据库服务器(所有数据都存储在这一个地方)。那时使用的是Dell双CPU、4G内存的系统。在早期阶段,MySpace基本是通过添置更多Web服务器来对付用户暴增问题的。但到在2004年早期,在 MySpace用户数增长到五十万后,其数据库服务器已经开始疲于奔命了。 

第二代架构—增加数据库服务器 
    与增加Web服务器不同,增加数据库并没那么简单。如果一个站点由多个数据库支持,设计者必须考虑的是,如何在保证数据一致性的前提下让多个数据库分担压力。

    MySpace运行在三个SQL Server数据库服务器上—一个为主,所有的新数据都向它提交,然后由它复制到其它两个;另两个数据库服务器全力向用户供给数据,用以在博客和个人资料栏显示。这种方式在一段时间内效果很好——只要增加数据库服务器,加大硬盘,就可以应对用户数和访问量的增加。

    这一次的数据库架构按照垂直分割模式设计,不同的数据库服务于站点的不同功能,如登录、用户资料和博客。垂直分割策略利于多个数据库分担访问压力,当用户要求增加新功能时,MySpace只需要投入新的数据库加以支持。在账户到达二百万后,MySpace还从存储设备与数据库服务器直接交互的方式切换到SAN(存储区域网络)—用高带宽、专门设计的网络将大量磁盘存储设备连接在一起,而数据库连接到SAN。这项措施极大提升了系统性能、正常运行时间和可靠性。然而,当用户继续增加到三百万后,垂直分割策略也变得难以维持下去。

第三代架构—转到分布式计算架构 
    几经折腾,最终,MySpace将目光移到分布式计算架构——它在物理上分布的众多服务器,整体必须逻辑上等同于单台机器。拿数据库来说,就不能再像过去那样将应用拆分,再以不同数据库分别支持,而必须将整个站点看作一个应用。现在,数据库模型里只有一个用户表,支持博客、个人资料和其他核心功能的数据都存储在相同数据库。

    既然所有的核心数据逻辑上都组织到一个数据库,那么MySpace必须找到新的办法以分担负荷——显然,运行在普通硬件上的单个数据库服务器是无能为力的。这次,不再按站点功能和应用分割数据库,MySpace开始将它的用户按每百万一组分割,然后将各组的全部数据分别存入独立的SQL Server实例。目前,MySpace的每台数据库服务器实际运行两个SQL Server实例,也就是说每台服务器服务大约二百万用户。据MySpace的技术人员说,以后还可以按照这种模式以更小粒度划分架构,从而优化负荷分担。 

第四代架构—求助于微软方案 
    2005年早期,账户达到九百万,MySpace开始用微软的C#编写ASP.NET程序。在收到一定成效后,MySpace开始大规模迁移到ASP.NET。 
    账户达到一千万时,MySpace再次遭遇存储瓶颈问题。SAN的引入解决了早期一些性能问题,但站点目前的要求已经开始周期性超越SAN的I/O容量——即它从磁盘存储系统读写数据的极限速度。 

第五代架构—增加数据缓存层并转到支持64位处理器的SQL Server 2005 
    2005年春天,MySpace账户达到一千七百万,MySpace又启用了新的策略以减轻存储系统压力,即增加数据缓存层——位于Web服务器和数据库服务器之间,其唯一职能是在内存中建立被频繁请求数据对象的副本,如此一来,不访问数据库也可以向Web应用供给数据。

    2005年中期,服务账户数达到两千六百万时,MySpace因为我们对内存的渴求而切换到了还处于beta测试的支持64位处理器的SQL Server 2005。升级到SQL Server 2005和64位Windows Server 2003后,MySpace每台服务器配备了32G内存,后于2006年再次将配置标准提升到64G。

    事实上,MySpace的Web服务器和数据库仍然经常发生超负荷,其用户频繁遭遇“意外错误”和“站点离线维护”等告示,他们不得不在论坛抱怨不停…… 

    MySpace正是在这样不断重构站点软件、数据库和存储系统中,才一步步走到今天。事实上,MySpace已经成功解决了很多系统扩展性问题,其中存在相当的经验值得我们借鉴。MySpace系统架构到目前为止保持了相对稳定,但其技术人员仍然在为SQL Server支持的同时连接数等方面继续攻坚,尽可能把事情做到最好。 

(二) Amazon 
    亚马逊书店无疑是电子商务发展的里程碑。2000年到现在,世界网络业腥风血雨。Amazon曾经成为网络泡沫的头号代表。如今,当这个“最大的泡沫”用几经易改的数字把自己变成了坚实的IT巨人。 

    历览Amazon发展过程,其成功经验在于,它创造性地进行了电子商务中每一环节的探索,包括系统平台的建设,程序编写、网站设立、配送系统等等方面。用Amazon当家人贝索斯的话说就是,“在现实世界的商店最有力的武器就是地段,地段,地段,而对于我们来说最重要的三件事就是技术,技术,技术。” 

(三) eBay 
    eBay是世界闻名的拍卖网站,eBay公司通信部主管凯文•帕斯格拉夫认为,“eBay成功的最重要原因在于公司管理和服务。” 
    其成功的奥秘可以列举为以下几点: 
    ①敢为天下先—在网络尚不普及的时代,eBay率先进入网络拍卖领域; 
    ②依托虚拟商场所产生的特有的“零库存”是eBay公司取得成功的另一个重要原因。该公司的核心业务没有任何库存风险,所有的商品都是由客户提供,它只需要负责提供虚拟的拍卖平台—网络和软件。所以,eBay公司的财务报表上不会出现“库存费用”和“保管费用”等。 
③自eBay公司成立开始,它就一直遵循两条“黄金原则”:建设虚拟社区,给网民以家的感觉;保证网站稳定安全地运行。

二、 国内大型网站开发时的几点建议 
    从本节开始,我们将结合国内外大型IT网站在技术扩展方面的沉痛教训和成功经验,探讨在如今刚刚开始的Web 2.0时代如何应对国内网站即将面临的数据访问量增加(甚至是急剧膨胀)的问题,并提出一些供参考的策略和建议。 

(四) 搭建科学的系统架构 
    构建大型的商业网站绝对不可能像构建普通的小型网站一样一蹴而就,需要从严格的软件工程管理的角度进行认真规划,有步骤有逻辑地进行开发。对于大型网站来说,所采用的技术涉及面极其广泛,从硬件到软件、编程语言、数据库、Web服务器、防火墙等各个领域都有了很高的要求,已经不是原来简单的 html静态网站所能比拟的。以著名的Yahoo!为例,他们的每一个大型网站工程都需要大量相应专业人员的参与。 

(五) 页面静态化 
    可不要小看纯静态化的HTML页面!其实在很多情况下,HTML往往意味着“效率最高、消耗最小”,所以我们尽可能使我们的网站上的页面采用静态页面来实现。但是,对于大量内容并且频繁更新的网站,我们无法全部手动实现,因此可以开发相应的自动化更新工具,例如我们常见的信息发布系统CMS。像我们经常访问的各个门户站点的新闻频道,甚至他们的其他频道,都是通过信息发布系统来管理和实现的。信息发布系统可以实现最简单的信息录入自动生成静态页面,还能具备频道管理、权限管理、自动抓取等功能,对于一个大型网站来说,拥有一套高效、可管理的CMS是必不可少的。 

(六) 存储问题 
    存储也是一个大问题,一种是小文件的存储,比如图片这类;另一种是大文件的存储,比如搜索引擎的索引。 
大家知道,对于Web服务器来说,不管是Apache、IIS还是其他容器,图片是最消耗资源的,于是我们有必要将图片与页面进行分离,这是基本上大型网站都会采用的策略,他们都有独立的图片服务器,甚至很多台图片服务器。这样的架构可以降低提供页面访问请求的服务器系统压力,并且可以保证系统不会因为图片问题而崩溃,在应用服务器和图片服务器上,可以进行不同的配置优化以保证更高的系统消耗和执行效率。

(七) 数据库技术—集群和库表散列 
    对于大型网站而言,使用大型的数据库服务器是必须的事情。但是,在面对大量访问的时候,数据库的瓶颈仍然会显现出来,这时一台数据库将很快无法满足应用,于是我们需要借助于数据库集群或者库表散列技术。

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

    上面提到的数据库集群由于在架构、成本、扩张性方面都会受到所采用数据库类型的限制,于是我们需要从应用程序的角度来考虑改善系统架构,其中,库表散列是常用并且最有效的解决方案。我们在应用程序中安装业务和应用或者功能模块将数据库进行分离,不同的模块对应不同的数据库或者表,再按照一定的策略对某个页面或者功能进行更小的数据库散列,比如用户表,按照用户ID进行表散列,这样就能够低成本的提升系统的性能并且有很好的扩展性。在这一方面一个现成的例子就是搜狐。它的论坛就是采用了这样的架构,将论坛的用户、设置、帖子等信息进行数据库分离,然后对帖子、用户按照板块和ID进行散列数据库和表,最终可以在配置文件中进行简单的配置便能让系统随时增加一台低成本的数据库进来补充系统性能。 

(八) 缓存策略 
    这绝对不单指低级的缓存技术相关的编程,应从整个架构角度着眼,深入研究Web服务器、数据库服务器的各层级的缓冲策略,最后才是低级的缓冲技术的编程。不同的Web服务器、数据库服务器及Web编程语言都有自己不同的缓冲策略。例如数据库存储方面,SQL Serve 2005中的主动式缓存机制,Oracle数据的cache group技术,Hibernate的缓存包括Session的缓存和SessionFactory的缓存;Web服务器方面,Apache提供了自己的缓存模块,也可以使用外加的Squid模块进行缓存,这两种方式均可以有效的提高Apache的访问响应能力,IIS缓冲器技术;至于web开发语言,所用缓存技术更存在很大不同,例如ASP.NET 2.0中提出了两种缓存应用程序数据和缓存服务页输出的策略,这两种缓存技术相互独立但不相互排斥,PHP有Pear的Cache模块,等等。 

(九) 镜像 
    镜像是大型网站常采用的提高性能和数据安全性的方式,镜像的技术可以解决不同网络接入商和地域带来的用户访问速度差异。在镜像的细节技术方面,这里不阐述太深,有很多专业的现成的解决架构和产品可选。也有廉价的通过软件实现的思路,比如Linux上的rsync等工具。 

(十) 负载均衡 
    负载均衡将是大型网站解决高负荷访问和大量并发请求采用的终极解决办法。 
负载均衡技术发展了多年,有很多专业的服务提供商和产品可以选择,基于LAMP解决方案的Lighttped+Squid是相当不错的解决负载均衡和加速系统的有效方式。

(十一) 硬件四层交换 
    第四层交换使用第三层和第四层信息包的报头信息,根据应用区间识别业务流,将整个区间段的业务流分配到合适的应用服务器进行处理。第四层交换功能就象是虚IP,指向物理服务器。它传输的业务服从的协议多种多样,有HTTP、FTP、NFS、Telnet或其他协议。这些业务在物理服务器基础上,需要复杂的载量平衡算法。在IP世界,业务类型由终端TCP或UDP端口地址来决定,在第四层交换中的应用区间则由源端和终端IP地址、TCP和UDP端口共同决定。

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

(十二) 软件四层交换 
    大家知道了硬件四层交换机的原理后,基于OSI模型来实现的软件四层交换也就应运而生,这样的解决方案实现的原理一致,不过性能稍差。但是满足一定量的压力还是游刃有余的。

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

(十三) 软件投资问题 
    据报导,目前国内除了一些上市企业和特别大知名大公司以外,很少有企业在成本中考虑正版软件的购置费用。这种思维极有可能给中国互联网带来噩梦。如果一些公司真正面临软件资金方面的困难,完全可以考虑使用开源世界的LAMP解决方案(Linux+Apache+MySQL+Perl、PHP或者 Python Web编程语言);否则,随着我国加入WTO范围的不断扩大,盗版打击必然越来越严。因此,“苟且偷生”必将自食其果。 

    另外,随着网络带宽日渐提升,WEB 2.0技术必将影响到网络世界的几乎每一个角落。因此,如何积聚技术人员进行技术攻关并进一步加强安全防范也成为一个日益严峻的问题,宜尽早纳入到公司的议事日程。 
   
四、 总结 
    中国电子商务真正理性发展的一个标志,是大量的传统企业实实在在地开始用互联网来处理商务、做生意,而现在这样的浪潮已经开始。北京发行集团,联合SINA、6688.com等单位共同推出的网上虚拟书店—新新书店就是这样的一个标志。 

    随着网络带宽日渐提升,随着网络理念和WEB 2.0技术的断深入人心,各种B2B、B2C、C2C等电子商务模式很可能以立体交叉方式整合到各种大型商务网站中来。因此,作为公司的技术人员,作为临危救驾的“白衣骑士”,如何应对海量存储、海量访问问题,海量信息检索的问题,日益严峻的安全问题,等等,已经刻不容缓。

当互联网吵吵嚷嚷的进入2.0时代,当互联网的技术不再是那么高不可攀,当复制变成家常便饭,互联网热闹起来了

     myspace火了,中国冒出更多的myspace

     youtube刚刚起来,中国的视频网站就遍地开花

     51拔地而起,中国出了无数的SNS

     facebook则改变了中国站长的抄袭方式,不再学chianren了,校内火了
     ..........

     当抄袭变成习惯,我想说的是,模仿,站长,你准备好了吗?

     如果你打算做垃圾站,或者赚点广告费的网站,请不要点击这篇文章,我从技术角度方面谈谈WEB2.0网站的模仿问题。

     当投资和流量都不是问题的时候,我想说的是,您真的一帆风顺吗?

     拿SNS网站来说,当匆匆上线的2.0,当一笔笔投资砸进去的时候,当流量上去的时候,您的困惑在什么地方?

     我做过多个2.0公司的技术顾问,简单的谈谈2.0公司遇到的问题(涉及隐私,我用A B C D代替),这里就不再赘述大家众所周知的页面静态化,缓存和代码安全等问题了,有点技术的2.0公司的CTO都知道这些东西,我们谈点发展之后的问题

A公司

     A公司做的是SNS网站,程序是两个毛头小伙子做的,目标直指51,程序开发是一帆风顺,功能也比51牛多了,推广也是一帆风顺(A公司有自己独到的推广 方式。但是当ALEXA到2W的时候问题出来了,每天下午4点左右,网站速度慢的惊人,基本上打不开,公司三台服务器CPU100%,让人郁闷的是公司的 网络配置方式,居然是双WEB的集群,而单独一台DB数据库。整个瓶颈在数据库,于是我建议做DB的集群,分析了一下数据结构,MD,典型的WEB程序员 的作品,没有一点数据库设计规范,功能实现是可以,如果要扩展,不可能,集群基本上是不可能的,怎么办?不能办,于是,一个月的时间修改程序,数据结构基 本上换了一遍 前期砸进去的几十万打了水飘,用户走光了。

     结论:WEB2.0前期设计的时候不应该只考虑功能,应该认真考虑一下底层和数据结构了。

B公司

     B公司也是做的SNS网站,程序是3个人开发的,CEO是某名牌大学的经济学硕士,有点知己网的味道,又有一些特色出来,说实话,公司的潜力不错,CEO 有很强的运作能力,感觉前景不错。系统架构还行,但是---但是系统崩溃了,why?系统没有考虑到用户有个海量的说法,文件也有个海量的说法,用户的相 册,图片全部存贮在WEB服务器的一个分区上,每个用户一个目录,而打开性能监视器,磁盘的IO高的惊人,基本上无暇响应。众所周知,文件系统也是一个数 据库,单独大文件无所谓,关键是整个是300多个G的零碎文件,大量的读写操作,系统崩溃,数据丢失,文件系统的一个链断了,用户数据全部丢失!!!这是 一个非常沉重的问题,系统整整停了一个月来做数据恢复(单独文件很容易,但是海量文件目前还没有一个软件能组织起来软件架构)。解决方案:修改程序架构, 做分布式文件存贮(程序修改用了8天,但是文件转移却又用去了将近一个月),20万用户损失殆尽

     结论:WEB2.0前期的设计应该有应付海量存贮的考虑,整个涉及了程序架构的修改,前期规划不好的话基本上思路一条。

C公司

     C公司是一个值得尊敬的公司,CEO技术出身,和比尔盖茨一样,大学未毕业出来做网络,01到03年做短信狠赚了一笔,后来做的小项目也小有所成,说实 话,我很佩服。公司做的是校友方面,但是更偏重myspace风格,注重个人主页,推广方面也下了大手笔。系统崩溃的原因其实很简单,由于采用的是微软的 SqlServer,而微软直接就告诉了我们,SQLSERVER不支持集群,他们的数据库超负载,100%就没有下去过,只能横向增加配置,采用了4路 4核CPU系统,但是系统还是崩溃了... 高互动注定了高负载。解决方案: 现从基本入手,解决掉几个程序耗能大户,对数据库采用横向切割,将用户每10万进行分组,同时对数据库系统进行散列,将多个表垂直分割,同时进行文件分组 ,解决问题. 因为修改了数据结构,程序也基本上大动了一下。 好在系统没有出大错,损失不算很大,不过对用户体验造成了很坏的影响。

     结论:WEB2.0前期设计应该有良好的散列考虑,程序应该能有配合的扩充性,符合数据库的扩充

D公司

     D公司是一个各个方面做的比较好的公司,做了CDN加速,图片也独立分出了N个服务器,数据库不错的一个,(CTO是个数据库专家),系统崩溃的原因在于 WEB,按道理说WEB很容易做集群的,但是发现集群并解决不掉问题,他们的集群只允许做4台的WEB集群,但是4台都当掉了。仔细分析,找到原因,我估 计整个也是大部分CTO最容易犯的一个错误,或者说他们根本就想不到的问题,就是WEB上传的问题,上传的时候由于时间的原因,线程是保持链接的,300 个线程就可以把一个WEB Server当掉了。解决方案:这个最简单,把上传和其他耗能大户分离出独立出来。程序改动不是很大,但是之前半个月速度满对用户体验的损失也不可小视。

     结论:没有什么结论了,毕竟有海量访问经验的CTO不多,也就是那几个大站的。

     总结:不是泼冷水,模仿其实是很容易的,随便找几个WEB程序员就能做到,并且很简单,速度可能还很高效,因为WEB2.0无非就是跟数据库打交道,会操 作数据库就会做。但是真正做大并不容易,因为能应付海量访问的程序并不简单,现在的程序员都太自命不凡,其实真正有经验的并不多,不要相信一个月薪5K- -10K的程序员能给你多大的惊喜,能应付海量访问的程序员不是那个价格。如果您想做2.0,想做大,有几个个建议:

     一.找DBMS的专家设计好数据库,大部分程序员都不知道分区视图,数据散列,数据组的概念

     二.设计好程序架构(这个其实不难,有个高人指导就行了),保持良好的扩展性,成本考虑可以找兼职的系统架构设计师做好系统架构,确定将来的发展瓶颈。

     三.考虑好文件存贮的问题。文件存贮的技术含量看起来很低,其实是很高的,可以考虑反向代理的方案。文件存贮出问题了,站点基本上就完蛋了,不仅仅是RAID的问题和存贮服务器的问题,不过道理倒是一点就破的

     四.中国国情考虑,这个最致命,需要考虑电信和网通的问题,CDN并不能解决所有问题。互动性的东西并CDN并不是很有效。最关键的是,现有的双线机房遇 到DDOS攻击基本上都会当掉,原因很简单,双线机房都是私人机房,本身就不会有太高的带宽,随便攻击一下就可以D掉(顺带提一个笑话,我知道一个双线机 房的老总总共1G的带宽却买了4G的金盾墙,很简单800M的攻击就可以搞定)。

     五.网络延迟的问题,这是分布式系统必须要考虑的,程序要能容忍0到100秒的数据延迟的功能,也就是同步的问题。不要小看这几十秒,问题很大的,如果你 的站点有交互式功能,比如即时聊天,你可以想象一下是个什么结果。对于即时聊天的东西,可以用反向代理来解决(成本较高)。但是对于留言和评论的影响不 大,但是如果系统为了健壮做了缓存和静态化的时候,这个东西可能就是灾难性的了。

     六.分散你的程序,如果你没有太多的资金构筑动辄百万的服务器,建议把功能分散开来,比如相册一台服务器,留言一台服务器

     七.看好你的程序员,如果没有很好的激励措施的话你的程序员很容易写出敷衍性的代码,而这个可能就是将来的大患,程序架构定下来后要修改可能就要费牛劲了。最好你的CTO能对你100%的衷心,100%的负责。

     八.文件同步的问题,这个问题可能你觉得没有必要,如果你看一下网通和电信的TTL就明白了,同步要支持续传,并且不能是持续的,否则你的成本会高出N倍,不要期望能通过你的软件实现,交给你的程序员吧,把上面的话告诉他他就知道怎么做了。

     九.最狠的一个问题了,也是吃亏最大的问题,不管您跟网警的关系多好,看好你的用户,审核好你的东西,一被停机可能就致命,本人就吃过N次亏。

大型高负载的网站的体系结构和web2.0时代的网站高负载解决方案

从事发布系统(web publish system)的研究和开发快两年了,从小型应用到中型应用,基本上没有参与大型应用(千万pv/day)的部署,网络上这种技术的探讨都不是特别全面,有的提及发布系统对分布式部署,以及海量负载,有的干脆只层网络层面进行讲解,我感觉这是个系统工程,不仅要考虑到应用层面(user layer or app layer),也要考虑到系统层面(kernel layer or system layer),还要考虑到数据库层面(database layer),否则可能有失偏颇。

       我现在从三个层面就我的理解说一些我的一些看法,碍于知识和实践的局限性,也会相当有限。

       所谓应用层面指的是前端应用,因为对网站来说,网友接触最多的就是前端页面,影响负载的很大程度上也是每天上千万的page view带来的visit,对web1.0的网站来说,前端页面往往都是静态化的,即html化的,这也是为了降低负载,因为web应用服务器解析 html页面的速度是最快的,而页面的静态化一般都是由web级的(主要)和桌面局域网级别的(很少)发布平台发布的,基于分布式的考虑,发布系统最好能够分发产生的html页,分发到光纤或者高速局域网中的不同host上,以便分散访问压力。当然也可以使用系统层的同步工具完成这个工作,注意要对页面的域名对应信息进行保存,防止产生404 error。我个人比较喜欢系统层的网络同步,速度比较快,稳定性也比较高。应用层的分发一般借助ftp的方式,速度不是特别快,容易产生拥塞,稳定性自然下降。

       如果分布式的分发静态页面仍然存在瓶颈,怎么办?国内大型的门户网站往往采取可缓存的反向代理方式部署的负载均衡技术来解决,一般都是squid做前端 cache和反向代理。负载均衡也有软件级的(dns 轮询)负载均衡和硬件上的负载均衡甚至两者的结合进行实现,具体实施细则将在下一篇中进行阐述。说到静态化,也不只是web1.0的传统新闻门户采用, web2.0的应用前端也可静态化,或者部分静态化,比如:社区型门户,帖子就可以静态化,可以采取即时静态或者异步静态的方式,也可以触发静态化。这种静态化可以降低数据库层的压力,数据库服务器如果始终工作在大负载的访问压力下,很容易崩溃,尽可能的将经常用到的数据静态化,缓存起来会极大的降低压力。(猫扑、网易、搜狐等社区都是采用的这种方式)

        上文提到了静态化能减轻数据库服务器的压力,可是却影响了更新的即时性,有些应用需要数据的即时显示,不允许缓存或者静态化,这就需要对数据库服务器的结构进行合理部署。除了要在设计应用之初,很好的设计数据库结构,使用好的模式之外,还要对数据库服务器进行分布式部署甚至库表散列。在数据库集群(database culuster)方面,很多数据库都有不错的解决方案,包括OracleSybase甚至mysql,只不过mysql采用的是master+ slave的结构,选用了何种数据库,就参照相应的解决方案进行部署。除了在数据库选择上进行负载均衡之外,也可以在单数据库本身进行考虑,比如库表的散列,根据应用的特点,将大的、影响性能的数据库或者数据库的单表进行散列、拆分。比如:按用户id进行散列,按分类进行散列,或者按地区进行散列。

         说到系统层,可能就是OSWeb Server了,大型应用的OS基本都是Unix(包括freebsd或者HP Unix)或者类Unix(各种linux版本,redhat居多),这不是说MicrosoftOS就不合理了,合理的应用也可部署大型应用,只不过效能会很受限制。Web Server层面,还是apache当家,尤其是静态页和图片,当然也可以根据具体的需求,根据内容的特殊性选择Lighttpd(比较适合做纯静态、图片服务器、视频服务器等)、甚至iiswindows下用的居多),系统层的web服务器的配置还是很有讲究的,比如对cache的配置,反向代理的配置等。比较好的web加速和代理服务器有:SquidNginxHAProxyLighttpd,这四个可能是用的比较多的了。其中业内比较出名的Flickrtudou用的是lighttpdsina51.com使用了,至少部分使用了Nginx

        缓存系统对高负载的重要性是不言而喻的,前面提到的静态化,需要进行有效缓存,经常用到的查询和结果需要进行缓存,只要设定好更新缓存的规则,对性能的提升是n个数量级的。Linux下,有内存级别的缓存,高速缓存,很多应用都是用tmpfs来进行数据中转,php上用的最多的是memcached apache有文件系统级别的cachesquid也是做前端cache的主要手段。腾讯、网易等都是用了squid做前端cache server

       前面提到的负载均衡,有软件级别的,比如LVSHAProxyLinux-HA项目等,硬件层面的诸如:f5BigIp3DNSalton的解决方案,北电的方案等,都是比较成熟的,不过都需要付出相当可观的¥。

       以前谈到过关于高负载、大访问量的门户型web1.0网站的体系结构,提到了许多诸如front-end cacheclustered databaseproxy servercdn等技术,随着web2.0的温度越来越highweb2.0的一些代表性网站的体系结构也被晒了出来,我在这里进行简单的整理,呈现给大家。

       案例1豆瓣

      豆瓣是由阿北(杨勃4个多月时间(很神速,关键是胸有成竹),基于linux+lighttpd+fastcgi+python+quixote+mysql架构部署的 web2.0网站,豆瓣的搜索引擎使用twisted,这个是豆瓣的后台,书的价格以及比较信息都是在此之上搜索各大购物网站而来的,mysql用了 innodbmyisam两种引擎,读/写频繁的用innodb,读多写少、写多读少(比如log)或者需要full text index的用myisamreplication/cluster做数据复制和集群,晚上用mysqldumpbackup

        案例2youtube

       出于开发效率的考虑,youtube的大部分代码都是python的, web server有两种,一种是apache+fastcgi,另一种是lighttpd(主要做为视频内容服务器)youtube可能是lighttpd 最好的案例。youtube每一个视频都有4个缩略图(Thumbnails),这个缩略图的产生对服务器的负载是个极大的考验,每一秒都给disk i/o带来压力,youtube采用了独立的服务器culuster来应对这方面的压力,也对操作系统和缓存做了优化。另外,缩略图的request也导致了lighttpd性能下降,通过 Hack Lighttpd 增加更多的 worker thread很大程度解决了这个问题,被google收购以后,开始使用google的存储法宝bigtable,一下子提升了在 performanceredundancycache等方面的表现。(看来这次收购还是效果颇大)出于redundancy的考虑,每一个 video都放到一组mini cluster上,这组mini cluster上存储了相同内容的视频,the hotest video放在了cdn上,使压力分布到不同的节点上,非热门的,访问量不高的自己进行单独处理。维护的工具也是常见的rsync(同步工具)ssh (远程登录)等。数据库上,youtube跟很多web2.0的站点一样,偏向使用mysql,主要是存储一些meta data,诸如视频信息、图片信息、用户信息等。youtube通过删除swap交换分区来解决数据库遇到的swap颠簸问题。

         youtube最初的 DB 只有 10 块硬盘,后来追加了一组RAID1。在扩展性方面,采用的是主流的方式,master/slave复制(replication),分散IO。最终的解决之道是是业务层面的分区(在用户名字或者 ID 上做文章,应用程序控制查找机制),而不是物理上的数据库层面的表分区。youtube也用了memcached

       案例3myspace

       myspace6500万的订阅者(还在上升),是因特网上增长最快的网站之一,每天还有260000新用户注册。它经常因为性能问题而受指责, MySpace不得不处理其他网站很少碰到的或大或小的一些问题。它们是怎么做的呢?使用的平台是 ASP.NET 2.0 + Windows + IIS + SQL Server myspace 每天处理15亿的页面查看,白天处理230万并发的用户,在50万用户的时候,采用简单的磕磕绊绊的体系结构,100万用户时进行了痛苦的垂直分割解决伸缩性,300万用户时Scale-Out 胜过Scale-Up(按比例增加), 900万用户的时候,站点迁移到ASP.NET,增加了虚拟存储,260万用户的时候myspace采用了64位技术,当小于300万个帐号的时候,他们使用了一种数据库体系结构,围绕着垂直分割的概念,提供不同服务比如界面登录,用户资料和博客等的网站的各部分都有单独的数据库。垂直分割方案有助于分开数据库读和写的工作量,并且当用户需要一个新特征时,MySpace 将会加入一个新的在线数据库来支持它。MySpace 从直接使用附着于它的数据库的服务器的存储设备转换到一个存储区域网络(SAN),里面大量的磁盘存储设备由一个高速,专用网络联系到一块,同时数据库连接到SAN。到SAN的改变提高了性能,正常运行时间和可靠性。当超过300万个帐号的时候,垂直分割解决方案就不好使了,因为它们重复了一些水平的信息像跨过所有垂直片的用户帐号。有这么多的重复它会使系统变慢,肯定要失败。个人应用比如Web 站点子部分上的博客将会增长到对于单独一个数据库服务器来说太大的程度,在逻辑上重组所有核心数据到一个数据库里 
,把它的用户基本信息分成100万帐号一个的块,然后把所有有键的数据放到SQL Server不同实例的这些帐号中,在 900-1700万帐号这个阶段,迁移到ASP.NET后,使用了比先前的体系结构更少的资源。150个服务器运行新的代码就能够做原来246个服务器做的同样的工作。再看看存储瓶颈,实施SAN解决了原来的一些性能问题,但是现在Web站点的需求开始间歇性地超过了SANI/O能力,它从磁盘存储读写的速度,使用每个数据库100个帐号的分开方式达到了极限,因为这已经超过了极限;迁移到一个虚拟存储体系结构,那里整个SAN被当作一个大的存储池来对待,不需要特定的磁盘为特定的应用服务。现在MySpace在设备上从相对新的SAN厂商,3PARdata方面已经标准化了。增加了一个高速缓存层,服务器放在Web服务器和数据库服务器之间,它唯一的工作就是捕获内存中频繁访问的数据对象的副本,然后把它们用于Web应用,不需要数据库查询。超过2600万注册帐号后,开始迁移到64SQL server以解决它们的内存瓶颈问题。它们的标准数据库服务器配置使用64GBRAM

      Myspace的经验告诉我们:你可以使用微软的技术构建大型网站;从一开始就应该使用缓存;高速缓存是一个更好的地方存储临时数据,比如Web站点上跟踪一个特定用户的会话产生的临时文件,就不再需要记录到数据库里;嵌入OS特征来检测拒绝服务攻击会产生无法解释的错误;把数据分布到地理位置不同的数据中心,以免发生断电事故。从开始就考虑使用虚拟存储/簇文件系统。它能让你大量并行IO访问,而且不需要任何重组就能够增加所需要的磁盘。

一个刚入门的初学者开发一个网站后,能从哪些方面对系统的性能进行提升呢?

  1. 编码级别.这个是最小的级别,可能也是对性能的提升产生效果最小的.不过,我们需要特别注意一些宝贵的资源释放,往往这些错误在测试的时候不容易发现,系统一旦上线接受高访问量的考验就崩溃了.
  2. 页面级别.对于WEB系统来说,页面是一个很重要的一部分,客户端和服务端就是通过静态的HTML,JS等代码进行交互的.页面的缓存策略,页面的大小直接决定了客户端讯问网站的速度和网络流量.页面级别的性能优化比编码级别更有效一点.
  3. 构架级别.一个好的构架能提升系统性能,而构架也可能成为整个系统的杀手.对于分布式的系统更是如此.如果在一个环节发生了问题就可能导致整个系统的性能产生明显巨大的问题.
  4. 配置与部署.一个同样的系统可能在两个相同硬件配置的服务器上产生明显的性能差异.由于网站是需要IIS进行解析的,换句话说,网站所有的流量都要经过IIS这个关口,如果IIS的配置不当的话,对网站造成的影响是致命的.

    下面,我将就这几个方面介绍网站性能优化的一个具体做法,当然,方法并不是绝对的,所有方法都仅供参考.其中很多的方法我也是从一些网站性能优化的书上摘抄下来的.

一、编码级别的优化.

  1.     数据连接.

o                                尽量晚打开连接,尽量早关闭连接.

o                                优化SQL语句或者存储过程,尽量缩短查询运行时间

下面两个连接方法就有很大的差别:

1.                  SQLConnection conn=new SQLConnection(".....");  

2.                  //打开连接  

3.                  conn.open();  

4.                  SqlCommand cmd=new SqlCommand("....",conn);  

5.                  ...  

6.                  ...  

7.                  cmd.ExecuteNonQuery();  

8.                  //关闭连接  

9.                  conn.Close(); 

10.               SQLConnection conn=new SQLConnection(".....");  

11.               SqlCommand cmd=new SqlCommand("....",conn);  

12.               ...  

13.               ...  

14.               //打开连接  

15.               conn.open();  

16.               cmd.ExecuteNonQuery();  

17.               //关闭连接  

18.               conn.Close(); 

上面的第一种方法就是过早的打开了数据连接,这样是非常消耗资源的,要像第二种方法样,在要执行查询的时候才打开连接.

  1.     数据查询

o                                Select记录的时候,只返回需要的字段,不要Select * 把所有的字段都返回,数据越多对于服务器的压力就越大.对于分布式程序还会占用更多的网络流量.

o                                不要一次取出所有行,仅取出当前页面需要的数据,这就涉及到分页了.

o                                尽量使用DataReader来进行数据读取,DataReader是只读向前形式读取数据的,性能要比Dataset高.

o                                使用DataReader的时候,尽量一次返回多个记录集,需不是为每个记录打开一次数据库.

o                                如果需要在一个代码段中执行多个SQL语句,可以使用存储过程来优化性能.

  1.     释放资源

o                                使用Using来自动释放对像. 

  1.     其它优化

o                                不要依赖异常.异常是不可知的错误,

o                                使用泛型集合代替普通的集合. net2.0以上提供了很多泛型集合,使用泛型集合代替普通集合能提高性能.比如下面的代码耗时2908毫秒:

1.                  ArrayList list=new ArrayList();  

2.                  for(int i=0;i<10000000; i++)  

3.                  list.add(i);  

4.                  int count=0;  

5.                  for(int i=0;i<list.Count;i++)  

6.                  count=(int)list[i]; 

改用泛型集合后代码耗时只用370毫秒

7.                  List<int> list=new List<int>();  

8.                  for(int i=0;i<10000000; i++)  

9.                  list.add(i);  

10.               int count=0;  

11.               for(int i=0;i<list.Count;i++)  

12.               count=(int)list[i]; 

o                                不要大量使用反射,反射虽能减少项目依赖,但是会有比较大的性能损失,不推荐大量使用.

 

  1. 网站配置

o                                发布前禁用调试
发布前记得要把Web.config 中compilation节点的debug设置为False来禁用调试.否则应用程序性能会有很大的影响.在VS2005里面新建一个网站后,在Web.config中会有这样一个节点:

1.                  <!--   

2.                  设置 compilation debug="true" 将调试符号插入已编译的页面中  

3.                  。但由于这会 影响性能,因此只在开发过程中将此值 设置为 true  

4.                  -->  

5.                  <compilation debug="true"></compilation> 

在开发网站的时候设置的是True,但是在发布的时候一定要记得把它设为False.

o                                避免将错误页设置为同一个网站的某个页面.(事实上很多网站都是把错误页设置为本站的某个页面),这个设置不是很合理.以前我也不怎么觉得这有多大的关系统.但是在我前不久访问一个好友网站的时候,由于出错,它把我引向了错误页,那个错误页又是设置为自动跳转到网站首页的,所以跳到首页后出错又把我引向错误页,错误页再一次帮我跳到首页......这样就导致了恶性循环.这种情况一般不常见,但是在网站过于繁忙导致没有足够线程的时候会发生这样的异常.把错误页设置为其它网站的某个友好页面能解决这个问题.

  1. 网站部署

o                                发布前先编译.
asp.net2.0提供了预编译机制,能避免首次访问网站编译带来的性能损失.使用IDE的发布操作能很方便地进行编译.

o                                HTTP压缩.
在IIS中配置HTTP压缩能减少30%的网络流量.对于CPU占用不高而网络带宽有限的网站来说,可以采用压缩来减少页面加载时间.

  1. 页面加整
    • 尽可能把几个图片合成一个图片来减少向服务器请求的次数.(以前我一直以为要把大图切成小块加载速度才会快,事实刚好相反,实验证明加载一张大图要比加载这张大图切成的小块的时间要快得多.)
    • 尽量不要使用表格进行布局,特别是不要把整个页面放在一个大表格里,使用这个表格来定义整个页面(比如居中).因为浏览器只有读到了一个标记的结束后才会呈现(比如读到表格的</table>),如果把整个页面放在一个大表格中的话,那么只有等整个页面加载完毕了才会呈现在观众面前,用css布局的话,就算是网速慢,也会加载一点内容就呈现一点内容.不会出现速个屏幕为白色.
    • 分离CSS,尽量把CSS分离到单个文件中去,而不要在每个页面的顶部都生成一段CSS代码.css文件能被客户端缓存,使用独立的CSS文件能减少页面的数据量.
    • 最后,千万不要用WORD生成HTML文件,那是外行做!
  2. 其化优化
    • 减少不必要的服务端事件.比如清空TextBox的操作,可以直接用一个不回发的客户端按钮来实现.

1.     <input type="reset" valie="重置"

而不必要用 :

2.     <asp:Button ID="..." Runat="server" text="重置" OnClick="..." />  

3.     在后台写按钮事件:  

4.     textbox1.text="";  

5.     textbox2.text="";  

6.     ......... 

    •   使用Page.IsPostBack来减少不必要的处理.通常我们可能需要在页面首次加载的时候初始化一些数据,而在单击页面上的按钮回发页面后不需要进行这些处理,可以通过Page.IsPostBack判断页面是否是首次加载.来避免重复执行一些不要的代码.

从LiveJournal后台发展看大规模网站性能优化方法

于敦德 2006-3-16

一、LiveJournal发展历程

LiveJournal是99年始于校园中的项目,几个人出于爱好做了这样一个应用,以实现以下功能:

  • 博客,论坛
  • 社会性网络,找到朋友
  • 聚合,把朋友的文章聚合在一起

LiveJournal采用了大量的开源软件,甚至它本身也是一个开源软件。

在上线后,LiveJournal实现了非常快速的增长:

  • 2004年4月份:280万注册用户。
  • 2005年4月份:680万注册用户。
  • 2005年8月份:790万注册用户。
  • 达到了每秒钟上千次的页面请求及处理。
  • 使用了大量MySQL服务器。
  • 使用了大量通用组件。

二、LiveJournal架构现状概况

三、从LiveJournal发展中学习

LiveJournal从1台服务器发展到100台服务器,这其中经历了无数的伤痛,但同时也摸索出了解决这些问题的方法,通过对LiveJournal的学习,可以让我们避免LJ曾经犯过的错误,并且从一开始就对系统进行良好的设计,以避免后期的痛苦。

下面我们一步一步看LJ发展的脚步。

1、一台服务器

一台别人捐助的服务器,LJ最初就跑在上面,就像Google开始时候用的破服务器一样,值得我们尊敬。这个阶段,LJ的人以惊人的速度熟悉的Unix的操作管理,服务器性能出现过问题,不过还好,可以通过一些小修小改应付过去。在这个阶段里LJ把CGI升级到了FastCGI。

最终问题出现了,网站越来越慢,已经无法通过优过化来解决的地步,需要更多的服务器,这时LJ开始提供付费服务,可能是想通过这些钱来购买新的服务器,以解决当时的困境。
毫无疑问,当时LJ存在巨大的单点问题,所有的东西都在那台服务器的铁皮盒子里装着。

2、两台服务器

用付费服务赚来的钱LJ买了两台服务器:一台叫做Kenny的Dell 6U机器用于提供Web服务,一台叫做Cartman的Dell 6U服务器用于提供数据库服务。

LJ有了更大的磁盘,更多的计算资源。但同时网络结构还是非常简单,每台机器两块网卡,Cartman通过内网为Kenny提供MySQL数据库服务。

暂时解决了负载的问题,新的问题又出现了:

  • 原来的一个单点变成了两个单点。
  • 没有冷备份或热备份。
  • 网站速度慢的问题又开始出现了,没办法,增长太快了。
  • Web服务器上CPU达到上限,需要更多的Web服务器。

3、四台服务器

又买了两台,Kyle和Stan,这次都是1U的,都用于提供Web服务。目前LJ一共有3台Web服务器和一台数据库服务器。这时需要在3台Web服务器上进行负载均横。

LJ把Kenny用于外部的网关,使用mod_backhand进行负载均横。

然后问题又出现了:

  • 单点故障。数据库和用于做网关的Web服务器都是单点,一旦任何一台机器出现问题将导致所有服务不可用。虽然用于做网关的Web服务器可以通过保持心跳同步迅速切换,但还是无法解决数据库的单点,LJ当时也没做这个。
  • 网站又变慢了,这次是因为IO和数据库的问题,问题是怎么往应用里面添加数据库呢?

4、五台服务器

又买了一台数据库服务器。在两台数据库服务器上使用了数据库同步(Mysql支持的Master-Slave模式),写操作全部针对主数据库(通过Binlog,主服务器上的写操作可以迅速同步到从服务器上),读操作在两个数据库上同时进行(也算是负载均横的一种吧)。

实现同步时要注意几个事项:

  • 读操作数据库选择算法处理,要选一个当前负载轻一点的数据库。
  • 在从数据库服务器上只能进行读操作
  • 准备好应对同步过程中的延迟,处理不好可能会导致数据库同步的中断。只需要对写操作进行判断即可,读操作不存在同步问题。

5、更多服务器

有钱了,当然要多买些服务器。部署后快了没多久,又开始慢了。这次有更多的Web服务器,更多的数据库服务器,存在 IO与CPU争用。于是采用了BIG-IP作为负载均衡解决方案。

6、现在我们在哪里:

现在服务器基本上够了,但性能还是有问题,原因出在架构上。

数据库的架构是最大的问题。由于增加的数据库都是以Slave模式添加到应用内,这样唯一的好处就是将读操作分布到了多台机器,但这样带来的后果就是写操作被大量分发,每台机器都要执行,服务器越多,浪费就越大,随着写操作的增加,用于服务读操作的资源越来越少。

由一台分布到两台

最终效果

现在我们发现,我们并不需要把这些数据在如此多的服务器上都保留一份。服务器上已经做了RAID,数据库也进行了备份,这么多的备份完全是对资源的浪费,属于冗余极端过度。那为什么不把数据分布存储呢?

问题发现了,开始考虑如何解决。现在要做的就是把不同用户的数据分布到不同的服务器上进行存储,以实现数据的分布式存储,让每台机器只为相对固定的用户服务,以实现平行的架构和良好的可扩展性。

为了实现用户分组,我们需要为每一个用户分配一个组标记,用于标记此用户的数据存放在哪一组数据库服务器中。每组数据库由一个master及几个slave组成,并且slave的数量在2-3台,以实现系统资源的最合理分配,既保证数据读操作分布,又避免数据过度冗余以及同步操作对系统资源的过度消耗。

由一台(一组)中心服务器提供用户分组控制。所有用户的分组信息都存储在这台机器上,所有针对用户的操作需要先查询这台机器得到用户的组号,然后再到相应的数据库组中获取数据。

这样的用户架构与目前LJ的架构已经很相像了。

在具体的实现时需要注意几个问题:

  • 在数据库组内不要使用自增ID,以便于以后在数据库组之间迁移用户,以实现更合理的I/O,磁盘空间及负载分布。
  • 将userid,postid存储在全局服务器上,可以使用自增,数据库组中的相应值必须以全局服务器上的值为准。全局服务器上使用事务型数据库InnoDB。
  • 在数据库组之间迁移用户时要万分小心,当迁移时用户不能有写操作。

7、现在我们在哪里

问题:

  • 一个全局主服务器,挂掉的话所有用户注册及写操作就挂掉。
  • 每个数据库组一个主服务器,挂掉的话这组用户的写操作就挂掉。
  • 数据库组从服务器挂掉的话会导致其它服务器负载过大。

对于Master-Slave模式的单点问题,LJ采取了Master-Master模式来解决。所谓Master-Master实际上是人工实现的,并不是由MySQL直接提供的,实际上也就是两台机器同时是Master,也同时是Slave,互相同步。

Master-Master实现时需要注意:

  • 一个Master出错后恢复同步,最好由服务器自动完成。
  • 数字分配,由于同时在两台机器上写,有些ID可能会冲突。

解决方案:

  • 奇偶数分配ID,一台机器上写奇数,一台机器上写偶数
  • 通过全局服务器进行分配(LJ采用的做法)。

Master-Master模式还有一种用法,这种方法与前一种相比,仍然保持两台机器的同步,但只有一台机器提供服务(读和写),在每天晚上的时候进行轮换,或者出现问题的时候进行切换。

8、现在我们在哪里

现在插播一条广告,MyISAM VS InnoDB。

使用InnoDB:

  • 支持事务
  • 需要做更多的配置,不过值得,可以更安全的存储数据,以及得到更快的速度。

使用MyISAM:

  • 记录日志(LJ用它来记网络访问日志)
  • 存储只读静态数据,足够快。
  • 并发性很差,无法同时读写数据(添加数据可以)
  • MySQL非正常关闭或死机时会导致索引错误,需要使用myisamchk修复,而且当访问量大时出现非常频繁。

9、缓存

去年我写过一篇文章介绍memcached,它就是由LJ的团队开发的一款缓存工具,以key-value的方式将数据存储到分布的内存中。LJ缓存的数据:

  • 12台独立服务器(不是捐赠的)
  • 28个实例
  • 30GB总容量
  • 90-93%的命中率(用过squid的人可能知道,squid内存加磁盘的命中率大概在70-80%)

如何建立缓存策略?

想缓存所有的东西?那是不可能的,我们只需要缓存已经或者可能导致系统瓶颈的地方,最大程度的提交系统运行效率。通过对MySQL的日志的分析我们可以找到缓存的对象。

缓存的缺点?

  • 没有完美的事物,缓存也有缺点:
  • 增大开发量,需要针对缓存处理编写特殊的代码。
  • 管理难度增加,需要更多人参与系统维护。
  • 当然大内存也需要钱。

10Web访问负载均衡

在数据包级别使用BIG-IP,但BIG-IP并不知道我们内部的处理机制,无法判断由哪台服务器对这些请求进行处理。反向代理并不能很好的起到作用,不是已经够快了,就是达不到我们想要的效果。

所以,LJ又开发了Perlbal。特点:

  • 快,小,可管理的http web 服务器/代理
  • 可以在内部进行转发
  • 使用Perl开发
  • 单线程,异步,基于事件,使用epoll , kqueue
  • 支持Console管理与http远程管理,支持动态配置加载
  • 多种模式:web服务器,反向代理,插件
  • 支持插件:GIF/PNG互换?

11MogileFS

LJ使用开源的MogileFS作为分布式文件存储系统。MogileFS使用非常简单,它的主要设计思想是:

    • 文件属于类(类是最小的复制单位)
    • 跟踪文件存储位置
    • 在不同主机上存储
    • 使用MySQL集群统一存储分布信息
    • 大容易廉价磁盘

原文来自于:http://blog.csdn.net/wangyunpeng0319/article/details/8252796

原文地址:https://www.cnblogs.com/guoyongrong/p/3466910.html