高可用上文咱们已经讲过了,可当前互联网时代,怎么少的了高并发呢?高并发和高可用同样, 已经变成各个系统的标配了,若是你的系统QPS没有个大几千上万,都很差意思跟人打招呼,虽然可能天天的调用量不超过100。前端
高并发这个词,我我的感受是从电商领域开始往外流传的,特别是电商领域双11那种藐视全球的流量,再把技术架构出来分享一把,如今搞得全互联网都在说高并发,并且你注意回忆一下全部你看到的高并发系统,每每都逃不开一个核心概念,那就是缓存+哈希,一切都是以这个概念和基础的,仿佛这就是高并发的核心技术了。web
缓存+哈希=高并发?面试
(一)咱们看到的高并发技术redis
围绕这个核心技术,一般咱们看到的各类高并发的架构系统,在博客,论坛,现场分享出来的高并发系统,都跑不出如下几个方面的东西。算法
1资源静态化数据库
就是那种单个页面流量巨大无比,每秒的QPS几十万上百万的系统,确实并发高的系统,核心解决方案就是静态化,靠机器和带宽去抗,假如没有CDN的话,全部流量都落到同一个IP下面的话,基本上也就是用Nginx的文件静态化了,单机的承受能力主要取决于带宽和单机的性能,要再多的话,那就LVS(或者F5)+集群了,这种的典型场景就是搞活动时候的首页,活动页面了,还有就是引流搜索引擎的着陆页了,通常都是现成的图片和文字静态化,固然,这种还有不少前端的技巧和技术了,这一点我不是很了解,就不得瑟了,就中后台来讲,大部分状况下直接Nginx搞定了,核心仍是使用了缓存技术。编程
2读写分离和分库分表后端
读写分离是你们看到的第二个高并发的架构了,也很常规,由于通常状况下读比写要多得多,因此数据库的主库写,从库们提供读操做,一下就把数据库的并发性能提升了。数组
若是还不够,那么分库分表把,把数据分到各个数据库的各个机器上,进一步的减小单台机器的压力,从而达到高并发的目的。缓存
若是是分库分表,有时候使用的就是哈希技术了,以某个字段哈希一下而后来分库分表,读写分离的读操做,基本也是经过哈希技术把读落到不一样的机器上去减轻单机压力。
3万能的缓存
说到高并发,不得不说缓存了,如今各类缓存的工具也不少也很成熟,memcache,redis之类的KV数据库做为缓存已经很是成熟了,并且基本上均可以集群化部署,操做起来也很简单,简直变成了一个高并发的代言词了,核心就是缓存技术了,而memcache和redis只是用来实现这个缓存技术的工具而已。
4无敌的哈希
但凡大数据处理,高并发系统,必言哈希,随机插入,时间复杂度O(1),随便查询,时间复杂度O(1),除了耗费点空间之外,几乎没什么缺点了,在如今这个内存廉价的时代,哈希表变成了一个高并发系统的标配。
5正面的例子
咱们来看个例子,看看一些个你们眼中标准的高并发系统的设计,这些设计你们应该都看过,无非就是上面的几个要点,最重要的就是缓存+哈希,这两个东西的组合好像无所不能。
活动秒杀页面
活动秒杀页面,这是个标准的高并发吧,到了搞活动的那个时刻,单页面的访问量是天量数据了,但这种系统有个特色:逻辑简单,只要带宽和性可以,就必定能提供稳定的服务服务。
能迅速的返回数据便可,没有什么计算逻辑,这种高并发系统的设计基本上就是在怎么压榨机器的IO性能了,若是有CDN绝对使用CDN,能在本机读取的毫不走网络获取,能读取到内存中毫不放在硬盘上,把系统的磁盘IO和网络IO都尽量的压榨,使用缓存+哈希技术,只要设计合理,99%的状况能搞定。活动页面的冲击感实在太强,想象一下几千万人同时访问网站尚未挂,让不少人以为高并发应该就是这样子,这估计也是高并发此次常常在电商技术中出现的缘由吧,由于搞个活动就能够搞出一个高并发事件。
这样的场景再扩展一点,就是凡是能提早提供数据的并发访问,就能够用缓存+哈希来搞定并发。
12306
接下来,咱们再看看这个星球并发量最疯狂的网站,瞬间的访问量碾压其余网站的12306,这种场景下的高并发也有个特色,那就是虽然量大,但其实没法给每一个用户提供服务。
相似的其实还有商品的抢购系统,商品和车票一共就1000张,你100万的人抢,你系统作得再好,也没法给100万人提供服务,以前12306刚刚上线的时候不少人喷,说若是让某某公司来作确定能作好,但你们不少只看到了表面,让某很厉害的公司来作,最多也只能作到你们访问的时候不会挂掉,你买不到车票仍是买不到,并且如今的12306体验也已经作得很好了,也不卡了,可是仍是不少人骂,为何?还不是由于买不到票。
对于这样的系统,设计关注的就不只仅是提升性能了,由于性能瓶颈已经摆在那了,就1000张票,作得更多的是分流和限流了,除了缓存+哈希来保证用户体验之外,出现了奇葩验证码,各个站点分时间点放票。而后经过排队系统来以一种异步的方式提供最终的服务。
咱们给这样的场景再扩展一下,凡是不能提早提供数据的,能够经过缓存+哈希来提升用户体验,而后经过异步方式来提供服务。
(二)高并发系统如何设计
若是把上面两个场景的状况合并一下,仿佛缓存+哈希变成万能的了,不少人眼中的高并发就是上面的场景的组合,认为缓存+哈希就能够解决高并发的问题,其余的场景中,加上缓存提升读写速度,在加上哈希提供分流技术,再经过一个异步提供最终服务,高并发就这么搞定了,但其实是不是这样呢?显然没那么简单,那如何来设计一个高并发的系统呢?
1合理的数据结构
举个例子来讲吧,搜索提示功能你们都知道吧,就是下面这个图的东西。
若是是google,baidu这种大型搜索系统,或者京东淘宝这种电商系统,搜索提示的调用量是搜索服务自己调用量的几倍,由于你每输入一个键盘,就要调用一次搜索提示服务,这算得上是个标准的高并发系统吧?那么它是怎么实现的呢?
可能不少人脑子里马上出现了缓存+哈希的系统,把搜索的搜索提示词存在redis集群中,每次来了请求直接redis集群中查找key,而后返回相应的value值就好了,完美解决,虽然耗费点内存,可是空间换时间嘛,也能接受,这么作行不行?恩,我以为是能够的,但有人这么作吗?没有。
了解的人应该知道,没有人会这么来实现,这种搜索提示的功能通常用trie树来作,耗费的内存很少,查找速度为O(k),其中k为字符串的长度,虽然看上去没有哈希表的O(1)好,可是少了网络开销,节约了不少内存,而且实际查找时间还要不比缓存+哈希慢多少,一种合适当前场景的核心数据结构才是高并发系统的关键,缓存+哈希若是也当作一种数据结构,但这种数据结构并不适用于全部的高并发场景,因此高并发系统的设计,关键在合理的数据结构的设计,而不在架构的套用。
2不断的代码性能优化
有了上面的数据结构,而且设计出了系统了,拿到线上一跑,效果还行,但感受没达到极限,这时候可千万不能就直接上外部工具(好比缓存)提高性能,须要作的是不断的代码性能的优化,简单的说,就是不断的review你的代码,不断的找出能够优化的性能点,而后进行优化,由于以前设计的时候就已经经过理论大概能算出来这个系统的并发量了,好比上面那个搜索提示,若是咱们假定平均每一个搜索词6个字符,检索一次大约须要查询6次,须要2-3毫秒,这样的话,若是8核的机器,多线程编程方式,一秒钟最多能接受3200次请求(1000ms/2.5ms*8),若是没达到这个量级,那么确定是代码哪里有问题。
这个阶段可能须要借助一些个工具了,JAVA有JAVA的性能优化工具,你们都有本身以为好使的,我自己JAVA用得不多,也没啥可推荐的,若是是Golang的话,自带的go tool pprof就能很好的进行性能优化。
或者最简单的,就是把各个模块的时间打印出来,压测一遍,看看哪一个模块耗时,而后再去仔细review那个模块的代码,进行算法和数据结构的优化,我我的比较推崇这个办法,虽然比较笨,可是比较实在,性能差就是差,比较直观能看出来,也能看出须要优化的点,并且比较贴近代码,少了外部工具的干扰,可能也比较装逼吧。
这个过程是一个长期的过程,也是《重构:改善代码的既有设计》中提到的,一个优秀的系统须要不断的进行代码级别的优化和重构,因此高并发系统的实现,就是不断的优化你代码的性能,不断逼近你设计时的理论值。
3再考虑外部通用方法
以上两个都完成了,并发量也基本达到理论值了,可是还有提高的需求,这时候再来考虑外部的通用方法,好比加一个LRU缓存,把热词的查询时间变成O(1),进一步提升性能。
提及LRU,多说一句,这是个标准的缓存技术了,实现起来代码也不复杂,就是个哈希表+链表的数据结构,一个合格的开发人员,即使没有据说过,给定一个场景,应该也能本身设计出来,我见过不少简历都说本身有大型高并发系统的开发经验,能熟练运用各类缓存技术,也对缓存技术有深刻的了解,可是一面试的时候我让他写个LRU,首先有50%的人没据说过,OK,没听过不要紧,我描述一下,而后给一个场景,硬盘上有N条数据,而且有一个程序包,提供GET和SET方法,能够操做磁盘读写数据,可是速度太慢,请设计一个内存中的数据结构,也提供GET和SET方法,保存最近访问的前100条数据,这个数据结构就是一个LRU了,让面试者实现出来,若是以为写代码麻烦,能够把数据结构设计出来描述一下就好了,就这样,还不少人不会,这怎么能说是对缓存技术有深刻了解呢?就这样,怎么能说有过大型高并发系统的经验呢?这只是开源工具的使用经验罢了。
在没把系统的性能压榨彻底以前,不要使用外部的通用方法,由于使用了之后就没有太多进一步优化空间了。
4最后靠运维技术了
上面几种都已经弄完了,还须要提高性能,这时候再考虑运维的技术了,好比常规的加负载均衡,部署成集群之类的,经过运维和部署的方法提升服务的并发性。
高并发系统只是相对的,没有什么无上限的高并发,流量的洪流来了,再高的高并发同样挂,新浪微博的高并发应该作得很好吧?可是林心如发条微博说她和霍建华谈恋爱了,同样把微博搞挂了(非官方消息啊,我猜想的,呵呵,那天下午新浪微博正好挂了),呵呵,你说要是TFBOY明天过生日,微博是否是要连夜加几个redis集群啊?若是有微博的朋友,留个言溜溜呗:)
三、总结
罗里吧嗦说了这么多,其实我就想表达一个意思,无论是前面的高可用,仍是今天的高并发。
代码才是关键,架构都是锦上添花的东西,既然是锦上添花的,必然坑多,没有什么捷径。
代码的健壮性决定了高可用,这些印度人就能作到,而高性能,高并发须要的不只仅是代码的健壮性,还有数据结构的设计和代码的调优能力了。架构模式是你们总结出来的,和你的系统可能关系不是很大,学习太多的架构,脑壳会乱,还不如实打实的看几本书,而后对着架构多推敲练习,不少人对数据结构嗤之以鼻,以为对于现有的开发来讲,数据结构没那么重要了,但对于后端开发来讲,数据结构是很重要的技能,虽然面试的时候不会让你去翻转一棵二叉树,但二叉树是什么,什么场景下用仍是应该知道的吧?
找准合适的数据结构,不断的优化代码,这样来提高你的系统性能,这样的系统才是你可控的,才有不断优化的空间,更好的高并发,若是一开始就上外部的缓存技术,极可能若是性能达不到要求,就没有优化空间了,由于要修改外部的系统仍是很困难的。
时间和空间的平衡
最后咱们来讲说架构中时间和空间的平衡吧,这里的时间指代比较广,多是开发时间,但大部分指的是执行时间,也就是算法的时间复杂度了,而空间就是算法中常常说的空间换时间中的空间了,一个好的系统,设计出来必然是各类时间复杂度和空间复杂度平衡出来的结果,架构设计的过程,并不只仅是模块的堆叠,在走到岔路口的时候,更多的是时间和空间平衡以后选的一个技术方案,这一篇,我会用一个搜索提示服务设计的实际例子,来讲一下架构设计的过程当中,时间和空间的各类矛盾,怎么分析,怎么选择,最后淌过这些时空的坑。
1. 搜索提示是什么
搜索提示是搜索引擎的重要组成部分,虽然通常是做为一个单独的服务来对外提供服务,但在一个搜索系统中,搜索提示是很是重要的组成部分,我还没看到哪一个比较成熟的搜索引擎没有搜索提示功能的。首先,咱们看看搜索提示是什么,你们确定都用过,就是下面这些个东西:
2. 搜索提示的场景和目的
搜索提示通常状况下是为了提升用户的搜索体验,更快的选择合适的搜索词,提升检索的效率的,可是由于搜索框的流量实在是太大了,因此搜索提示也扮演着广告变现的责任,互联网嘛,有流量就有变现,好比下面这个图,明显就是一个广告啦。
3. 初步技术选型
1搜索提示的需求
要实现一个搜索提示系统,首先须要肯定的是须要提示出来什么东西,有两种提示方式。
一种是提示出其余的搜索词,这也是大部分的搜索提示所作的,提示出其余用户的相似搜索词。
还有一种是提示出现有的结果集有的东西,这种实现方式比较少见,好比一个生鲜类的电商网站,商品数量比较少,那么不必去提示一些用户的搜索词,直接把商品名称(好比苹果,桃子,橘子)提示出来就好了,这种提示方式咱们这里不讨论,由于实现起来比较简单。
2技术栈
既然知道需求了,那么开始选择技术栈了。
首先,既然有其余用户的搜索词,那么必然有一个离线的数据收集和处理的系统来完成其余用户的搜索日志处理,生成须要的数据。
其次,须要一个单独的API服务,来提供搜索提示的功能,输入为不完整的搜索词,输出为根据这个搜索词提示出来的其余搜索词,检索方式的话,通常都是使用前缀匹配的方式了,这个你们都比较承认。
最后,须要前端有个js代码来实时调用后台的API,这个不在咱们的讨论范围内。
整个系统的结构图应该是下面这个样子,离线模块处理完日志数据之后,推送到API模块中,给前面的前端提供服务。
好了,框框设计好了。也就是架构图完成了哦,真是牛逼的架构啊,三个框,离线,在线,前端全齐了。接下来,咱们来看看在线API部分的设计吧,咱们先假设离线数据都已经准备好了,就是一堆用户的搜索词,如何快速的前缀匹配这些词就成了API设计部分的关键了,有这么几种实现方式。
粗暴的短平快方式
用redis保存全部信息,每条信息相似
{KEY:北 VALUE:北京,北京大学,北大,北京赶上西雅图}
{KEY:北京 VALUE:北京,北京大学,北京赶上西雅图}....
每次来了请求的话,直接查询redis给出结果返回,就是占点空间,最好还须要一台单独的服务器。
优雅点的实现方式
前缀匹配嘛,最早想到的数据结构就是Trie树了,因此全部的Key能够用Trie树来保存和检索,速度也挺快的,并且空间占用比较少。
复杂点的实现方式
既然是检索嘛,就直接用搜索引擎的倒排索引技术来实现嘛,速度也够,并且数据量也能够支持得很大。
4. 时间与空间的平衡一
实际工程应用中,这三种实现方式我都见过,并且有些实现方式是把这三种结合起来使用了,后面的文章我会说到。具体使用哪种须要看你的实际场景,这三种实现方式差很少正好对应三种场景。
若是你是个小型的电商或者论坛之类的,天天的搜索量也不是很大,并且在可见的将来也不会变得很大,并且也不差钱,那么直接第一种,说不定一天就能撸出来,速度还不错,可是这种有一些缺陷,首先,value值不能太复杂,影响效率,因此可扩展性不是很强,而如今的电商搜索提示中每每还有不少其余信息须要保存,redis做为缓存服务器提供高并发服务的前提是数据量比较小,最好在2K之内,这样的话用redis就有点不合适了。这种方案是个存空间的选择了,用空间换取了检索时间和开发时间,多亏有redis这种神器。
若是是个大型的搜索引擎或者电商,搜索日志已是巨量了,并且搜索词多种多样,那么第三种倒排索引技术为基础的实现方式多是更好的选择,并且既然是大搜,技术都是现成的,索引分片,集群都是现成的,直接改了上就是。这种方式用长期的开发时间和检索速度上稍微的下降换取了内存空间,若是从头开始作的话,时间成本比较高。
大部分时候,第二种实现方式是你们都采用的方式,首先没有第一种那么粗暴,而且能完成方案一的因此功能,单机就能达到较好的效果,也不用索引分片,也不用集群,因此工程复杂性不是很高,也能在较短的时间内实现出来。其次第二种方案可扩展性较强,后面挂个倒排文件就能够变成简化版的第三方案。这种方式用算法换取了内存空间,用O(n)替代了O(1),换取了内存空间,也是标准的计算机领域的时间换空间了。
经过一番分析下来,决定使用第二种实现方式,就是Trie树的方式了,好了,API的基本选型肯定了,那么开始设计,准备写代码吧。
5. Trie树的多种结构
既然肯定了Trie树的实现方式,那么首先要了解一下Trie树吧,以及Trie树的各类结构,看看具体用哪一个吧。
1基本Trie树
Trie树又叫字典树,本质上是一个多叉树,每个节点就是一个多叉的结构,若是是英文的匹配,那么是一个26叉树,每一个节点一个26长度的数组,每一个节点的数据结构以下:
而Trie树画出来就是下面这个样子。
从画出来的图,很直观的能够看出来这棵树的构造方法和遍历方法,若是是纯英文的话,每一个节点都有一个26长度的数组,来了一个字符,经过字符的编号直接就能够遍历到下一个节点,查找的时候复杂度就是O(K),K表示查找的字符串长度,这种数据结构简单明了,实现起来也很容易。
2优化后的Trie树
基本Trie树的数据结构有个问题,就是内存使用得太多了,若是是中文查找的话,须要把全部的中国字都编号到这个数组中,内存就爆了,因而有一种优化方法,就是把数组变成变长的,这种Trie树的节点数据结构变成下面的样子了,节点查找变成一个顺序查找或者二分查找了。
3双数组Trie树
所谓双数组Trie树,固然就是经过两个数组来实现这棵树了,这两个数组分别叫base数组和check数组,一个是基础数组,一个是检查数组。
Trie树其实是一种有限状态机,经过状态转移矩阵在各个状态之间跳转,双数组Trie树极大的节省了空间,大体就是下面这个样子,我后面会有一篇专门的文章来讲Trie树实现的,这里就不详细展开了,实在等不及的能够本身先搜索一下相关资料看看双数组Trie树吧。
6. 时间与空间的平衡二
OK,三种Trie树的实现方式都说了,如今要开始抉择了,咱们先看看这三种数据结构的时间和空间。
第一种空间占用大,特别是中文的状况,检索的时间效率为O(n),其中n为每次请求的字符串的长度,这种实现方式基本上属于新人练手的水平,纯粹为了了解这个数据结构或者大学生作作课程设计,工程化的可能性几乎为0。
第二种空间基本不浪费,但检索的时间效率若是按照二分进行每一个节点的查找的话,每一个节点的查找时间变成了O(lg(n)),总体的查找时间变成K*O(log(n)),一样插入效率也变低了。
第三种状况空间不浪费,时间效率也为O(n)。
初看,确定选第三种了,可是!!第三种实现方式有个致命的缺陷,就是没法向下遍历(具体能够本身看看双数组的实现方式),也就是说我输入北京,找不到北京大学,北京爱上西雅图,由于它已经不是一个树型结构了,没法向下遍历了。因此若是不对第三种结构进行改造的话,是没法知足咱们的功能的。要改造,最简单的办法就是在每一个词后面挂一个链表,表示这个词的后继词都是什么,像下图这样。
若是按上图那么来的话,须要辅助的空间来存储后继词,那么问题又来了,又是一次时间和空间的抉择了,是选择K*O(log(n))的第二种方案,而后后继词实时遍历树来获取(又要耗费必定的时间),仍是选择选择第三种方案,用空间换取时间呢?
好,既然这样,咱们来仔细算算这个帐,咱们以每一个节点都存一个中文来算,虽然经常使用的汉字大概2500个,但其中最经常使用的才500左右。先看第二种方案,那么咱们大概估算出,每一个节点的平均数组长度大概600(实际上除了第一层的节点,后面的节点数组长度彻底达不到这个量级,用600属于极限估算了),600的二分查找大约须要7到8次,取个平均值4次,那么每次查询的时间就是4*K(K是字符串的长度),若是咱们定好最长的提示词不超过8个字(太长也没意义),那么首先这个树的高度就是8了,若是50万的词量的话,使用多少内存大概能算出来,而后每次遍历下级节点的时间就是600^(8-K)(若是数组的每一个元素都有值),我去,这么大,吓死了,好,咱们即使假设每一个节点的数组长度平均为60,要遍历完也要60^(8-K),也吓尿了,因此实时遍历全部子节点的方式不可取,并且后继词最多也就提示出10个,遍历出这么多词还要排序,遍历所有节点实在是没有必要,因此,第二种方案要么放弃,要么也要改造,如何改造呢?
由于词基本上都是离线算好的,稍微把节点的数据结构优化一下,在节点中加一个字段,表示哪一个子节点有须要的数据(排序前10的词),这样往下遍历的时候就直接遍历相应的下标就能够了,就能把60^(8-K)这种遍历减小到几十次,从而找到10个提示词,咱们把这个结构叫二次优化的Trie树。
这一轮的时间和空间的比拼,第三个方案感受就要胜利了,但第二个方案的优化版貌似也还能接受,一个耗费空间,查询速度快,一个节省空间,查询速度慢点。
这里多说一下,其实上面只是预估的办法比较搓,这么写是为了说预估的技能,最直接的就是拿着日志统计一遍,获得一堆不超过8位长度的搜索词,同时也能算法两个方案的内存使用规模和大概的查找效率,这样的预估办法最准确,可是在大部分时候咱们并无这么多数据,因此只能作一些基本的预估。
7. 离线数据处理
好了,咱们先把检索部分放一放,来看看离线数据处理部分吧。咱们先要肯定一下什么东西须要在离线部分算好,什么东西须要在线处理?
首先,日志的清洗确定是离线部分了,咱们先要把没有搜索结果的词去掉,而后去掉太长的词(假定超过8的都不要),而后保留有必定热度的词(好比天天搜索量超过10次的词),等等一些规则之后,假如剩下了50万的词,那这50万就是咱们的基础数据了。
其次,Trie树的构建是离线构建好仍是实时往服务推送由服务端去构建呢?
还有,排序的时候是离线给每一个搜索词打个分,而后实时排序呢?仍是离线把序都排好,服务端直接使用结果呢?
8. 时间与空间的平衡三
虽然是离线处理,但同样有时间和空间的选择。咱们先来看构建部分,Trie树的构建是离线构建好仍是实时往服务推送由服务端去构建,首先咱们须要肯定的是这个搜索提示服务需不须要实时更新,通常状况下,搜索提示没有那么强的实时性要求,通常一天或者两天更新一次体验也不会太差,因此作实时更新的搜索提示,要不就是你实在是太蛋疼了,要不就是遇到了一个特别让人蛋疼的产品经理(卧槽,黑了一下产品经理啊)。因此咱们使用离线构建的方式构建好两个数组和辅助的数据结构,都存在磁盘上,服务端启动的时候读取文件就好了,这是用离线时间换取的服务端的时间,是很划得来的。
再来看看排序的部分,很明显,排序离线作好也比较合适,排序的位置基本不会有太大的变化,可是若是排序离线作好的话,那么辅助的数据结构就会比较大了,由于每一个前缀后面跟着的10个词都要排好序放在辅助结构中,但若是咱们只是把每一个词打个分(好比就按热度给个分),而后用第二个方案(优化的Trie树)的存储方式,在线的时候去排序,那么辅助结构就会小不少,两种状况的结构大概就是下面这样的区别。
左边的是全排序好了的,直接使用,双数组Trie树+辅助结构方式;右边的是只是打了分的,优化的Trie树,遍历出结果之后实时排序的。离线排序的空间占用大,即使优化一下,把词都放一个地方单独存着,辅助结构中只保存词的编号,同样也比较占地方,可是查询速度快啊。在线排序的方式不怎么占地方,就是每一个节点多了一个分数的字段,须要实时排序一下,虽然是实时排序,但个数就10个,无论是快排仍是堆排,都很快的,因此时间效率也慢不到哪去。
9. 总体的时空平衡
综合衡量一看,我我的以为两种方式都能接受,具体选哪个就仁者见仁了。
若是搜索词的量比较稳定,不会有太大的变化,那么使用双数组Trie树+辅助数据结构+离线构建Trie树+离线排序的方式更合适。
若是搜索词虽然如今是50万,但极可能会增长得比较多,或者像下图同样,搜索提示的页面还会承载不少其余的数据的话,那么使用二次优化的Trie树+离线构建Trie树+离线打分+实时排序的实现方式更合适,由于能节省更多的内存给后续扩充词语用或者给其余数据用。
还有若是对速度要求苛刻,那么就第一种,若是没那么苛刻,那就第二种。
架构设计没有好坏,只有合适不合适。
10. 总结
上面分析了这么一大堆,淌过三个的时间与空间的坑,终于基本肯定了技术方案了,这其实也是系统架构设计中常常会要遇到的选择了,架构师们把这些选择作完之后,能够开始细分模块设计开发了,因此,一个小小的系统就这么多选择,各类空间和时间的平衡,你说架构师哪那么好当?呵呵,你觉得就画完这篇文章的第一图就架构结束了啊。
这里只是用搜索提示做为一个例子来讲明系统设计的时候须要时时刻刻关注时间和空间这两个因素的平衡,如今不少人设计系统的时候基本上不太关注时间,由于高配的服务器,几十上百GB的内存随便用,因此大多数都把设计往空间上去靠,用更多的空间来换取执行效率,这自己并无什么问题,谁不但愿更快啊,可是有时候预估一下,有可能虽然牺牲了一点时间效率,可是换来了很多的空间,这样的系统在数据量变大时有更多的可扩展空间,我以为是很是值得的交换。
再有,对数据结构和算法的了解以及预估算能力实际上是平衡时间和空间的重要技能,也是架构设计中避坑的基本技能,因此有公司的面试题会出现请你估算一下黄河出海口的面积这类估算题,由于预估算能力也是重要的架构技能吧。
11. 更深刻一下
上面只是这个系统的一小部分,搜索提示须要作的远不止如此,想一想下面几个场景,若是是你,你要如何设计呢?如何平衡时间和空间呢?欢迎讨论哈。
须要拼音支持,就像这样
须要拼音首字母支持
某些搜索提示须要更加详细的信息
须要对每一个用户的搜索历史进行搜索提示【这个比较难点】
这个坑系列算是结束了,如今我正在作一些推荐广告相关的工做,后续也会分享一些相关的东西给你们,还有分词、相关搜索、分布式的东西会依次出来哦。