作者:李元洪
前期文章
1.背景介绍
建立索引是搜索的前提,其目的是将常用的查询条件按照一定的文档格式组织和存储起来,便于快速响应用户的查询。在这里不深入讲解索引相关的基础知识,我们结合美学的业务和技术特点,重点阐述如何设计和架构维护索引的推送平台。
主要从以下几个方面进行介绍:
- 整体设计思路
- 技术框架
- 实时更新模块
- 全量补偿模块
- 参考资料
2.整体设计思路
索引文档的建立比较简单,一般来说,就是将数据库中的基础数据(比如用户的姓名,年龄等等),按照一定的格式(json|xml)生成文档,然后存储在索引库中,这里的索引库可以是数据库,也可以是文件系统。索引文档独立存储后,就会面临一个比较复杂的问题,如何保证索引文档和数据库中的数据一致?举个例子,如果用户表中新注册一个用户张三,我们为张三建立了索引同步到索引文件中,某一天张三改名为李四,我们应该尽可能的保证索引文件中的张三也同步改名为李四。为什么是尽可能保证?因为张三改名为李四,可以通过正常的途径,也可以用数据订正的方式。所有这些可能性,都会导致两份数据存在差异,因此我们重点要解决的问题是保证索引数据及时更新,并且有机会纠正非法操作导致的数据差异。
整体上来说,一旦有数据变更,应该立即通知索引文档变更,保证用户能够立即检索到修改的数据;同时我们还要定期去检查索引文档中的数据,修正其中的脏数据,避免用户搜索错位。
3.技术选型
由于涉及到多个应用的交互,我们通过消息中间件来进行系统间的通信,通过定时任务来做全量索引的清理。
服务全部中心化,通过rpc进行系统调用。
索引存储使用杭研NDIR的HTTP服务
4.实时更新模块
服务端有数据变更,需要及时通知索引变更,通过消息中间件可以进行服务端端工程和索引推送工程之间解耦,避免服务端做数据更新的时候,一直同步等待后续的索引任务执行结束,这是一个通用的解决手段,我们选择rabbitmq是比较看重消息的可靠性。
服务端发送给索引推送工程(Dispatcher)的报文包括关键的这几个字段{OP:ADD,ID:123,resType:user},代表新增了一条ID=123的用户。
dispatcher接收到消息后,主要进行消息解析和数据拼装等操作,这些步骤都是按部就班执行就行,唯一需要注意的是异常和重试策略,最好设计一定的重试次数,避免异常一直阻塞消息队列,如果达到重试的最大次数,直接丢弃,让定时补偿来修复数据。
5.全量补偿模块
全量补偿最简单的方式是设置定时器每天定时跑数据库,将所有的数据同步到NDIR中,这里有几个需要注意的问题。
(1)如何快速的跑完数据库中百万级别的数据?
(2)如何手动补偿失败的数据?
针对这两个问题,选择使用了淘宝的调度框架tbSchedule,可以很好支持任务的分片与任务状态记录,方便快速执行一组线程任务。
比如针对百万级别的用户,我们可以按照用户的ID进行分片,一种最简单的方式基于ID的尾数模100,然后启动100个任务去并行执行,tbschedule能够保证任务不重复可靠的执行完成,这样大大减少了任务执行的时间。
6.参考资料
http://doc.hz.netease.com/pages/viewpage.action?pageId=21529071
http://dubbo.io/
http://www.rabbitmq.com/
http://code.taobao.org/p/tbschedule/wiki/index/
网易云大礼包:https://www.163yun.com/gift
本文来自网易实践者社区,经作者李元洪授权发布