【问题标题】:Searching across shards?跨分片搜索?
【发布时间】:2008-11-04 00:06:34
【问题描述】:

短版

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

加长版

我所说的分片是指有多个数据库,每个数据库都包含总数据的一小部分。对于(一个天真的)示例,数据库 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" 上找到,但没有子字符串。通过这种方式,您无需查询每个分片,因此搜索可能具有可扩展性。

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

【问题讨论】:

    标签: database scalability sharding


    【解决方案1】:

    没有灵丹妙药。

    连续搜索每个分片是不可能的,显然,由于您会产生非常高的延迟。

    因此,如果需要,您希望并行搜索。

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

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

    索引

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

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

    并行搜索

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

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

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

      • 谢谢。我实际上已经广泛阅读了该网站。我试图澄清我上面的问题;希望这超出了您有用链接的文章。
      【解决方案3】:

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

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

      【讨论】:

      • 请看我上面的说明。
      【解决方案4】:

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

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          猜你喜欢
          • 2017-09-12
          • 1970-01-01
          • 2014-02-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-24
          • 2019-03-07
          相关资源
          最近更新 更多