深入了解 Windows Azure

构建多租户应用程序在 Windows Azure

Bruno Terkaly
Ricardo Villalobos

下载代码示例

那里是一个庞大而充满活力的生态系统的服务提供程序打包解决方案和承载它们在云平台上。一般来说,这些软件作为服务 (SaaS) 公司使用多租户的体系结构。你可以找到很多实际的例子在 bit.ly/vIPcyc。如果你想想它,如 Facebook 或 Hotmail,在 Web 上流行的应用程序的大部分是多租户应用程序。这种方法使得从商业角度来说,因为可以通过多个订阅服务器之间共享它们最大化计算和存储资源。所有的要点之一云计算后是通过分享大量的计算和存储资源,最大限度地提高效率。

我们得到的频繁问题有关的最佳做法和实施使用 Windows Azure 的多租户架构的模式。这是两列,将向您介绍一些关键概念和原则,以及提供一些指导,你可以开始加快对一些核心构建基块的实际操作技能的第一。

多租户软件的概念很简单。它是一个单一的、 综合性的系统,支持多个客户端组织 (住户),在每个租客运行安全地并行在相同的硬件和软件,完全不知道有其他人。处理得当,它允许服务提供者在实现极为高效利用 Windows Azure 的同时向租户提供大量的功能。租户的重点安全、 低成本和良好的性能。

云建筑师必须仔细考虑一些关键的支柱,构建多租户系统时:

  • 标识与安全
  • 数据隔离和隔离
  • 计量和性能分析
  • 同时维护 Sla 向上和向下缩放

我们将讨论前两个在这里和我们的下一列中的后两个。

表达式的值相同

身份扮演多租户的体系结构中的核心作用。对于初学者,租客必须保证其私有数据不能访问其他用户的目标是要在订阅服务器之间共享的情况除外。Microsoft SharePoint 提供一个示例。您可能有仅对特定的租客,可见的文档,但你也可能会有一些共享的工作组 (两个或更多租户可以跨组织)。底线 — — 身份中央方面起作用的数据可见性。

在今天的世界中,身份管理系统必须是可互操作,秉承开放标准 (如由本组织的结构化信息标准提高地位或绿洲维护)、 WS 信任和 WS-安全等。在一起,这些标准允许多租户系统评估的存在和经纪人相互之间的关系的房客和服务提供商的安全邮件交换中的信任。此外,多租户的体系结构通常支持多个身份提供程序,如谷歌、 Facebook、 雅虎和微软活。在更复杂的情况下,服务提供商将支持公司的标识,如活动目录。对 Web 单一登录 (SSO) 的支持也是重要的。

基于声明的身份管理

它被普遍接受基于索赔的标识管理办法提供最大的价值。首先,基于索赔的方法将身份的不同部分集中到单个抽象标记组成的索赔和开证人或权力机构。这种办法的价值是他们基于开放标准,高度互操作性。基于声明的身份管理允许服务提供商来解耦从巨大的、 低级的水暖代码的标识管理的应用程序。不支持 Web 服务标准 (WS-信任,WS-联邦、 WS-安全),令牌格式 (安全断言标记语言 [SAML]、 JSON Web 键 [JWK],简单 Web 令牌 [SWT]) 和加密 (X.509) 是微不足道。毕竟,这些标准始终不断,所以封装并提取身份管理是至关重要的。

所有这些挑战的答案是 Windows Azure 活动目录的访问控制服务 (ACS),从而从根本上简化了实现基于声明的身份管理系统。ACS 中移除此低级的水暖和因素放在服务提供程序的代码,使其相对容易实现基于声明的身份管理系统。使 ACS 如此强大的是很多工作可以通过基于 Web 的门户。ACS,可大大简化新租户的资源调配。

这意味着你开发人员,不需要处理很多复杂的应用程序内的标识管理。ACS 解决了困难,时间密集的问题,如:

  • 如何将未经身份验证的请求重定向到空房的标识提供程序
  • 如何验证传入令牌颁发的身份标识提供程序
  • 如何分析 (阅读索赔) 的传入令牌
  • 如何执行授权检查
  • 如何将标记转换通过添加、 删除或更改的索赔类型和值

我们建议您通过几个基于 Web 的教程,可以开始运行。你会发现一个好上进行身份验证的用户 bit.ly/uyDLkt。如果你运行 Visual Studio 2012,维托里奥 Bertocci 四部分发表于 bit.ly/12ZOwN9 将提供所需要的指导。在 Visual Studio 内的模具继续改善,让开发人员不必手动编辑配置文件。您可以下载工装和从 Sdk bit.ly/NN9NVE

图 1 描述了多个身份提供程序支持与租客的经验。


图 1 支持多个身份提供程序

图 2 表示真正发生的事情当你利用 ACS。租客是完全不知道,ACS 做幕后的所有工作。你看到在该工作流图 2 以获取安全令牌,通常在 SAML 2.0 格式的多租户应用程序结束。真正的美是已标准化多租户应用程序接收的令牌,无论所选择的租客的身份标识提供程序。ACS 透明地经纪人向您指定在 ACS 门户令牌格式转化的身份标识提供程序特定的标记格式。


图 2 高级视图的访问控制服务门户

有的 JavaScript,查询为标识提供程序列表中您想让您的应用程序支持,ACS 然后为每个标识提供程序生成的登录链接。由系统处理所有必要的重定向都要获取到您的应用程序的标准安全标记。"依赖方"是只需你多租户应用程序中,因为多租户应用程序依赖于发行人提供有关身份信息。

如果你通过前面提到的教程,您将看到中显示的屏幕图 3。ACS 门户的入门部分分为四个部分,简化了将身份管理集成到一个基于云计算、 多租户应用程序的过程。节 1 允许您从列表中选择您想要支持的身份提供程序。此预排,我们会选择谷歌、 微软的 Live ID 和 yahoo!作为标识提供程序。与一个小的额外工作,您还可以包括 Facebook 和 Active Directory 身份。节 2 是捆绑发生。它是您将在其中指定的 ACS 返回的安全令牌,通常应用程序的起始页的 URL。毕竟,ACS 需要终结点,以传递到令牌所需的格式。第 2 节中您还可以指定所需的标记格式。


图 3 Windows Azure ACS 门户

第 2 节是在其中选择索赔您想要包括安全令牌中的身份提供程序。依赖方 (服务提供商的多租户应用程序) 将使用这些索赔都唯一地标识租客和作出授权决定,定义在服务范围内的租客的特权。现有的索赔因身份标识提供程序 ; 而异 与谷歌不同 Windows Live,例如。与谷歌和雅虎,令牌中的索赔可以包括电子邮件地址、 用户名称、 nameidentifier 和提供程序名称。对于微软的 Live ID,不过,你只有 nameidentifier 和提供程序名称,而不是电子邮件或用户的名称。你会需要处理那些在应用程序中的微妙之处。

节 4 允许您将一些元数据和代码集成到该服务。这在 Visual Studio 内完成模具。您需要里面的应用程序配置文件,将绑定到 ACS 应用元数据。Visual Studio 2012 年模具使这一步操作一个指向和点击的经验,而与 Visual Studio 2010 你会需要手动编辑 web.config 的 sytem.web 部分。

微软最近发布了 Windows Azure Active Directory,允许您利用 Web SSO 与您的业务线 (LOB) 应用程序,对楼宇和在云计算中。如果您的目标是要在 LOB 应用程序中实现身份管理,在应用程序运行这两个处所和在云计算,你就会想要阅读的信息在 bit.ly/157yVPR。本文档说明了如何利用现有的 LOB 应用程序来使它可供其他 Windows Azure Active Directory 租客管理员在其组织中使用 Windows Azure 活动目录。

Bertocci 博客张贴 (前面提到的) 将您带到在屏幕图 4,其中显示了身份和访问可用于在多租户应用程序中添加配置代码。Visual Studio 2012 完全消除了需要手动编辑任何配置文件。正如你所看到的我们选择三个身份提供程序和定义领土和多租户应用程序返回的 URL。领土是只是一个 URI,标识应用程序用户登录到。此 URI 还允许您将应用程序和答复地址的索赔相关联。你就会改变领土和返回 URL,一旦您部署到 Microsoft 数据中心的应用程序。最后,您将添加一个管理密钥,你从 ACS 门户到数字符号标记为安全目的。


图 4 Visual Studio 2012 身份和访问对话框

将代码添加到应用程序

多租户应用程序需要保存到永久存储的已登录的用户。这是最初所需的资源调配的过程,但也可能是必要的如果租客活动进行跟踪。在这篇文章中使用的数据存储区是 Windows Azure 的 SQL 数据库,但您可以轻松地更改此到 Windows Azure 表,可能还包括房地上的数据存储。在 Page_Load 方法中的 Default.aspx.cs 文件,我们可以轻松地阅读的安全令牌和解析索赔中,如下所示:

 

protected void Page_Load(object sender, EventArgs e) {   // Grab the ClaimsIdentity object.
Think of it as a token   // and set of claims for the currently logged in user.
ClaimsIdentity ci =     Thread.CurrentPrincipal.Identity as ClaimsIdentity;   // Create a TenantTokenManager object that parses the claims.
TenantTokenManager tenantTokenManager = new TenantTokenManager(ci);   // Save logged in user to persistent storage.
tenantTokenManager.SaveTenantToDatabase(); }

将此逻辑封装,我们会向我们的云项目,所示来添加一个 TenantTokenManager 类图 5

图 5 TenantTokenManager 类

public class TenantTokenManager {   // Claims that uniquely identify tenants.
public System.Security.Claims.ClaimsIdentity SecurityToken { get; set; }   public string IdentityProviderName                         { get; set; }   public string IdentityProviderNameIdentifier               { get; set; }   public string IdentityProviderEmail                        { get; set; }   public string TenantId                                     { get; set; }   public string TenantName                                   { get; set; }   public TenantTokenManager(System.Security.Claims.ClaimsIdentity ci)   {     try     {       // Save a copy of the ClaimsIdentity security token.
this.SecurityToken = ci;       // Extract the provider name (Yahoo, Google, Microsoft Live).
IdentityProviderName = (from c in ci.Claims         where c.Type ==         "https://schemas.microsoft.com/accesscontrolservice/         2010/07/claims/identityprovider"         select c.Value).SingleOrDefault();       // Extract the nameidentifier (a unique identifier of       // a tenant from the identity provider).
IdentityProviderNameIdentifier = (from c in ci.Claims         where c.Type ==           "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"         select c.Value).SingleOrDefault();       // Extract the emailaddress (not available in Microsoft Live ID).
IdentityProviderEmail = (from c in ci.Claims         where c.Type ==           "https://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"         select c.Value).SingleOrDefault();       // Create a unique TenantId based on nameidentifier       // and provider name.
TenantId =         IdentityProviderName + "-" + IdentityProviderNameIdentifier;       // Extract name from security token (not available       // from Microsoft Live ID).
TenantName = SecurityToken.Name == null ? "
Not Avail." : SecurityToken.Name;     } catch (Exception ex) { throw ex; }   }   public void SaveTenantToDatabase() { IdentityDataStore.SaveTenantToDatabase(this); } }

TenantTokenManager 类封装了两项重要职能。 第一,它所分析的安全令牌从索赔。 在我们的例子,该令牌的格式是 SAML,但它可能只是简单地智威汤逊或 SWT。 注意可以使用简单的 LINQ 查询来提取个人索赔从令牌。 并注意代码中,对于微软 Live ID,你不能得到任何名称或电子邮件的数据。 在这种情况下,空值将返回从 LINQ 查询。 代码中的注释解释索赔的意思。 我们也加入了 TenantTokenManager 使用 SaveToDatabase 方法,以便可以调配并跟踪租户对节能的支持。

在应用程序中的下一个逻辑步骤是做出授权决定基于身份或身份的角色成员资格。 例如,如图所示,在图 6,该存储的过程只返回基于 TenantId 的记录。 这说明了如何你可能开始思考的数据隔离和隔离。

图 6 存储过程返回基于 TenantId 的记录

    CREATE PROCEDURE [dbo].[GetTenantData]   @TenantId nvarchar(max) AS BEGIN   SELECT     [id],     [TenantId],     [TenantName],     [ProviderName],     [NameIdentifier],     [Email],     [SomeTenantData1],     [SomeTenantData2]   FROM TenantRecords   WHERE TenantId = @TenantId   return; END

数据隔离和隔离

当它来到的身份结合数据在多租户系统中时,有一些重大问题要解决。 第一,建筑师必须想出如何保持完全孤立的其他租户的敏感数据。 很明显,你不能让事情-信用卡号码、 社会安全号码,电子邮件等等,将以任何方式泄露。 每个租客必须绝对保证是其数据保持窥探。 与此同时,可能还需要数据中的租客,如共享日历、 照片或简单文本消息的共享。 另一个需要解决的问题是资源调配的审核跟踪,藉以服务提供商可以跟踪租户的用法和登录模式。 这允许组织跟踪由管理员级别的用户,帮助解决意外的应用程序行为所做的更改。

在任何多租户系统中,有更多的技术挑战,使要使成本效益最大化同时为租户提供性能良好、 灵活的数据服务和数据模型的服务提供程序。 这一挑战尤其是由于很难纯粹各种数据类型。 考虑单独的 Windows Azure 支持大量的存储选项,如表、 斑点、 队列、 SQL 数据库、 Hadoop 和更多。 为服务提供商面临的技术挑战是重要的因为是非常不同的每种存储类型。 建筑师需要平衡成本、 性能、 可伸缩性以及最终的租户对数据的需求。

让我们看的四个常见的 Windows Azure 存储类型快速看。 Blob 用来存储非结构化的文本和二进制数据。 通常,blob 是图像、 音频或其它多媒体对象,尽管作为一个 blob 存储有时二进制可执行代码。 队列用于存储消息可能被访问的租客。 他们提供的缩放实例多租户应用程序的可靠消息。 表提供了 NoSQL 功能需要存储大量的非结构化数据的应用程序。 最后,SQL 数据库提供一个功能全面的关系数据库作为一种服务 (DBaaS) 的应用程序需要这个。

Blob 这些是比较容易理解 Windows Azure 表或 SQL 数据库。 你可以阅读更多有关在 blob bit.ly/VGHszH。 Windows Azure 帐户可以有许多的 blob 容器。 Blob 的容器可以有许多的 blob。 大多数服务提供商将有多个帐户。 所采取的典型方法是指定每个租客的容器名称。 这使您能够定义的访问权限、 衡量绩效和量化的 blob 服务消费。 最近,微软已修订其网络拓扑结构,大大提高了计算和存储资源,支持高达 10Gbps 的存储节点网络速度之间的带宽。 更多关于这在 bit.ly/PrxhAW

命名约定为 blob 可能会强制您保持容器名称到 TenantIds 的地图。 您可以使用电子邮件地址,因为他们是唯一的但 Windows Live ID 并不提供这种说法在范围内的安全令牌。 对于谷歌和雅虎,您需要删除"@"符号和"."因为 blob 容器只能包含字母、 数字和破折号。

中的代码图 7 演示了资源调配 blob 容器的方法。 此代码可能是租客的注册和资源调配过程的一部分。 请注意 TenantId 作为容器名称。 在真实世界的情况下,当然,可能有某种类型的查找表,提供基于 TenantIds 的容器名称。 在代码中的图 7,服务提供商选择了一个单独的 Windows Azure 帐户 (AccountTenantImages) 来存储图像的租户。 请注意,代码"blobClient.GetContainerReference(tm.TenantId),"这就是为新租客置备一个 blob 容器是哪里。

图 7 为租客调配资源 Blob 的容器

// Grab the ClaimsIdentity object.
Think of it as a token // and set of claims for the currently logged in user.
ClaimsIdentity ci =   Thread.CurrentPrincipal.Identity as ClaimsIdentity; // Parse the claim.
TokenManager tm = new TokenManager(ci); // Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(   Microsoft.WindowsAzure.CloudConfigurationManager.GetSetting(   "AccountTenantImages")); // Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); // Retrieve a reference to a container.
CloudBlobContainer container = blobClient.GetContainerReference(tm.TenantId); // Create the container if it doesn't already exist.
container.CreateIfNotExists();

另一个重要的一点是 blob 支持用户定义的元数据,这意味着每个 blob 可以支持一个或多个名称 / 值对。 然而,blob 存储不允许您查询全球范围内对其元数据的 blob。 在元数据中查找信息,你有两个选项。 第一次是从一个 blob 容器获取所有 blob 和他们,然后枚举搜索的名称-值对。 可扩展性更强的方法是在表存储,和 blob URL 中存储的元数据。 这种方法允许您查询表存储,以查找所需的 blob,然后从存储中检索 blob 和查询直接从单个 blob 的元数据。

队列因为队列通常用作机制提供可靠、 异步消息传递多租户应用程序内,住户一般从他们绝缘。 说到这,帐户有许多队列和队列有很多消息。 可以想象,云建筑师可以为每个租户提供单独的队列。 但这一决定将基于多租户应用程序的特定需要。 请记住,这种做法不可能很好地扩展和可能变得难以管理作为租户数目上升超出 100。

有很多的数据隔离和隔离选项在 Windows Azure 表内可用。 例如,服务提供商可以提供一个存储帐户每租客。 因为每个存储帐户显示为在 Windows Azure 账单上的行项目,这种方法可以是很有用的如果你想要识别每租客的确切费用。 另一个选项是结合在一个单一的存储帐户中的多个租户。 这种方法使您能够组租户由地理区域、 监管要求和潜在的复制的要求。 但是,您仍然需要这样一个帐户内的租户不会对其他租户的数据访问层中的分区方案 — — 除非,当然,需要数据共享的战略。 承载多个租户在单一账户的一种办法是,表名称中包括 TenantId 和给自己的表的副本的每个租客。

然而,另一种方法是把多个租户在单个表中,在这种情况下您可能需要使用表内置分区键和从另一个单独的行键来保持租户的数据。 它是常见的是使用 TenantId 作为分区键,因为它扩展也同时提供了极好的查询的性能。

中的代码图 8 演示如何多个租户可以共享单个表。 代码阐释了如何租客可能检索使用 Windows Azure 表的电子邮件地址和电话号码。 请注意 PartionKey 基本上是 TenantId,可以从登录凭据,或直接或通过另一个查找表。

图 8 分离数据在 Windows Azure 表使用 PartionKey 和 RowKey

// Grab the ClaimsIdentity object.
Think of it as a token // and set of claims for the currently logged in user.
ClaimsIdentity ci =   Thread.CurrentPrincipal.Identity as ClaimsIdentity; // Parse the claim.
TokenManager tm = new TokenManager(ci); // Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(   Microsoft.WindowsAzure.CloudConfigurationManager.GetSetting(   "AccountTenantTables")); // Create a cloud table client object.
CloudTableClient tableClient = storageAccount.CreateCloudTableClient(); // Create an email address table object.
CloudTable emailAddressTable =   tableClient.GetTableReference("EmailAddressTable"); // Set up the filter for the partition key.
string pkFilter = TableQuery.GenerateFilterCondition("PartitionKey",   QueryComparisons.Equal, tm.TenantId); // Set up the filter for the row key.
string rkFilter = TableQuery.GenerateFilterCondition("RowKey",    QueryComparisons.Equal, tm.IdentityProviderName); // Combine the partition key filter and the Row Key filter.
string combinedFilter = TableQuery.CombineFilters(rkFilter,   TableOperators.And, pkFilter); // Construct a query.
TableQuery<EmailAddressEntity> query =   new TableQuery<EmailAddressEntity>().Where(combinedFilter); // Execute the query.
EmailAddressEntity emailAddressEntity =   emailAddressTable.ExecuteQuery(query).First(); // Pull the data out that you searched for; // do something with emailAddress and phoneNumber.
string emailAddress = emailAddressEntity.EMailAddress; string phoneNumber = emailAddressEntity.PhoneNumber;

 

总结

构建多租户应用程序需要对身份和数据的分离和隔离问题很好理解。服务提供商可以使自己免受不必写了大量的与管理有关的身份通过利用的 ACS 的低级水暖代码。多租户应用程序可以支持多种身份提供程序,并避免其代码库的困惑与一些这里提供的技术。此外,强健的身份管理,简化了隔离或共享租客数据所需的工作。

在下个月的专栏中,我们会处理的多租户架构的其他关键支柱 — — 计量和业绩分析和缩放。同时,我们建议更多的信息感兴趣的读者阅读"发展中国家多租户云计算,第 3 版,应用"可在 bit.ly/asHI9I

Bruno Terkaly是 Microsoft 的开发推广人员。他的知识深度来源于多年来相关领域以及使用大量平台、语言、框架、SDK、库和 API 编写代码的经验。他不辞辛苦,就有关构建基于云的应用程序(特别是使用 Windows Azure 平台)编写代码、发布博客并给予现场演示。他已经发布了两个应用程序到 Windows 应用商店:Teach Kids Music 和 Kids Car Colors。您可以阅读他的博客 blogs.msdn.com/b/brunoterkaly

Ricardo Villalobos 是一名资深的软件设计师,具有 15 年为供应链管理行业设计和创建应用程序的经验。他持有几个不同的技术证书,并获得了达拉斯大学商务管理专业的硕士学位。他是 Microsoft 的 Windows Azure CSV 孵化团队的云架构师。您可以阅读他的博客在 blog.ricardovillalobos.com

Terkaly Villalobos 和比利亚洛沃斯共同提出大行业会议 ; 可用性,电子邮件在他们 bterkaly@microsoft.comRicardo.Villalobos@microsoft.com.

衷心感谢以下技术专家对本文的审阅:帕特里克 · 巴特勒 Monterde (Microsoft) 和 · 布尚 · 内内 (Microsoft)
帕特里克是在微软的云建筑师。在他当前的角色,他是负责开发云战略和 Microsoft 服务的云 IP。之前这一作用,帕特里克 · 工作作为全球范围内的 Windows Azure 技术销售他在那里负责全球企业客户能够顺利通过 Windows Azure 平台提供支持。帕特里克还担任在 MCS 专门从事企业应用程序开发中的高级顾问。
在加入之前微软,帕特里克 · 举行若干职位从开发、 管理、 软件体系结构。他带来了十二年的企业管理咨询经验横跨多个行业,包括 ; 军事、 卫生保健、 石油和天然气、 政府和法律。他主要从事 Windows Azure 平台,SQL Azure、.NET 开发、 Microsoft SQL Server 和项目管理。帕特里克 · 持有学士学位在计算机科学从常青州立学院和多发性硬化症在从凤凰城大学的计算机信息系统。读帕特里克的最新进展在: https://blogs.msdn.com/b/patrick\_butler\_monterde/  

· 布尚 · 内内带领云建筑师团队在 Microsoft 可以帮助战略 ISV 合作伙伴开发 Windows Azure 上的应用程序。· 布尚 · 已发表的技术文章数、 引用的应用程序,和合著一本的书。他还提出了在云事件的数目。