前不久公司请来了位互联网界的技术大牛跟我们做了一次大型网站架构的培训,两天12个小时信息量非常大,知识的广度和难度也非常大,培训完后我很难完整理出全部听到的知识,今天我换了个思路是回味这次培训,这个思路就是通过本人目前的经验和技术水平来思考下大型网站技术演进的过程。
大型网站定义
首先我们要思考一个问题,什么样的网站才是大型网站,从网站的技术指标角度考虑这个问题人们很容易犯一个毛病就是认为网站的访问量是衡量的指标,懂点行的人也许会认为是网站在单位时间里的并发量的大小来作为指标,如果按这些标准那么像hao123这样的网站就是大型网站了,如下图所示:
其实这种网站访问量非常大,并发数也非常高,但是它却能用最为简单的Web技术来实现:我们只要保持网站的充分的静态化,多部署几台服务器,那么就算地球上所有人都用它,网站也能正常运行。
大型网站是技术和业务的结合,一个满足某些用户需求的网站只要技术和业务二者有一方难度很大,必然会让企业投入更多的、更优秀的人力成本实现它,那么这样的网站就是所谓的大型网站了 。
服务器部署
一个初建的网站往往用户群都是很小的,最简单的网站架构就能解决实际的用户需求,当然为了保证网站的稳定性和安全性,我们会把网站的应用部署到至少两台机器上,后台的存储使用数据库,如果经济实力允许,数据库使用单台服务器部署,由于数据是网站的生命线,因此我们常常会把部署数据库的服务器使用的好点,这个网站结构如下所示:
这个结构非常简单,其实大部分初建网站开发里往往业务逻辑没有企业级系统那么复杂,所以只要有个好的idea,建设一个新网站的成本是非常低的,所使用的技术手段也是非常的基本和简单。
我们要准备三台服务器,而且还要租个机房放置我们的服务器,这些成本对于草根和屌丝还是非常高的,幸运的是当下很多大公司和机构提供了云平台,我们可以花费很少的钱将自己的应用部署到云平台上,这种做法我们甚至不用去考虑把应用、数据库分开部署的问题,更加进一步的降低了网站开发和运维的成本,但是这种做法也有一个问题,就是网站的小命被这个云平台捏住了,如果云平台挂了,俺们的网站服务也就跟着挂了。
这里我先讲讲自己独立使用服务器部署网站的问题,如果我们要把网站服务应用使用多台服务器部署,这么做的目的一般有两个:
不过要做到以上两点,并不是我们简单将网站分开部署就可以满足的,因为大多数网站在用户使用时候都是要保持用户的状态,具体点就是网站要记住请求是归属到那一个客户端,而这个状态在网站开发里就是通过会话session来体现的。
Session机制
分开部署的Web应用服务要解决的一个首要问题就是要 保持不同物理部署服务器之间的session同步问题 ,从而达到当用户第一次请求访问到服务器A,第二个请求访问到服务器B,网站任然知道这两个请求是同一个人,解决方案很直接:服务器A和服务器B上的session信息要时刻保持同步,那么如何保证两台服务器之间session信息的同步呢?
为了回答上面的问题,我们首先要理解下session的机制,session信息在Web容器里都是存储在内存里的,Web容器会给每个连接它的客户端生成一个sessionid值,这个sessionid值会被Web容器置于http协议里的cookie域下,当响应被客户端处理后,客户端本地会存储这个sessionid值,用户以后的每个请求都会让这个sessionid值随cookie一起传递到服务器,服务器通过sessionid找到内存中存储的该用户的session内容,session在内存的数据结构是一个map的格式。
那么为了保证不同服务器之间的session共享,那么最直接的方案就是让服务器之间session不断的传递和复制,例如java开发里常用的tomcat容器就采用这种方案,以前我测试过tomcat这种session同步的性能,我发现当需要同步的Web容器越多,Web应用所能承载的并发数并没有因为服务器的增加而线性提升,当服务器数量达到一个临界值后,整个Web应用的并发数甚至还会下降,为什么会这样了?
原因很简单,不同服务器之间session的传递和复制会消耗服务器本身的系统资源,当服务器数量越大,消耗的资源越多,当用户请求越频繁,系统消耗资源也会越来越大。如果我们多部署服务器的目的只是想保证系统的稳定性,采用这种方案还是不错的,不过web应用最好部署少点,这样才不会影响到web应用的性能问题,如果我们还想提升网站的并发量那么就得采取其他的方案了。
Session案例解析
时下使用的比较多的方案就是使用独立的缓存服务器,也就是将session的数据存储在一台独立的服务器上,如果觉得存在一台服务器不安全,那么可以使用memcached这样的分布式缓存服务器进行存储,这样既可以满足了网站稳定性问题也提升了网站的并发能力。
不过早期的淘宝在这个问题解决更加巧妙,他们将session的信息直接存储到浏览器的cookie里,每次请求cookie信息都会随着http一起传递到web服务器,这样就避免了Web服务器之间session信息同步的问题,这种方案会让很多人诟病,诟病的原因是cookie的不安全性是总所周知的,如果有人恶意截取cookie信息那么网站不就不安全了吗?这个答案还真不好说,但是我觉得我们仅仅是跟踪用户的状态,把session存在cookie里其实也没什么大不了的。
其实如此专业的淘宝这么做其实还是很有深意的,还记得本文开篇提到的hao123网站,它是可以承载高并发的网站,它之所以可以做到这一点,原因很简单它是个静态网站,静态网站的特点就是不需要记录用户的状态,静态网站的服务器不需要使用宝贵的系统资源来存储大量的session会话信息,这样它就有更多系统资源来处理请求,而早期淘宝将cookie存在客户端也是为了达到这样的目的,所以这个方案在淘宝网站架构里还是使用了很长时间的。
在我的公司里客户端的请求到达Web服务器之前,会先到F5,F5是一个用来做负载均衡的硬件设备,它的作用是将用户请求均匀的分发到后台的服务器集群,F5是硬件的负载均衡解决方案,如果我们没那么多钱买这样的设备,也有软件的负载均衡解决方案,这个方案就是大名鼎鼎的LVS了。
这些负载均衡设备除了可以分发请求外它们还有个能力,这个能力是根据http协议的特点设计的,一个http请求从客户端到达最终的存储服务器之前可能会经过很多不同的设备,如果我们把一个请求比作高速公路上的一辆汽车,这些设备也可以叫做这些节点就是高速路上的收费站,这些收费站都能根据自己的需求改变http报文的内容,所以负载均衡设备可以记住每个sessionid值对应的后台服务器,当一个带有sessionid值的请求通过负载均衡设备时候,负载均衡设备会根据该sessionid值直接找到指定的web服务器,这种做法有个专有名词就是session粘滞,这种做法也比那种session信息在不同服务器之间拷贝复制要高效,不过该做法还是比存cookie的效率低下,而且对于网站的稳定性也有一定影响即如果某台服务器挂掉了,那么连接到该服务器的用户的会话都会失效。
解决session的问题的本质也就是解决session的存储问题,其本质也就是解决网站的存储问题,一个初建的网站在早期的运营期需要解决的问题基本都是由存储导致的。
上文里我提到时下很多新建的Web应用会将服务器部署后云平台里,好的云平台里或许会帮助我们解决负载均衡和session同步的问题,但是云平台里有个问题很难解决那就是数据库的存储问题,如果我们使用的云平台发生了重大事故,导致云平台存储的数据丢失,这种会不会导致我们在云平台里数据库的信息也会丢失了,虽然这个事情的概率不高,但是发生这种事情的几率还是有的,虽然很多云平台都声称自己多么可靠,但是真实可靠性有多高不是局中人还真不清楚哦,因此使用云平台我们首要考虑的就是要做好数据备份,假如真发生了数据丢失,对于一个快速成长的网站而言可能非常致命。