预测:多云

SQL Azure 和 Windows Azure 表存储

Joseph Fultz

下载代码示例

在我们家,经常会有这种情形:我们决定晚上轻松点儿,出去吃饭。每个人都很开心,也很享受晚餐的轻松时光。我们家周边有很多餐馆可以选择,事实证明,除非有人明确表示想吃什么,否则我们很难决定到哪里吃饭。

当我的许多客户和同事要决定在云中使用哪种存储机制时,也会遇到同样的问题:面对看起来都差不多的选择,到底应该选择哪一个呢?通常,解决困惑的关键就是理解 Windows Azure 表存储和 SQL Azure 的差别。

我无法告诉任何人选择哪种技术,但会提供一些指导方针,帮助大家针对 Windows Azure 表存储和 SQL Azure 的功能和限制,在评估解决方案和解决方案团队的需要时作出决定。此外,我还会添加一些代码,让您能够获得一些使用这两种技术的开发人员体验。

数据处理

SQL Azure 和其他关系数据库通常在存储系统之上提供数据处理功能。一般来说,相比于数据库的原始存储和检索方面,RDBMS 用户更感兴趣的是数据处理。

例如,如果您想了解公司在给定时间段内的总收入,可能要扫描数百 MB 的销售数据,然后计算 SUM。在数据库中,您可以向数据库发送一条查询命令(几个字节),让数据库将数据(可能多达数 GB)从磁盘检索到内存中,根据适当的时间段过滤数据(通常会减少到数百 MB),计算销售数据的总和,然后将结果返回到客户端应用程序(几个字节)。

若要在纯存储系统上进行此操作,需要运行应用程序代码的计算机通过网络从存储系统中检索所有原始数据,然后开发人员还要编写代码对数据执行 SUM 操作。为了进行数据处理而将大量数据从存储系统传输到应用程序,开销非常大,也非常慢。

SQL Azure 通过查询、事务和存储过程来提供数据处理功能,这些功能均在服务器端实现,只需要向应用程序返回结果。如果您的应用程序需要处理大型数据集,那么 SQL Azure 就是一个很好的选择。如果您的应用程序需要存储和检索(扫描/筛选)大型数据集,但不需要进行数据处理,那么 Windows Azure 表存储就是您的首选。

— Windows Azure 首席项目经理 Tony Petrossian

检查选项

简单地扩展范围以包含其他存储机制,能够展现整个蓝图的一小部分,而从较高的层次更容易将存储选项划分到各个大类中:

  • 关系数据访问:SQL Azure
  • 文件和对象访问:Windows Azure Storage
  • 基于磁盘的本地缓存:角色本地存储

但是,为了进一步验证选择,您可以开始问一些简单的问题,例如:

  • 如何使所有角色在一般情况下都能访问文件?
  • 如何使文件可以使用,并轻松更新文件?
  • 如何在提供结构化访问语义的同时还能提供充足的存储和性能?
  • 哪一种方案能提供最佳的性能或最好的可伸缩性?
  • 培训方面有什么要求?
  • 有什么管理案例?

通往明确决定的道路开始变得泥泞,很容易迷失在功能的好处与限制的比较当中。让我们重新回到 SQL Azure 和 Windows Azure 表存储上,我打算描述一些理想的使用模式,并为每个模式提供一些代码示例。

SQL Azure 基础知识

SQL Azure 提供了关系数据库的基本功能,可供应用程序使用。如果某个应用程序需要在关系数据库管理系统 (RDBMS) 中托管数据,那么可以采用 SQL Azure。它提供了所有常用语义,可以通过 SQL 语句进行数据访问。此外,SQL Server Management Studio (SSMS) 可以直接挂接到 SQL Azure 上,它提供了无需使用代码来处理数据库的方法,这些方法众所周知且易于使用。

例如,使用 SQL Azure Web 管理控制台和 SSMS,只需几步就能设置一个新的数据库。这些步骤包括:

  1. 通过 Web 创建数据库
  2. 创建规则,以便从本地计算机访问数据库。
  3. 通过本地 SSMS 连接到 Web 数据库
  4. 在数据库容器上下文中运行 DDL

如果应用程序当前使用的是 SQL Server 或类似的 RDBMS 后端,那么 SQL Azure 会是将您的数据转移到云中的最简单方法。

SQL Azure 还是提供基于云的结构化数据访问的最佳方法。无论应用程序是否托管在 Windows Azure 中,这都是事实。如果您的应用程序是手机应用程序,甚至是桌面应用程序,SQL Azure 都可以提供方法,将数据放到云中,然后通过这些应用程序进行访问。

在云中使用数据库与使用内部托管的数据库没有太大区别,除了一点需要注意:身份验证需要通过 SQL Server 身份验证进行处理。您可能想看看代号为“Houston”的 Microsoft 项目,该项目是为 SQL Azure 开发的新管理控制台,使用 Silverlight 构建。有关此项目的详细信息,请参见 sqlazurelabs.cloudapp.net/houston.aspx

SQL Azure 开发

快速编写一个仅包含一个 Windows 窗体的示例程序,并在该窗体中承载一个数据网格,用于显示 Pubs 数据库中的数据,这样的过程与采用本地数据库时相比,并不会变得更复杂。我在 Visual Studio 中利用向导来添加新的数据源,而向导将逐步引导我创建连接字符串和数据集。在本例中,我最终在 app.config 中得到了一个类似如下的连接字符串:

<add name="AzureStrucutredStorageAccessExample.Properties.Settings.pubsConnectionString"

     connectionString="Data Source=gfkdgapzs5.database.windows.
net;Initial Catalog=pubs;Persist Security Info=True;User ID=jofultz;Password=[password]"

     providerName="System.Data.SqlClient" />

通常,集成身份验证是首选的数据库安全措施,因此再使用 SQL Server 身份验证就显得有点奇怪。SQL Azure 通过实施 IP 访问列表以尽可能降低曝光面,您需要为每个可能连接到数据库的 IP 范围向该列表中添加一项。

现在,在 Pubs 数据库中选择 Titleview 视图,回到我特意提供的小示例,采用系统默认名称的数据集 pubsDataSet 中会有一些生成的代码,如图 1 所示。

图 1 为访问 SQL Azure 自动生成的代码

我做了一些拖放操作,将 DataGridView 拖到了窗体中,并对连接进行了配置。建立连接之后,我运行了程序,得到一个简单的数据网格视图,如图 2 所示。

图 2 简单网格中的 SQL Azure 数据

我不打算建议您在 Visual Studio 中通过向导来创建一个企业级应用程序,但是想告诉您,数据访问或多或少类似于 SQL Server,并且会像预期一样进行。这意味着,您可以针对它生成一个实体模型并使用 LINQ,因为如果它是本地的而不是托管的,我就会这么做(请参见图 3)。

图 3 使用实体模型和 LINQ

有一个强大的新功能,超越了通常基于 SQL Server 的本地数据库范围,那就是可以将数据以 OData 源的形式公开提供的选项(目前通过 sqlazurelabs.com 提供)。您获得类似如下的 REST 查询:

https://odata.sqlazurelabs.com/  

  OData.svc/v0.1/gfkdgapzs5/pubs/  

  authors?$top=10

这会生成一个 OData 响应;如果使用 $format=JSON 参数,则会生成 JSON 响应。 这对于应用程序开发人员来说是一个非常大的喜讯,因为您不仅能获得标准的 SQL Server 行为,而且还能通过配置获得额外的访问方法,甚至不用编写一行代码。 这可以让我们把重点放在能够增加业务价值的服务或应用层面,而不用探索如何跨网络将数据从存储中移进和移出。

如果应用程序需要传统的关系型数据访问,SQL Azure 很可能是更好、更简单的选择。 但是,还有一些其他原因能证明 SQL Azure 比 Windows Azure 表储存更具竞争力。

第一个原因是,如果您的事务率非常高,则说明对数据存储执行查询(所有操作)的频率很高。 SQL Azure 不按事务收费。

SQL Azure 还为您提供了在各种 Windows Azure 数据库之间设置 SQL Azure 数据同步 (sqlazurelabs.com/SADataSync.aspx) 的选项,以及在本地数据库和 SQL Azure 安装之间同步数据的能力 (microsoft.com/windowsazure/developers/sqlazure/datasync/)。 我将在以后的专栏中讨论如何对本地存储设计和使用 SQL Azure 与 DataSync,届时将介绍如何将 SQL Azure 用于分支节点体系结构。

Windows Azure 表存储

现在,您已经了解了将 SQL Azure 用于存储的优势。 那么,什么时候使用 Windows Azure 表存储更合适呢? 在以下几种情况中,SQL Azure 可能不是合适的选择。

如果某个应用程序正在进行改造以便迁移到 Web,或者是数据存储层的实现尚未完成,您可能需要考虑一下 Windows Azure 表存储。 同样,如果您不需要关系型存储,或者是访问只限于一次一个表且不需要合并,那么 Windows Azure 表存储就很合适。 在这种情况下,您的数据集会很小,合并操作可以由 LINQ 在客户端处理。

如果您的数据量超过了 SQL Azure 支持的最大数据量(目前为每个实例 50GB),也需要考虑 Windows Azure 表存储。 请注意,数据量的限制可以通过数据分区来克服,但会增加 SQL Azure 的成本。 在 Windows Azure 表存储中,相同大小的空间可能会更便宜,而且还通过声明的分区键内置了分区功能。

此外,由于 Windows Azure 表存储是按事务收费的,对于低访问频率的数据或能够轻松缓存的数据会是很好的选择。

能够凸显 Windows Azure 表存储优势的其他情景包括:应用程序需要某种结构化的访问(例如索引查找),但存储的主要是对象或二进制大型对象 (BLOB)/字符大型对象 (CLOB);您的应用程序可通过支持在表中存放不同类型的数据而受益;因为 SQL Server 安装中的现有数据结构(或因缺乏某种数据结构)而难以进行迁移。

使用 Windows Azure 表存储

首先,因为假设要将“表存储”关联到 SQL 数据库,所以使用 Windows Azure 表存储看起来可能会比较麻烦。 在名称中使用“表”不会有什么帮助。 在考虑 Windows Azure 表存储时,我建议您将其视为对象存储。

作为一名开发人员,请不要将注意力集中在存储结构或机制上,而是要关注对象以及您要通过它完成的任务。 在 Windows Azure 表存储中设置对象,对于开发人员来说往往是最大的障碍,但通过对象访问 Windows Azure 表存储则很自然,特别是当您使用 LINQ 时。

在开始使用 Windows Azure 表存储时,需要将对 System.Data.Services.Client 的引用添加到您的项目中。 此外,如果您未使用 Visual Studio 云模板(可为您提供所需的引用),请添加对 Microsoft.WindowsAzure.StorageClient.dll 的引用。

接下来,创建一个您可以使用的对象/实体(从 Authors 表中窃取):

public class TableStorageAuthor:

  Microsoft.WindowsAzure.StorageClient.TableServiceEntity {

  public int Id {get; set;}

  public string LastName { get; set; }

  public string FirstName { get; set; }

  public string Phone { get; set; }

  public string Address { get; set; }

  public string City { get; set; }

  public string State { get; set; }

  public string Zip {get; set;}

}

您可以使用 TableServiceContext 定义一个数据服务客户端上下文来处理与存储的连接,并执行创建/读取/更新/删除 (CRUD) 操作(如图 4 所示)。TableStorageAuthor 类被用作模板类,以便声明 AuthorData 元素,将会为该元素返回一个针对 Authors 表的表查询方法。 它还被用作所实现的 Add 操作的参数类型。

图 4 访问 Windows Azure 表存储

public class AuthorDataServiceContext : TableServiceContext {

  public IQueryable<TableStorageAuthor> AuthorData {

    get {

      return this.CreateQuery<TableStorageAuthor>("Authors");

    }

  }



  public AuthorDataServiceContext (

    Uri baseAddress, StorageCredentials credentials)

    : base(baseAddress.AbsoluteUri, credentials) {}



  public void Add(TableStorageAuthor author) {

    this.AddObject("Authors", author);

    DataServiceResponse dsResponse = SaveChanges();

  }

}

创建目标表:

TableClient.CreateTableIfNotExist("Authors");

使用熟悉的对象创建和属性分配模式来创建一些数据,并将这些数据添加到在存储中创建的表中(请参见图 5)。

图 5 将数据添加到 Windows Azure 表存储中

var TableClient = StorageAccount.CreateCloudTableClient();



TableStorageAuthor author = new TableStorageAuthor();

author.FirstName = "Joseph";

author.LastName = "Fultz";

author.RowKey = System.Guid.NewGuid().ToString();

author.Id = author.RowKey;

author.State = "TX";

author.PartitionKey = "TX";



AuthorDataServiceContext ctx = 

  new AuthorDataServiceContext(

  StorageAccount.TableEndpoint, 

  StorageAccount.Credentials);

ctx.Add(author);

添加完所有数据之后,就可以使用 LINQ 进行操作了。 例如,针对实体的选择操作为:

AuthorDataServiceContext ctx = 

  new AuthorDataServiceContext(

  StorageAccount.TableEndpoint, 

  StorageAccount.Credentials);



var authors = 

  from a in ctx.AuthorData

  select a;



foreach (TableStorageAuthor ta in authors) {

  Debug.WriteLine(ta.FirstName + " " + ta.LastName);

}

我没有实现更新和删除操作,但具体方式是类似的。 有一点可能与将 LINQ 用于实体框架的代码略有不同的是用于创建 TableServiceContext 的代码,以及用于构建和使用 TableServiceContext 的后续代码。 如果您正在使用 REST 和 DataServiceContext,执行此操作就非常自然。

您使用 TableServiceContext、TableServiceEntity 和 LINQ 的感受与对 SQL Azure 使用实体框架和 LINQ 的感受是一样的,虽然在 Windows Azure 表存储方案中需要手动编写的代码更多。

基于解决方案的评估

正如先前所述,如果应用程序已经建立了一个关系型存储,最好稍稍借助 SQL Azure 迁移向导这样的工具将该存储迁移到 SQL Azure。 但是,如果不是这样的情况,或者应用程序的云功能部分不需要 RDBMS 的完整功能,请参见图 6 中的表格,看看哪些列最符合解决方案要求和体系结构的需求。

图 6 比较 SQL Azure 和 Windows Azure 表存储

功能 SQL Azure 共同的优势 Windows Azure 表存储
选择语义 跨表查询 基于主键的查询 单键查询(按分区)
性能和规模 通过多索引、标准化的数据结构等实现高性能,通过跨 SQL Azure 实例手动分区实现可扩展性   通过分区实现自动大规模扩展,即使在大规模部署上也能实现一致的性能
用户体验 众所周知的管理工具和传统的数据库设计 熟悉的高水平开发人员体验 直接序列化;不需要 ORM;通过删除关系模型简化了设计模型
存储样式 传统的关系设计模型 适用于所有类型数据的数据存储 单个表中支持多种类型
成本因素 没有事务成本,按数据库大小付费 同一数据中心以外的网络流量成本 没有空间开销成本,按照使用量付费
数据加载和同步 在本地存储和基于云的存储之间进行同步;通过传统的提取、转换和加载 (ETL) 机制轻松将数据移进移出;在不同数据中心的 SQL Azure 数据库之间同步    

值得注意的是,关于图 6 中的一些项(例如,与 Windows Azure 表存储中的管理和数据负载相关的项),市场上已经有一些第三方解决方案可以提供其中缺少的功能。 因此,对于重大项目,需要考虑此类工具的成本和功能。

我预期许多应用程序将会需要混合的数据方法,以便充分利用技术。 例如,Windows Azure 表存储可用于优化提取时间,同时仍然能为文档、视频、图像和其他此类媒体等资源提供大规模扩展功能。 然而,为了便于搜索相关项的元数据,相关的数据和对象指针应当存储在 SQL Azure 中。 这样的设计还能减少针对 Windows Azure 表存储的事务流量。 这种互补设计能够提供以下好处:

  • 保持高吞吐量,以便查询获得资源
  • 减小 SQL Azure 数据库的大小,使其成本始终保持最低
  • 通过将大型文件存储到 Windows Azure 表存储而不是 SQL Azure 中,将存储成本降至最低(尽管 BLOB 存储是首选的文件存储方式)
  • 按键和分区提取此类资源,并从 SQL Azure 数据库上卸载检索查询,以此来维持高检索性能
  • 允许对 Windows Azure 表存储中保存的数据进行自动的大规模扩展

简而言之:您的设计应该综合利用这两种存储机制,各自发挥长处,而不要指望用一种机制完成所有的任务。 无论采用哪种方式,我们仍然期待着云能给我们一个答案。

Joseph Fultz 是达拉斯 Microsoft 技术中心的架构师,协助企业客户和 ISV 设计和制作软件解决方案以满足商业和市场需求。他在 Tech·Ed 及类似的内部培训活动中做过讲座。

衷心感谢以下技术专家对本文的审阅:Jai Haridas、Tony PetrossianSuraj Puri