Friday, August 29, 2008

如何部署高可用性和高伸缩性的网站?

如何部署高可用性和高可伸缩性的网站?这是一个很复杂的问题,到目前为止,我还没有实际的经验,都是自己学习和思考得到的一点结果。
前段时间,长沙一个公司做了一个彩票投注的网站,上海那边的公司就想直接拿过去用,不想再重新开发一套系统。问题是开发人员多数都有一个毛病,认为别人做的不如自己做的,上海就有这样一个,他说给我一个月时间,我就可以做出比这个更好的网站。除去有关业务有关市场的东西不谈,这位兄弟说的话的确很难让人相信,业务人员不信,我觉得他更是没弄明白部署一个生产的网站所包含的工作,显然,他认为,部署一个网站就是写完代码,然后copy到服务器上就可以了。 事情比他想象的复杂的多,如果这个网站是一个intranet的应用,可能还好说些,但是这是一个面向彩民的网站,实现一年销售2亿的网站,在部署这样一个网站的时候,可用性和伸缩性是不能不考虑的问题。在最终得到的生产环境中,网站代码可能只是很小的一部分, 你需要集群,需要cache,需要分部文件系统dfs,需要负载均衡,需要数据库集群,以及配套的一对硬件,要把这些理清楚,如果只懂java,jsp是远远不够的。
我没有实际参与部署过这种为海量用户服务的网站,心里很忐忑,一旦我们运营的网站出现这样那样 的问题怎么办? 所幸找到了一个很好的案例,这个案例不仅仅是从软件设计上说如何支持可伸缩性,而是完整的介绍了整个网站的部署,它就是livejournal,一个很早开始blog服务的网站,这是一个有8百多万用户,每秒处理2000次点击的网站。
开发livejournal的这群人值得称赞,他们分享了网站开发和部署过程中的很多心得,并且开源了他们自己开发的很多支持网站运营的工具,其中最著名的大概就应该是memcache了,这个cache系统已经在很多大型网站得到了应用,可以从这里下载他们的一个演示文档。下面按照整个部署涉及到的环节说说我的体会。
1.perlbal
一个livejournal自己开发的reverse proxy,用来进行负载均衡(big-ip好象也是用来做负载均衡,但是没搞清楚和perlbal的关系)
2. mogilefs
一个livejournal自己开发的分布式文件系统(DFS, distributed file system),分布式文件系统又包括一些不同的类型,主要是看他们解决的问题,有的用来支持高并发任务,有的使用来支持高可用性,而mofilefs是同时支持高并发和高可用性两个特性,而且支持任何本地文件系统。 问题是为什么我们要用分布式文件系统??它应该是用来处理系统产生的数据文件,最直观的大概就是系统生成的日志了,在集群环境下,如果没有dfs,那么每台主机都会产生单独的分离的日志文件,如果采用dfs,那么所有集群中的应用可以向同一个文件输出日志,而且便于维护。(老实说,这个我没有弄太清楚)
dfs与raid的关系也需要提一下,一般来说raid只是硬盘的阵列,如果部署raid的主机崩溃,那么raid也没用了,除非是有san(store area networ)支持的raid,可以跨主机。 而dfs由于本身是分布式的,是跨主机的,不存在这个问题。
3. web server cluster
这个集群是基本的,相信了解集群的人都应该知道web server的集群是最基本的
4. memcache
一个livejournal开发的分布式缓存系统,目前的应用非常广泛,可以在多台主机启动多个memcache服务,它们会自动协作,对应用程序来说就好象只有一个memcache服务。可以存储任何形式的内容(需要做深入研究)
但是对什么内容进行缓存呢?
首先要是被经常读取的内容,而这些内容可以通过查看数据库的日志,比如那些对象查询的最多等等。mysql提供了slow log的功能。
5. mysql cluster
数据库集群这块是对我影响最大的。以前一直认为是要采用大型数据库的本身支持的集群(想来应该非常昂贵),不然是实在想不出还有什么集群方式,而且既然有数据库集群,那么前面是不是也要有一个load balancer? 不过这个load balancer应该是数据库服务器本身提供,就相当于有一个逻辑数据库,应用程序面向的是这个逻辑数据库,不需要知道后端的集群有多少数据库实例,这个逻辑数据库负责组装数据,分布请求,负载均衡。。。不过,这的确应该是一个昂贵的解决方案。
后来,了解了sharding,是一种数据库分区的概念,包含水平和垂直两种shard方式(集群也包括水平和垂直两种,垂直的就是单个应用,但是起先是运行在普通的web server中,后来是运行在小型机中,而水平集群就是采用便宜的web server阵列,每个主机都部署一个应用),水平就是将一个表的列进行拆分,可能数据量大的,或者不经常使用的列拆分到一个独立的表; 垂直就是按照一个规则将表中的数据进行分区,避免一个表中的数据过大,常见的是用户表(user),比如规则是按照id的奇偶来决定将user存入哪个表,那么可能在数据库中就存在usre_odd, user_even两个表,它们的表模式一模一样,但是一个用来保存id为奇数的用户,一个用来保存id为偶数的用户。shard需要进行额外的编码,但是会带来巨大的性能提升。
一般来说采用sharding就可以不用昂贵的数据库集群方案,而且后来想到的一个问题是,数据库服务器一般会采用raid,raid本身就提供了高速的io,以及数据冗余,所以我更加倾向与raid+sharding的方案了。
当时livejournal的方案显然更复杂,除了sharding之外,mysql也做了集群,并且每个用户组都有一个数据库集群,想来只有存在海量用户的系统需要这样,实在很壮观阿。 但是从它讨论的master-salve这种数据库集群方式中,我又想通了不少问题,所以在我原来raid+sharding的方案上,我又增加一个slave,也做一个数据库集群,但是slave不一定需要raid,看具体的应用,我是想在进行统计报表的时候就可以使用slave的数据,而不需要访问master,master处理在线数据,提供实时服务,嘿嘿。。。。如果slave也需要处理在线作业,那么也可以在slave上配置raid, 当然也可以象livejournal一样,master提供读写,而slave只提供读。
数据库这库学问太深,还有很多其他的方面,我也只想了这么多,想到哪里写到哪里。。。

参考资料:
Django Master Class: http://toys.jacobian.org/presentations/2007/oscon/tutorial/
Database sharding unraveled: http://lifescaler.com/2008/04/database-sharding-unraveled-part-i/
Scalability Best Practices: Lessons from eBay: http://www.infoq.com/articles/ebay-scalability-best-practices
Scaling Your Java EE Applications: http://www.theserverside.com/tt/articles/article.tss?l=ScalingYourJavaEEApplications