Golang中的多租户

时间:2018-09-28 17:01:36

标签: sql go multi-tenant

我目前正在Go中编写一项服务,需要与多个租户打交道。我已经决定使用一个数据库共享表方法,并使用“ tenant_id”定界符来分隔租户。

服务的结构如下:

gRPC server -> gRPC Handlers -
                              \_ Managers (SQL)
                              /
HTTP/JSON server -> Handlers -

两台服务器,一台gRPC(管理)和一台HTTP / JSON(公共API),每台服务器都在各自的例程中运行,并具有各自的处理程序,可以利用不同管理器的功能。经理(让我们称其为“库存经理”),全部生活在不同的根级包中。据我所知,这些是我的域实体。

在这方面,我有一些疑问:

  1. 我找不到支持多个租户的任何ORM for Go。在sqlx包之上编写自己的代码是否有效?

  2. 将来的其他服务也将需要多租户支持,所以我想我还是必须创建一些库/程序包。

  3. 今天,我通过为公共API服务器使用ResolveTenantBySubdomain中间件来解决租户。然后,我将解析的租户ID放在与调用一起发送给管理器的上下文值中。在管理器的不同方法中,我从上下文值中获取租户ID。然后将其与每个SQL查询/ exec调用一起使用,如果缺少或无效的租户ID,则返回错误。我是否应该为此使用上下文?

  4. 在gRPC服务器上解析租户,我相信我必须使用UnaryInterceptor函数进行中间件处理。自从gRPC API接口只能由其他后端服务访问,我猜这里不需要通过子域来解决。但是我应该如何嵌入租户ID?在标题中?

真的希望我问正确的问题。 问候,卡尔。

1 个答案:

答案 0 :(得分:3)

  

我找不到任何支持多个租户的ORM for Go。在sqlx包之上编写自己的代码是否有效?

Go中的ORM是一个有争议的话题!一些Go用户喜欢它们,另一些讨厌它们,并且喜欢手动编写SQL。这是个人喜好问题。在这里询问主题库的建议是不合时宜的,无论如何,我不知道任何多租户ORM库–但是没有什么可以阻止您使用sqlx的包装器(我每天在系统正是这样做的。)

  

将来其他服务也将需要多租户支持,所以我想我还是必须创建一些库/程序包。

以适合您的编程和接口模式的方式从那些内部服务中抽象出这种行为是有意义的,但是这里没有进一步的细节可以更具体地回答。

  

今天,我通过为公共API服务器使用ResolveTenantBySubdomain中间件来解决租户。然后,我将解析的租户ID放在与调用一起发送给管理器的上下文值中。在管理器的不同方法中,我从上下文值中获取租户ID。然后将其与每个SQL查询/ exec调用一起使用,如果缺少或无效的租户ID,则返回错误。我是否应该为此使用上下文?

context.Context主要是关于取消,而不是请求传播。根据{{​​3}}对于WithValue函数的使用是可以接受的,但是documentation widely使用当前实现的context包是一种不好的代码味道传递值。与其使用缺乏类型安全性和许多其他属性的隐式行为,何不通过将租户ID传递给相关的函数调用来在下游数据层的函数签名中显式?

  

解决gRPC服务器上的租户,我相信我必须使用UnaryInterceptor函数进行中间件处理。由于gRPC API接口只能由其他后端服务访问,因此我认为此处不需要按子域进行解析。但是我应该如何嵌入租户ID?在标题中? [原文]

对于您的设计选择,gRPC库没有保留意见。您可以使用标头值(将租户ID作为“环境”参数传递给请求),也可以将租户ID参数显式添加到需要它的每个远程方法调用中。

请注意,以这种方式在服务之间传递租户ID会在它们之间建立外部信任 –如果服务A提出了服务B的请求并用租户ID对其进行注释,则您认为服务A具有执行必要的访问控制检查,以验证该租户的用户确实在发出请求。在此简单模型中,没有什么可以阻止流氓服务C向服务B询问有关某些任意租户ID的信息。另一种实现方式是实施更复杂的无人信任策略,从而为每个服务提供足够的访问控制信息,以决定是否应满足针对特定租户的特定请求。