并发服务设计的三种架构
2014-2-6 陈叶皓 chenyehao@gmail.com
在上一篇里面,我提到了,使用异步编程的方法,可以设计出基于单台服务器高并发高吞吐量的软件系统。好的互联网产品会吸引成千上万人同时在线,互联网软件架构师的目标,就是使软件系统支持水平扩展,通过购买更多的服务器,增加系统能承载的用户数量,也就是并发访问的数目。所以,单台服务器在现实中是不够用的,即便够用,也需要存在备用的服务器,以便某台服务器出故障时,不中断服务。下面我从简单到复杂,介绍并发服务设计会用到的三种架构。
一、内容服务
常见于新闻网站,博客网站,航班查询,这种网站的特点是
1. 以静态信息为主
2. 数据变化不频繁,或者实时性要求不高
以博客网站为例,如果用户发表了一篇博客,而其他用户在5分钟之后才能看到,其实并不影响总体的用户体验。
这种架构可以说是最简单,与传统企业应用也没有太大差别,基本上就是
负载均衡设备
|
网页服务器集群
|
缓存集群
|
数据库集群
的架构,反正哪一块撑不住了,就可以往哪一块添加服务器。如果需要提高系统数据的实时性,需要写一些同步代码,比如数据库更新之后,通知缓存也刷新数据
二、在线交易
常见于电商网站,通常会包含在线支付和库存管理等模块。这种场景有以下特点
1. 有状态,有约束。例如付款之后,订单状态改变成“已付款”,才可以发货
2. 并发会产生错误。例如用户同时抢购最后一件库存,并发时不应该让所有看到这件库存的用户都买到。
对于交易系统的架构设计,最重要的是解决并发冲突,保证那些影响状态的操作,串行地执行。简单来说,架构设计要提供“把用户并发请求,串行地来进行处理”的能力。
一个很好的设计方案,是使用actor模型,也就是使用支持actor模型的编程语言,使用编程语言内置的消息队列,把并发的请求添加到提供服务功能的actor的消息队列中。这样就成功地把并发请求转换成串行请求,使得在线支付和库存扣除等必须串行操作的模块能够正确运行。
基于actor模型的设计,需要额外考虑如何消除单点故障,因为把并行任务串行化,本身要求系统中不能同时存在功能完全相同的模块。引入zookeeper可以使这方面的工作简化。
三、高性能并行计算
由于数据量和计算量实在太大,无法依靠单台服务器完成计算,或者是单台服务器计算时间过长,用户无法忍受等待时间,需要把计算量由多台服务器来分担,同时计算并汇总结果。典型的网站例子就是google的搜索首页,用户进行一次搜索需要上千台服务器同时计算。
这种架构和传统的顺序执行架构不同,需要架构师习惯并发和异步的思维方式,把任务分配给多台服务计算,叫做map,汇总结果,称为reduce,所以google的经典算法,就是mapreduce。
实现mapreduce,只能是一种异步操作,这体现在两个方面
1. 主进程分配任务给服务器A时,不能等待,立刻执行把任务分配给服务器B的操作。如果等待了,那就又变成顺序操作,完全不能缩短整个任务的执行时间。
2. 到服务器A的计算结果返回,是一种函数回调,这时服务器B的操作如果还没有完成,主进程会继续等待服务器B完成计算并返回结果。拿到所有结果后,再进行合并排序等处理,返回给请求方。
因此,实现mapreduce的核心是掌握异步计算,除了使用支持异步计算的编程语言(大多是函数式),目前还有开源的流计算框架可以选择。他们主要是
1. Twitter Storm
2. Yahoo! S4
使用这些框架,程序员可以专注于实现事件与算法,当然框架本身也有学习成本。如果问我的选择,我会选择自己写算法,定制模块的执行效率总是超过通用模块。
四、总结
在实际的互联网应用中,会是这三种架构的混搭,比如提供信息查询的功能,任何网站都会包含。提供交易功能,会用到第二种架构。网站规模进一步扩大,会用到第三种架构。分析具体情况,选择合适的方案。