Google AppEngine(GAE)中的多租户

多租户是一个已经讨论了很多年的主题,并且有许多出色的参考资料可供使用,因此我将仅作一个简短的介绍。

多租户是一种软件体系结构,其中软件的单个实例在服务器上运行,为多个客户端组织(租户)提供服务。 使用多租户体系结构,可以将应用程序设计为虚拟地对其数据和配置(业务逻辑)进行分区,并且每个客户端组织都可以使用自定义的虚拟应用程序实例。

它非常适合SaaS(软件即服务)云计算。 但是,它们的实现可能非常复杂。 架构师必须了解安全性,访问控制等。

多租户可以以几种不同的方式存在:

部署中的多租户

  1. 完全隔离的业务逻辑(专用服务器定制的业务流程)
  2. 虚拟化应用程序服务器(专用应用程序服务器,每个应用程序服务器一个虚拟机)
  3. 共享虚拟服务器(共享VM上的专用应用程序服务器)
  4. 共享的应用程序服务器(线程和会话)

在这里可以看到不同安装的频谱:

多租户和数据

  1. 专用物理服务器(数据库位于隔离的物理主机中)
  2. 分片虚拟化主机(虚拟机上的独立数据库)
  3. 共享主机上的数据库(同一物理主机上的单独数据库)
  4. 共享数据库中的专用架构(同一数据库,专用架构/表)
  5. 共享表(相同的数据库和模式,按键–行分隔)

在开始使用API​​之前,了解Google内部数据存储解决方案的工作方式非常重要。 介绍Google的BigTable技术:

它是Google自己的应用程序(例如Search,Google Analytics,gMail,AppEngine等)的存储解决方案

BigTable 不是

  • 数据库
  • 水平分片的数据
  • 分布式哈希表

:稀疏,分布式,持久的多维排序图。 从根本上讲,它是散列的哈希值(地图图或字典的dict)。 AppEngine数据位于分布在多台计算机中的一个“表”中。 每个实体都有一个用于唯一标识的键(父+子+ ID),但是也有元数据可以告诉该实体属于哪个GAE应用程序(appId)。

从上图可以看出,BigTable以称为Tablet的格式分发其数据,基本上是数据的一部分。 这些平板电脑位于云中的不同服务器上。 要索引到特定记录(记录和实体几乎是同一件事),请使用称为Key的64KB字符串。 此项包含有关您要读取的特定行和列值的信息。 它还包含一个时间戳,以允许存储数据的多个版本。 此外,特定实体组的记录是连续定位的。 这有助于扫描记录。

现在我们可以深入研究Google如何实施Multitenancy。

在App Engine的1.3.6版本中实现了Namespace API(请参阅参考资料),它的设计具有很高的可定制性,它具有可以控制的代码挂钩,因此您可以设置适合自己应用程序需求的多租户。

该API与所有相关的App Engine API(数据存储区,Memcache,Blob存储区和任务队列)一起使用。

用GAE的术语来说,

命名空间==租户

在数据存储的存储级别,名称空间就像一个应用程序ID。 本质上,每个名称空间都将数据存储作为对应用程序数据的另一种视图。 因此,查询不能跨越名称空间(至少目前),并且每个名称空间的键范围都不同。

创建实体后,其名称空间不会更改,因此请执行

namespace_manager.set(…)

不会对其密钥产生任何影响。

同样,创建查询后,将设置其命名空间。 与...相同
memcache_service()
以及所有其他GAE APIS。 因此,重要的是要知道哪些对象具有哪些名称空间。

在我看来,由于GAE用户的所有数据都保存在BigTable中,因此有助于将GAE Key对象可视化为:

申请编号| 祖先键| 种类名称| 密钥名称或ID

所有这些值都提供了一个地址来查找应用程序的数据。 同样,您可以将多租户密钥想象为:

申请编号| 命名空间 | 祖先键| 种类名称| 密钥名称或ID

现在,让我们简要讨论一下API(Python):

功能名称 争论 API
get_namespace 没有 返回当前名称空间,如果未设置名称空间,则返回空字符串。
set_namespace 名称空间:无值将取消默认名称空间值。 除此以外,

([0-9A-Za-z ._-] {0,100})

设置当前HTTP请求的名称空间
validate_namespace 值:包含要评估的名称空间的字符串。 如果不是,则引发BadValueError([0-9A-Za-z ._-] {0,100})。 异常 = BadValueError 如果名称空间字符串无效,则引发BadValueError异常。

这是一个简单的示例:

数据存储示例
tid = getTenant()

namespace = namespace_manager.get_namespace()

try:
         namespace_manager.set_namespace('tenant-' +    str(tid))
 
         # Any datastore operations done here
         user = User('Luis', 'Atencio')
         user.put()

finally:

        # Restore the saved namespace     
        namespace_manager.set_namespace(namespace)  

这里要注意的重要事情是GAE提供的模式。 对于Java API,这将完全相同。 finally块非常重要,因为它将名称空间恢复为原始名称空间(在请求之前)。 省略finally块将导致在请求期间设置名称空间。 这意味着无论是数据存储查询还是Memcache检索,任何API访问都将使用先前设置的名称空间。

此外,为了查询创建的所有名称空间,GAE提供了一些元查询,例如:

元查询
 from google.appengine.ext.db.metadata import Namespace

q = Namespace.all()
if start_ns:
     q.filter('__key__ >=', Namespace.key_for_namespace(start_ns))
if end_ns:
     q.filter('__key__ <=', Namespace.key_for_namespace(end_ns))

results = q.fetch(limit)
# Reduce the namespace objects into a list of namespace names
tenants = map(lambda ns: ns.namespace_name, results)
return tenants 

资源:

参考:我们的JCG合作伙伴 Luis Atencio在Reflective Thought博客上的Google AppEngine(GAE)中的多租户

    相关文章 :


    翻译自: https://www.javacodegeeks.com/2011/12/multitenancy-in-google-appengine-gae.html

    • 0
      点赞
    • 0
      收藏
      觉得还不错? 一键收藏
    • 0
      评论

    “相关推荐”对你有帮助么?

    • 非常没帮助
    • 没帮助
    • 一般
    • 有帮助
    • 非常有帮助
    提交
    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值