26

实现一个自己的搜索引擎的初始规划(2017 版)

 5 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzUzNjAxODg4MQ%3D%3D&%3Bmid=2247484280&%3Bidx=3&%3Bsn=169f751008fefd2cd514f592d2ee7fa9&%3Bchksm=fafde9d6cd8a60c0404cdbf01bd2b14d78bccec4fe6e3ee33b7fd3ddb7cc13eddb93ab1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在想自己和刚毕业的时候处理问题有什么不同。刚毕业的时候如果想卸载停用什么东西提示说正在使用,我就去找个强力卸载软件。如果我想清理浏览器缓存,会直接用工具,如果想找到缓存路径选择性的清理,会百度一下这个浏览器的默认缓存路径在哪里。现在,我会打开资源监视器查看磁盘活动,对文件,找到使用文件的进程;对应用,找到它在读写的文件路径。

FVzyuuu.jpg!web

现在接口服务组的性能卡在memcahe缓存上。对于缓存的过渡依赖,而且为了维护这个缓存数据,业务流程的复杂性大大提高。其实本身接口这块业务流程是很简单的,只是要求承担很大的并发量。要高并发,业务就更得简单。nginx服务单台机器号称能承载10亿的并发,为啥?逻辑简单啊,就是按照规则找到对应的处理服务,将请求转发过去。

前段时间接了个私活。话说这一年多的时间还真干了不少事情,干过私活创过业的。业务就是创建一个带支付的途家+携程。刚拿到活儿,因为是php的,我又不会php,愁死了。因为是男票帮忙接的活儿。我就说是男票把我给卖了。确实是,他接活儿,但是自己看都不看一眼,只负责拿钱。我自己啥都没有,还怕做不好坏了男票的名声。本来人家预算是2w的,我说这个得5w。最后给了3w。1个月时间确实是搞定了。总结一下,这个从UI设计到编码测试只有我一个人的项目,就前端JS样式这一样,别人也很难做的很快。我之所以能做的很快,综合能力是一方面,最重要的原因是:业务逻辑理的顺,包括支付,结算,后台给商家打款,统计分析。业务逻辑划分的清楚,做起来工作量就没有那么大。话说男票给我接私活这事儿,我嘴里是埋怨的,心里很清楚:他之所以给我接这个活儿是因为我想做。他并不是为了钱,是真心知道我想要什么。而我嘴上的埋怨也只是因为一时的辛苦发泄一下而已。这埋怨也是笑着埋怨的,谁也没当回事情。在日本的时候看过一个日文版的韩国水木连续剧<黄真伊>,真伊有两个爱她超过爱自己的母亲。她的生母和老师。生母拼其一生想让真伊得到爱,老师拼其一生想让真伊得到痛。因为痛是才艺的源泉。恩浩注定不能和真伊在一起,因为他的软弱。爱一个不对的人,心就像是浮萍,漂泊探索一无所获。看破看不破,终究是寂寞。真伊与正翰的爱感化了所有人,而真伊终究也没与正翰白首不相离。而爱一个对的人,他们的经历是别人所不能比的,他们最终心里都是踏实的。真伊为才艺而生,正翰为天下而活。这才是他们的平静与归宿。不像真伊那般有才,也不像真伊那般命苦。过着幸福的小生活,做着自己想做的事,吾复何求。

又想到离线数据那个小项目,在想之前跑全量只是取ID都要跑四个小时,我写的程序只要20多分钟,为啥呢,最重要的原因也是划分的清楚。人家问我这个项目用到了哪些线程之间共享资源的地方,我说:这里面有个AtomicInteger作为线程计数器算不算,我需要计算是不是所有的线程都是正常跑完终止的。其他的共享资源我都放到一个类里面了,但是Map我就是用的HashMap,也没用到ConcurrentHashMap,话说咱也是知道并发包里的各种并发容器的原理的。但是业务逻辑划分清楚了,我能保证写HashMap的时候,只有一个线程在访问,我没有必要非要用并发啊。所有的线程最终要生成全量文件,我用几百个线程,每个线程生成一个文件,各自读写打包压缩,各不干扰,当然要比给文件加锁,等待写操作快得多。话说这个技巧也已经被用的很多了,lucene的添加索引就是这么干的。

上周开会的时候,我突然想到(其实之前早就想到了,但是每次说都没人搭理,就过去了),媒资接口高并发的地方都是根据各种条件取数据,其他的程序都是为了维护这份数据服务的,维护数据很复杂。除了接业务线的消息,还有自己的数据库和缓存对比补数据的。将来,因为联通和电信要做物理隔离,隔离后还需要一个写缓存的统一监控专门负责给业务线返回更新消息,数据补偿的。然而所有的这些复杂逻辑,一个搜索引擎全能搞定。

之所以我之前提议没人搭理,分析其原因:我们目前的组内搜索引擎做的不好,大家只会用最简单的功能。而我并没向大家完整介绍过搜索引擎都能干什么,而且我自己什么都没有做。阳哥自己搭建了一套redis来做日志的统一收集,我受到启发。 现在,我有服务器,熟悉java底层和算法,搭建一套适合中国人用的搜索引擎又是我一直以来的心愿,现在又有业务场景需要用,干嘛不自己做一套。 之前离开人人之后看过王志亮写的庖丁jade的源码,觉得自己也是可以做这么一套框架的,况且只是一个持久层框架,原理非常清晰明了。果然,来到乐视看到了和庖丁jade非常像的mango框架。如果现在我不研发这么一套专门应用场景的,适合中文分词的,非常合适作为列表缓存的搜索引擎框架出来,过两年肯定会有人比我先发布的,因为确实是很有应用场景的。

先说为什么接口服务要用搜索引擎。搜索引擎可以支持高并发,之前用过基于lucene的solr搜索引擎,可以支持单台上万的并发。它是有多少内存就可以吃掉多少内存的,将集中式缓存的以空间换时间用到了极致。接口服务只更新缓存,不更新DB。如果换做搜索引擎,搜索引擎每分钟从数据库的从库中读取数据,对数据库基本没压力。业务线给我们发消息,我更新完缓存再返回消息也需要好几分钟。用搜索引擎实时性会更高。业务逻辑简单,现在接口服务用到了庞大的SOA架构,逻辑复杂,响应时间长。用搜索引擎,只需要一个接口服务调用搜索引擎搞定所有事情。搜索引擎内的数据高度结构化,可以添加复杂的条件,函数,分组,排序,实际上也是在JVM内完成的,直接和内存中数据交互。速度快太多了。接口服务目前的瓶颈在缓存上(必须在缓存上啊,整个都在和缓存打交道),经常性的缓存返回数据时间长。多个键值的时候mget性能差,还很容易堵塞,影响到整个服务。目前能采用的措施就是将一部分任务转给DB,另外考虑将memcache换成Redis缓存。不管是memcache还是redis,都不合适这种动辄就100K以上的大数据的情况。键值对的缓存最佳应用场景都应该是key和value体积都是极小的。所以我们现在的尝试其实都不解决本质问题。用的dubbo做的RPC调用也有问题,dubbo有自己的bug,一旦遇到就很头大。增加这层dubbo,增加了通讯开销和系统复杂性,实际性的好处却没得到发挥。而搜索引擎本身就是为大数据而生,大数据量,大数据体,高并发,而且对于这种多维查询,是搜索引擎最合适的用武之地。搜索引擎也可以单独作为RPC的被调用方,直接给其他业务线用。我们甚至可以将接口服务接收请求接口层都去掉,接口服务只有一个搜索引擎。 德伟最头疼的部署问题迎刃而解。

最最重要的原因,搜索引擎是基于全文索引的,目前的搜索模型纯波尔模型,向量空间模型,概率模型都是不适合像媒资这种主要是ID列表查询的。相应的,搜索引擎的分析工具的侧重面也是不合适媒资这样的业务场景的。

来看接口服务目前的架构:

ZJNrUfN.jpg!web

很复杂且不合理,需要很多的优化。其中还用到了Falcon监控平台和美团点评的CAT监控。数据库更新目前要通知ES搜索引擎,通知缓存,通知业务线。

换用搜索引擎之后的架构:

IbUveqy.jpg!web

就是这么简单,要不是为了保持目前的对外接口不变,接口api都可以不要。

搜索引擎自己集成日志,监控。想要调试也只要输入参数,内部处理过程可以一目了然。从实现上,包装lucene做一个平台即可。较其他搜索引擎优化的点:着重提高根据ID维度作为查询条件的有序输出,将接口的常用操作函数化,使其适合作为接口服务。将solr中不合适中文分词的词根化等环节去掉,加强中文特有的拼音,近义词的搜索(等后续有时间时优化)。集成jvm,内存,cpu的日志,监控和报警,部署方便。初始不需要做太多,以后根据业务场景需要慢慢优化。其实我是要尝试使用自己的算法的 ,自认才疏学浅,没好意思说。

推荐阅读:

漫画:性能、可用性和锁

架构视角-文件的通用存储原理

为什么要持续重构

aUfqmqN.jpg!web

作者是一个有美国硅谷、日本东京工作经验,十二年坚持一线写代码的程序媛。坚持原创文章。欢迎技术交流!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK