All posts by dotte

网站架构资料收集整理

1.系统概况图

clip_image001

图1.1 系统架构概况图

clip_image003

图1.2 较为完整的系统架构图

2.系统使用的主要技术

下列排名不分先后

2.1前端

JavaScript,html,css,silverlight,flash

Jquery

Javascript类库,用来简化html的操作,事件处理,动画,异步访问,用于web的快速开发。最新版本是1.7.1,分为开发环境(大小为229k)和生产环境(大小为31k)。特点是轻量,体积小;css兼容1-3;跨浏览器。凡客,当当,亚马逊。

如果从框架角度分级的话,可以有以下分类:

  • 零级,完成base工作,包括扩展原有对象的方法,Ajax通讯部分,比较精简
  • 一级,完成effect工作,包括增加常用效果转换函数,如tween、drag、maskLayer、fade等的特效
  • 二级,完成component工作,包括对话框、列表、树、日历等的组件
  • 三级,完成application工作,包括完整的前端平台,允许用户定义能实现一定功能的模块

一些UI控件和开发框架只做零级Prototype.js,和一级jQuery/Mootools;一些做到了三级,如Dojo和EXT。

Kissky

小巧灵活,简洁实用,使用起来让人感觉愉悦。淘宝,腾讯。

2.2后端

Php,Perl,asp,ruby,python,.net,java,jsp(java server page)

静态语言:java, .net

动态语言(脚本语言):php, asp, jsp, perl, python, ruby

Php是老牌的脚本语言,尽管出现了很多的新语言,但是php还是大多数网站的首选,据说全世界70%的网站都使用php。LAMP(linux+apache+mysql+php)是经典组合。

ASP是Active Server Page的缩写,意为“动态服务器页面”。ASP是微软公司开发的代替CGI脚本程序的一种应用,它可以与数据库和其它程序进行交互,是一种简单、方便的编程工具。ASP的网页文件的格式是。常用于各种动态网站中。

JSP(Java Server Pages)是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准。JSP技术有点类似ASP技术,它是在传统的网页HTML文件(*.htm,*.html)中插入Java程序段(Scriptlet)和JSP标记(tag),从而形成JSP文件(*.jsp)。 用JSP开发的Web应用是跨平台的,既能在Linux下运行,也能在其他操作系统上运行。

Pythonruby是近几年崛起的开源语言,特点是容易上手,能快速完成原型。同时也是较为成熟脚本语言。Python是豆瓣的主要语言,google,youtube等网站也都在使用。

http://www.python.org/about/quotes/

Twitter的前端主要使用ruby,motorola和NASA也都使用了ruby。

http://www.ruby-lang.org/en/documentation/success-stories

2.3缓存

Squid cache

开源。

Squid服务器群,把它作为web服务器端的前置cache服务器,缓存相关请求来提高web服务器速度。Squid将大部分静态资源(图片,js,css等)缓存起来,也可以缓存频繁访问的网页,直接返回给访问者,减少应用服务器的负载。

memcached

开源。

WikipediaFlickrTwitterYoutube

memcached服务器群,一款分布式缓存产品,很多大型网站在应用; 它可以应对任意多个连接,使用非阻塞的网络IO。由于它的工作机制是在内存中开辟一块空间,然后建立一个HashTable,Memcached自管理这些HashTable。因为通常网站应用程序中最耗费时间的任务是数据在数据库的检索,而多个用户查询相同的SQL时,数据库压力会增大,而通过memcached的查询缓存命中,数据直接从memcached内存中取,每次缓存命中将替换到数据库服务器的一次往返,到达数据库服务器的请求更少,间接地提高了数据库服务器的性能,从而使应用程序运行得更快。它通过基于内存缓存对象来减少数据库查询的方式改善网站系统的反应,其最吸引人的一个特性就是支持分布式部署。

2.4中间件

Java,.net,c,c++

2.5存储

2.5.1关系数据库

Oracle,mysql,mssql,postgreSQL

postgreSQL

关系数据库,拥有15年的历史。免费,开源。可以运行在linux、unix和windows上,支持事物、主外键、连接、视图、触发器、存储过程。包含大量的数据类型,也支持大对象。支持多种语言,c,c++,java,c#,perl,python,ruby等等。

2.5.2 NoSQL存储

MongoDB,Redis,CouchDB,Cassandra,HBase

NoSQL(not only sql),不仅仅是SQL。用来弥补关系数据库在某些方面的不足。例如:

l 高并发读写。每秒上万次的读写,关系数据库有点吃力。

l 海量数据的高效存储和访问。例如:对一张表有2亿数据的表进行读写,效率较为低下。

l 高扩展性。对于数据库的升级和扩展,增加节点,往往需要停机和数据迁移。

有一些地方不需要关系数据库,例如:

l 事务一致性。某些场合不需要事务,对于数据的一致性也没有严格要求。

l 读写实时性。有些场合不需要实时的读写。

http://baike.baidu.com/view/2677528.htm

Mongodb

文档型nosql,支持主从复制。有很多的大公司使用。支持多种编程语言。

http://www.mongodb.org/display/DOCS/Production+Deployments

Disney,SAP,淘宝(监控数据),sourceforge,大众点评(用户行为分析,用户、组)。

Redis

键值型nosql,vmware赞助,支持多种编程语言。Twitter,淘宝,新浪微博都有使用。

Couchdbcassandrahbase

都是apache旗下的项目。

2.5.3文件系统

商用中间件,自定义文件系统

2.6操作系统

Windows,linux,unix

2.7 Web应用服务器软件

IIS,apache,tomcat,jboss,weblogic(BEA,商用,收费),websphere(IBM,商用,收费),lighttpd,nginx

IIS

微软windows操作系统专用。

Lighttpd

lighttpd,是一个德国人领导的开源软件,其根本的目的是提供一个专门针对高性能网站,安全、快速、兼容性好。lighttpd并且灵活的web server环境。具有非常低的内存开销,cpu占用率低,效能好,以及丰富的模块等特点。lighttpd是众多OpenSource轻量级的web server中较为优秀的一个。支持FastCGI, CGI, Auth, 输出压缩(output compress), URL重写, Alias等重要功能,

Nginx

开源

Nginx+php(FastCGI)+Memcached+Mysql+APC 是目前主流的高性能服务器搭建方式!适合大中型网站,小型站长也可以采用这种组合!

Nginx 超越 Apache 的高性能和稳定性,使得国内使用 Nginx 作为 Web 服务器的网站也越来越多,其中包括国内最大的电子地图MapBar、新浪博客、新浪播客、网易新闻等门户网站频道,六间房、56.com等视频分享网 站,Discuz!官方论坛、水木社区等知名论坛,豆瓣、YUPOO相册、海内SNS、迅雷在线等新兴Web 2.0网站,更多的网站都在使用Nginx配置。

2.8 框架

Javascript:Jqueryprototype.jsKisskyextjs

.NET:企业库unityNHibernateSprint.NETibatisMVCMEFPrismlog4net23个开源项目lucene.NET

Java:hibernatespringstrutseasyjflog4j开源项目lucene

Python:djangoflaskbottletornadouliwebweb.py

Ruby:rails

PHP:PEAR

3.主流网站架构演进

3.1第一步:物理分离webserver和数据库

刚开始我们的网站可能搭建在一台服务器上,这个时候由于网站具备了一定的特色,吸引了部分人访问,逐渐你发现系统的压力越来越高,响应速度越来越慢,而这个时候比较明显的是数据库和应用互相影响,应用出问题了,数据库也很容易出现问题,而数据库出问题的时候,应用也容易出问题,于是进入了第一步演变阶段:将应用和数据库从物理上分离,变成了两台机器,这个时候技术上没有什么新的要求,但你发现确实起到效果了,系统又恢复到以前的响应速度了,并且支撑住了更高的流量,并且不会因为数据库和应用形成互相的影响。

clip_image005

图3.1

3.2第二步:增加页面缓存

好景不长,随着访问的人越来越多,你发现响应速度又开始变慢了,查找原因,发现是访问数据库的操作太多,导致数据连接竞争激烈,所以响应变慢,但数据库连接又不能开太多,否则数据库机器压力会很高,因此考虑采用缓存机制来减少数据库连接资源的竞争和对数据库读的压力,这个时候首先也许会选择采用squid等类似的机制来将系统中相对静态的页面(例如一两天才会有更新的页面)进行缓存(当然,也可以采用将页面静态化的方案),这样程序上可以不做修改,就能够很好的减少对webserver的压力以及减少数据库连接资源的竞争,OK,于是开始采用squid来做相对静态的页面的缓存。

clip_image007

图3.2

3.3第三步:增加页面片段缓存

增加了squid做缓存后,整体系统的速度确实是提升了,webserver的压力也开始下降了,但随着访问量的增加,发现系统又开始变的有些慢了,在尝到了squid之类的动态缓存带来的好处后,开始想能不能让现在那些动态页面里相对静态的部分也缓存起来呢,因此考虑采用类似ESI之类的页面片段缓存策略,OK,于是开始采用ESI来做动态页面中相对静态的片段部分的缓存。

clip_image009

图3.3

3.4第四步:数据缓存

在采用ESI之类的技术再次提高了系统的缓存效果后,系统的压力确实进一步降低了,但同样,随着访问量的增加,系统还是开始变慢,经过查找,可能会发现系统中存在一些重复获取数据信息的地方,像获取用户信息等,这个时候开始考虑是不是可以将这些数据信息也缓存起来呢,于是将这些数据缓存到本地内存,改变完毕后,完全符合预期,系统的响应速度又恢复了,数据库的压力也再度降低了不少。可以使用的技术有:memcached。

clip_image011

图3.4

3.5第五步:增加webserver

好景不长,发现随着系统访问量的再度增加,webserver机器的压力在高峰期会上升到比较高,这个时候开始考虑增加一台webserver,这也是为了同时解决可用性的问题,避免单台的webserver down机的话就没法使用了,在做了这些考虑后,决定增加一台webserver,增加一台webserver时,会碰到一些问题,典型的有:

1、如何让访问分配到这两台机器上,这个时候通常会考虑的方案是Apache自带的负载均衡方案,或LVS这类的软件负载均衡方案;

2、如何保持状态信息的同步,例如用户session等,这个时候会考虑的方案有写入数据库、写入存储、cookie或同步session信息等机制等;

3、如何保持数据缓存信息的同步,例如之前缓存的用户数据等,这个时候通常会考虑的机制有缓存同步或分布式缓存;

4、如何让上传文件这些类似的功能继续正常,这个时候通常会考虑的机制是使用共享文件系统或存储等;

在解决了这些问题后,终于是把webserver增加为了两台,系统终于是又恢复到了以往的速度。

clip_image013

图3.5

3.6第六步:分库

享受了一段时间的系统访问量高速增长的幸福后,发现系统又开始变慢了,这次又是什么状况呢,经过查找,发现数据库写入、更新的这些操作的部分数据库连接的资源竞争非常激烈,导致了系统变慢,这下怎么办呢,此时可选的方案有数据库集群和分库策略,集群方面像有些数据库支持的并不是很好,因此分库会成为比较普遍的策略,分库也就意味着要对原有程序进行修改,一通修改实现分库后,不错,目标达到了,系统恢复甚至速度比以前还快了。

clip_image015

图3.6

3.7第七步:分表、DAL和分布式缓存

随着系统的不断运行,数据量开始大幅度增长,这个时候发现分库后查询仍然会有些慢,于是按照分库的思想开始做分表的工作,当然,这不可避免的会需要对程序进行一些修改,也许在这个时候就会发现应用自己要关心分库分表的规则等,还是有些复杂的,于是萌生能否增加一个通用的框架来实现分库分表的数据访问,这个在ebay的架构中对应的就是DAL,这个演变的过程相对而言需要花费较长的时间,当然,也有可能这个通用的框架会等到分表做完后才开始做,同时,在这个阶段可能会发现之前的缓存同步方案出现问题,因为数据量太大,导致现在不太可能将缓存存在本地,然后同步的方式,需要采用分布式缓存方案了,于是,又是一通考察和折磨,终于是将大量的数据缓存转移到分布式缓存上了。

clip_image017

图3.7

3.8第八步:增加更多的webserver

在做完分库分表这些工作后,数据库上的压力已经降到比较低了,又开始过着每天看着访问量暴增的幸福生活了,突然有一天,发现系统的访问又开始有变慢的趋势了,这个时候首先查看数据库,压力一切正常,之后查看webserver,发现apache阻塞了很多的请求,而应用服务器对每个请求也是比较快的,看来是请求数太高导致需要排队等待,响应速度变慢,这还好办,一般来说,这个时候也会有些钱了,于是添加一些webserver服务器,在这个添加webserver服务器的过程,有可能会出现几种挑战:

1、Apache的软负载或LVS软负载等无法承担巨大的web访问量(请求连接数、网络流量等)的调度了,这个时候如果经费允许的话,会采取的方案是购买硬件负载,例如F5、Netsclar、Athelon之类的,如经费不允许的话,会采取的方案是将应用从逻辑上做一定的分类,然后分散到不同的软负载集群中;

2、原有的一些状态信息同步、文件共享等方案可能会出现瓶颈,需要进行改进,也许这个时候会根据情况编写符合网站业务需求的分布式文件系统等;

在做完这些工作后,开始进入一个看似完美的无限伸缩的时代,当网站流量增加时,应对的解决方案就是不断的添加webserver。

clip_image019

图3.8

3.9第九步:数据读写分离和廉价存储方案

突然有一天,发现这个完美的时代也要结束了,数据库的噩梦又一次出现在眼前了,由于添加的webserver太多了,导致数据库连接的资源还是不够用,而这个时候又已经分库分表了,开始分析数据库的压力状况,可能会发现数据库的读写比很高,这个时候通常会想到数据读写分离的方案,当然,这个方案要实现并不容易,另外,可能会发现一些数据存储在数据库上有些浪费,或者说过于占用数据库资源,因此在这个阶段可能会形成的架构演变是实现数据读写分离,同时编写一些更为廉价的存储方案,例如BigTable这种。

clip_image021

图3.9

3.10第十步:进入大型分布式应用时代和廉价服务器群梦想时代

经过上面这个漫长而痛苦的过程,终于是再度迎来了完美的时代,不断的增加webserver就可以支撑越来越高的访问量了,对于大型网站而言,人气的重要毋庸置疑,随着人气的越来越高,各种各样的功能需求也开始爆发性的增长,这个时候突然发现,原来部署在webserver上的那个web应用已经非常庞大了,当多个团队都开始对其进行改动时,可真是相当的不方便,复用性也相当糟糕,基本是每个团队都做了或多或少重复的事情,而且部署和维护也是相当的麻烦,因为庞大的应用包在N台机器上复制、启动都需要耗费不少的时间,出问题的时候也不是很好查,另外一个更糟糕的状况是很有可能会出现某个应用上的bug就导致了全站都不可用,还有其他的像调优不好操作(因为机器上部署的应用什么都要做,根本就无法进行针对性的调优)等因素,根据这样的分析,开始痛下决心,将系统根据职责进行拆分,于是一个大型的分布式应用就诞生了,通常,这个步骤需要耗费相当长的时间,因为会碰到很多的挑战:

1、拆成分布式后需要提供一个高性能、稳定的通信框架,并且需要支持多种不同的通信和远程调用方式;

2、将一个庞大的应用拆分需要耗费很长的时间,需要进行业务的整理和系统依赖关系的控制等;

3、如何运维(依赖管理、运行状况管理、错误追踪、调优、监控和报警等)好这个庞大的分布式应用。

经过这一步,差不多系统的架构进入相对稳定的阶段,同时也能开始采用大量的廉价机器来支撑着巨大的访问量和数据量,结合这套架构以及这么多次演变过程吸取的经验来采用其他各种各样的方法来支撑着越来越高的访问量。

clip_image023

图3.10

4.分析

随着平台做大做强,很可能会走向定制操作系统,定制数据库,甚至定制硬件,定制任何可以定制的东西这样一条路。

在服务器、架构、组件等技术选择方面,主要有两个方向:1选择成熟商用。2选择开源+自主研发。下面就这两个方向逐一进行简单分析。

1商用的优缺点

l 商用的优点之一是成熟,稳定,搭建快速。

l 商用的缺点之一是费用高,随着服务器的增加,license的费用上升,成本偏高。

l 商用的产品是通用化的,缺乏定制性,不能满足个性需要。

2开源+自主研发的优缺点

l 源码开放,可控性好,出现问题,可以从底层解决,扩展性好。

l 短期时间、人力投入大,初期见效慢;长期产出大,见效明显。

l 可以在软件和硬件的多个层面不断优化,充分满足个性化需要。

商用和开源+自主研发各有优缺点,各有互补性,要根据使用场景的不同来进行选择,也可以根据需要配合使用。

5.总结

目前大型网站的主流是LAMP(linux+apache+mysql+php),或者是在这基础之上的扩展,例如增加缓存,增加中间件(中间件大多使用java,c,c++或者.NET编写,或者购买成熟的中间件产品,IBM就有很多成熟的中间件产品);又或者替换其中的某些部分,例如前端使用python,ruby,lua这些新近流行的脚本语言,数据存储部分使用nosql或者文件系统。这样的选择有历史原因、费用原因、业务原因,也有在网站发展之后需要满足新的需求而衍生出来解决特定问题的原因。

也有初期使用微软系(windows+.NET+MSSQL)来构建网站的,在后面又根据需要加入其他体系的的电商,例如:京东,当当,凡客等。也有始终采用微软系的网站,国外的微软官网stackoverflow,还有曾经辉煌的myspace

其实,现在的发展趋势是:混合体系,而非单一的体系。就是说技术体系不是单一的,也不是固定一成不变的,而是根据业务以及网站的发展,以及技术的发展,选择合适的技术解决适当的问题。

架构的变更不是一件小事,对业务和网站的发展都很重要,不可能几天或者一半个月就变更一下,也不可能有事没事变更一下,应该是在关键的时候,有需要的时候,或者根据计划定期升级。

我觉得有一种方式可以帮助我们进行选择。就是根据我们的目标,或者说预估的业务量,预估的成交量,预估的用户量,划分几个平台发展里程碑,或者是时间段。然后根据平台发展的里程碑来规划技术选型的里程碑。考虑规模的同时,还需要考虑业务的类型,产生的数据的类型,对这些数据的处理需求等因素。

可以先定几个里程碑,这个里程碑的时间,可以根据前面的业务预估来裁定。先根据第一个里程碑要满足的业务需求,来选择当前的技术架构,并且进行存储空间规划。然后针对第一个到第二个里程碑的过度,进行预留设计,保证将来的平稳过渡。或者只是预留扩展的余地,这方面有时候有点难度,不过应该尽量做。

在第二个里程碑之前的1-2个月进行第二个里程碑技术架构的讨论和设计,因为这时候相比原有的第二个里程碑的业务估计可能会有变动,或者技术上有了新的选择,都可以及时考虑到本次的设计中来。以此类推后面的里程碑技术架构变更。

还有就是突发情况,因为总会有一些意料之外的情况发生,有的是业务发展的需要,有的是被动的需要。针对这些突发情况,也会进行架构的升级。

参考文献

QCon北京2012大会

http://www.qconbeijing.com/

全球软件开发大会

QCon是由InfoQ主办的全球顶级技术盛会,每年在伦敦、北京、东京、纽约、圣保罗、杭州、旧金山召开。自2007年3月份首次举办以来,已经 有包括传统制造、金融、电信、互联网、航空航天等领域的近万名架构师、项目经理、团队领导者和高级开发人员参加过QCon大会。

秉承“促进软件开发领域知识与创新的传播”原则,QCon各项议题专为中高端技术人员设计,内容源于实践并面向社区。演讲嘉宾依据各重点和热点话题,分享技术趋势和最佳实践;作为主办方,InfoQ努力为参会者提供良好的学习和交流环境。

1.淘宝

LAMP, .NET, Nginx, windows, linux, Oracle, MySQL, Lua, NoSQL

淘宝网,是一个在线商品数量突破一亿,日均成交额超过两亿元人民币,注册用户接近八千万的大型电子商务网站,是亚洲最大的购物网站。

· 日均 IP [周平均]   134700000

· 日均 PV [周平均]   2559300000

· 日均 IP [月平均]   137280000

· 日均 PV [月平均]   2608320000

· 日均 IP [三月平均]   130620000

· 日均 PV [三月平均]   2481780000

淘宝开放低耗服务器设计规范

电子商务网站(淘宝网)的系统架构解析

淘宝开源项目

存放淘宝所有的开源项目

揭秘淘宝自主研发的文件系统-TFS

目前,国内自主研发的文件系统可谓凤毛麟角。淘宝在这一领域做了有效的探索和实践,Taobao File System(TFS)作为淘宝内部使用的分布式文件系统,针对海量小文件的随机读写访问性能做了特殊优化,承载着淘宝主站所有图片、商品描述等数据存储。

淘宝开源Key/Value结构数据存储系统Tair技术剖析

Tair是由淘宝网自主开发的Key/Value结构数据存储系统,在淘宝网有着大规模的应用。您在登录淘宝、查看商品详情页面或者在淘江湖和好友“捣浆糊”的时候,都在直接或间接地和Tair交互。

走进淘宝开源平台

Node.js获得企业开发者亲睐

LinkedIn和淘宝部分功能使用了Node.js

淘宝的可伸缩高性能互联网架构揭秘

Java在淘宝的应用(淘宝的架构变迁)

HBase技术在淘宝中的应用

冯大辉谈数据库架构

淘宝架构师的年度展望

何崚谈阿里巴巴前端性能优化最佳实践

电子商务网站(淘宝网)的系统架构解析

2.腾讯

Php, asp

· 日均 IP [周平均]   222000000

· 日均 PV [周平均]   1776000000

· 日均 IP [月平均]   218640000

· 日均 PV [月平均]   1749120000

· 日均 IP [三月平均]   213930000

· 日均 PV [三月平均]   1711440000

谈腾讯开放平台关键技术

3.又拍网

Erlang, Python, PHP, Redis

又拍网架构中的消息/任务系统

3.赶集网

Php, MySQL

4.新浪微博

php

唐福林谈Redis应用实践

唐福林是新浪微博开放平台资深工程师,目前负责t.cn短链、用户关系、计数器等底层服务。他曾负责过包括新浪邮箱全文搜索在内的多个基于Lucene的 垂直搜索引擎开发,以及新浪爱问和新浪播客的运维,对承载大数据量、高并发的互联网基础设施建设有丰富的经验。他在QCon杭州2011大会的开放平台专 题做了名为《新浪微博开放平台中的Redis实践》的讲座,并和参会者做了热烈的讨论。会后,InfoQ中文站对唐福林做了采访。

新浪微博的注册用户数在3个月内从1.4亿增长到2亿,用户之间的关注,粉丝关系更是要再高出一个数量级,而且读取量还在以更快的速度增长。新浪微 博开放平台的接口中还有很多的数字,这些数字的读写量巨大,而且对一致性,实时性都要求很高。传统的 mysql+memcache 方案在这些场景下越来越力不从心,于是新浪微博开放平台大胆启用了 NoSql 领域的新贵 Redis 。

5.Facebook

LAMP

Facebook系统架构

Facebook架构设计中文版

Facebook架构学习

6.Twitter

Lamp,ruby

Twitter使用的大部分工具都是开源的。其结构是用Rails作前端,C,Scala和Java组成中间的业务层,使用MySQL存储数据。所有的东西都保存在RAM里,而数据库只是用作备份。Rails前端处理展现,缓存组织,DB查询以及同步插入。这一前端主要由几部分客户服务粘合而成,大部分是C写的:MySQL客户端,Memcached客户端,一个JSON端,以及其它。

中间件使用了Memcached,Varnish用于页面缓存,一个用Scala写成的MQ,Kestrel和一个Comet服务器也正在规划之中,该服务器也是用Scala写成,当客户端想要跟踪大量的tweet时它就能派上用场。

Twitter是作为一个“内容管理平台而非消息管理平台”开始的,因此从一开始基于聚合读取的模型改变到现在的所有用户都需要更新最新tweet的消息模型,需要许许多多的优化。这一改动主要在于三个方面:缓存,MQ以及Memcached客户端。

架构的变迁

Twitter架构(Cache篇)

7.eBay

lamp

可伸缩性的最佳实践

eBay的架构特点

聊聊电商网站的架构与安全

8.凡客

.net,c,c++

· 日均 IP [周平均]   6990000

· 日均 PV [周平均]   62910000

· 日均 IP [月平均]   7650000

· 日均 PV [月平均]   68850000

· 日均 IP [三月平均]   7983000

· 日均 PV [三月平均]   71847000

栾义来:凡客历程分享——应对规模和复杂性挑战

架构总监的来年展望

9.一号店

Java, jsp, linux, mysql, postgresql, oracle

· 日均 IP [周平均]   2610000

· 日均 PV [周平均]   23490000

· 日均 IP [月平均]   2793000

· 日均 PV [月平均]   25137000

· 日均 IP [三月平均]   2583000

· 日均 PV [三月平均]   20664000

1号店电商系统演进之路

10.银泰网

.net,jsp,java

11.当当

.net,php,jquery

CDN

CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各 处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应 时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。

http://baike.baidu.com/view/21895.htm

NoSQL开篇——为什么要使用NoSQL

说说技术型创业团队的技术选择

续——冯大辉谈技术性创业团队的技术选型

互联网技术平台迁移杂谈

分享我的大型Java多用户商城系统开发的心得和困难

电子商务软件及软件服务提供商论坛

基于J2EE架构的电子商务网站实例解析

中小型电子商务网站架构-从业总结

1、大型网站架构设计图

clip_image025

2、PlentyOfFish 网站架构

http://www.dbanotes.net/arch/plentyoffish_arch.html

超过 3000 万的日点击率

对于动态出站(outbound)的数据进行压缩,这耗费了30%的CPU能力,但节省了带宽资源

负载均衡采用 ServerIron (Conf Refer)(ServerIron 使用简单,而且功能比 NLB 更丰富)

一共三台 SQL Server,一台作为主库,另外两台只读数据库支撑查询,大力气优化 DB

3、YouTube 的架构

http://www.dbanotes.net/opensource/youtube_web_arch.html

相当大的数据流量——每天有10亿次下载以及6,5000次上传

大部分代码都是 Python 开发的

Web 服务器有部分是 Apache, 用 FastCGI 模式。对于视频内容则用 Lighttpd 。(国内的豆瓣用的Lighttpd)

启用了单独的服务器群组来承担视频压力,并且针对 Cache 和 OS 做了部分优化,访问量大的视频放在CDN上,自己的只需承担小部分访问压力

用 MySQL 存储元数据–用户信息、视频信息什么的。

业务层面的分区(在用户名字或者 ID 上做文章,应用程序控制查找机制)

4、Yahoo!社区架构

http://www.dbanotes.net/arch/yahoo_arch.html

5、Amazon 的 Dynamo 架构

http://www.dbanotes.net/techmemo/amazon_dynamo.html

 

clip_image029

6、财帮子(caibangzi.com)网站架构

http://www.dbanotes.net/arch/caibangzi_web_arch.html

7、说说大型高并发高负载网站的系统架构(更新)

http://www.toplee.com/blog/71.html

from:http://www.cnblogs.com/virusswb/archive/2012/01/10/2318169.html

Redis作者谈Redis应用场景

毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象构建不同的冰箱。希望你喜欢这个比喻。

下面是一篇新鲜出炉的文章,其作者是Redis作者@antirez,他描述了Redis比较适合的一些应用场景,NoSQLFan简单列举在这里,供大家一览:

1.取最新N个数据的操作

比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取

  • 使用LPUSH latest.comments<ID>命令,向list集合中插入数据
  • 插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID
  • 然后我们在客户端获取某一页评论时可以用下面的逻辑(伪代码)
FUNCTION get_latest_comments(start,num_items):
    id_list = redis.lrange("latest.comments",start,start+num_items-1)
    IF id_list.length < num_items
        id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")
    END
    RETURN id_list
END

如果你还有不同的筛选维度,比如某个分类的最新N条,那么你可以再建一个按此分类的List,只存ID的话,Redis是非常高效的。

2.排行榜应用,取TOP N操作

这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。

3.需要精准设定过期时间的应用

比如你可以把上面说到的sorted set的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。

4.计数器应用

Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。

5.Uniq操作,获取某段时间所有数据排重值

这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。

6.实时系统,反垃圾系统

通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。

7.Pub/Sub构建实时消息系统

Redis的Pub/Sub系统可以构建实时的消息系统,比如很多用Pub/Sub构建的实时聊天系统的例子。

8.构建队列系统

使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。

9.缓存

这个不必说了,性能优于Memcached,数据结构更多样化。

from:http://blog.nosqlfan.com/html/2235.html?ref=rediszt

Microsoft .NET Frameworks features details

This article describes the features and enhancements that has happened with respect to Microsoft .NET Frameworks

Microsoft .NET Frameworks….

Features and enhancements that has happened with respect to Microsoft .NET Frameworks

Objective

To know the series of events happened with respect to .NET framework.

Microsoft .NET Framework Details

Features: .NET Framework Version – V1.0/1.1: Released in Year 2002/2003

 

  1. CLR 1.0/1.1
  2. C#.NET was introduced
  3. Upgraded to VB.NET from VB 6
  4. Upgraded to ASP.NET from ASP 3
  5. Upgraded to ADO.NET from ADO
  6. Remoting (previously DCOM) was introduced
  7. Web Services introduced
  8. Visual Studio Versions:  2002/2003

 

Features: NET Framework Version – V 2.0: Released in Year/2005

 

  1. CLR 2.0
  2. C#/VB/ASP/ADO.NET 2.0
  3. Web Services Enhancements (WSE)
  4. ASP.NET AJAX
  5. Visual Studio Versions:  2005

 

Features: NET Framework Version – V 3.0: Released in Year/2006

 

  1. CLR 2.0
  2. C#/VB/ASP/ADO.NET 2.0
  3. Windows Presentation Foundation (WPF) introduced
  4. Windows Communication Foundation (WCF) introduced
  5. Windows Workflow Foundation (WF) introduced
  6. Windows CardSpace introduced
  7. Visual Studio Versions:  VS 2005

 

Features: NET Framework Version – V3.5: Released in Year/2008

 

  1. CLR 2.0
  2. C#/VB/ASP/ADO.NET 3.5
  3. Language Integrated Query (LINQ)
  4. WCF/WPF/WF 3.5
  5. ASP.NET AJAX is built-in
  6. Visual Studio Versions:  VS 2008

 

Features: NET Framework Version – V3.5 SP1: Released in Year/2009

 

  1. Silverlight
  2. Entity Framework
  3. ASP.NET MVC

 

Features: NET Framework Version – V4.0: Released in Year/2010

 

  1. CLR 4.0
  2. C#/VB/ASP/ADO.NET 4.0
  3. LINQ/EF 4.0
  4. WCF/WPF/WF 4.0
  5. Silverlight 3.0
  6. ASP.NET MVC 2.0
  7. F#.NET introduced
  8. Dynamic Programming
  9. Parallel Programming
  10. Visual Studio Versions: VS 2010

 

Features: NET Framework Version – V4.5: Beta is released

 

  1. Visual Studio Versions: VS 2011

For further reading on V4.5, visit http://www.asp.net/vnext/overview/whitepapers/whats-new

from:http://www.dotnetfunda.com/articles/article1792-microsoft-net-frameworks-features-details.aspx

SQL Server 的事务和锁

最近在项目中进行压力测试遇到了数据库的死锁问题,简言之,如下的代码在 SERIALIZABLE 隔离级别造成了死锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT @findCount=COUNT(id) FROM MyTable
WHERE [fk_related_id]=@Argument
IF (@findCount > 0)
BEGIN
    ROLLBACK TRANSACTION
    RETURN ERROR_CODE
END
INSERT INTO MyTable ([fk_related_id],…)
VALUES (@Argument,…)
COMMIT TRANSACTION
RETURN SUCCESS_CODE

 

在搞清楚这个问题的过程中做了不少的实验,与各位共享。这一篇是开篇,主要说明的是 SQL Server 的四种(其实还有别的)经典的事务隔离级别,以及在不同的隔离级别下锁的使用手段,以及所带来的不同的数据一致性。

SQL Server 中锁的种类(Schema操作就暂时不涉及了)

锁类型 描述
(Shared Lock) 用于只读操作数据锁定
(Update Lock) 用于数据的更新,在数据真正的需要更新的时候会申请升级为X锁。
X(Exclusive Lock) 独占锁,用于数据的更改。
Key-Range Lock(稍后讨论) 仅仅在 Serializable 隔离级别保护数据,以避免任何有可能使得本事务第二次读取信息产生错误的数据插入操作

各个事务隔离级别下锁的使用

SQL Server 中有四种事务隔离级别,具体的大家去参建 MSDN。下面列出在不同的事务隔离级别下这些锁是如何使用的:

隔离级别 读数据锁状态 写数据锁状态 锁持有时间
Read Uncommitted 不获得任何锁 不获得任何锁
Read Committed 数据获得S锁 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; 读完即释放,并不持有至事务结束。
Repeatable Read 数据获得S锁 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁; 持有至事务结束
Serializable 数据获得S锁,同时获得Key-Range锁。 对于 INSERT、DELETE、UPDATE的执行,获得X锁;对于UPDATE的标记,获得U锁,同时获得Key-Range锁。 持有至事务结束

我们可以利用这些知识形象说明各个隔离级别下的数据一致性:

Read Uncommitted 级别

(1)脏读

image

(2)更新丢失

image

(3)不可重复读

image

(4)幻读

clip_image001

Read Committed 级别

(1)脏读

clip_image001[5]

(2)更新丢失

clip_image002

(3)不可重复读

clip_image003

(4)幻读

clip_image004

Repeatable Read 级别

(1)脏读

clip_image005

(2)更新丢失

clip_image006

(3)不可重复读

clip_image007

(4)幻读

clip_image008

Serializable 级别

(1)脏读

clip_image009

(2)更新丢失

clip_image010

(3)不可重复读

clip_image011

(4)幻读

clip_image012

我们从上图可以比较直观的看到以下的结论

脏读 更新丢失 不可重复读 幻读
Read Uncommitted 可能 可能 可能 可能
Read Committed 不可能 可能 可能 可能
Repeatable Read 不可能 不可能 不可能 可能
Serializable 不可能 不可能 不可能 不可能

这一篇到此为止,下一篇详细介绍 Key-Range Lock 并分析开篇提到的死锁问题。

 

 

在这篇随笔中,我们的主要关注点在 Key-Range Lock。Key-Range Lock有 S-S、S-U、I-N、X-X几种情况。我们一个一个来说,力求明白。遗憾的是,这里可能会比较冗长,那么死锁分析只好依次顺延了。

Range S-S锁的获取规则

MSDN 对 Range 锁的规则有部分描述,但是言简意赅,以下我们会将各种情况分解开来,理清MSDN中涉及的或者未涉及的规则,这些规则适用于SQL Server 2000/2005/2008/2008 R2。关于MSDN的描述,请参见:http://technet.microsoft.com/zh-cn/library/ms191272(en-us,SQL.110).aspx。

在描述规则之前需要声明的是,我们的聚集索引就建立在 WHERE 字句之上,这很重要,否则是不会获得 Range 锁的,也就达不到 SERIALIZABLE 的要求了;另外,为了讨论简便,以下的 SQL 全部省略 SET TRANSACTION ISOLATION LEVEL SERIALIZABLE 的声明。

我们假设有以下的表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE TABLE [dbo].[MyTable](
    [id] [int] IDENTITY(1,1) NOT NULL,
    [index_column] [int] NOT NULL,
    [data] [int] NOT NULL,
    CONSTRAINT [PK_MyTable] PRIMARY KEY NONCLUSTERED
    (
        [id] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]
CREATE UNIQUE CLUSTERED INDEX [IX_MyTable] ON [dbo].[MyTable]
(
    [index_column] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

并假设我们有如下的数据:

1
2
3
4
5
6
7
8
9
10
INSERT INTO [MyTable] ([index_column],[data]) VALUES (1, 1)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (2, 2)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (3, 3)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (4, 4)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (5, 5)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (15, 6)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (16, 7)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (18, 8)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (25, 9)
INSERT INTO [MyTable] ([index_column],[data]) VALUES (30, 10)

那么这张表看起来应该是这样的(我另外还将Index的Hash值以及row所在的数据页Dump出来了,以便咱们做实验)。

id index_column data index hash row page
1 1 1 (8194443284a0) 78
2 2 2 (61a06abd401c) 78
3 3 3 (98ec012aa510) 78
4 4 4 (a0c936a3c965) 78
5 5 5 (59855d342c69) 78
6 15 6 (f1de2a205d4a) 78
7 16 7 (f07ed88b2b23) 78
8 18 8 (e9069d930a93) 78
9 25 9 (b81181109ebc) 78
10 30 10 (8034b699f2c9) 78

对于WHERE子句中的条件命中现有记录的情况

规则一:如果 WHERE 子句使用的是“相等”条件,例如“WHERE [index_column]=6”,并且该索引是唯一索引,则该索引不会获得Key-Range S-S锁,仅仅是Key上获得普通S锁;

假设我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=1

那么我们使用 sp_lock 得到锁的情况:

image

可以发现第一个索引上获得了S锁,但并不是 Range S-S 锁。

规则二:如果 WHERE 子句使用的是“范围”条件,例如“>、<、BETWEEN、IN”等。不论该索引是否唯一,WHERE子句规定都会成为 Range S-S 锁作用的范围,除此之外,在索引排序规则之下,这个作用范围的“下一个”索引项也会获得Range S-S锁。

我们必须首先解释一下“下一个”是怎么一回事,“下一个”索引项有两种情况:

第一:如果在索引排序规则下,作用范围之外按照数据排布的方向能够找到一个存在的,或者是“残存的”索引项(已经提交删除,数据库中再也看不到了,但是还没有从B树数据页中删除),那么这个索引项就是“下一个”索引项;

第二:如果在索引排序规则下,作用范围之外按照数据排布的方向找不到任何残存的索引项,那么无限远(Resource Hash为0xffffffff)的索引项就是“下一个”索引项。

我们结合规则二进行说明,例如我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>=1 AND [index_column]<=4

那么 index_column 中的值为 1、2、3、4的索引会获得 Range S-S 锁,除此以外,4之后的下一个索引值,也就是5对应的索引会获得 Range S-S锁。这和我们的实验结果刚好一致。

image

 

我们再来看着一个,例如我们执行:

SELECT [data] FROM [MyTable] WHERE [index_column]>=20 AND [index_column]<=40

那么 index_column 为 25、30的索引会获得 Range S-S 锁,除此以外,30之后的下一个索引值,也就是“无限远”会获得 Range S-S 锁,请看实际Dump的锁的使用情况:

image

 

我们最后练一个稍稍复杂点儿情况:

SELECT [data] FROM [MyTable]

WHERE ([index_column]>=2 AND [index_column]<=4) OR ([index_column]>=10 AND [index_column]<=16) OR ([index_column]>=30 AND [index_column]<=40)

这里想说明的问题是,我们的“范围”是指一个个的闭合的范围,要一个个套用规则进行分析,我们现在有3块儿闭合的范围,分别是 [2,4]、[10,16]、[30,40]。我们一个个的来,对于[2,4],在这个范围内2,3,4,5获得 Range S-S锁;

对于[10,16]范围,15,16,18获得 Range S-S锁;对于[30,40]范围,30,无限远获得 Range S-S锁,一共9个。

image

 

规则一补充:如果 WHERE 子句使用的是“相等”条件,但是该索引不是唯一索引,那么除了WHERE命中的索引获得 Range S-S锁之外,“下一个”索引也会获得 Range S-S锁。

我今天仔细的做了关于这个规则的验证。另外查阅了 SQL Server 2000 – 2008 Internals 的图书中关于这个问题的记载。在不是唯一索引的情况下,没有以上这种固定的选择规则。以上规则只有在一些特定情况下才出现。而其他规则是没有问题的。

对于WHERE子句中的条件不能命中任何记录的情况

规则三:如果 WHERE 子句使用的是“相等”条件,不论索引是否为唯一索引,若不能够命中任何记录,除该 WHERE 子句规定的那个不存在的记录作为 Range S-S的一部分之外,该记录的“下一个”索引值也将会获得 Range S-S 锁。

例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=6

那么下一条索引记录为15所对应的索引,因此这个索引将会获得 Range S-S 锁。

image

 

又例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]=31

那么下一索引记录应该是“无限远”对应的索引,则这个索引将会获得 Range S-S 锁。

image

 

规则四:如果WHERE子句中使用“范围”条件,不论索引是否为唯一索引,若不能够命中任何记录,除该 WHERE 子句规定的那个不存在的范围作为 Range S-S的一部分外,该范围的“下一个”索引值也将会获得 Range S-S锁。

例如,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>=6 AND [index_column]<=10

我实在是写不动了,请各位开动脑筋吧,这里直接给结果:

image

 

再来一个例子吧,我们执行

SELECT [data] FROM [MyTable] WHERE [index_column]>30 AND [index_column]<40

结果是:

image

 

好了,这一篇终于搞定了。下一篇我们到了 Range S-U 以及 Range I-N 这下会死锁了,有好戏看了。

 

在上一篇中忘记了一个细节。Range T-K 到底代表了什么?Range T-K Lock 代表了在 SERIALIZABLE 隔离级别中,为了保护范围内的数据不被并发的事务影响而使用的一类锁模式(避免幻读)。它由两个部分构成:

第一个部分代表了他锁定了一个索引范围,在这个范围内,所有索引使用 T 锁进行锁定;

第二个部分是而这个范围内已经命中的Key,这些 Key 将使用 K 锁进行锁定。

合并在一起我们说在这个范围内,索引范围和特定的row的锁定模式为 Range T-K。

举上一篇的一个例子吧:

SELECT [data] FROM [MyTable] WHERE [index_column]>=20 AND [index_column]<=40

的锁的使用情况是:

image

实际上,上述语句产生的锁有两个部分,第一个是 Range S 锁,范围是 20-40 的索引范围,第二是 Key 上使用的 S 锁,在图中可以看到有三个 Key 被命中了,分别是“无限远”,“25”对应的索引以及“30”对应的索引。其 Mode 为 Range S-S,其 Type 为 KEY,也就是,他们的范围锁为 Range S,Key 锁为 S 锁。

更新和插入操作涉及的锁

涉及的锁主要是两种,一种是 Range S-U 锁,另一种是 Range X-X 锁。

Range S-U,这个选定索引范围会获得 S 锁而命中的 Key 使用 U 锁锁定,以便将来转换为 X 锁。而在更新时,则彻底成为 X 锁,这个范围内的锁模式也就成了 Range X-X。由于更新的数据列不同(有可能是索引列,有可能不是),使用的索引也不同(聚集,非聚集,唯一,等),因此其情况就不容易像 Range S-S 锁那么容易得出规律了。总的来说有几种情况还是一致的,这里就不再逐个实验了(这里强烈推荐阅读 SQL Server 2008 Internals 这本书关于锁的章节,讲述的很清楚):

首先,在相等判断(例如“=”),且索引为唯一索引的情况下。如果该索引命中,不会有 Range T-K 锁锁定记录范围,而相应的记录直接获得 U 锁或者 X 锁;

其次,在相等判断,不论索引是否为唯一索引,如果该索引没有命中记录,则 Range T-K 锁锁定 “下一个”记录。(关于“下一个”的解释请参见上一篇);

第三,在范围条件(>、<、BETWEEN),不论索引是否唯一,如果该索引命中,不但该范围会获得 Range T-K 锁,而该范围的“下一个”记录也会获得 Range T-K 锁。

为什么 Serializable 隔离级别更容易死锁

我们从第一篇的图可以看到,SERIALIZABLE 级别能够保证最严格的数据一致性,但是这些保卫的手段只要稍稍变化就可以发展为死锁。事实上,在各种隔离级别中,数据一致性越高,则越容易发生死锁;数据一致性越低,则发生死锁的概率就越小。

在这些隔离级别中,SERIALIZABLE 是最容易死锁的,这得益于 Range T-K 锁使锁定的范围不仅仅限于现有数据,还有未来数据;不仅仅限定现有的若干数据页,而是一个广大的范围。

这其中,最恐怖的问题莫过于“下一个”数据的锁定。这非常容易造成大范围死锁。我们以第一篇的例子来说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
SELECT @findCount=COUNT(id) FROM MyTable
WHERE [fk_related_id]=@Argument
IF (@findCount > 0)
BEGIN
    ROLLBACK TRANSACTION
    RETURN ERROR_CODE
END
INSERT INTO MyTable ([fk_related_id],…)
VALUES (@Argument,…)
COMMIT TRANSACTION
RETURN SUCCESS_CODE

在这个例子中,表 MyTable 的列 fk_related_id 是一个唯一索引(非聚集),事务隔离级别为 SERIALIZABLE。不同的存储过程执行会传入不同的 @Argument,表面看来,这不会有任何的问题,但是由于“下一个”数据的锁定,在稍高水平的并发上,就出现了大约 80% 的失败情况,这些失败都来源于死锁。我们挑选了其中的一次:

我们试图以每秒钟 15 个的压力在 @Argument 属于 [1, 1000] 的范围内进行存储过程调用。在这个过程中,有一个 @Argument 为 115 的记录首先成功的插入了进去!

id fk_related_id data
1 115

接下来有一个 @Argument 为 74 的记录获得了机会,我们假设它的 Session Id 为 A。它执行了 SELECT 语句:

id fk_related_id data
1 115 (A 获得了Range S-S Lock)

接下来有一个 @Argument 为 4 的记录获得了机会,我们假设它的 Session Id 为 B。它执行了 SELECT 语句:

id fk_related_id data
115 (A 、B获得了Range S-S Lock)

接下来,Session A 执行到了 INSERT 语句,那么 Range S-S 锁会试图进行一个转换测试(Range I-N 锁),但这显然是行不通的,因为 Session B 也获得了 Range S-S Lock,因此 Session A 陷入了等待;

而 Session B 也执行到了 INSERT 语句,相同的,它也陷入了等待;这样,Session A 等待 Session B 放弃 Range 锁,Session B 等待 Session A 放弃锁,这是一个死锁了。

而更糟糕的事情是,凡是 @Argument 小于 115 的记录,他都会试图令下一个记录获得新的 Range S-S 锁,从而进入无限的等待中,至少,1-115 号记录死锁,并且最终 114 个需要放弃,1个成功。这就是为什么 SERIALIZABLE 隔离级别不但会发生死锁,而且在某些时候,是大面积死锁。

总之:在 SERIALIZABLE 隔离级别下,只要有类似同一索引为条件先读后写的状况的,在较大并发下发生死锁的概率很高,而且如果碰巧既有的记录索引按照排序规则在非常靠后的位置,则很可能发生大面积死锁。

那么如何解决这个问题呢,呃,降低隔离级别当然是一个方法,例如,如果你能接受幻读,那么 REPEATABLE READ 是一个不错的选择。但是我突然在某篇博客中看到了使用 SELECT WITH UPDLOCK 的方法。事实上,这种东西让死锁更容易了。

例如,一个存储过程 SELECT B,而后 SELECT A;而另外的存储过程先 SELECT A,再 SELECT B,那么由于顺序不同,排他锁仅仅是 Read 的情况就可能发生死锁了。

那么为什么 REPEATABLE READ 会好得多呢?因为 REPEATABLE READ 紧紧锁定现有记录,而不会使用 Range 锁。我们仍然以上述存储过程为例,这样,只有两个被锁定的行数据在同一个页上(因为默认情况下使用页级锁),或者说挨得足够近,才有可能死锁,并且这个死锁仅仅限于这个数据页上的记录而不会影响其他记录,因此死锁的概率大大降低了。

我们实际测试中,在相同的测试条件下,并发提高到 100 的情况下时才有不到 0.1% 的死锁失败几率。当然我们付出了允许幻读的代价。

from:http://www.cnblogs.com/qanholas/archive/2012/05/02/2479340.html

Flickr Architecture

Update: Flickr hits 2 Billion photos served. That’s a lot of hamburgers.

Flickr is both my favorite bird and the web’s leading photo sharing site. Flickr has an amazing challenge, they must handle a vast sea of ever expanding new content, ever increasing legions of users, and a constant stream of new features, all while providing excellent performance. How do they do it?

Site: http://www.flickr.com

Information Sources

  • Flickr and PHP (an early document)
  • Capacity Planning for LAMP
  • Federation at Flickr: Doing Billions of Queries a Day by Dathan Pattishall.
  • Building Scalable Web Sites by Cal Henderson from Flickr.
  • Database War Stories #3: Flickr by Tim O’Reilly
  • Cal Henderson’s Talks. A lot of useful PowerPoint presentations.

    Platform

  • PHP
  • MySQL
  • Shards
  • Memcached for a caching layer.
  • Squid in reverse-proxy for html and images.
  • Linux (RedHat)
  • Smarty for templating
  • Perl
  • PEAR for XML and Email parsing
  • ImageMagick, for image processing
  • Java, for the node service
  • Apache
  • SystemImager for deployment
  • Ganglia for distributed system monitoring
  • Subcon stores essential system configuration files in a subversion repository for easy deployment to machines in a cluster.
  • Cvsup for distributing and updating collections of files across a network.

    The Stats

  • More than 4 billion queries per day.
  • ~35M photos in squid cache (total)
  • ~2M photos in squid’s RAM
  • ~470M photos, 4 or 5 sizes of each
  • 38k req/sec to memcached (12M objects)
  • 2 PB raw storage (consumed about ~1.5TB on Sunday
  • Over 400,000 photos being added every day

    The Architecture

  • A pretty picture of Flickr’s architecture can be found on this slide . A simple depiction is:
    — Pair of ServerIron’s
    —- Squid Caches
    —— Net App’s
    —- PHP App Servers
    —— Storage Manager
    —— Master-master shards
    —— Dual Tree Central Database
    —— Memcached Cluster
    —— Big Search Engine

    – The Dual Tree structure is a custom set of changes to MySQL that allows scaling by incrementally adding masters without a ring architecture. This allows cheaper scaling because you need less hardware as compared to master-master setups which always requires double the hardware.
    – The central database includes data like the ‘users’ table, which includes primary user
    keys (a few different IDs) and a pointer to which shard a users’ data can be found on.

  • Use dedicated servers for static content.
  • Talks about how to support Unicode.
  • Use a share nothing architecture.
  • Everything (except photos) are stored in the database.
  • Statelessness means they can bounce people around servers and it’s easier to make their APIs.
  • Scaled at first by replication, but that only helps with reads.
  • Create a search farm by replicating the portion of the database they want to search.
  • Use horizontal scaling so they just need to add more machines.
  • Handle pictures emailed from users by parsing each email is it’s delivered in PHP. Email is parsed for any photos.
  • Earlier they suffered from Master-Slave lag. Too much load and they had a single point of failure.
  • They needed the ability to make live maintenance, repair data, and so forth, without taking the site down.
  • Lots of excellent material on capacity planning. Take a look in the Information Sources for more details.
  • Went to a federated approach so they can scale far into the future:
    – Shards: My data gets stored on my shard, but the record of performing action on your comment, is on your shard. When making a comment on someone else’s’ blog
    – Global Ring: Its like DNS, you need to know where to go and who controls where you go. Every page view, calculate where your data is, at that moment of time.
    – PHP logic to connect to the shards and keep the data consistent (10 lines of code with comments!)
  • Shards:
    – Slice of the main database
    – Active Master-Master Ring Replication: a few drawbacks in MySQL 4.1, as honoring commits in Master-Master. AutoIncrement IDs are automated to keep it Active Active.
    – Shard assignments are from a random number for new accounts
    – Migration is done from time to time, so you can remove certain power users. Needs to be balanced if you have a lot of photos… 192,000 photos, 700,000 tags, will take about 3-4 minutes. Migration is done manually.
  • Clicking a Favorite:
    – Pulls the Photo owners Account from Cache, to get the shard location (say on shard-5)
    – Pulls my Information from cache, to get my shard location (say on shard-13)
    – Starts a “distributed transaction” – to answer the question: Who favorited the photo? What are my favorites?
  • Can ask question from any shard, and recover data. Its absolutely redundant.
  • To get rid of replication lag…
    – every page load, the user is assigned to a bucket
    – if host is down, go to next host in the list; if all hosts are down, display an error page. They don’t use persistent connections, they build connections and tear it down. Every page load thus, tests the connection.
  • Every users reads and writes are kept in one shard. Notion of replication lag is gone.
  • Each server in shard is 50% loaded. Shut down 1/2 the servers in each shard. So 1 server in the shard can take the full load if a server of that shard is down or in maintenance mode. To upgrade you just have to shut down half the shard, upgrade that half, and then repeat the process.
  • Periods of time when traffic spikes, they break the 50% rule though. They do something like 6,000-7,000 queries per second. Now, its designed for at most 4,000 queries per second to keep it at 50% load.
  • Average queries per page, are 27-35 SQL statements. Favorites counts are real time. API access to the database is all real time. Achieved the real time requirements without any disadvantages.
  • Over 36,000 queries per second – running within capacity threshold. Burst of traffic, double 36K/qps.
  • Each Shard holds 400K+ users data.
    – A lot of data is stored twice. For example, a comment is part of the relation between the commentor and the commentee. Where is the comment stored? How about both places? Transactions are used to prevent out of sync data: open transaction 1, write commands, open transaction 2, write commands, commit 1st transaction if all is well, commit 2nd transaction if 1st committed. but there still a chance for failure when a box goes down during the 1st commit.
  • Search:
    – Two search back-ends: shards 35k qps on a few shards and Yahoo!’s (proprietary) web search
    – Owner’s single tag search or a batch tag change (say, via Organizr) goes to the Shards due to real-time requirements, everything else goes to Yahoo!’s engine (probably about 90% behind the real-time goodness)
    – Think of it such that you’ve got Lucene-like search
  • Hardware:
    – EMT64 w/RHEL4, 16GB RAM
    – 6-disk 15K RPM RAID-10.
    – Data size is at 12 TB of user metadata (these are not photos, this is just innodb ibdata files – the photos are a lot larger).
    – 2U boxes. Each shard has~120GB of data.
  • Backup procedure:
    – ibbackup on a cron job, that runs across various shards at different times. Hotbackup to a spare.
    – Snapshots are taken every night across the entire cluster of databases.
    – Writing or deleting several huge backup files at once to a replication filestore can wreck performance on that filestore for the next few hours as it replicates the backup files. Doing this to an in-production photo storage filer is a bad idea.
    – However much it costs to keep multiple days of backups of all of your data, it’s worth it. Keeping staggered backups is good for when you discover something gone wrong a few days later. something like 1, 2, 10 and 30 day backups.
  • Photos are stored on the filer. Upon upload, it processes the photos, gives you different sizes, then its complete. Metadata and points to the filers, are stored in the database.
  • Aggregating the data: Very fast, because its a process per shard. Stick it into a table, or recover data from another copy from other users shards.
  • max_connections = 400 connections per shard, or 800 connections per server & shard. Plenty of capacity and connections. Thread cache is set to 45, because you don’t have more than 45 users having simultaneous activity.
  • Tags:
    – Tags do not fit well with traditional normalized RDBMs schema design. Denormalization or heavy caching is the only way to generate a tag cloud in milliseconds for hundreds of millions of tags.
    – Some of their data views are calculated offline by dedicated processing clusters which save the results into MySQL because some relationships are so complicated to calculate it would absorb all the database CPU cycles.
  • Future Direction:
    – Make it faster with real-time BCP, so all data centers can receive writes to the data layer (db, memcache, etc) all at the same time. Everything is active nothing will ever be idle.

    Lessons Learned

  • Think of your application as more than just a web application. You’ll have REST APIs, SOAP APIs, RSS feeds, Atom feeds, etc.
  • Go stateless. Statelessness makes for a simpler more robust system that can handle upgrades without flinching.
  • Re-architecting your database sucks.
  • Capacity plan. Bring capacity planning into the product discussion EARLY. Get buy-in from the $$$ people (and engineering management) that it’s something to watch.
  • Start slow. Don’t buy too much equipment just because you’re scared/happy that your site will explode.
  • Measure reality. Capacity planning math should be based on real things, not abstract ones.
  • Build in logging and metrics. Usage stats are just as important as server stats. Build in custom metrics to measure real-world usage to server-based stats.
  • Cache. Caching and RAM is the answer to everything.
  • Abstract. Create clear levels of abstraction between database work, business logic, page logic, page mark-up and the presentation layer. This supports quick turn around iterative development.
  • Layer. Layering allows developers to create page level logic which designers can use to build the user experience. Designers can ask for page logic as needed. It’s a negotiation between the two parties.
  • Release frequently. Even every 30 minutes.
  • Forget about small efficiencies, about 97% of the time. Premature optimization is the root of all evil.
  • Test in production. Build into the architecture mechanisms (config flags, load balancing, etc.) with which you can deploy new hardware easily into (and out of) production.
  • Forget benchmarks. Benchmarks are fine for getting a general idea of capabilities, but not for planning. Artificial tests give artificial results, and the time is better used with testing for real.
  • Find ceilings.
    – What is the maximum something that every server can do ?
    – How close are you to that maximum, and how is it trending ?
    – MySQL (disk IO ?)
    – SQUID (disk IO ? or CPU ?)
    – memcached (CPU ? or network ?)
  • Be sensitive to the usage patterns for your type of application.
    – Do you have event related growth? For example: disaster, news event.
    – Flickr gets 20-40% more uploads on first work day of the year than any previous peak the previous year.
    – 40-50% more uploads on Sundays than the rest of the week, on average
  • Be sensitive to the demands of exponential growth. More users means more content, more content means more connections, more connections mean more usage.
  • Plan for peaks. Be able to handle peak loads up and down the stack.

from:http://highscalability.com/flickr-architecture