「InfoQ」150 毫秒?,如何做到99%的搜索请求延迟低于

即时通讯的兴起改变了我们的交流方式 。 与来回的电子邮件相比 , 我们发送和接收消息的数量和速度都要高得多 。 在进行即时对话时 , 我们也希望能够轻松地搜索重要的短语、瞬间或有参考价值的东西 。 数据交换请求数量的快速增长为消息传递的可伸缩和快速发现带来了许多新的工程挑战 。 在这篇博文中 , 我们将讨论如何改进消息搜索体验 , 基本方法是从头开始改进消息传递后端架构 , 并引入我们称为InSearch的消息搜索后端 。
【「InfoQ」150 毫秒?,如何做到99%的搜索请求延迟低于】本文最初发布于LinkedIn工程博客 , 经原作者授权由InfoQ中文站翻译并分享 。
即时通讯的兴起改变了我们的交流方式 。 与来回的电子邮件相比 , 我们发送和接收消息的数量和速度都要高得多 。 在进行即时对话时 , 我们也希望能够轻松地搜索重要的短语、瞬间或有参考价值的东西 。 数据交换请求数量的快速增长为消息传递的可伸缩和快速发现带来了许多新的工程挑战 。
在这篇博文中 , 我们将讨论如何改进消息搜索体验 , 方法是从头开始改进消息传递后端架构 , 并引入我们称为InSearch的消息搜索后端 。 挑战
如果我们使用LinkedIn的传统搜索基础设施来支持消息搜索 , 那么构建并提供近线索引服务的成本将会高得令人望而却步 。 这是因为:与其他用例相比 , 要索引的消息数据总量非常大 。 考虑到消息交换的增加(每秒数千次写操作) , 对索引的更新速度要高得多 。 这些数据需要进行静态和传输加密 , 因为消息数据是高度机密的 。
此外 , 我们注意到 , 搜索查询与正在创建的消息的比率非常低 。 这使得降低搜索基础设施的成本成为一个重要的问题 。 我们使用这个和其他对于数据和使用模式的观察来设计了这样一个系统 , 它满足我们所有的需求 , 同时又具有成本效益 。 整体架构
「InfoQ」150 毫秒?,如何做到99%的搜索请求延迟低于
文章图片
InSearch的高层架构
搜索器(Searcher)
消息搜索仅限于会员各自的收件箱 。 你只能在自己的收件箱中进行搜索 , 因此 , 只需要针对你的数据在内存中建立索引 , 从而快速地处理查询 。 从使用情况来看 , 我们还知道 , 使用消息搜索的会员通常是高级用户 , 这意味着他们经常依赖于我们的搜索功能 。 比较理想的情况是 , 按会员索引 , 并使索引可缓存 , 这使我们研究了仅在会员执行搜索时生成会员索引 , 然后缓存索引的想法 。
我们的搜索服务内部使用Lucene作为搜索库 。 处理高度机密数据(如消息)的一个关键要求是确保所有数据都在磁盘上加密 。 同时 , 我们还需要能够支持高速率的更新 。 将索引存储在磁盘上需要一个很长的过程(从磁盘读取加密的索引、解密、更新索引、再次加密并将其持久化) , 这使得写入操作非常低效——需要注意的是 , 这是一个写密集型系统 。
因此 , 我们牺牲了创建索引的速度来获得更好的写吞吐量 。 这是通过将每个原始文档加密存储在一个键-值存储区来实现的 , 键是memberId和documentId的组合 , 而值是加密的文档(即消息) 。 注意 , 这是一个简化版本 , 在生产环境中 , 它更加复杂 , 因为我们有不同的文档类型 , 而参与者不一定是会员 。 使用这种设计 , 新消息就是添加到键值存储中的新行 , 这使得向系统写入数据非常快 。 我们使用RocksDB作为我们的键值存储 , 因为它在LinkedIn已经被验证是可靠和有效的(参见FollowFeed和Samza的例子) 。 它也不会伤害到我们 , 因为我们有大量的内部专家来支持它 。
「InfoQ」150 毫秒?,如何做到99%的搜索请求延迟低于
文章图片
具有RocksDB键值结构的高级搜索器流
当一名会员执行他或她的第一个消息搜索时 , 我们从RocksDB运行一个键的前缀扫描(前缀是会员ID) 。 这将为我们提供该会员的所有文档用于构造索引 。 在第一次搜索之后 , 索引被缓存在内存中 。 结果呢?我们观察到的缓存命中率约为90% , 而总第99百分位延迟约为150毫秒 。


推荐阅读