在分片中跨多个数据库排序
Order by across multiple database in sharding
假设我们正在开发一个拥有数十亿用户的 Instagram。我们在多个数据库中对照片 table 进行分片(在不同的分片 instances/servers/devices 中),并且在照片 table 中我们有一个 createdAt
列。现在用户在应用程序中打开主页选项卡,应用程序应该显示最近的 20 张照片 (order by createdAt desc
) globally(not locally) across the photo table在多个数据库中。 SQL 查询应该如何?
我们必须对照片进行分片 table,因为数十亿用户会制作出数千亿张照片。我们无法在一台服务器的一个数据库中的一个 table 中存储和提供数千亿张照片。
假设我们有 100 台数据库服务器,一种可能的解决方案是查询 select id from photo order by createdAt desc limit 20
超过 100 台数据库服务器的照片 table。然后在我们的后端,我们得到 20*100 = 2000 张照片行,并在后端按 createdAt(Node.js、Java、Python 等)和 return 对它们进行排序前 20 行。
听起来您要找的是 Spider storage engine from MariaDB。
这将使您在不同的服务器上拥有每个分区。您应该意识到,像这样的架构永远不会完全透明 - 要从中获得最佳(甚至良好)性能,您必须围绕底层数据存储的性能副作用来设计整个应用程序。
如果按用户拆分数据库服务器是此 table 的逻辑映射,则在应用程序中应用映射(最好是不需要数据库查找的映射),然后直接使用该数据库服务器 SELECT .. FROM photos ORDER BY createdAt DESC
现在谈论分片还为时过早。在你的数据集中有数百万个条目之前不要考虑它。
到那时,您将至少重新设计一次架构。只有在第二次或第三次重新设计之后,您才应该担心分片。比如...
到达那里后,这里有一些提示:
- 一个 table(或一小群密切相关的tables)将被拆分到多台机器("sharding")。
- 其他 tables 将需要在分片中复制,或保存在单独的机器上。维护这些 table 成为一项单独的管理任务。
- 它将被一些 "id" 分片。您对 id 的选择可能需要更改;但不要详述它。 UUID 存在性能问题,但让多个客户端独立构造唯一的 id。有更好的方法;稍后回电。
- 您将需要多层机器——用于数据库、Web 服务器、路由器等。
- 需要查看所有分片的查询写起来会很复杂 并且 会慢到 运行。所以尽量避免这样。
- 分片可以通过哈希或字典或两者的混合来完成。
- 编写一个工具将用户从一个分片迁移到另一个分片。该工具是简化许多任务的关键——硬件升级、软件升级、崩溃修复、负载平衡等。
- 将照片放在不同的服务器上;只在数据库中保留 URL。这可以简化事情,更有效地利用硬件等。
- 100B 照片,每张 1MB -- 这将需要 许多 标准机器或几个巨大的 SAN。保持它独立于数据库可以让您单独扩展它。
- “所有分片中的 20 张最新照片”——建议您使用具有 API 的非分片服务器,其主要目的是接收 URL 并维护该列表;加上提供清单。这可能是一台服务器可以处理的全部。并且一直触及所有分片可能会使整个系统崩溃。
- 您将需要数百台服务器来满足您的描述;你的预算是多少?您的 HA 要求是什么?数百台机器 == 每隔几天就有一台崩溃。并且您将需要每隔几天添加另一台服务器以增加容量。您将招聘多少 SA/DBA IT 专家?
Flickr 是多年前在分片 MySQL 服务器上构建的。所以,这是可能的。他们有一个 "group",其唯一目标是上传一百万张图片。 "whale" 给了他们一些挑战。
从每个数据库中获取前 20 行并在应用程序内存中排序的简单方法。
有更好的解决方案,可以避免使用数据库的游标将所有 20*100=2000 个数据一起加载到内存中。因为每个数据库的所有数据都是有序的,我们可以只比较当前游标的数据,将最小(或最大,ASC或DESC的依赖)数据保留在获取的数据中,然后用游标调用next。每个 next
只需要调用 real next 一次。它被称为 stream order by.
有点复杂,幸好Apache ShardingSphere完成了数据分片功能,并使用smart order by merge来处理上述算法。
假设我们正在开发一个拥有数十亿用户的 Instagram。我们在多个数据库中对照片 table 进行分片(在不同的分片 instances/servers/devices 中),并且在照片 table 中我们有一个 createdAt
列。现在用户在应用程序中打开主页选项卡,应用程序应该显示最近的 20 张照片 (order by createdAt desc
) globally(not locally) across the photo table在多个数据库中。 SQL 查询应该如何?
我们必须对照片进行分片 table,因为数十亿用户会制作出数千亿张照片。我们无法在一台服务器的一个数据库中的一个 table 中存储和提供数千亿张照片。
假设我们有 100 台数据库服务器,一种可能的解决方案是查询 select id from photo order by createdAt desc limit 20
超过 100 台数据库服务器的照片 table。然后在我们的后端,我们得到 20*100 = 2000 张照片行,并在后端按 createdAt(Node.js、Java、Python 等)和 return 对它们进行排序前 20 行。
听起来您要找的是 Spider storage engine from MariaDB。 这将使您在不同的服务器上拥有每个分区。您应该意识到,像这样的架构永远不会完全透明 - 要从中获得最佳(甚至良好)性能,您必须围绕底层数据存储的性能副作用来设计整个应用程序。
如果按用户拆分数据库服务器是此 table 的逻辑映射,则在应用程序中应用映射(最好是不需要数据库查找的映射),然后直接使用该数据库服务器 SELECT .. FROM photos ORDER BY createdAt DESC
现在谈论分片还为时过早。在你的数据集中有数百万个条目之前不要考虑它。
到那时,您将至少重新设计一次架构。只有在第二次或第三次重新设计之后,您才应该担心分片。比如...
到达那里后,这里有一些提示:
- 一个 table(或一小群密切相关的tables)将被拆分到多台机器("sharding")。
- 其他 tables 将需要在分片中复制,或保存在单独的机器上。维护这些 table 成为一项单独的管理任务。
- 它将被一些 "id" 分片。您对 id 的选择可能需要更改;但不要详述它。 UUID 存在性能问题,但让多个客户端独立构造唯一的 id。有更好的方法;稍后回电。
- 您将需要多层机器——用于数据库、Web 服务器、路由器等。
- 需要查看所有分片的查询写起来会很复杂 并且 会慢到 运行。所以尽量避免这样。
- 分片可以通过哈希或字典或两者的混合来完成。
- 编写一个工具将用户从一个分片迁移到另一个分片。该工具是简化许多任务的关键——硬件升级、软件升级、崩溃修复、负载平衡等。
- 将照片放在不同的服务器上;只在数据库中保留 URL。这可以简化事情,更有效地利用硬件等。
- 100B 照片,每张 1MB -- 这将需要 许多 标准机器或几个巨大的 SAN。保持它独立于数据库可以让您单独扩展它。
- “所有分片中的 20 张最新照片”——建议您使用具有 API 的非分片服务器,其主要目的是接收 URL 并维护该列表;加上提供清单。这可能是一台服务器可以处理的全部。并且一直触及所有分片可能会使整个系统崩溃。
- 您将需要数百台服务器来满足您的描述;你的预算是多少?您的 HA 要求是什么?数百台机器 == 每隔几天就有一台崩溃。并且您将需要每隔几天添加另一台服务器以增加容量。您将招聘多少 SA/DBA IT 专家?
Flickr 是多年前在分片 MySQL 服务器上构建的。所以,这是可能的。他们有一个 "group",其唯一目标是上传一百万张图片。 "whale" 给了他们一些挑战。
从每个数据库中获取前 20 行并在应用程序内存中排序的简单方法。
有更好的解决方案,可以避免使用数据库的游标将所有 20*100=2000 个数据一起加载到内存中。因为每个数据库的所有数据都是有序的,我们可以只比较当前游标的数据,将最小(或最大,ASC或DESC的依赖)数据保留在获取的数据中,然后用游标调用next。每个 next
只需要调用 real next 一次。它被称为 stream order by.
有点复杂,幸好Apache ShardingSphere完成了数据分片功能,并使用smart order by merge来处理上述算法。