关于SAE
Sina App Engine(简称SAE)是新浪研发中心于2009年8月开发,并于2009年11月3日正式推出的国内首个公有云计算平台,是新浪云计算战略的核心组成部分。
SAE选择国内流行最广的Web开发语言PHP作为支持语言,Web开发者可以在Linux、Mac、Windows上通过SVN、SDK或者Web版在线代码编辑器进行开发、部署及调试,团队开发时还可以进行成员协作,不同的角色对代码、项目拥有不同的权限。SAE提供了一系列分布式计算、存储服务供开发者使用,包括分布式文件存储、分布式数据库集群、分布式缓存、分布式定时服务等,这些服务将大大降低开发者的开发成本。同时,由于SAE整体架构的高可靠性和新浪的品牌保证,大大降低了开发者的运营风险。另外,作为典型的云计算平台,SAE采用“所付即所用,所付仅所用”的计费理念,通过日志和统计中心精确计算每个应用的资源消耗(包括CPU、内存、磁盘等)。
总之,SAE就是简单高效的分布式Web服务开发、运行平台。
SAE中的SQL
随着NoSQL的兴起,最近有一种观点认为SQL已经过时,不再需要了,但从SAE的角度讲,发表这种观点为时尚早。虽然SQL有扩展性上的弱势,但MySQL对于绝大多数Web开发者来说,仍是不可或缺的数据存储方式。亚马逊AWS和Google
App Engine(GAE)一开始就都没有打算支持MySQL,比如AWS当年因为要推广SimpleDB,而一度忽视了对MySQL的支持。但事实证明,“先进”的设计理念并没有战胜用户“顽固”的使用习惯,所以AWS后来还是推出了RDS。
幸运的是,SAE从一开始就尊重开发者的使用习惯,支持MySQL服务。因为从我们的调查来看,MySQL和memcache还是开发者首选的两个最重要的依赖服务。只有完美地支持它们,才能降低开发者的开发、学习、迁移成本。
对于公有云计算平台来说,提供MySQL服务的最大挑战在于当许多用户的数据库跑在你的平台上时,如何保证数据库服务的稳定性以及用户之间的隔离性。试想,如果一个初级用户,创建了一个很大的表,在select查询时,又不带索引,这种行为对于数据库平台的伤害是显而易见的。通常来讲,解决这个问题,一般有两种方案。一种方案是依赖虚拟化技术,通过不同层次的虚拟化方案,可以实现不同数据库之间的隔离性(如图1所示)。但这种方案的弊端也是显而易见的——成本高。以论坛为例,支持3万个论坛,基本会需要1000台物理机,这种成本显然是SAE无法承受的。另一种方案就是将不同用户的MySQL以进程的方式隔离,每个用户一个MySQL实例,这样自然能从一定程度上提高隔离性,但也有缺点:首先是它的成本仍然不够低,其次当实例很多时,加上主库、从库,端口对应关系很难维护,而最重要的是,这种模式的I/O隔离实现有一定难度。
图1 通过虚拟化来实现数据库之间的隔离性
SAE通过RDC(Relation Database
Cluster)来实现公有云计算平台上数据库的稳定性和隔离性。RDC实际上可以理解为一个数据库中间层,它位于用户和后端实际存储MySQL中间,结构如图2所示。
图2 RDC的结构
目前,SAE上所有应用的MySQL请求都是由RDC提供的,RDC完全兼容MySQL5协议,因此用户无需修改代码,就可以将程序完美地运行在RDC上。RDC的最大特性就是提供了SQL语句预判机制,RDC通过算法分析每条SQL语句的执行效率,当发现该SQL可能损害数据库平台时,就将其拦截,同时将拦截原因以标准mysql
error的方式返回给用户。当然,如果RDC判断该SQL无害,则自动放行,接下来该SQL语句便在实际DB上执行。
RDC还提出了“并发执行时间和”的概念来引导开发者优化自己的表结构和SQL语句,并取代传统MySQL的并发连接数限制,主要原因是传统的连接数限制较为粗鲁,不能区分用户。换句话说,无法区分“SQL优化得好的用户”和“SQL执行性能低下的用户”。而“并发执行时间和”很好地解决了这个问题,它突出一个思想:“对于SQL效率高的用户支持更大的并发,而SQL执行效率低的用户则可能不会获得大的并发”,以鼓励用户优化自己的SQL,提高SQL的执行效率,减少对系统的消耗。
“并发执行时间和=当前并发的mysql query所消耗的执行时间和”。举个例子,如果RDC系统的并发执行时间和为10000ms:
A用户的平均每条SQL消耗100ms,那么A获得的最大并发为100;
B用户的平均每条SQL消耗1000ms,那么B获得最大并发仅为10。
这样,我们就可以发现:当用户具有良好的SQL编写和使用能力时,就可以获得高并发能力;反之,当开发者滥用SQL语句或者表结构不合理时,就只能得到低并发能力。
通过RDC,SAE以非常小的成本支持大量用户的数据库服务。目前,RDC还不支持自动分库分表,也就是说,对于这种和业务场景紧密相关的需求,还是需要由开发者来完成。当然,目前有一些分布式数据库产品,试图支持自动分库分表功能,它们大多需要开发者在表结构上指定partition
key字段,然后数据库通过该key做分布策略。但这种方式有两个问题:第一,有时需要用户精妙地选择partition
key,这会花费用户不小的学习成本;第二,用户需要事先对自己可能使用的容量做预估,但这往往比较困难,而且任何需要预估容量的扩展性并不是彻底的动态扩展。
针对关系型数据库的一些难以解决的扩展性问题,SAE特意开发了一组NoSQL服务,来鼓励用户将那些需要动态扩展的数据,尽可能地通过我们的NoSQL服务来存储。
SAE 中的NoSQL
SAE的NoSQL服务所包含的内容如图3所示。
图3 SAE的NoSQL服务
其中,MemcacheX是SAE的分布式缓存系统,Rank是SAE为了满足排行榜需求而开发的Top排行榜服务,Counter则是分布式计数器服务。而KVDB系统为开发者提高支持动态扩展的键值式数据存储服务。下面重点介绍KVDB。
在开发KVDB之前,SAE试图寻找现有的NoSQL产品来满足SAE对NoSQL的潜在需求,这些需求包括以下方面。
本地存储引擎可换。由于目前Flash、SSD等技术的发展,使传统数据存储引擎有可能因此被一些新型的存储引擎所代替,比如LevelDB等,所以这就要求我们的实现不应该绑定在某个存储引擎上,而应该更集中于上层的框架。
任意模块都可以水平扩展。我们不希望有一个single master的东西存在,因为这种方式有可能在后期成为性能瓶颈。
支持读写分离。这方面大多存储引擎都支持。
支持前缀查找。这个需求对于开发者非常重要,从而排除了很多以Hash为索引方式的存储引擎。
支持第二索引。也就是说,不仅仅可以通过key查找value,还可以通过value反查key。
支持认证。因为KVDB要对外提供服务,所以也就要求必须有认证过程。
基于上面的需求,SAE决定自行开发一套键值分布式存储系统,即KVDB,它的整体架构如图4所示。
图4 键值分布式存储系统架构
从图4可以看出,用户通过client api使用KVDB,每次请求前,client都需要向meta
server请求得到appname-key到实际存储节点的映射关系(除非映射信息本身就在cache中)。获取映射信息后,client直接向该节点进行数据请求,此过程无需meta
server参与,从而提高了数据读写速度。meta server实际存储的是映射关系,并且支持无限扩展,所有meta
server的映射关系都读自后端落地的Internal DB,也就是说meta server始终处于只读状态,而映射关系的写入则是从Internal
DB操作。Interal DB支持主从备份,从而保证可靠性。后端的实际存储引擎可替换、按组分布,每一组都由一个主库和若干从库组成。meta
server可以自动感知后端DB的监控情况和主从同步情况,一旦发现异常,则自动更改映射关系,将请求导向正常的DB。
细心的读者不难发现,KVDB有两个很关键的问题需要解决:第一,多个meta server如何保证它们映射关系的一致性;第二,后端存储的重平衡。
传统的保证数据一致性的方式可以选择ZooKeeper,但SAE评估其对于解决这个问题有点过于复杂,所以SAE利用一种更简单、更实用的方式来解决。因为映射关系的更改操作直接写入Internal
DB,而meta server只相当于Internal DB里数据的一种cache,所以每个meta server都不停地向Internal
DB检查自身数据的同步情况。如果所有meta server都和Internal DB中的映射关系同步,那么一定说明所有meta
server数据一致;反之,一旦出现某个meta server和Internal DB一段时间内持续同步不成功,则该meta
server自动退出服务。
这带来一个问题,一旦Internal DB出现故障,比如磁盘损坏或者网络故障,将会导致一个致命的问题:所有meta
server都因为和Internal DB不同步出现问题,而选择自行下线,于是使得没有任何meta server提供服务,进而影响整个KVDB的使用,这种现象当然是不允许的。
为了解决这个问题,KVDB自行设计了基于PAXOS的网络协议,每个meta server在退出服务前,都向所有的meta
server(假设N个)发起一轮会话,询问是否允许自己退出服务,在得到N/2+1的同意后,则自动退出服务;否则根据拒绝信息里含的数据选择是否持续询问或者接受其他人的会话。在默认配置下,每个meta按照“先到先同意”的原则处理会话。通过这样的设计,在极端情况出现时(Internal
DB出现故障),KVDB也能保证至少N/2个meta server提供服务。
对于云计算平台来说,重平衡是一个很重要的特性,不仅对于NoSQL,对于SQL也是一样。因为云计算无法预知用户的使用量,所以即使在用户申请服务时进行基于权重的分配,仍然不可避免在服务运行一段时间后,平台出现不平衡的情况。对于KVDB而言,不平衡主要体现在两个维度:磁盘使用量和节点负载。
目前,业界带重平衡功能的存储服务一般使用简单的阈值公式来判断是否需要重平衡,比如节点的最大chunk数量和最小chunk数量之差是否大于一个阈值,如果大于则触发重平衡。但这种判断模式过于简单,不能在所有的情况下都工作正常,所以KVDB开发了一套基于严格数学理论的判断重平衡方法。
我们知道,数学期望表示一个系统的均值,而均方差表示系统里的值和均值的偏离程度。于是,我们在触发重平衡时就可以利用这样的概念。以机器负载为例,如果大多数机器负载都很高,表示负载的数学期望很高,那么KVDB需要做的并不是重平衡而是扩容,这时需要将新的节点加入服务,以缓解现在系统压力;而如果大多数机器的负载都很低,只有个别机器的负载很高,也就是负载的数学期望不高,而均方差很高,这表明系统并没有扩容的迫切要求,而真正需要做的是重平衡。当然,KVDB的重平衡判断还需要对上面的概念做加工,比如判断算法还需要将均方差进行归一化,这样方便运维人员在固定范围内根据系统实际情况指定参数。
KVDB的重平衡过程完全无缝,对用户透明。当进行重平衡时,系统会自动切换为双写模式,以保证用户的插入、删除、更新操作不必挂起。等重平衡完成时,会自动切回常规模式。
如上所述,SAE提供了以RDC支持的MySQL服务和以KVDB为代表的NoSQL服务,来满足开发者各种层次的需求,这样既降低了用户的迁移成本,又能从一定程度上满足动态扩展性的需求。
|