通过user_id和entity_id对数据库进行分片

时间:2018-04-11 20:36:30

标签: database database-performance sharding high-availability

我现在的员工有很多物品。每个项目都有user_id和明显item_id属性。为了提高性能和高可用性,我的团队决定对表格进行分类。 我们正在讨论两种策略:

分片item_id

就高可用性而言,如果分片已关闭,则所有用户都会丢失临时1 / N的项目。性能将在所有分片中均匀分布(随机分布)

分片user_id

如果分片已关闭,则N个用户中的1个将无法访问其商品。性能可能不是因为我们拥有1000个项目的用户以及只有一个项目的用户。此外,还有一个很大的缺点 - 现在我们需要传递item_id和user_id才能访问项目。

所以我的问题是 - 选择哪一个?也许你可以用一些数学公式来指导我,以决定在不同情况下哪一个更好

P.S。我们已经有了副本,但它们对我们的写入吞吐量变得无用了

更新

我们有serp页面,我们需要按ID获取项目以及用户想要查看他/她的项目的用户配置文件等页面。与第二种模式不同,第一种模式是最常用的模式。 我们可以轻松放弃ACID事务,因为我们已经开始构建微服务(因此最终几乎所有大型实体都将被封装在特定的微服务中)。

2 个答案:

答案 0 :(得分:3)

我看到了几种攻击方式:

  • 你打算怎么打碎?单独的主服务器,单独的模式 由同一台服务器提供服务,但由不同的存储背景服务?
  • 您如何访问此数据?它基本上是关键/价值吗?您是否需要一次查询所有用户的项目?您的CRUD操作需要具有哪些事务处理?
  • 根据您存储的数据,您是否预见到不平衡的分片存在问题?
  • 您是否需要针对其他数据对此数据进行关系查询 在你的系统中?

<强>折衷

  • 如果您在服务器/数据库实例边界之间拆分分片,则item_id分片意味着您将无法对单个user_id的信息执行单个查询...您需要查询每个分片然后在应用程序级别聚合结果。我发现汇总有比你想象的更多的陷阱......最好把它保存在数据库中。
  • 如果您可以使用单个数据库实例,则通过创建由不同存储子系统支持的表/模式进行分片将允许您扩展写入仍然可以跨它们执行关系查询。但是,使用这种方法,你的所有鸡蛋仍在1个服务器篮子中。
  • 如果您按user_id进行分片,并且想要通过将用户移动到另一个分片来重新平衡分片,则需要立即原子地移动所有用户的行。如果有很多行,这可能很难。如果您按item_id进行分片,则可以一次移动一个项目。这允许您逐步重新平衡您的分片,这很棒。
  • 如果您打算将这些服务器拆分为单独的服务器,以便不能跨模式执行关系查询,那么将键/值存储作为DynamoDB使用可能会更好。然后,您只需要担心一个端点,并且分片在数据库层完成。没有中间件来确定使用哪个分片!

关键权衡似乎是能够查询所有特定用户的数据(按user_id进行分片),而不是跨分片更轻松地平衡和重新平衡数据(按item_id进行分片)。 / p>

我将专注于您需要如何存储和访问数据的问题。如果您确实只需要item_id访问,则按item_id进行分片。避免拆分您的数据库会妨碍您查询数据库。

如果您仍然不确定,请注意您可以按item_id进行分片,然后选择稍后user_id进行分片(您可以通过基于user_id进行重新平衡然后执行新行只会写入他们user_id所属的分片。)

根据您的更新,听起来您的主要关注点不是关系查询,而是扩展对此特定数据池的写入。如果是这种情况,按item_id分片可以让您最灵活地随着时间的推移重新平衡数据,并且不太可能在第一时间产生热点或变得不平衡。这需要基于user_id跨分片聚合查询,但只要那些“给定用户的所有项目”查询不需要一致性保证,您应该没问题。

答案 1 :(得分:2)

我担心没有任何公式可以计算所有案例的答案。它取决于您的数据模式和系统功能要求。

如果您的系统中单独的item_id具有合理的含义,并且您的用户通常使用来自单独的item_id的数据(例如Instagram之类的服务item_id与用户照片有关,我建议你按item_id进行分片,因为从技术角度来看,这个选择有很多好处:

  • 确保所有分片均匀负载
  • 确保您服务的优雅降级:当分片停止时,用户将无法访问其项目的1 / N,但可以使用其他项目
  • 您无需通过user_id访问item_id

这种方法也有一些缺点。例如,备份给定用户的所有项目将更加困难。

如果只有完整的item_id系列具有合理含义,则user_id

进行分片更合理