Sina App Engine 数据存储服务架构

阅读数:10067 2011 年 5 月 31 日

一、什么是 Sina App Engine

Sina App Engine(简称 SAE)是新浪研发中心于 2009 年上旬开始内部开发,并在 2009 年正式推出第一个 Alpha 版本的国内首个公有云计算平台(http://sae.sina.com.cn),SAE 是新浪云计算(简称浪云)战略的核心组成部分。

SAE 作为国内的公有云计算,从开发伊始借鉴吸纳 Google、Amazon 等国外公司的公有云计算的成功技术经验,并很快推出不同于他们的具有自身特色的云计算平台。SAE 选择在国内流行最广的 Web 开发语言 PHP 作为首选的支持语言,Web 开发者可以在 Linux/Mac/Windows 上通过 SDK 或者 Web 版在线 SDK 进行开发、部署、调试,团队开发时还可以进行成员协作,不同的角色将对代码、项目拥有不同的权限;SAE 提供了一系列分布式计算、存储服务供开发者使用,包括分布式文件存储 Storage、分布式数据库集群 RDC、分布式缓存 MemcacheX、分布式定时服务 Cron、分布式异步队列 TaskQueue、邮件服务 Mail 等,这些服务将大大降低开发者的开发成本。同时又由于 SAE 整体架构的高可靠性和新浪的品牌保证,大大降低了开发者的运营风险。另外,作为典型的云计算,SAE 采用“所付即所用,所付仅所用”的计费理念,通过日志和统计中心精确的计算每个应用的资源消耗(包括 CPU、内存、磁盘等)[1]

总之,SAE 就是分布式 Web 服务的开发、运行平台。

附,SAE 和传统的虚拟主机托管 VPS 的主要区别:

类项

SAE

VPS

核心用户

Web 开发者

无核心用户

使用方式

服务使用

设备租用

目标

力争覆盖 Web 服务所有需求,提供多种服务给开发者使用

仅基本需求

SLA(服务承诺)

高可靠性及严格的服务承诺

依服务商变化,无严格协议

计费方式

所付即所用,所付仅所用

预付费,无精确计费

SAE 在 2009 年 11 月 3 日发布了 alpha1 版本,2010 年 2 月 1 日发布了 alpha2 版本,2010 年 9 月 1 日发布了 beta 版本,截止到 2011 年 4 月 30 号,注册开发者已经接近 10000 人,活跃 App 接近 3000 个,每天独立代码部署行为超过 3000 次。

二、SAE 的数据存储服务

众所周知,Web 应用的最核心的是数据,数据对用户异常重要,对开发者本身也是最重要的信息。所以,保证用户和应用数据的可用性、可靠性、安全性就是云计算平台实现的重中之重。

SAE 数据存储关系图

如上图所示,SAE 作为 Web 计算中心通过 Apache HTTP+PHP 提供给用户 Web 服务,Web 服务通过 API 调用 SAE 内置的各种服务和外置的第三方服务(图中所示仅为 SAE 官方内置服务的数据存储部分)[2]。服务分成两类:计算型服务 Computing 和存储类服务 Storage。而计算型服务又分成同步计算服务(如 FetchURL、Image 等)和异步计算(如 Cron、TaskQueue 等)服务,而存储服务则分成非持久化存储服务和持久化存储服务,本文只针对介绍存储服务。

非持久化存储服务包括了传统意义上的缓存服务,它能够提供大并发和高速读写,但是不保证数据的完全可靠,也就是说,当发生系统故障时可能会发生数据丢失和不一致。按照功能非持久化存储分成了通用缓存和功能性存储,SAE 上的 MemcacheX 就是通用性缓存,大家可以理解为 LAMP 架构中常见的 memcached。计数器服务 Counter 和排行榜服务 Rank 属于功能性缓存,可以为特定场景下的需求提供更方便的服务,值得一提的是,计数器服务和排行榜服务的 HA 可靠性都比通用的 MemcacheX 高,具有一定的容灾和数据修复迁移能力,所以他们也兼有持久化存储的特性。

持久化存储服务用来存储用户需要落地的数据,这类服务强调高可靠性和高可用性,在分布式环境中以最终一致性来保证 HA。持久化存储服务根据存储数据是否为结构化又分成两类:结构化数据存储包括传统意义的关系型数据库 MySQL(在 SAE 中,以 RDC 提供)+NoSQL 数据库(KV,在开发中)和非结构化数据存储(分布式文件存储 Storage)。

从目前国内外流行的 Web 应用和网站看,MySQL 和 memcached 是最重要的服务组件,MySQL 提供实际数据存储,memcached 提供高速访问缓冲,甚至有些游戏网站直接拿 memcached 当实际存储,然后定时将其中的数据刷到 MySQL 中实现落地。从 Facebook、Twitter 等网站的公开文档中,也都可以看到,memcached 在其架构中被广泛使用,而且也没有放弃 MySQL,MySQL 仍作为其核心数据的存储服务。

所以,MySQL 和 memcached 服务对应的 RDC(Relational Database Cluster) 和 MemcacheX 也是 SAE 的所有数据存储服务中最重要的组件,从实际的运维经验中也确实如此,像数据库的主从同步、缓存的失效和无法写入等问题都直接关系到线上应用的用户体验,所以本文着重介绍 RDC 和 MemcacheX,了解了这两个服务,也就了解了 SAE 数据存储的核心。

三、RDC(Relational Database Cluster)

随着 NoSQL 概念的兴起,传统 MySQL 关系型数据库在云计算时代遇到了挑战,无论是亚马逊还是 Google,在其云计算服务伊始都不约而同的避免了关系型数据库而主推其 NoSQL 数据库。但是,从 AWS SimpleDB 等服务的实际效果来看,普通开发者对于传统 MySQL 的依赖仍然十分严重。所以,出于降低开发者学习成本和迁移成本的考虑,SAE 从一开始就确定了“不能放弃 MySQL”,要对用户提供 MySQL 服务的目标,而这也就是 RDC 的设计和实现的初衷 。

对于 RDC,用户可以简单的理解其为 MySQL 的中间层或者代理层,类似 MySQL Proxy。所有的 SQL 请求都由 RDC 传递到后端的实际存储上。

RDC 作为对外提供服务的数据库集群,具有和传统 MySQL Proxy 截然不同的目标和要求,那是解决公有云数据库集群的安全性,为用户提供的强隔离性,而这个特性是私有云计算平台上的数据库集群所不具备的。除此之外,RDC 要求还具有对数据库的监控、管理功能,实时监控用户的 DB 的健康状况和主从同步延迟情况,一旦发现异常,将会在 15 秒内完成切换工作,用户的请求会被转发到其他正常的机器上。和某些私有云计算平台上的数据库集群提供的水平扩展和垂直划分不同,RDC 不提供用户数据库水平扩展,而是通过提供以下两个地址:

w.rdc.sae.sina.com.cn:3307 => 写库(主库)
r.rdc.sae.sina.com.cn:3307 => 读库(从库)

由应用层自行处理,对于 Sina App Engine 上的开发者,其实可以使用 PHP 语言级的数据库类 (SaeMysql) 自动实现读写分离。

RDC 从 2010 年 9 月开始完成设计并开始编码,到 2010 年底完成测试,其自身采用的是多进程非阻塞方式的通讯框架,自身性能消耗较少,根据内部性能测试,开启 SQL cache 时对比直接访问 MySQL 的性能损耗在 5% 以内。

RDC 在 2010 年底正式上线,目前 SAE 上所有的数据库访问都通过 RDC 来提供,并且已经稳定运行了半年。RDC 虽然为分布式数据库集群,但是对终端用户完全透明,用户在使用 RDC 时,不会感觉到和使用传统的 MySQL 数据库有任何差异,甚至用户都不用知道 RDC 的存在。用户可以使用所有 MySQL 标准客户端(MySQL5 以上)操作 RDC,如 mysql_query、mysql_connect 等,错误处理和标准 MySQL 客户端处理模式一样,用户操作 RDC 的示例代码:

$con=mysql_connect('w.rdc.sae.sina.com.cn:'.$_SERVER['HTTP_MYSQLPORT'],SAE_ACCESSKEY,SAE_SECRETKEY);
if (!$con) 
    die('could not connect: ' . mysql_error());
$sql = "SELECT * FROM Person";
if(!mysql_query($sql,$con))
    echo mysql_errno() . ": " . mysql_error() . "\n";

RDC 整体架构图

RDC 的整体架构如上图所示,开发者通过 SAE StdLib(自动支持主从分离)或者标准 MySQL PHP 函数(手工访问 w.rdc.sae.sina.com.cn:3307 和 r.rdc.sae.sina.com.cn:3307 来控制主从分离)在 SAE 平台上调用 RDC。当一条 SQL 语句到达 RDC 时,RDC 先将其翻译解析,然后查看 cache 的解析结果,如果命中则根据结果做出判断(SQL 预判,见下文),如果没有命中则送到后端(根据 accesskey 到 DB 的映射关系)进行判断。判断结果完成后,如果是拦截则直接返回用户 MySQL Error 并通过 errmsg 告知拦截原因,否则就进行正常的 SQL 访问。

RDC 支持的数据库后端的数量为百万级,其自身设计为无状态结构,并且可以随时水平扩展(而后端数据库的水平扩展由用户自己负责),accesskey 到 DB 的映射关系由 SAE 自身的支持分布式一致性的 trigger 服务保障。

RDC 后端的 DB 为标准的 MySQL 一主多从结构,具体几个从库由用户级别对应的 SLA 决定(默认是两个从库),主从之间通过 binlog 做最终一致性保证。目前 RDC 上的 MySQL 的存储引擎为 MyISAM,以后会支持 InnoDB。RDC 不支持非 SAE 环境直连,这里主要是因为用户客户端如果不在 SAE 的环境中就很难保证和数据库的网络状况。用户如果想管理数据库可以通过 SAE 应用页面里的 PHPAdmin 进行操作。

在编码实现上,RDC 类似 MySQL5(除去存储引擎部分),但在细节上和标准 MySQL 还是有几个显著区别:

  1. RDC 采用多进程实现(SAE 上的服务几乎都是多进程结构),而标准 MySQL 采用多线程
  2. RDC 对 SQL 语句的解析是词法解析,而标准 MySQL parser 则是标准的语法解析,这样做的好处是词法分析更快,而 RDC 并不需要完整的挂接语义动作
  3. RDC 的 cache 层在词法分析后,这意味着即使用户的 SQL 语句有些改动,比如多了 1 个空格,仍会命中 cache;而标准 MySQL 的 query cache[3]则在语法分析前,SQL 语句即使多了 1 个空格,仍然会使 cache 失效

RDC 自带一个监控进程,监控分成两部分:健康监控和主从监控。健康监控会定期连接 DB,发现故障时,自动做切换。主从监控通过分析 slave stat 和 binlog pos 来确定主从延迟情况,发现高延迟时,将请求自动切换到低延迟的 DB。RDC 的监控还自带了网络状况检查和跨 IDC 配置,以支持跨 IDC 部署 RDC 需求。

安全性保证

安全性是 RDC 作为公有云计算数据库服务的最大挑战,试想,如果一个初学用户在上千万记录的表上执行不带 where 语句的 select 是什么后果,如果一个恶意用户故意频繁执行大量的 join 是什么后果。为了解决这些问题,RDC 设计了三道“防护线”的策略来保护用户数据库的隔离性。

SQL 预判机制

RDC 会根据自身算法预先评估 SQL 语句的效率,当发现有可能是性能不高的 SQL 语句时,会对开发者做出提示(这在 RDC 内部叫软拦截),而当发现可能对整个数据库平台造成伤害的 SQL 语句时,会直接在 RDC 层将其屏蔽掉,并以标准 MySQL 的错误返回方式告知开发者。RDC 会对以下几种语句做出预判:

select 
update 
insert 
delete 
replace 
create table 
alter table 
create index 

以最复杂的 select 语句为例,RDC 的判断依据包括了:select 语句是否带 where 语句、查询条件是否带了恰当的索引、是否带有子查询、是否带有连表 join 操作、子查询和 join 和主查询的关系、join 和子查询的复杂度、是否有不恰当的排序、是否有 limit 限定等。

目前,该判断算法已经申请专利。

并发执行时间和

RDC 率先提出这个概念,来取代传统 MySQL 的并发连接数限制,原因主要是因为传统的连接数限制较为粗鲁,不能区分用户,换句话说, 无法区分"SQL 优化得好的用户"和"SQL 执行性能低下的用户"。而并发执行时间和很好的解决了这个问题,

并发执行时间和 = 当前所有活的请求已经执行的时间和

举个例子,如果 SQL 并发执行时间和为 10000ms:

A 用户的平均每条 SQL 消耗 100ms,那么 A 获得的最大并发为 100

B 用户的平均每条 SQL 消耗 1000ms,那么 B 获得最大并发仅为 10

并发执行时间和从技术层面突出一个产品引导:“对于 SQL 效率高的用户支持更大的并发,而 SQL 执行效率低的用户则可能不会获得大的并发”,以鼓励用户优化自己的 SQL,优化自己的表结构,提高 SQL 的执行效率,减少对系统的消耗。

慢查询保护

MySQL 自身会产生慢查询日志,正常应用的慢查询肯定不会超过一定额度,那么超过这个额度我们就会给出建议和报警,如果应用超过慢查询系统上限,则可能导致 MySQL 服务暂时禁用(过十分钟会自动开启),以保护其他的数据库服务正常使用并督促应用的开发者尽快修改代码或作 MySQL 结构优化。

通过上面三种不同层面的策略,有效的保护了 RDC 的后端实际数据库。从实际运行效果看,98% 正常应用并不会受到 RDC SQL 保护的影响,而 %1 的应用因为数据库设计编码经验不足而触发了大量的 RDC 拦截,用户可以在 SAE 日志中心实时的看到这些日志,日志中心还会针对这些日志给出 MySQL 优化改进建议。事实证明,通过 RDC 使 SAE 避免了多次重大数据库故障。

四、MemcacheX

传统的公有云计算平台的 memcache 服务,往往是给开发者提供一个类 memcached 的实例,用户可以自主使用其 memcache 而不影响其他用户的 memcache。但这种实现有个致命缺陷:即当 memcached 实例出现故障时,会使应用全部缓存 key 穿透数据库,而很可能造成重大故障。除此之外别的缺点也不少,比如成本过大,每个 memcached 都有额外的内存 overhead,从而浪费了不少空间,再比如扩容时必须重启服务,这样导致扩容会导致用户的 key 失效等等。

SAE MemcacheX 服务设计和实现的目的就是克服上述缺点,代替现有的 memcached 服务,从而降低运行成本,并且为用户提供高可靠性的缓存服务。

MemcacheX 架构图

从上图可以看出,用户通过标准 memcache 客户端使用 MemcacheX 服务,用户的 key 通过客户端的一致性 hash 分散在所有的 MemcacheX 节点上,这点和标准的 memcached 服务几乎一样,但不同的是每个用户的 key 加上了他们的应用名做前缀区分,这样多个用户的 key 可以共享一个 MemcacheX 实例,甚至共享同一套 slab 内存池,提高了内存使用率。每个用户都独立享有实例的统计信息和 LRU 信息,也就是说,当某个用户的 memcache 内存使用到了其申请的大小上限时,key 只会和本用户的 key 做 LRU 交换,而不会影响其他的 key。MemcacheX 还对 slab 算法进行了改进,因为 memcached 的 slab 算法并没有伙伴系统[4]的回收逻辑,所以可能会导致在明明还有内存的时候,分配不成功,MemcacheX 对此的改进有效的降低了这种可能性。MemcacheX 支持内存自动扩容,扩容过程不用重启服务,所以用户无需担心扩容后的穿透问题。

因为每个用户的 key 都会被一致性 hash 在所有 MemcacheX 的 N 个节点上,所以当某个节点出现故障时,理论上只有 1/N 的 key 受到影响,而当 N 足够大时,就不会对用户的应用造成致命影响,从而提高了 HA。

MemcacheX 还具备一个功能,就是 connection LRU 保护。新浪动态应用平台的实际运维经验表明,因为系统的不可靠性和 Web 开发人员代码质量的不可控性,传统 memcached 容易造成连接资源耗光的的情况,比如下面的代码:

$memcache_obj=new Memcache;
$memcache_obj->connect('memcache_host',11211);
if($memcache_obj->get('key')!=false)
do_mysql_query()
$memcache_obj->close();

试想,当数据库操作 do_mysql_query() 因为某种原因阻塞住时,该代码就会造成 memcached 的连接资源没能及时释放,当并发访问量很大时,可能造成瞬间 memcached 文件描述符资源耗尽,从而影响服务,即使当数据库恢复正常时,memcached 仍然不可用。

MemcacheX 的 connection LRU 就是解决这个问题的,connection LRU 是指当极端情况下的连接资源耗尽时,可以淘汰旧的连接以保证可以正确建立新的连接。这样做固然会影响某些应用的正常逻辑,但可以在特殊时期保证新用户的正常使用。

2011 年 3 月,MemcacheX 已经在 SAE 上线。经过测试和实践检验,MemcacheX 和传统 memcached 拥有同样的性能,并且具有更高的可靠性。

通过 RDC 和 MemcacheX,SAE 很好的支持了近万开发者的数据库和缓存服务,RDC 每天请求量超过 6000 万,MemcacheX 的每天请求量则超过 1 亿,两者共同承担了 90% 以上数据读写需求,也正是因为这两个服务,才保证了公有云计算平台上的用户数据读写的可用性和可靠性。另外,除了 RDC 和 MemcacheX,Sina App Engine 技术团队近期还研发了很多重量级产品[5]:支持系统层文件排重的分布式强一致性文件部署系统 CodeFS、计数器服务 Counter、排行榜服务 Rank,以及正在开发中的分布式 NoSQL 存储 SAE KV。对于这些服务的架构和技术细节,我会在以后的文章和大家分享。

欢迎使用 SAE:

  1. Sina App Engine 注册页面,http://sae.sina.com.cn/
  2. Sina App Engine 体验账号申请页面,http://sae.sina.com.cn/?m=home&a=exp
  3. 微博开发平台 SAE 账号申请页面,http://open.t.sina.com.cn/apps/new

参考资料:

  1. Sina App Engine 架构 - 云计算时代的分布式 Web 服务解决方案
  2. Sina App Engine-deep inside cloud service
  3. MySQL query cache
  4. Buddy System
  5. SAE 服务总体说明

感谢胡键对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。