煮酒论坛

 找回密码
 申请新用户
搜索
热搜: 活动 交友 discuz
查看: 4641|回复: 2

平台网站架构设计之我所见

[复制链接]
发表于 2010-2-24 00:52:24 | 显示全部楼层 |阅读模式

从架构设计师的角度来看,架构就是一套构建系统的准则。通过这套准则,我们可以把一个复杂的系统划分为一套更简单的子系统的集合,这些子系统之间应该保持相互独立,并与整个系统保持一致。而且每一个子系统还可以继续细分下去,从而构成一个复杂的企业级架构。

  一 选择技术方案和物理架构

  如何选择技术方案和物理架构,对很多刚接触平台网站研发的人来说这可能是个头疼的问题。这些问题的源头很简单就是能否提高开发效率,使平台具有高性能高负载性。就我遇到的常见的有这么几个问题:

  a) 开发语言和数据库

  一说到开发语言和数据库,很多人便开始做语言的比较,最常见的争论有:“asp.net和java哪个好”,“解释性语言和编译性语言哪个好”等。我个人觉的最关键是你和你的团队最擅长的开发语言和数据库是哪个,古语有云:“工欲善其事,必先利其器!”,趁手的开发语言和数据库有助于事半功倍。试想如果你选择了一个并不很熟悉的语言,也许这个语言和数据库在基础性能上的确比你掌握的语言好,但是在研发过程中学习曲线肯定长。而且遇到问题的时候因为不熟悉的原因,浪费更多的时间去寻找解决方法,而且找到的方法不一定是最好的,说不定还不如你自己用熟悉的语言解决来的快。

  也许有朋友会说:“这几种开发语言和数据库我都熟悉”,那么就要看你对这几种开发语言和数据库的熟悉程度了,对各种开发语言和数据库的特性了解的越深入,越有助于提高开发效率。而且目前主流的开发语言和数据库都提供性能调优,只有深入了解了开发语言和数据库的特性和原理,那么性能调优就很容易。

  个人觉的重要的就这两点,开发效率和性能。

  b) 成熟框架还是自己实现

  目前主流的开发语言的使用者中有很多前辈都提供了他们自己总结实现的框架,比如JAVA中的“S-S-H”组合,PYTHON的DJANGOO等。我个人的一些经验是,尽量使用开源的成熟框架,因为平台研发初期使用成熟的开源框架,能提高开发效率,并且在质量上有保证。我曾经接手过一个平台的改版,框架是前面开发人员自己写的,里面的一些设计思想不是很成熟,导致平台在负载增高后性能很差,整改起来很麻烦,只能一点一点的分离出来,耗费时间和经历。

  有的朋友可能会问什么才是成熟的框架,个人总结的几点:

  1 能提供使用指南,比如 COOKBOOK, USE GUIDE等。有这些提供,那么入门使用变的容易,也方便维护,而且有助于深入了解其特性和原理。

  2 有官方支持,比如官方讨论社区,邮件列表等,并且有BUG收集处理机制。有句话叫大树底下好乘凉,有了官方支持,当使用过程中遇到问题的时候,直接就可以通过查找前人的使用心得和问题来解决问题,遇到BUG的时候,提交上去,也能找到解决之法。

  3 官方在不断的更新发布稳定版本。这一点很重要,官方如果及时帮你解决目前已知的或者未知的BUG,那么对使用者来讲,就没什么后顾之忧了,如果官方停止更新了,那么我建议还是早点换下家吧,因为如果这个框架好,那么肯定会越来越好,官方也会不断的更新它。还有就是稳定永远是第一位,可以在不影响生产环境的情况下进行无缝升级更新。

  4 身边使用者很多,经常能看到相关的讨论或者总结。目前很多成熟框架都是国外开发者发布的,如果使用者E文不好也是个讨厌的事情,那么如果身边有很多同样的使用者和很多讨论,那么对于使用者来说是种福音,共同探讨和学习。

  那么除此之外最好是开源的框架,平台初期访问量不大,因此对性能的要求不高,成熟的框架的使用都不会出现什么问题。当访问量急剧增高之后,那么性能要求也变高,一些框架中隐藏的问题也因此出现。这时候如果是开源的框架,使用者可以深入了解它的源代码,洞悉其实现机制,根据自己的实际情况进行调优。如果不是那么使用者也只能改变方向去解决问题,条条大路通罗马。

  c) web server/db server/cache server 相关

  在架构设计中web server/db server/cache server是很重要的一点,我个人觉的这一块必须是使用具有前瞻性,易配置,能监控和维护的产品,总结的几点:

  1 丰富和深入的配置选项。如果能提供丰富和深入的配置选项,那么在安全和性能调整上可以很方便的进行操作,并且不中断实际的生产环境。

  2 基于高并发模型。比如这几年热门的基于epoll的nginx,可以有效的减少连接处理时间,增大同时并发数。

  3 支持负载均衡和请求分发。当平台的访问量增高之后,单台服务器肯定是很难支撑,这时候就需要增加服务器来分担压力,这时候server的负载均衡和请求分发就很重要了。

  4 高效的缓存机制。高效的缓存机制可以帮助平台提高负载能力,减少重复资源的读取和处理时间。比如用于小文件缓存的SQUID,VARNISH,用于数据库缓存的memcached等。

  5 实时的状态监控机制。实时的监控状态报告,可以有助于平台维护人员迅速了解平台性能运行状况,根据状况进行调整。

  如果是开源的那就更好了,可以深入了解其源代码,并根据自己的实际需要进行配置和定制。

  d) 操作系统

  选择合适的操作系统,个人觉的最主要是稳定安全,易管理和维护,易监控。稳定安全的操作系统一般官方会持续的发布补丁和新版本,解决BUG和漏洞等。并且官方或者第三方会不断的提供新的管理维护监控工具,并且能让管理维护人员通过编写脚本来维护管理。而且合适的操作系统能让研发人员充分利用其特性,发挥平台的最大性能。

  f) 物理架构

  这里的物理架构是指服务器的搭建方式。有的朋友可能资源有限只有一台服务器,有的朋友资源充分有十几台服务器或者更多,我个人觉的这都不是问题。平台初期的话,我想大部分访问量都不高,web server/db server/cache server放在一台服务器上都没问题。但是自己心里最好能预估一下这个平台会发展到什么样的规模,在做架构设计的时候,按照事先预估的来决定怎么做物理架构,并为以后的架构升级做准备。说到这里,想到前百度架构师雷鸣说过的一句话,当你的会员数达到目前的5倍或10倍的时候,架构就要升级。

  二 平台研发

  前期做好了技术方案,就进入到实质研发过程中来了,个人感觉平台网站的研发有别于传统的IT项目研发,因为以前就是客户/需求分析人员/美工之间进行交涉,而现在平台网站研发会多接触一个角色叫产品,产品决定了最后的平台网站是什么样的,有什么功能,每个功能的流程和用例是什么样子的,也就是原型设计。并且在研发人员实现之后,还要由测试人员进行测试。关于原型设计,请看我的另外一篇文章《项目需求原型设计》。

  在上述过程中,产品会经常要求研发人员:“某某功能是这样的,你赶快给我实现并解决。这个功能不对,要改。那个功能出现问题,要改”,而研发人员可能正在忙着其他功能的实现,于是很容易产生冲突。在此我推荐使用敏捷开发方式,设立短的发布周期进行迭代开发,产品提出来的问题统一在一个周期内解决,到下一个周期一起发布,到下一个周期再进行下一周期的功能改进和BUG修正。并使用JIRA这种成熟的项目管理系统进行管理,为以前的更改留下历史,总结经验。

  那么在正常的研发过程中,特别是团队研发,我个人觉的需要注意的几点:

  1 合适的开发工具。还是那句话“工欲善其事,必先利其器!”,使用合适的开发工具和插件,能提高开发效率,节省开发成本。团队使用统一的开发工具,可以减少出错的几率,防止版本冲突等。

  2 如何控制代码质量。因为团队里大家的水平有高有低,所以团队研发的时候,需要去建立固定的开发规范,比如:“命名规范”,“代码包引用规范等”。当某个人解决某个功能的时候,为了确保代码质量和减少出错几率,最好能画出流程图和配上设计意图说明,来进行讨论确定,同时也可以帮助新人快速成长。

  3 需要引入新框架。有时候,某个成员会觉的某某框架的新特性非常好用或者非常合适手头的问题,那么就想引入这个新框架,我的建议,在充分了解的基础上来决定,不能因为某个特性而引入一堆用不到的特性,那样会让项目代码显的冗余。

  4 知识总结和培训。当某个成员遇到问题,并解决后或者学习到新东西的时候,不妨拿出来大家一起探讨一下,说不定就有助于提高平台的性能,为大家提供更好的设计思路。

  三 架构优化

  “过早优化是万恶之源”,所以关于架构优化,我放在研发完成并上线之后来讲。个人觉的没有百分百可用的架构,得看你实际的业务流程和运行情况来进行优化。当你运行了一段时间后,收集到一定的数据,找出性能的弱点后进行针对性调整和优化,当平台的负载强度达到一定程度,就得立即着手做架构升级。

  有的朋友会问,有时候网站就是莫名其妙的变慢,但是不知道从何下手怎么办,或者凭经验改改这个改改那个选项,好了一点但好的不彻底。我的经验是从数据开始,从最外围开始画圈,找到源头。先从外围开始收集日志,比如access_log访问日志或sql_log数据库操作日志,找出访问最多的10条日志和执行时间最长的10条日志,然后根据日志去反查到底是什么引起的操作,然后一条条的解决。如果解决不了,那么就考虑重构。其他问题解决方式跟这个差不多,就不赘述了。从我自己已有的经验来看,往往就是因为几个功能点的恶化,引起了整体的性能变差。

  所以在研发的时候,功能点的实现要好好考虑,前端部分,页面,图片等的大小和有效缓存,后端的局部数据和全局数据的缓存高效利用,数据库层SQL语句尽量避免跨表查询,数据库索引的利用等。

  四 其他相关

  存储

  当平台网站的访问量不断增长的同时,数据也会跟着不断的增长,所以早期做好数据如何存储的方案非常重要。

  现在比较常见的是HASH URL,根据文件名的HASH来选择存储不同的目录,比如20091014131213_abc.xxx 那么就存储到 2009/10/14/a/20091014131213_abc.xxx这样的目录下,方便以后根据目录来划分服务器。

  搜索

  当平台网站的访问量不断增长的同时,数据搜索也变成了一个问题。肯定有朋友会说,直接数据库模糊查询有什么问题,你试想当你的数据表里有几百万数据你用select * from table where title like '%key%' 没法用索引,那就是全表扫描,拿得花多少时间,一个人查询还没问题,那几百个呢,那你的平台不就歇菜了。还好现在已经有了成熟方案Lucene,只要按照它提供的接口去实现,你就可以使用。

 楼主| 发表于 2010-2-24 00:53:37 | 显示全部楼层
新型的大型bbs架构(squid+nginx)

这个架构基于squid、nginx和lvs等技术,从架构上对bbs进行全面优化和保护,有如下特点:

1、高性能:所有的点击基本上全部由前端缓存负责,提供最快速的处理。

2、高保障度:不需考虑应用程序稳定与否、程序语言是何种、数据库是何种,都能从架构上保证稳定。

3、高可用性:对应用程序的修改达到最简化:在程序的某些地方加入清缓存的语句即可,当然还需要做页面静态化的工作和统计工作。

首先看图,这个图比较大:


这个架构的特点和一些流程的说明:

1、主域名和图片域名分离

域名分离可以使流量分离,缓存策略分离等等,好处诸多。bbs初期一定要做好规划,将图片用另外的域名独立服务,即使没有足够机器,域名也要先分开。另外,图片服务器可以使用有别于主域名的另一个域名,一个好处是可以减少读取cookie对图片服务器的压力,另一个是提高安全性,避免cookie泄露。

2、使用LVS作为前端、二级代理和数据库的访问入口

使用LVS作为入口,比其他任何一种方式都来得更优质。首先LVS的负载能力很强,因为它工作在网络协议的第4层,使用虚拟ip技术,所以它本身并不担负任何流量的处理,仅仅是一个封包转发的功能;第二,LVS的配置相对简单而且稳定,一般去调整的几率比较低,也减少了因人为等因素而出现故障;第三,LVS可以处理任何端口的负载均衡,所以它基本可以做所有服务的负载均衡和容错。在这个架构中,除了处理http的80端口之外,LVS也处理了数据库mysql的3306端口,在数据库这个应用中是采用的双机热备策略。

3、使用nginx+squid作为最前端的缓存组合

在这个架构中,是最能体现app_nginx_squid_nginx架构的优势的。在这个架构中的bbs运行在缓存上,用户每发布一张帖子,都需要使用purge指令清除该帖子的缓存,如果是squid在最前端,那么每次发布一张帖子,都需要在所有的squid中调用purge指令,这样在机器比较多的时候,purge将成为一个巨大的压力。

所以在这里将nginx放在最前端并使用手工url_hash的方式分流,将经常需要purge的帖子页面和列表页面按一个url对应一台squid的策略,分布到各台squid上,并提供了一台或一组backup的squid,个别squid出现异常时将自动使用backup的机器继续提供一段时间的服务直到其正常。在这样的架构下,purge就不再是关键问题,因为一个url只会对应到一台机器上,所以purge的时候,后端app_server找到对应的机器就可以了。

可以看到在前端中还有一台nginx(purge)的机器,这台机器是专用于purge的,只要发送purge指令和需要清除的url到这台机器,就可以找到相应的服务器并清除缓存了。另外,purge时还需要清理backup机器上的缓存,所以无论前端机器增加到多少,purge指令只会在2台机器上执行,如果backup机器使用到2-3台,purge指令就会在3-4台机器上执行,仍然在可接受范围之内。

nginx作为前端,另有的好处:

1/使用nginx的日志统计点击量非常方便
2/nginx也可作为缓存,一般可以直接负责favicon.ico和logo等固定的小图片

4、基于nginx的中层代理



前端的lvs和squid,按照安装方法,把epoll打开,配置文件照搬,基本上问题不多。

这个架构和app_squid架构的区别,也是关键点就是:加入了一级中层代理,中层代理的好处实在太多了:
1、gzip压缩
压缩可以通过nginx做,这样,后台应用服务器不管是apache、resin、lighttpd甚至iis或其他古怪服务器,都不用考虑压缩的功能问题。

2、负载均衡和故障屏蔽
nginx可以作为负载均衡代理使用,并有故障屏蔽功能,这样,根据目录甚至一个正则表达式来制定负载均衡策略变成了小case。

3、方便的运维管理,在各种情况下可以灵活制订方案。
例如,如果有人用轻量级的ddos穿透squid进行攻击,可以在中层代理想办法处理掉;访问量和后台负载突变时,可以随时把一个域名或一个目录的请求扔入二级cache服务器;可以很容易地控制no-cache和expires等header。等等功能。。。

4、权限清晰
这台机器就是不写程序的维护人员负责,程序员一般不需要管理这台机器,这样假如出现故障,很容易能找到正确的人。
对于应用服务器和数据库服务器,最好是从维护人员的视线中消失,我的目标是,这些服务只要能跑得起来就可以了,其它的事情全部可以在外部处理掉。

在这个架构中,假如后端的app_server上把帖子页和列表页直接生成了静态页面,那么使用中层代理再做一次url_hash,将可以解决后端app_server的硬盘容量的压力,但是如果使用到url_hash的话,那做容错就相对麻烦了。所以建议不要采用生成静态页的方式,后端的压力一般不会非常的大,所以没有必要生成静态页。假如前端squid的命中率实在太低下,造成大量穿透,可以考虑使用二级代理暂顶。

5、基于LVS的数据库双机热备

在这个架构中,因为大量的并发和访问量都由前端的缓存处理掉了,所以后端的mysql主要压力来自于数据的写入,所以压力并不是非常大,并且负载比较稳定,一般不会随着访问量上升而提高过快,估计目前一台64位的机器,加满内存并使用高速的硬盘,前端负载数亿访问量时数据库都不会出现性能问题。在数据库这方面应主要考虑故障恢复,因为数据库崩溃的话,按照一般使用备份恢复的做法,耗时很长而且难免丢失数据,是很棘手的问题。使用双机热备的方案,出现故障时首先可由一台时刻同步着的备用数据库即刻充当主数据库,然后卸下的数据库可以有充分的时间对其进行维修,所以是个很安全有效的办法。

当然,数据库的优化还是要细心做的

细心地调一遍,性能会好很多。

6、图片服务器

图片服务器我在这个架构中没有特别详细的介绍,在大型的bbs系统下,图片常常会出现容灾现象——图片数量严重超过了单台前端服务器容纳能力,导致前端服务器命中率低下。处理容灾问题也是非常棘手的,往后会有更详细的介绍。

7、简单的点击量统计办法

1/使用js的script标签访问另一(台)组服务器的空文件,然后定期向数据库更新
2/在前端的nginx上直接开启日志功能,按需要统计点击量的链接规则进行记录,然后定期更新数据库
 楼主| 发表于 2010-2-24 00:55:23 | 显示全部楼层
nginx图片服务器的架构方案

图片服务通常数据容量较大,而且访问也频繁,鉴于此,图片服务就会有两种问题,一是存储问题,二是访问量问题。
存储问题就是硬盘容量问题,花钱买硬盘就可以了,看似简单,但着实也是最苦的问题。按目前探索来看,最好的方式是:在任何时刻遇到硬盘空间不够时,买颗硬盘插上,最多改改配置,就能立刻利用;另外,硬盘要能充分利用,不然图片存储量大再加上备份,很恐怖,最好是每颗硬盘都用上100%的空间。
访问量也是个大问题,如果服务不允许防盗链,那么访问量会引起带宽、服务器压力等问题,有钱的话直接扔CDN,没钱或者有更多的钱,就自己做吧。根据垣古不变的真理“越老的图,访问量也相对较少”这一点,分成两大部分,一边处理最新的图片,一边处理老旧的图片。最新的图片访问量大,但存储量较少;老图片访问量低,但存储量大。
大概分析完了,开始制定方案。

一、拟定一个存储目录规则:
在现有的/a/b/abcde.jpg这样的hash方式下多加一个日期的目录变成:/200810/16/a/b/abcde.jpg或者/2008/10/16/a/b/abcde.jpg。按日期制定这个目录规则后,就可以按年月来拆机器了。

二、分机器,分硬盘
按之前的计划,分成两个组,一组服务器用lvs做负载均衡负责新图片;另一组服务器做旧图片访问和备份。新图机器找几台好点的服务器,SCSI硬盘;旧图机器没太大要求,PC机就行,找够硬盘就可以,现在IDE的1T硬盘也不太贵,最好再搭个raid就省事了,最主要是这些机器要多。
照这个图,搭一搭



说明一下:
1、图片服务通过lvs作为入口,处理能力上还是有保障的。
2、利用nginx直接对外服务,不必用squid。
3、图中的红线是指主nginx会将/2006和/2007年的图片分别代理到两台存档服务器,如果发现主nginx的cpu占用比较大,那么可以考虑使用nginx的proxy_store将图片存到主服务器上,定期清理。
4、图中有一台存储分配服务器,作为图片服务更新图片的统一入口,有新图片或者修改图片的话,由这台服务器负责将图片放到正确的服务器上去。
5、旧图片服务器当前用年份来划分,每年增加两台服务器,亦可是加两块硬盘,注意,不要相信raid,一定要有两台机器,地理上分在两个城市则更好。
6、因为旧数据2006和2007年的数据基本上是没有变化的,所以假如硬盘够大,那么可以把两年的数据合并在一起。
7、如果细心定制,那么旧图片服务器的硬盘100%塞满是可以的,旧数据的容量基本上不会大幅增长,小小预留1-2G空间就可以了。
使用这个架构的话,到了2009年,我会把2008年的数据想办法迁到旧图服务器上,硬盘不够的话,加硬盘就可以了。如果图片量实在太大,主服务器连一年的数据都装不下,那可以用启用月份来划分;如果一个月都装不下了,那也太夸张了,那就启用日期吧;如果一天的数据都装不下,那就◎#¥%……※。
您需要登录后才可以回帖 登录 | 申请新用户

本版积分规则

小黑屋|手机版|Archiver|守望轩 ( 湘ICP备17013730号-2 )|网站地图

GMT+8, 2018-9-24 17:23 , Processed in 0.025221 second(s), 17 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表