9

精简版

如果我将用户分成碎片,我如何提供“用户搜索”?显然,我不希望每次搜索都击中每个碎片。

长版

通过分片,我的意思是有多个数据库,每个数据库都包含总数据的一小部分。对于(一个天真的)示例,数据库 UserA、UserB 等可能包含名称以“A”、“B”等开头的用户。当一个新用户注册时,我简单地检查他的名字并将他放入正确的数据库。当返回的用户登录时,我会再次查看他的姓名以确定从中提取信息的正确数据库。

分片与读取复制的优势在于读取复制不会扩展您的写入。所有发送到主服务器的写入都必须发送到每个从服务器。从某种意义上说,它们都承载相同的写入负载,即使读取负载是分布式的。

同时,分片不关心彼此的写入。如果 Brian 在 UserB 分片上注册,则 UserA 分片不需要听到它。如果 Brian 向 Alex 发送消息,我可以在 UserA 和 UserB 分片上记录该事实。这样,当 Alex 或 Brian 登录时,他可以从自己的分片中检索所有发送和接收的消息,而无需查询所有分片。

到目前为止,一切都很好。搜索呢?在此示例中,如果 Brian 搜索“Alex”,我可以检查 UserA。但是,如果他用姓氏“史密斯”搜索亚历克斯呢?每个碎片都有史密斯。从这里,我看到两个选项:

  1. 让应用程序在每个分片上搜索 Smiths。这可以缓慢(连续查询每个分片)或快速(并行查询每个分片)完成,但无论哪种方式,每个分片都需要参与每次搜索。就像读取复制不会扩展写入一样,搜索命中每个分片也不会扩展您的搜索。您可能会遇到搜索量高到足以压倒每个分片的时间,而添加分片对您没有帮助,因为它们都获得相同的量。
  2. 某种本身可以容忍分片的索引。例如,假设我要搜索的字段数量恒定:名字和姓氏。除了 UserA、UserB 等之外,我还有 IndexA、IndexB 等。当新用户注册时,我会将他附加到我希望找到他的每个索引上。所以我把 Alex Smith 放到 IndexA 和 IndexS 中,他可以在 "Alex" 或 "Smith" 上找到,但没有子字符串。通过这种方式,您不需要查询每个分片,因此搜索可能是可扩展的。

那么搜索可以缩放吗?如果是这样,这种索引方法是否正确?还有其他的吗?

4

5 回答 5

11

没有灵丹妙药。

连续搜索每个分片是不可能的,显然,由于您将产生难以置信的高延迟。

因此,如果必须,您希望并行搜索。

有两个现实的选项,您已经列出了它们——索引和并行搜索。请允许我更详细地说明您将如何设计它们。

您可以使用的关键见解是,在搜索中,您很少需要完整的结果集。您只需要结果的第一页(或第 n 页)。因此,您可以使用相当多的回旋空间来减少响应时间。

索引

如果您知道搜索用户的属性,您可以为他们创建自定义的、单独的索引。您可以构建自己的倒排索引,它将指向每个搜索词的 (shard, recordId) 元组,也可以将其存储在数据库中。懒惰地、异步地更新它。我不知道您的应用程序要求,甚至可能只在每晚重建索引(这意味着您在任何一天都不会拥有最新的条目——但这对您来说可能没问题)。确保优化此索引的大小,使其适合内存;请注意,如果需要,您可以对该索引进行分片。

自然,如果人们可以搜索类似的东西"lastname='Smith' OR lastname='Jones'",您可以读取 Smith 的索引,读取 Jones 的索引,然后计算并集——您不需要存储所有可能的查询,只需要存储它们的构建部分。

并行搜索

对于每个查询,向每个分片发送请求,除非您知道要查找哪个分片,因为搜索恰好在分布键上。使请求异步。获得第一页结果后立即回复用户;收集其余的并在本地缓存,这样如果用户点击“下一步”,您就可以准备好结果,而无需重新查询服务器。这样,如果某些服务器比其他服务器花费的时间更长,则您无需等待它们为请求提供服务。

当您使用它时,记录分片服务器的响应时间,以观察不均匀数据和/或负载分布的潜在问题。

于 2008-11-06T02:20:21.373 回答
2

我假设您正在谈论分片:http: //highscalability.com/unorthodox-approach-database-design-coming-shard

如果您阅读那篇文章,他会详细介绍您的问题,但回答很短,您可以编写自定义应用程序代码来将不同的分片组合在一起。您可以进行一些智能哈希来查询单个分片并将数据插入分片。您需要提出更具体的问题才能获得更具体的答案。

于 2008-11-04T00:32:18.037 回答
1

实际上,您确实需要每次搜索都命中每个分片,或者至少每次搜索都需要针对包含来自所有分片的数据的索引执行,这归结为同一件事。

假设您基于用户的单个属性进行分片,可能是用户名的哈希。如果您的搜索功能允许用户根据用户的其他属性进行搜索,那么很明显没有单个分片或分片子集可以满足查询,因为任何分片都可能包含与查询匹配的用户。您不能在执行搜索之前排除任何分片,这意味着您必须针对所有分片运行查询。

于 2008-11-04T00:37:56.433 回答
1

您可能想查看 Sphinx ( http://www.sphinxsearch.com/articles.html )。它支持分布式搜索。GigaSpaces 具有并行查询和合并支持。这也可以通过 MySQL 代理 ( http://jan.kneschke.de/2008/6/2/mysql-proxy-merging-resultsets ) 来完成。

构建非分片索引类型首先破坏了分片的目的 :-) 如果需要分片,集中式索引可能不起作用。

我认为所有的碎片都需要同时被击中。结果需要过滤、排序、排序、分组,并从所有分片中合并结果。如果分片本身不堪重负,您必须执行通常的操作(重新分片、扩大规模等)以再次使它们不堪重负。

于 2008-11-06T20:42:45.563 回答
0

RDBM 不是文本搜索的好工具。看看Solr会好很多。Solr 和数据库之间的性能差异将达到 100X 的数量级。

于 2012-02-11T01:40:25.343 回答