赵海平大神谈异步处理对分布式系统的优化

所属分类: 网站运营 / 网站优化 阅读数: 74
收藏 0 赞 0 分享

单机时代的数据请求

十五年前写软件是很简单的,一个Client对应一个DB Server,或者多个Client对应一个DB Server,每一个Client执行各自的服务。当时的讨论很多是说,这个东西要写在Client端还是写在DB Server端,流行的思路有两种:

1.把DB Server写得很复杂,比如Oracle数据库,而Client端则写得很简单,只有调用返回
2.DB很简单,只有简单的表,而Client写得复杂。很多创业公司会这样做,因为他们对SQL不是很熟悉,但是很熟悉PHP。早期Facebook就是典型的代表


大数据时代的数据请求

单机时代随着两个趋势而逐渐成为历史。一个趋势是随着互联网的流行,越来越多的人开始上网使用Web服务,而且很多时候用户增长速度是非常快的,结果造成一台DB Server无法储存下所有用户的数据。第二个趋势是计算机能力越来越强,网络服务针对每一个用户要做的事情也变多了,比如Facebook不仅要保存一个用户的个人信息,还有他的关系链信息,他的使用习惯、点击习惯等,就造成一个用户的数据量也大大增加,仅仅访问一个DB Server就准备好一个页面变成了不可能的事情。

这就带来了一个问题:针对多个DB Server的程序应该怎么写?

针对这个问题也有两个思路:

1.串行同步。先query DB1,返回res1,再使用res1做另一个DB的query,返回res2。这是在第二个Query依赖第一个Query结果的情况
2.并行同步。针对DB1的query跟针对DB2的query同步进行。这是两个Query之间没有依赖关系的情况。Facebook早期专门写了一个并行处理的函数,用法是 ExecParallelQuery(conn1,Query1,conn2,Query2)
这个时候的代码就比以前的代码更加复杂了,不过还是能实现需要实现的需求。但这时候带来了一个新的问题,就是等待。一个页面的加载可能需要调用不同的函数,而不同的函数可能是由不同的团队写的。比如获取朋友关系的函数getFriends把自己需要的数据用同步的方式获取了,但如果一个第三方开发者过来,则不仅要调用这个函数,还需要调用其他函数,这样其他函数的执行就需要等待前面这个getFriends函数返回了结果之后才能开始执行,就很慢了。

要如何做到并行处理在代码层面很直观,在机器上的执行效率又好呢?

异步的处理思路就是这么来的。

所谓异步就是,我这个函数知道这里需要访问哪几个DB Server,但我先不着急去访问,而是先记录一下,等等看其他函数是不是也要访问这个DB,如果有的话,待会儿再一起去访问。异步处理的指令比如说是 conn.asyncExec(Query) ,这个可以立刻返回一个Future对象,意思就是“待会儿再去执行”。如果每个函数都返回这种Future对象,那么就可以根据这些Future对象来判断哪些请求没有依赖可以并行处理,哪些请求有依赖需要串行处理了。如此,不同的团队写出来的函数就不用一个等一个,而是可以在更高层面上互相合作。

然而这又带来了一个问题,那就是异步处理的写法是具有传染性的。如果一个服务中有的函数写的异步,有的函数没写异步,就会造成有的函数返回了Future Object,有的函数返回了数值,导致无法执行。要实现异步,需要关联的所有函数都用异步的写法返回Future Object才可以。

所以Facebook在转向异步处理的过程是非常痛苦的,一开始做了局部修改,再修改调用了局部修改过的函数的函数,所有调用的调用都要修改,最后全部改成了异步,只要有调用远程服务IO的操作都要改。每一个DB Query都拆分成两步,一个set request,一个receive response。这里的工作量很大,所以如果创业团队的话,最好是第一天就用正确的写法,就不会这么痛苦。

所有函数改写后,每一个函数执行都会返回Future Object。那么异步处理的第一步,就是将这些Future Object形成一棵依赖树的结构,好像这样:
201662104115662.jpg (602×332)

这里每个节点都是一个Future对象,每一个Future对象有两种状态,一个是等待执行,一个是完成执行。同级的节点是没有依赖关系的,可以并行执行;上下节点是有依赖关系的,需要串行执行,先执行下层再执行上层。

树结构形成后,从下到上执行,直到最上面的top parent节点被执行进入完成执行的状态,就是完成,比如一个页面加载完毕。

所以异步处理之后有一个很有意思的情况,那就是PHP这个语言已经跟以前不同了,不再是一上来就是执行,而是一上来先lazy一下,看清楚所有的Query之后再执行。

异步处理还需要解决的问题

到目前为止,这样做异步处理似乎已经是足够好的优化,但实际上还有问题。看看下面这个例子。

比如我们现在有两个查询需求。一个是查询你在淘宝上买过东西的朋友,另一个是查询你在淘宝上买过保时捷的朋友。常理来说,我们会先想到查询你在淘宝上的朋友,再进行另一个条件的查询,比如这样:

Java Code复制内容到剪贴板
  1. IdList friends = waitFor(getFriends(myId));   
  2. yield return getTaoBaoBuyers(friends);  

但是对于保时捷这个查询而言,这是不对的,因为淘宝上买保时捷的人是很少的,可能就一两个,而淘宝上的好友数可能有上百。因此保时捷的查询应该是这个次序比较优化:

Java Code复制内容到剪贴板
  1. IdList buyers = waitFor(getPorscheBuyer());   
  2. yield return getFriends(buyers);  

这个次序应该如何决定?实际上不应该在写程序的时候决定,因为写程序的时候是无法避免有先后顺序的——编辑器只能一行一行的写代码,但是机器执行却无需管这个。所以更好的方法应该是在执行代码之前再加入一个phase。

其实传统数据库的cardinality(基数)功能已经解决了这个问题。你在DB query里面使用 INNER JOIN 这个指令,其实DB已经能够预判哪一个表给出的row会比较少,从而以更优化的次序去执行。但现在我们用的编程语言,无论是PHP,Java,Python还是C/C++,并没有考虑这个问题。有人会开很多线程来解决这个问题,但这不是最佳方案,因为在Linux系统里,你的线程数要是上了200-300,就会有很大的overhead。

代码执行的次序,这是一个。另外最近几年还有一个流行的优化思路,就是上memcache。我们有时候会看到程序员把他自己的函数放进了memcache,相当于是依赖树的中间的一个节点,我就问他为什么要把他这个Class放入memcache,他可能会说,他觉得这个节点和这个节点的child被调用的次数多。我觉得这可能不是特别理想的。你今天觉得这个Class被调用的多,可以放进memcache,但明天是不是会有更重要的Class会更值得放进memcache,于是你又要把memcache的资源让给这个新的Class?如果你放入memcache的Class并不是最重要的,这就相当于真正优化的可能性被拿走了。

如何让异步执行的更好?

哪个query先执行,哪个query后执行,不应该是在编码阶段来做的。哪个Class该进memcache,哪个Class该出memcache,也不应该在编码阶段来做。应该有一个中间的阶段,专门进行这种调度工作,然而到目前为止,还没有公司能够做到,因为没有合适的语言。

异步处理在分布式系统中怎样做有更好的优化作用,我们需要更多的思考。希望大家能够把计算机当作科学去思考,而不仅仅是工程应用。我们现在看十几年前,对单机是非常了解了,那么未来过了五年十年再回来看,可能对分布式系统也会了解的比现在更多很多,可能给分布式系统写程序也会变得跟给单机写程序一样简单。当然这就需要更合适的工具语言去给大家提供这种异步的便利。是不是会有Haskell那样lazy的方式从系统层面解决这个问题?希望跟大家一起思考探讨。

更多精彩内容其他人还在看

快速更新网站内容的几种方法

自从有了CMS现在做个网站是件非常简单的事,网站的运作的中心是日常的网站内容更新和长期网站推广。其中网站内容的快速更新是重中之重,今天笔者来分享一下快速更新网站内容的几种方法。希望能为站长们更新网站内容提供一些帮助。 1、内容采集 内容采集是最直接的方法,采
收藏 0 赞 0 分享

Google给广大网站的搜索引擎优化(SEO)建议

为了把Google中文搜索本土化Google官方也确实做了大量的工作,其中在(网站管理员/站长)这块文章丰富了不少,作为营销爱好者笔者经常关注拜读之余也摘录一些自认为比较有价值的内容供大家参考。今天和大家分享的是:Google给广大网站的搜索引擎优化(SEO)建议。文章内容如下
收藏 0 赞 0 分享

创建一个方便Google处理的网站的详细建议

这又是一篇来自Google的文章,再继续发下去很多朋友会问我为什么又转搜索引擎的东西了。其实个人认为Google网站管理员/站长帮助里头还是很多精华的,例如:今天将要转载的这个(创建一个方便Google处理的网站的详细建议)就写得非常好。废话不多说了,下面来分享下创建一个方
收藏 0 赞 0 分享

排除法解决网站在搜索过程中表现不佳的现象

搜索引擎排名机制异常的复杂和严密,直接导致很多网站内容发布出来在搜索引擎的搜索结果表现不佳的现象,种现象一直困扰着很多站长。今天笔者给大家介绍一种比较有效的解决方法:排除法解决网站在搜索过程中表现不佳的现象。 这个排除法的步骤如下: 一、查看您的网站是否被
收藏 0 赞 0 分享

百度 google分别喜欢什么样的友情链接

友情链接对搜索引擎的重要性我就不说了,你去看下只要是做优化的网站几乎都是有友情链接。我发现一些做seo的公司,给客户优化网站的时候纯属就是靠友情链接,雇专门的友情链接专员来进行优化。但是这样做你真的有效果吗,我看到过一些网站,页面上几乎三分之一的页面是友情链
收藏 0 赞 0 分享

浅析网站首页的广告形式

一般而言,由于互联网用户在刚登录某网站时,会看到各种各样的广告。这些广告杂乱无章,因此,大多数的标语用户很容易看过就忘。行为追踪就是防止这种情况发生的方法之一,从而使得广告与用户的生活和目前的精神状态相关的机率更大。或者,您也可以采取不那么敏感的方式使广
收藏 0 赞 0 分享

友情连接与SEO的关系

外连的多少是SE判断一个网站质量的好坏的最基本的标准,谷歌的PR值,百度的超连分析技术等都是以连接网页的数量的多少来决定一个网页的质量的。相对,网站做友情连接,也是以这点为出发点的。但是,友情连接质量的高低往往会起到影响网站排名的关键性作用。因次,我们必须在
收藏 0 赞 0 分享

一个网站的好坏是网民说了算还是PR说了算

大概每一季度的PR更新,都能在站长界引起一阵不大不小的地震,谷歌在2009年端午节这一天,更新了其旗下品牌的PR值,让很多站长觉得这是谷歌在中国的传统节日端午送上的大礼。 谷歌也真够有心的了,偏偏在端午那一天与大家“意思意思”,PR值,对于广大的站长确
收藏 0 赞 0 分享

网站成功的必备条件分析小结

托尔斯泰有句名言:“幸福的家庭都是相似的,不幸的家庭各有各的不幸”。引申到建站方面,即“成功的网站都是相似的,失意的网站各有各的不幸”。 那么,网站的成功,都有哪些相似之处呢?网站成功需要哪些重要因素呢? 有人会说技术最重要
收藏 0 赞 0 分享

网站运营推广中的内容策略浅谈

一、提升流量的内容策略 提升流量(PV)的关键是什么呢?很简单,让用户大量点击网站的页面,阅读网站的内容。浏览的页面多了,流量自然就上去了。那如何才能增加用户的点击行为呢? 1、根据用户喜好,增加相应的文章数量。注意,这里说的文章,是指用户喜欢的内容。 2
收藏 0 赞 0 分享
查看更多