第一次系统性的写一些技术架构上的文章,当给自己日常零碎当中的事情,做一个梳理,就当预编译一次。

单说,如何架构一个网站?

我该怎么回答呢?其实这是老生常谈的问题,问题问的很大,涉及的范围非常多,总不能简单的跟人说,买台服务器,写好代码,解析域名,备案完毕,好了,架构完毕,跟一些外行的客户,不想与其废话时,倒是可以这么打发人家了,不过真要跟行家讨论这个问题,还不得被人鄙视,唾弃,于是仔细想想,道个1,2,3,4,5。。。有条有理的说一下,话说,面试来面试去,面别人,被别人面,不就在讨论这玩意儿么。

先说,网站架构的目的是什么?而不是说,麻木性质的去做这件事。

无非围绕三个方面,

一、高性能

二、高可用性

三、高拓展性

分述之,

一、高性能,

即站在用户的角度来说,输入网址,或者点击链接,页面,唰一下,展现在眼前,至于说,页面打开速度要多快,才算快,这个跟具体的每个用户的网络环境,还有操作系统本身的原因也有关系,一般来说,理想的状态,是页面在2s以内展现完毕,如果超过6-8s,用户可能就X掉网页了,超过12s,那就99%的可能性准备跟该用户说byebye了。


在提高网页速度的背后,我们需要去做的事情,就很多了。

现在假设我们要去做一个不久后,将会有大规模用户和点击量的网站,就那我之前公司的网站做个例子吧。

一开始,只是个小作坊,弄台服务器,跑起Redhat或者CentOs,装个Apache,搭个PHP(FastCgi),走着Mysql,开发好代码,放上去了,好了,第一版架构完毕,可能有人要问,就这样,就可以了吗,不用考虑,负载均衡,CDN,代码框架,网站性能监控神马的吗,是的,一开始小规模小作坊,小打小闹,没资金也没人,用户基本不知道你的网站,每天PV少的可怜,只有上线后,Money入账了,才能回过来不断改善产品,否则根本经不起技术上的投入成本这种折腾,当然了,如果早期你有风投给你投个几百万几千万美金,那是令谈。


好了,一段时间之后,经过你不懈的努力,推广宣传,你的网站访问量噌噌噌的上来了,呀,打开网页有点卡,好慢,噌~一下504,502,挂了,检查,Mysql连接太多,无法承受猛增的读写并发。此时的PV大概达到1W左右吧,好,怎么办呢,重启服务器,网站又能打开了,不过,这貌似不是解决办法,还要人守着,挂了,就重启不成。

于是,又弄了台机器,把数据库和代码物理分离了,现在两台机器了,也不会相互影响了,果然好多了。也不需要改动什么代码,只是改个Mysql所在的Ip地址,就可以顺利运行了。

好景不常在,好事不常留啊,随着用户量的增长,此时PV将要接近10W,网站又开始变卡了,又开始经常间断性的挂掉了,数据库的读写量已经超出了其自身的承受能力。


于是,缓存登场了,Memcached,分布式缓存,用它来保护数据库,让读写直接操作内存,减轻数据库的负担,另外,一些帖子文章,直接写入文件缓存,利用磁盘的IO,也来分担数据库的一部分压力,有没有发现网站的打开速度变快了,现在我们有三台机器,一台web,一台Memcached,一台Mysql


好了,现在我们要做的事情有很多了,一来是因为用户的持续增长,是预料之中的事情,二来,是不断增加的网站功能,需要我们不断改善我们现有的架构,第三,应该是最重要的,xx委,xx主任,给我们公司投钱了,至于为什么投钱,跟2XBoss的忽悠有关系,打着个拯救全人类,全中国下一代这种旗子,算了,这个就没什么好细说的了,咱是P民,无权关心,搞好技术再说。


于是大规模的购买设备,网站呢,要重构,且要增加很多功能模块,神马,微博了,动态了,消息了,相册,网盘了,哎呀,一个不伦不类的产品即将诞生,自称SNS,却混着BBS,且,有着两套关系系统,自称BBS,却带着多许不相关的玩意儿,哎呀,我去!割草!,sorry,说脏话了,我不是产品经理,我没资格说,那既然做了,那咱就只有保证产品的稳定运行吧,后来事实证明,这头不伦不类的东西,的确有些失败,这是后话,当然了,此时,用户量还在不断增长当中。



二、高可用性

站在用户角度来说,就是随时随地,访问你的网站,都可以正常打开,就是说,不宕机,虽说,不能保证一年365天,随时都能做到,但这种概率至少要大于99.9%。


数据库切片(水平拆分,垂直拆分)

垂直拆分,针对产品线来拆分,把原有的表,比如用户表,博客表,相册表,论坛表等,分别创建用户数据库,博客数据库,相册数据库,论坛数据库等(基于不同的数据库机器上)

水平拆分,针对某个表进行一定算法的分库分表,比如取模拆分或者根据用户id拆分,地域拆分等



服务器健康检查,对于Web,和DB,主备冗余,及时有效的监控和报警,常用的如Cacti+Rrdtool+nagios,去查看服务器,网络所处的状态



三、高拓展性

一般,面对公司内部开发架构来说的,

我们计划增加客户端,支持移动设备的访问,而且,我们要有自己的开放平台,可以让其他单位或者公司吧,可以访问我们的数据,好的,这个有意思,那网站就彻底重构一次吧。


我看之前的代码已经很不爽了,经过反复的产品开发叠加,代码已经极度冗余了,也不知道有多少文件是还在使用当中的,关键是,可拓展性,可维护性,已经几近让我抓狂,说干咱就干哪,话说,对于代码框架,我经常会去想,怎么样,才算一个高效,高可拓展性的,高可维护性的代码,而且,对于每个开发人员都在这套框架体系下,如何协调好,充分利用每个开发人员的能力,才是这个框架该做的。

要知道,起初,针对网站,可以出一套框架,之后,客户端出来了,为了调用用户数据,必须再重写一套,之后,开放平台又出来了,还得整一套?我的天哪,真想摔桌子,然后自己滚蛋,你们自己去玩吧,给点时间,咱好好整整,行不,别一天到晚,拿着个连KPI,全拼都拼不出来的玩意儿,整我,行不?你才几个人哪,有的没的。


PS:如果一个网站是传统的MVC,那最初的开发,和维护都还是不错的,但是这种框架,恐怕不能满足后期的拓展,要知道Amazon,在早期可是已经完全接口化开发了,随着公司的发展,内部外部的接口化,是不可避免的,比如说,有个同事在开发一个新产品,问道,用户的基本信息在那张表,哪几个字段,用户的博客数据在哪张表,好的,那你告诉它,在某某表,执行哪条Sql,或者让他去看,其他模块产品中类似的逻辑,问一次,二次,三次,还行,但是员工越来越多,一天问你三十次,你的感觉会怎么样,有没有拿起桌子上的电脑,砸他的冲动~

于是,面向MVC的接口化,开发,在所难免,且,好处多多,解决了这种繁琐的沟通以及,其他你想到的没想到的很多问题。

传统的,Model,View,Controller,当用户发Request到你的网站的某一个页面来的时候,Index做为入口,根据来源链接,匹配页面路由,映射到Controller,根据Model中的数据,反馈给View,然后生成html,通过浏览器呈现给用户,做到这一点,说明也算是一个网站的mvc框架了,且不说,其他的,缓存处理,模版引擎,内置常用方法等。

说到接口化,那么外网和内网的接口,是要区分出来的(私有接口,和开放接口),比如说,内网,一般在跨产品线开发时,内部调用,通过http,restful的访问,即可完成想要的数据,不用考虑安全性,虽说,它比https的性能高,但是终究是处在应用层,要调用传输层的Tcp,对于内网调用,性能还是偏低,可以增加一些缓存来提高性能,如果觉得不够,可以使用Facebook的Thift和Google的Protocol Buffers。对数据结构做了压缩,大大降低了数据文件的大小,可以很大的提高一部分性能。

外网,例如第三方公司,在调用你的接口时,你就必须加密ssl通道,且,增加一系列的加密验证算法,或者使用OAuth,可以直接使用2.0,做好接口的管理,比如接口的调用次数,调用频率,防止别人去反复恶意调用。


在网站的发展当中,遇到了问题,衡量一下,如果可以重构,就马上彻底重构,如果产品线太多,那就一步一步的来替换重构,否则,整个团队,恐怕就要陷到改Bug的泥潭当中了,而且,重构的越早越彻底,将有利于网站的扩展,发展,这个很重要,我是深受其害。