我们正在评估是否要将基于PostGres的多租户EAV系统迁移到Cassandra,并希望就我们的模式方法征求意见,以确定是否有必要使用Cassandra进行测试。我们的多租户系统层次结构由账户->应用程序组成,其中一个账户可以运行多个应用程序。查询需要按应用程序或按账户进行分隔(汇总账户的所有应用程序数据)。在我们的EAV模型中,账户可以创建自己的数据对象和自己的自定义字段。
我考虑过两种使用Cassandra的方法。第一种是在一个列族中保存一定数量的应用程序(比如20个)(以减少使用的列族数量)。每行将由一个复合列accountid->appid->dataobjectid->recordid标识。对于每个应用程序所需的数据对象,列会根据需要动态添加。这意味着如果列族有两个应用程序,则第一个应用程序的一行可能定义了20个列,而第二个应用程序可能定义了30个列。这意味着这两个应用程序总共有50个潜在列。现在,一个应用程序的平均列数为19。这意味着列族中列的平均数量为400。这看起来很合理,并利用了Cassandra的宽列支持。实际上,我们可能可以轻松支持更多的应用程序。缺点是二级索引会很困难,因为我们不允许用户创建自己的索引,所以查询不能更有效地进行。
第二种方法是有两个列族来保存1000个应用程序的所有数据。第一个列族将具有与上述相同的复合列,但它将在JSON文档中保存该行的整个数据对象。第二个列族将具有相同的复合键,但会向键添加另一个值,即表示JSON文档中字段的fieldid(我们的应用程序元数据管理器存储UUID以标识JSON文档中的每个“字段”),但对于每种数据类型都会有一个“fieldvalue”列-字符串、数字、十进制数、浮点数(日期和布尔值转换为数字)。这里的好处是我们可以轻松地为每个列建立索引以进行搜索,并且我们正在最小化我们创建的列族数量。
以上两种方法的优缺点是什么?我是否遗漏了明显的内容或误解了Cassandra(例如,我是否可以在第一次使用时拥有如此宽的复合列)?是否有其他更好的模式建议适用于这种类型的应用程序?
我考虑过两种使用Cassandra的方法。第一种是在一个列族中保存一定数量的应用程序(比如20个)(以减少使用的列族数量)。每行将由一个复合列accountid->appid->dataobjectid->recordid标识。对于每个应用程序所需的数据对象,列会根据需要动态添加。这意味着如果列族有两个应用程序,则第一个应用程序的一行可能定义了20个列,而第二个应用程序可能定义了30个列。这意味着这两个应用程序总共有50个潜在列。现在,一个应用程序的平均列数为19。这意味着列族中列的平均数量为400。这看起来很合理,并利用了Cassandra的宽列支持。实际上,我们可能可以轻松支持更多的应用程序。缺点是二级索引会很困难,因为我们不允许用户创建自己的索引,所以查询不能更有效地进行。
第二种方法是有两个列族来保存1000个应用程序的所有数据。第一个列族将具有与上述相同的复合列,但它将在JSON文档中保存该行的整个数据对象。第二个列族将具有相同的复合键,但会向键添加另一个值,即表示JSON文档中字段的fieldid(我们的应用程序元数据管理器存储UUID以标识JSON文档中的每个“字段”),但对于每种数据类型都会有一个“fieldvalue”列-字符串、数字、十进制数、浮点数(日期和布尔值转换为数字)。这里的好处是我们可以轻松地为每个列建立索引以进行搜索,并且我们正在最小化我们创建的列族数量。
以上两种方法的优缺点是什么?我是否遗漏了明显的内容或误解了Cassandra(例如,我是否可以在第一次使用时拥有如此宽的复合列)?是否有其他更好的模式建议适用于这种类型的应用程序?