【问题标题】:What's the best way to segment tenants and hostnames in DocumentDB?在 DocumentDB 中分割租户和主机名的最佳方法是什么?
【发布时间】:2017-05-11 16:09:14
【问题描述】:

我们有一个 B2B 模型,我们在 Azure 中为小型企业客户的员工、合作伙伴和客户托管一个门户。这目前在我们的 node.js Web 应用程序中运行良好,但我们希望迁移到 Azure Functions 以实现大规模,这导致我们重新考虑最初的设计。

目前,进入网络应用程序的每个 XHR 请求都经过这个逻辑:

  1. 检索主机名对应的siteconfig文档
  2. 从 siteconfig 文档中检索 organization_id
  3. 将 organization_id 插入查询的 WHERE 子句中

我们使用节点缓存将站点配置文档存储在内存中,因此检索时间仍然非常快,只有第一次请求主机名时,我们才会连续运行两个查询。

由于 Azure Functions 不存储请求之间的状态或没有缓存,我们将无法缓存主机名/组织 ID 关系。似乎如果我们在一个函数中为每个请求运行两个 DocumentDB 查询,那么我们的数据库成本将几乎翻倍。

所以我的问题是 - 有没有一种好方法可以在可以加载到 Azure 函数中的单个查询中检索这些信息?在 RDBMS 的旧世界中,我只会使用连接,甚至可能是这样的子查询:

SELECT c.name, c.price
FROM c
WHERE c.type = "product"
AND c.organization_id = 
  (SELECT d.organization_id FROM d WHERE d.hostname = @hostname)

以下是一些示例文档。具体来说,当一个请求进入到 portal.xyz.com/api/products 时,我们希望使用单个查询返回小部件 A 和小部件 B,而不是小工具,因为它属于不同的公司。

{
  id: "17500961",
  type: "organization",
  name: "XYZ inc."
}

{
  id: "34903332",
  type: "siteconfig",
  hostname: "portal.xyz.com",
  organizationid: "17500961"
}

{
  id: "86785057",
  type: "product",
  name: "Widget A",
  price: "9.99",
  organizationid: "17500961"
}

{
  id: "17979681",
  type: "product",
  name: "Widget B",
  price: "14.99",
  organizationid: "17500961"
}

{
  id: "24669887",
  type: "product",
  name: "Gadget",
  price: "899",
  organizationid: "31514620"
}

我们不想在数据请求中依赖从客户端传入的组织 ID,这提供了内部安全性,知道 X 公司永远无法检索除他们自己以外的任何组织的数据,这在服务器上由传入的请求标头。

我想到的一个解决方案是将主机名添加到每个文档中,但这似乎是大量冗余/复制数据。

DocumentDB 专家是否愿意对此进行权衡并提供一些指导?

【问题讨论】:

  • 我给您的第一个建议是通过两次往返来实现它,然后仅在您确认这不是高性能或太昂贵之后才优化到本地缓存。
  • 你是说在 DocumentDB 的单个查询中确实没有办法做到这一点?
  • 您可以使用您提出的方法、缓存或下面的 Fabios 其他建议。然而,这些增加了复杂性。我的意思是在你增加复杂性之前尝试直接的两次往返方法。
  • 我将阅读这里的字里行间,并假设您真的想说“这在 DocumentDB 中的一个查询中是不可能的,因此您应该找到另一种方法。”
  • 这就是我的意思

标签: azure azure-cosmosdb azure-functions


【解决方案1】:

有人可能会在 Cosmos DB/DocumentDB 方面提供其他选项,但从 Azure Functions 的角度来看,这里有一些选项:

1.使用身份验证信息派生组织 ID

您尚未描述如何对用户进行身份验证,但一种非常常见的方法是确保您的租户 ID(在您的情况下为组织 ID)之类的内容作为声明出现在签名令牌中,该令牌可以在服务器上进行验证。这完全消除了在颁发令牌后进行缓存或额外查找的需要。

2。使用外部缓存

Azure Redis Cache 之类的外部缓存可让您在函数环境之外维护所需的状态,并且可以在函数应用实例扩展时对其进行访问。这以物超所值的方式提供了出色的性能(您需要根据负载将成本与您为 Document DB 请求支付的费用进行比较)

3.局部静态映射

仅将此选项用作后备选项,因为它是不可预测的,并且可能会随着时间而改变。建议使用其他 2 个选项

您可以在 Function App 环境中维护本地缓存以减少查找次数。该缓存将确保这些查找不会在每个请求中发生,而是在每个运行时实例中发生,因此当您的函数应用程序扩展时,新实例不会填充该缓存,但是一旦缓存了信息,后续请求访问同一主机就不会需要获取组织信息。 如果您选择使用此解决方案,则需要密切关注应用程序的行为,因为如上所述,它可能会有所不同并且无法预测

我希望这会有所帮助。

【讨论】:

  • 你能详细说明#1吗?特别是,你如何在令牌中嵌入一些东西?还有,你如何验证它?
  • Fabio 回答 #3 的注意事项:1) D:\HOME(环境变量 %HOME%)在所有实例之间共享。 D:\local\Temp (%TMP%) 和 D:\local\AppData (%APPDATA%) 不在实例之间共享。这些是大小有限的。 2) 为了获得 Azure Functions 的本地缓存,我使用了 %TMP% 和 node-localstorage 的 JSONStorage 类。 3) #2 增加了复杂性。我对#3 的建议也是如此,但要少得多。我的理念是做最简单的事情,到目前为止,我不必求助于外部 Redis 缓存之类的东西,所以我相信它实际上比 #2 恕我直言更可取。
  • 谢谢,这里有很多很棒的信息。身份验证令牌可以工作,但我必须小心,因为一个最终用户可以访问多个客户的门户。 Redis Cache 看起来很棒,而且非常划算。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-23
  • 2020-09-16
  • 1970-01-01
  • 2013-06-18
  • 2012-05-26
  • 1970-01-01
  • 2020-08-02
相关资源
最近更新 更多