互联网服务端技术——如何学(下C)

老王又在周日的下午来骚扰你了,今天给你带来的应该是这个系列的最后一篇~ 前面该铺垫的都做的差不多了(如果没看过老王之前的文章,请打开微信关注:simplemain),今天给大家聊聊很现实的、距离大家平时生活接触到的一些技术。

题外话:老王一直这样认为,计算机科学是一门实践科学,脱离了实践的计算机技术大部分是扯淡的(比如:中国高校的大部分毕业论文)。好吧,跟老王一起来吧~

今天聊的是一些通用的分布式系统的架构设计:动态聚合系统、内容检索系统、通用评论系统等。这里面有些是老王实际做过的,有些是老王自己琢磨还没有实际落地的。因为架构设计是一个开放性的问题,没有标准答案,所以需要按照应用的具体情况(流量、数据量等)来设定。如果老王说的不对,请大家指正哈~

因为这一系列文章主要是一个概述,所以系统只讲大概的设计原理,后面老王会慢慢一个系统一个系统的讲透,包括原理、关键部件的设计和实现等。大家如果有兴趣,就关注老王,听老王慢慢扯技术的淡吧~

动态聚合系统

这个系统是大家平时可能用的最多的一个系统,他要完成的功能,就是微信朋友圈、微博等:你的好友或者你关注的对象发了一个消息、一篇文章,你就可以看到;或者是你发了一个动态,你的朋友就能看到。大家有没有想过这个系统怎么实现的呢?

老王有幸在几年前实现过这样的系统,那个时候开心网还很流行(偷菜、抢车位),贴吧正好要做一个叫做i贴吧的东东,也是实现类似功能。老王负责这个系统的后台开发。后来回到成都,在百词斩也实现了类似的这个功能。

这个系统抽象一下,功能描述就是这样的:

我的好友(或者我关注的人)发了一个动态,这个动态就会推给我,让我能看到。那怎么实现的呢?

ps:为了说起来方便,以下我们就统一说成“被关注者”(比如我的好友或者是微博大V)和“粉丝”(就是我),这样方便大家理解,免得说的绕口。

第一种:推(push)

这是很天然的一种方式。每个粉丝都有一个像邮箱一样的盒子,用来装被关注者推送过来的动态,当刷新动态的时候,就会从盒子里取出最新的动态展示给你。

对于粉丝不多的系统来讲(比如:微信朋友圈,平均每个人最多被一两百个朋友关注),这是一个非常天然的设计。一条动态发出来,就投递到所有粉丝的邮箱。由于量不大,整个投递过程非常短(投递的时候,可以借助消息队列(Message Queue)来完成)。

不过,当粉丝很多的时候(比如:微博的大V,有几百万甚至上千万的粉丝)的时候,这种方式就有点吃不消,比如推送一个粉丝需要10个毫秒,那么1000万粉丝就需要100000秒,也就是说,如果这个大V发一个消息,你要大概30个小时以后,才能看到。如果是一个实时信息,你能接受么?!

其实如果非要用这种方式来实现也是可以的,只是需要对这种推的方式做优化。我们可以借助算法里面的优化思想,用分层的多级推送,类似一棵多叉树,将一个O(n)复杂度的算法降低到O(lgn)。不过用这种方式实现整体的代价会比较大。那我们有没有其他的方式来实现呢?

第二种:拉(pull)

这个时候,每个粉丝不再拥有一个邮箱盒子。而是每次刷新动态的时候,去找你的被关注者要最新的动态,然后将所有的这些动态进行时间排序、合并等操作,最后展示到你的面前。

这种方式相对于前一种,更像是懒惰(lazy)模式。要才取,不要就不管。这种模式的优点就是大V发送消息的时候,系统没有太大的压力。而当用户读取的时候,才会有压力过来。实际上,这是将写压力转化成了读的时候的压力。

那这种实现方式是不是就没有问题呢?当然不是,比如你关注了成千上万个人,那你要是刷新一次,需要多少时间呢?如果我们算平均取一个好友的动态需要10毫秒,那么如果有1万关注,串行的来做就需要100秒,也就是差不多2分钟……你有耐心去等待刷一个朋友圈需要2分钟么?

那这种方式有优化的办法么?当然有。不过就是需要从产品和技术两头去折中。比如,你看好友动态的时候,如果这1万个被关注者都有更新,你看的过来么?必然是看不过来的。这个时候,我们就可以将最后更新的100个人的动态聚合出来给你。你看到这100个人,心里已经就很满足了,对吧~ (况且,1万个被关注者同时更新的可能性也极小)

另外,对于每个被关注者的动态,也可以用cache去缓存,就不用每次读数据库或者数据文件,可以极大的提升访问效率。

上面两种方式是不是看明白了呢?除了刚刚说的发动态,其实还有删除动态的问题。比如某人发了xx言论,觉得不好,要删掉,也会有同样的推、拉引起的问题。

好了,具体到我们现有的系统怎么来实现的呢?当时在贴吧的时候,由于存在大V这样的形态,所以最终选择了拉的方式,实现起来成本相对低一些。而微博据说是用的推拉结合,没有仔细考证过,这里就不评论了。

内容检索系统

这个系统,说白了就是google或者百度。你输入一段文字,给你把相关的文章找出来;或者是你输入一个单词,帮你把对应的释义找出来;你输入一个用户的昵称,帮你把对应的用户找出来……

老王在当年学校里创业的时候,用过Lucene(apache的开源项目)来做检索。当时完全不知道他的工作原理,就觉得这玩意儿真是牛逼啊,给他文章就能搜索出东西来。后来去了百度才知道,哦,原来是一个叫做分词和倒排索引的东东在起作用。回成都后,在百词斩指导相关同事做了用户搜索。

那具体怎么做呢?

实际上整个过程分成两大块:

提交部分:对内容切分(分词)和建倒排索引;

查询部分:源数据查询和内容合并排序。

先来看看提交部分:

当一个文本被提交到检索系统后(比如:爬虫爬取下来的网页,或者新用户注册到系统等),检索系统就先对文本进行切分。需要注意的是,切分需要按业务形态来进行。

比如对于百度这样的搜索引擎来将,文章是由词来构成,单个的字意义不大,所以,按词进行切分就是最合理的,自然就用到了分词的算法。

而对于用户名的检索,因为用户名本身比较短,且经常是无意义的几个字的组合,所以以字为单位就更有价值,切分就自然按照字为单位切分。

为了统一说法,我们不妨说最后切分的结果都叫做segment(简称s)。那我们就很容易将一篇文章article(简称a)切分成s1, s2, ..., sn的一个集合。就是如下这个关系:

a -> s1 s2 ... sn

我们叫这样的关系为正排拉链(就是按正常的逻辑排列的)。

如果有很多篇文章,分别切分的结果是:

a1 -> s1 s3 s4 s6

a2 -> s1 s2 s3

a3 -> s3 s6

对于这样的一个结果,我们可以反过来建立一个列表:

s1 -> a1 a2

s2 -> a2

s3 -> a1 a2 a3

s4 -> a1

s6 -> a1 a3

这样,我们就可以建立一个segment到article的对应列表,我们把这种列表叫做倒排拉链。

当我们要查找哪些文章含有s1的时候,就很明显可以直接输出a1和a2,对吧~

接下来我们看看查找部分:

由于数据量很大,我们有可能把s1,s2...sn的倒排拉链放到不同的服务器上,这个时候,我们就要先根据用户的请求,去不同的服务器找到对应的拉链数据。比如,用户输入了s1和s6,我们就要去他们所在的服务器找到对应的拉链。这是第一步。

接下来,我们就要对s1和s6的拉链结果进行合并和排序。合并的结果可能是这样的:a1出现2次,a2和a3各出现一次。明显,a1是最相关的,因此可能排在最前面(注意,这里说的是可能),a2和a3排在后面。那是不是一定就是这样的结果呢?不一定。比如有一种case,就是按时间优先排序的话,如果a1是一篇很老的新闻,那么有可能就不会排在前面展示,而是在后面。这就是看具体的业务需求来对结果排序。比如:新闻类的服务,一般会更强调实时性;电商类的服务,一般更关注信用度;百度这样的通用搜索引擎则更强调相关度。

好了,检索系统基本上就是这样一个工作的原理,老王讲清楚了嘛?

通用评论系统

这个系统可能是我们在平时生活中用的最多的一个系统之一了。朋友圈里评论一下、论坛里做个回复、买了东西做个评价……

这个系统大体上是这样的一个结构:

1、有一个承载主题:比如一篇主题贴、一件商品、一个朋友圈消息等

2、有一个回复列表:比如主题贴下的回复、商品下的评价、朋友圈消息的评论等

通用评论系统主要是解决回复列表的设计和实现。那这个系统在实现上有什么特别的地方么?

根据不同的数据量、请求压力,这个系统的实现确实是不一样的。

1、对于一个规模不大的系统来讲,可能就是数据库的一张表就可以完全满足要求。

每次用户提交的时候,我们就往这个表里面插入一行,而查询的时候,我们只要执行一个类似这样的sql就可以:select * from comment where topic_id = 1

2、如果是一个规模稍微大一些的系统,比如淘宝的商品评论系统。他的特点是主题(也就是商品)很多(比如可能几十上百万个),但是每个主题下面的评论可能几百到几万个。这样的系统与上面讲的系统相比,如果用一张表,可能就存不下了,或者是效率跟不上了。那怎么解决呢?

对于这种系统而言,一般采用数据拆分的方式来存储。做个最简单的比方,就是把id为1-10w的主题的评论放到一张表里,10w-20w的放到第二张表里……这样,只需要几十张表,就可以把数据存下来,并且查询的时候,也可以很轻松的查到。而每一张表的表结构,可能跟我们第一个表的结构基本一样,没有太大的变化。

3、如果规模再扩大,比如像贴吧这样的系统。上10亿的主题(用户发的主题贴),每个主题下有成千上万的回复,最长的回复可能是几百万。这样的系统就不是那么简单的了。光是找出这个长回复中间某一页,估计系统就卡住了。想想如果用sql怎么来写:select * from comment where topic_id =100000 limit 500000, 50

这个sql就是翻一个主题贴第1万页的操作,对吧。就算是查索引,系统也得查好一会儿。

那这样的系统怎么样来设计呢?我们一起来看看吧。

1、纵向拆分——将内容和索引分离:我们将评论的所有内容存储到一个系统,里面没有链式关系:

他就按照评论ID进行组织。不过提交的时候,也可以做一些优化:比如将同一主题的内容尽量的放到一起,这样查询的时候,就可以减少读盘的次数。

而另一方面,我们将关联关系放到另外一个系统里来组织,就维护一个主题ID->评论ID的一个链式关系。比如:

subject1: c1 -> c2 -> c5 -> c8

subject2: c4 -> c6 -> c17 -> c28

……

为什么要这样做呢?这样拆分以后,我们就可以明显减少链式关系的数据量(只需要存int的链表),从而就可以把尽量多的数据存放到内存,加快查询速度,对吧。即使在内存里没有找到,我们读取磁盘的数据量也会小很多很多,这样读盘的速度也会提升很多。找到相关位置的评论ID以后,我们只需要去实际内容系统中读取几十个评论的内容就完事儿了。

2、横向拆分——分库:跟之前讲的一样,还是需要按照主题进行数据拆分,主题1-10w的放到一起,10w-20w的放到一起…… 这样我们查询的时候,就只需要看这个主题id是多少,然后就去对应的库里面查询就好了。

之前老王和其他同事做贴吧贴子存储系统,整个调研、设计和开发一共做了大概半年多,几万行c/c++代码。最后系统存储了大概100亿级别的贴子。整体的思路大体就是这样。因为光调研文档就做了近百页,所以要讲透彻这个事情其实也还需要写很多篇文章来讲述,这里就讲个大概吧。如果大家感兴趣,后面就专门抽时间来聊聊这个系统。

====总结的分割线 ====

好了,大体上讲了几个通用的分布式系统的架构设计,基本上涵盖了我们常用的一些系统。他们组合包装一下,就是各种网站、app。不过还有几个系统没有涵盖,比如:实时聊天系统、商城和支付系统、视频直播系统等等。这几个系统,老王正在研究或者正在落地,等后面积累些经验以后再跟大家分享。(其实写每一个系统的时候,都是非常有意思的,哈哈哈~)

好吧,今天就聊到这里。聊了5期,终于把互联网服务端技术说了个大概,其实里面还有很多细节的内容,比如:负载均衡怎么弄?什么是一致hash?自动化运维怎么搞?监控统计和数据分析怎么弄?等等都还没有聊到。如果你感兴趣,就关注老王的微信:simplemain吧,后面都会有的~

时间: 2024-10-16 00:42:59

互联网服务端技术——如何学(下C)的相关文章

互联网服务端技术——如何学(中)

boys & girls,我们的中场休息结束了哈,赶紧搬板凳继续听老王扯技术的淡~ (悄悄的广播一下:如果没有看过上一篇的同学,请关注老王的微信simplemain,或者拉到本文末尾扫描/识别二维码) 上一篇,我们谈到了互联网服务端技术的整体蓝图.同时顺着这个蓝图中,介绍了语言.算法和数据结构.框架具体有哪些要求以及怎么样去学习他们.接下来,老王准备介绍另外几个比较基础,又在工程中大量使用的技术.具体是什么呢?我们接着往下看.首先我们还是把那幅蓝图摆出来(开始装B啦~). 聪明的同学一定已经发现

互联网服务端技术——如何学(上)

老王正式工作快10年了,前一段时间有幸去给母校的学弟学妹们聊了聊人生和理想.回来以后,有学弟学妹问我该如何学习.老王于是很认真的思索了这个问题.后来做了这样一个假设:如果让我讲讲所熟悉的互联网技术体系架构如何学,我该怎样讲? 老王顿时觉得有些紧张,虽然在二百(百度和百词斩)做了不少关于互联网Server的工作,也做过一些总结,但是这个话题实在太大太深厚了,要聊的东西实在太多(百度搜索"互联网服务端技术"的结果大约700万条),需要有相当的积累.老王是一个做技术的人,不太喜欢复杂和虚幻的

互联网服务端技术——如何学(下A)

时间一周周的真是过的好快,又到老王扯技术淡的时间了,快回来听老王扯淡吧~ 当年老王刚刚走出学校踏进社会的时候,一个百度的老同事(人称瀚哥,虽然不是我的直接导师,也可以算半个了,后来对我帮助挺大的~)就问我,觉得在学校的时间过的快嘛?我说快啊,你看这本科+研究生七年,一晃眼就过了.他说,你来工作了就会发现,工作以后,时间更快.现在回想一下,我工作都8年了,当年进公司的那一刻还历历在目-- 不知道为啥,突然就写出了上面这些文字,可能是人老了都爱回忆往事吧.好了,不扯闲淡了,开始我们的技术话题吧~ 老

互联网服务端技术——如何学(下B)

今天想跟大伙儿聊聊分布式组件.说到组件,老王当年就觉得是高大上的玩意儿.一听说谁谁谁在哪个公司,写某某组件,仰慕之情犹如滔滔江水延绵不绝~后来自己也写了一些所谓的组件以后,觉得这个并没有什么神秘的.所谓组件,老王是这么理解的:为了一个整体的环境能够完整的工作,而提供的一些功能相对独立.目标明确.有可能通用性强一些的函数.类.库.模块.系统或者服务等等.比如,你写一个打印的函数,提供给文字编辑的软件使用,你的函数就可以叫做打印组件:也可以提供一个打印服务给文字处理系统,你的服务也可以叫做打印组件.

为什么好多人想学Python 怎么快速学会高端技术

为什么好多人想学Python?怎么快速学会高端技术?大数据和人工智能时代的到来让Python迎来大爆发,各大互联网巨头都在使用Python进行开发,这吸引了很多非专业人士的关注.为了能够快速学习高端技术,越来越多的人选择专业的学习. 为什么越来越多的人选择学Python? 首先,市场环境推动.Python的迅猛发展不仅是企业需求紧迫推动,更是国家政策推动.此前有新闻报道,全国计算机登记考试出台了最新的调整方案:“Python 语言程序设计”将成为二级考试的新增科目;还有消息称浙江省信息技术课程出

【问底】夏俊:深入站点服务端技术(一)——站点并发的问题

url=http%3A%2F%2Fwww.csdn.net%2Farticle%2F2015-03-16%2F2824221&type=3&count=&appkey=&title=%E6%9C%AC%E6%96%87%E6%9D%A5%E8%87%AA%E6%8B%A5%E6%9C%89%E5%8D%81%E5%B9%B4IT%E4%BB%8E%E4%B8%9A%E7%BB%8F%E9%AA%8C%E3%80%81%E6%93%85%E9%95%BF%E7%BD%91%E

【问底】夏俊:深入网站服务端技术(一)——网站并发的问题

摘要:本文来自拥有十年IT从业经验.擅长网站架构设计.Web前端技术以及Java企业级开发的夏俊,此文也是<关于大型网站技术演进的思考>系列文章的最新出炉内容,首发于CSDN,各位技术人员不容错过. 注:本文首发于CSDN,转载请标明出处. [编者按] 本文来自拥有十年IT从业经验.擅长网站架构设计.Web前端技术以及Java企业级开发的夏俊,此文也是<关于大型网站技术演进的思考>系列文章的最新出炉内容,首发于CSDN,各位技术人员不容错过. 以下为正文: 一. 引子 <关于

都说衣不如新人不如故,技术是学新不学旧的?IPC+view+Handler+线程。

刚刚过去2019,新的一年2020年.都说衣不如新人不如故,技术是学新不学旧的?可是旧的知识不巩固,根基不固很容易在面试或者实战遇到很大的问题的 以下知识点PDF版后续可见 更多面试内容等等(更多完整项目下载.未完待续.源码.图文知识后续上传github.)(VX:mm14525201314)https://github.com/xiangjiana/Android-MS 一丶线程篇 1.线程池的好处? 四种线程池的使用场景,线程池的几个参数的理解? 参考答案:使用线程池的好处是减少在创建和销毁

客户端技术:Cookie 服务端技术:HttpSession

客户端技术:Cookie 服务端技术:HttpSession 07. 五 / android基础 / 没有评论 一.会话技术1.什么是会话:客户打开浏览器访问一个网站,访问完毕之后,关闭浏览器.这个过程称之为一个会话.就如同打电话.2.会话在编程中主要解决的问题是:保存各个用户的数据信息.3.保存用户各自数据的主要技术:客户端技术:Cookie服务端技术:HttpSession 二.Cookie1.获取Cookie采用request.getCookies()2.设置Cookie采用respons