精简版
如果我将用户分成碎片,我如何提供“用户搜索”?显然,我不希望每次搜索都击中每个碎片。
长版
通过分片,我的意思是有多个数据库,每个数据库都包含总数据的一小部分。对于(一个天真的)示例,数据库 UserA、UserB 等可能包含名称以“A”、“B”等开头的用户。当一个新用户注册时,我简单地检查他的名字并将他放入正确的数据库。当返回的用户登录时,我会再次查看他的姓名以确定从中提取信息的正确数据库。
分片与读取复制的优势在于读取复制不会扩展您的写入。所有发送到主服务器的写入都必须发送到每个从服务器。从某种意义上说,它们都承载相同的写入负载,即使读取负载是分布式的。
同时,分片不关心彼此的写入。如果 Brian 在 UserB 分片上注册,则 UserA 分片不需要听到它。如果 Brian 向 Alex 发送消息,我可以在 UserA 和 UserB 分片上记录该事实。这样,当 Alex 或 Brian 登录时,他可以从自己的分片中检索所有发送和接收的消息,而无需查询所有分片。
到目前为止,一切都很好。搜索呢?在此示例中,如果 Brian 搜索“Alex”,我可以检查 UserA。但是,如果他用姓氏“史密斯”搜索亚历克斯呢?每个碎片都有史密斯。从这里,我看到两个选项:
- 让应用程序在每个分片上搜索 Smiths。这可以缓慢(连续查询每个分片)或快速(并行查询每个分片)完成,但无论哪种方式,每个分片都需要参与每次搜索。就像读取复制不会扩展写入一样,搜索命中每个分片也不会扩展您的搜索。您可能会遇到搜索量高到足以压倒每个分片的时间,而添加分片对您没有帮助,因为它们都获得相同的量。
- 某种本身可以容忍分片的索引。例如,假设我要搜索的字段数量恒定:名字和姓氏。除了 UserA、UserB 等之外,我还有 IndexA、IndexB 等。当新用户注册时,我会将他附加到我希望找到他的每个索引上。所以我把 Alex Smith 放到 IndexA 和 IndexS 中,他可以在 "Alex" 或 "Smith" 上找到,但没有子字符串。通过这种方式,您不需要查询每个分片,因此搜索可能是可扩展的。
那么搜索可以缩放吗?如果是这样,这种索引方法是否正确?还有其他的吗?