最内层的就是用户代码,大部分PHP代码不需要做任何修改就可以跑在SAE平台上,小部分代码需要做一些修改以适应SAE的平台特性。这主要有两部 分:第一,SAE因为安全性禁用了本地I/O,所以fwrite等函数需要修改为使用Tmpfs读写本地临时文件或者直接通过Stor读写我们的分布式文 件存储;第二,用户在SAE上不能通过Curl访问非“SAE域”的资源,用户有抓取公网资源等需求,需要修改为调用FetchURL服务。我们提供了 PHP Wrapper以方便用户的修改。
PHP Zend为标准的PHP官方解释器,我们采用的版本为5.3.0。
SAE Zend Sandbox为一个逻辑概念,为用户的代码运行提供良好的隔离性。这里有两个层面,第一是通过标准的php.ini,我们设定 了一些特殊配置和禁用函数;第二,为了达到一些php.ini无法实现的沙盒功能,我们对Zend解释器核做了一些改进,以便通过用户标识将资源进行隔 离。另外我们还把一些SAE的特定服务也在Zend层做了融合。
Apache为标准的Apache Web Server,版本为2.2。不过我们禁用了htaccess,并提供了自己实现的替换方案 AppConfig。用户可以通过类自然语言的方式编写AppConfig,如- compress: if(out_header[“Content- Length”] >= 500) compress 表示按条件启动页面压缩。目前AppConfig提供的功能有:目录默认页面、自定义错误页 面、压缩、页面重定向、页面过期、设置响应头的content-type、设置页面访问权限。我们选择自行实现AppConfig还有一个考虑,就是因为 传统Apache的htaccess因为要按目录递归方式合并配置文件,效率不能满足SAE的需求。
HTTP Server沙盒为Apache的安全可靠运行提供了多种保护功能,比如防止某个用户恶意占用连接数从而导致整个Web服务不正常。
最外层的是标准POSIX环境,目前我们的服务跑在Linux 2.6上。
上面就是对SAE整体架构的概述,接着将详细讨论我们在架构设计上的一些具体考量点。
扩展性
扩展性是分布式系统的两个主要目的之一,SAE作为公有云计算,同样把服务的扩展性作为架构设计的重要指标,要求在用户增长、压力提升的情况下,可 以实现自动的服务扩展,同样当压力降低时,可以将服务收缩,以节约资源,整个过程无须人工参与。SAE人工只需做好容量规划和管理。目前国外的公有云计算 架构的扩展性主要有静态和动态两个思路。
静态扩展:用户和资源有强绑定关系。最典型的例子为Amazon的EC2和Ruby云计算平台Heroku,用户申请的资源和用户有严格的一对一关系,换句话说,A用户申请的虚拟机在A退还资源前,B用户不能使用,哪怕A用户的虚拟机处于闲置状态。
动态扩展:用户和资源没有强绑定关系。最典型的例子为Google App Engine,用户申请的资源和用户没有严格的一对一关系,换句话说,处理A用户请求的进程在处理完之后,可以马上处理B用户的请求。
两种扩展性各有利弊,静态扩展的长处是为平台提供了良好的隔离性,资源可以固定映射在某个用户下,但缺点是资源利用率不高;动态扩展的长处是资源利 用率高,这样整个云计算平台的成本会很低,但缺点是对隔离性有更高的要求,因为资源可以在很短的时间被多个用户使用。相比较,在安全性上,动态扩展要比静 态扩展的技术门槛更高。
在SAE平台上,我们采用以动态扩展为主、静态扩展为辅的兼而有之的设计。在Web计算池层是典型的动态扩展。而在SAE的某些服务中,又是以静态 扩展的方式展现,如RDC(Relational DB Cluster)分布式数据库集群,当用户申请了MySQL服务,我们就会在RDC后端根据 SLA创建一主多从的DB给用户,在用户显式删除该DB前,该DB都不会被别人使用。当然,通过RDC,任何一个用户也无需知道后端DB的实际地址,只需 访问RDC统一的Host和Port即可。
高可靠性(High Availability,简称HA)
HA是分布式系统的另一个主要目的,SAE同样以提供服务的高可靠性为架构设计的重要指标。HA的实现途径主要有两个:一个是硬件保证,另一个是架构的冗余设计。
在SAE平台上,所有服务器都是新浪标准采购的硬件设备,运行在国内最好的机房内,网络资源方面则享用门户网站所使用的带宽环境。另外,所有的硬件设备都有专门的运维部门负责,故障的响应速度和新浪内部服务一样。
在架构设计上,SAE通过对所有服务都进行冗余设计来提供服务的高可靠性。这里的服务可以分成计算型和数据型两种类别讨论。
针对计算型服务,冗余设计就是程序在多节点运行。我们要求SAE所有的内部代码程序要做到Stateless(无状态依赖),即无依赖部署无依赖启 动,随时终止进程随时重启进程,这样一旦出现机器故障或者程序自身Bug时,所有进程能够随着硬件环境的重新恢复而在第一时间重启。而多点执行的程序可以 保证,当某些程序出现故障时,整个系统仍然能够正常提供服务。
计算型程序多点部署,会带来一致性问题,最主要的困扰就是选举问题,如何在多个节点中选出一个主节点来执行。比如SAE上的分布式定时服务 Cron,采用多点部署方式,多个计算节点相互隔离,通过时钟同步服务同时触发用户设定的定时任务,但要求只能有一个节点负责执行。为了解决这个问 题,SAE设计出了一套分布式锁算法来提供选举服务。该算法可以在牺牲某些特定条件下的一致性来提供比Paxos算法更高的可靠性(3台机器在最高任意2 台机器发生故障的情况下整个选举过程仍然正常,而Paxos算法最多容忍1台)。目前,该算法正在申请专利,并广泛应用在SAE内部。
针对数据型服务,SAE主要是通过复制来保证服务的高可靠性。SAE上的数据存储服务普遍采用被动复制和主动复制两种方式。如SAE上MySQL之 间的主从Binlog同步就是典型的被动复制,用户只写写库,数据从写库同步到多个读库中。Taskqueue、DeferredJob等服务也采用被动 复制的方式,用户的任务描述会写到主内存级队列中,主队列利用后台线程将写操作同步到从队列上,一旦主队列发生故障,从队列会快速的切换为主队列。另外 SAE上也有部分服务采用主动复制(双写复制)的方式来保证HA,比如Cron,当用户通过App的工程配置文件appconfig.yaml设定定时任 务时,任务信息会以多写的方式写到多个持久化DB中,以供后续的事件触发。