数学之美:Reddit的排名算法

上一篇文章介绍了Hacker News 的排名规则。这次要介绍的是另外一个社会化新闻类网站Reddit 。Reddit对文章和评论使用了不同的排名算法,这边文章要介绍的是前者,后面的关于评论的排名在后面的文章作再作介绍。 Reddit与Hacker News有很大的不同点就是,Hacker News文章标题前面只有一个向上的小箭头,即只能投赞成票,而Reddit的每个文章标题前会有两个箭头,即一个向上,一个像下。分别代表“赞成”与“反对”。 Reddit已经把他们的所有源代码进行了公开,你可通过如下地址(https://github.com/reddit/reddit)进行下载研究。具体涉及到排序部分的代码如下:https://github.com/reddit/reddit/blob/master/r2/r2/lib/db/_sorts.pyx。为了效率,由于此部分代码是使用Python的C语言扩展来写,下面是用Python重写的代码:

from datetime import datetime, timedelta from math import log epoch = datetime(1970, 1, 1) def epoch_seconds(date): """Returns the number of seconds from the epoch to date.""" td = date – epoch return td.days * 86400 + td.seconds + (float(td.microseconds) / 1000000) def score(ups, downs): return ups – […]

数学之美:Hacker News的热门排名算法

Hacker News 是一家关于计算机黑客和创业公司的社会化新闻网站,由 Paul Graham 的创业孵化器 Y Combinator 创建。与其它社会化新闻网站不同的是 Hacker News 没有踩或反对一条提交新闻的选项(不过评论还是可以被有足够 Karma 的用户投反对票,或是投支持票);只可以赞或是完全不投票。简而言之,Hacker News 允许提交任何可以被理解为“任何满足人们求知欲”的新闻。

每个新闻标题前面有一个向上的三角形,如果你觉得这个内容很好,就点击一下,投上一票。根据得票数,系统自动统计出热门文章排行榜。但是,并非得票最多的文章排在第一位,还要考虑时间因素,新文章应该比旧文章更容易得到好的排名。

Hacker News 采用公式 (p – 1) / (t + 2)^1.5 做为排行依据(Hacker News使用Paul Graham开发的Arc语言编写,源码可以从arclanguage.org下载),其中P是投票数量,t是发表以来的时间,小时计。后来AMIX.DK 给出公式 Score = (P-1) / (T+2)^G 推广了上面的公式,Hacker News的公式变成了一个特例,其在G=1.5时的应用。历史上Hacker News有用G=1.8。

第一个因素是得票数P

在其他条件不变的情况下,得票越多,排名越高。从下图可以看到,有三个同时发表的帖子,得票分别为200票、60票和30票(减1后为199、59和29),分别以黄色、紫色和蓝色表示。在任一个时间点上,都是黄色曲线在最上方,蓝色曲线在最下方。

为什么是P-1?网络上的一种解释是,很多文章作者在提交的时候会给自己投上一票。其实更重要的原因是文章发布初期的投票数对排名影响非常的,仅仅是自己给自己投的一票,也占非常大的作用。

假设P不去减去1,那公式为: p / (t + 2)^1.5

如果一个作者发布完就给自己投票,那么文章的得分为1/(0+2)^1.5=0.3535 。假设另外一篇文章发布了8小时,那么需要多少的投票呢?x/(8+2)^1.5>0.3535 X>11.17~ 即一天前的帖子要有12票才能超过新提交的文章,这显然不合理。

这个具体减多少还要视网络环境而定,要是换在国内,估计P-100还不够。另外如果你不期望“高投票文章”与“低投票文章差距过大,可以在得票数上加一个小于1的指数,比如(P-1)^0.8。

第二个因素是距离发帖时间T

在其他条件不变的情况下,越是新发表的帖子,排名越高。或者说,一个帖子的排名,会随着时间不断下降。

从前一张图可以看到,经过24小时之后,所有帖子的得分基本上都小于1,这意味着它们都将跌到排行榜的末尾,保证了排名前列的都将是较新的内容。

如果,用户的第一个投票是在当前,1小时,2小时获得时,这个曲线的变化是什么呢?如下图,曲线斜率从大到小分别是当前、1小时、2小时。可以看到第一个投票的作用不断弱化,其权重不断降低。

[…]

Digg.com 的系统架构

在过去的几年间,我们一直致力于重构Digg的架构,现在我们称之为“Digg V4”.本文我们将全面介绍Digg的使用的系统和技术。找出Digg引擎的秘密。 首先,我们来看下Digg给大众用户提供的服务吧:

一个社会化的新闻站点 为个人可定制的社会新闻 广告平台 API 服务 博客和文档站点

人们通过浏览器或者其他应用来访问这些Digg服务。一些有Digg账户的用户,可以得到“我的新闻”。每位用户可以得到的我们称之为“热门新闻”。我们有digg.com和移动版的m.digg.com,API服务的services.digg.com,信息介绍的about.digg.com,为开发者服务的developers.digg.com。这些站点统一为用户,新闻发布者,开发人员提供了博客和文档服务。

本文主要介绍Digg在社会化新闻产品中使用的高级技术。

我们努力要做的

我们努力搭建以用户发布新闻和广告商发布广告为基础 一个社会新闻站点。

故事提交 注册用户提交文章,文章包含:一个标题,一篇段落,一个媒体类型,一个主题,或者一个缩略图。这些内容通过一系列的元字符标准(Facebook open graph protocol, OEmbed等)如从文章中解压出来,当然提交者在提交前最后这些元字符具体是什么。广告发布商将广告发布到另外一个独立的系统,当然如果Dugg够的话,完全可以成为故事。

故事列表 在个性化新闻产品“我的新闻“里,你追随的用户发布的所有故事以“故事列表”显示,采用最近发布,媒体类型,故事的主题等方式排列。

故事动作 用户可以对故事进行操作,比如说阅读,点击,Digg,掩埋,发表评论,投票等等。没有注册登录的用户只能阅读和点击这些故事。

故事推荐 我们会决定每个小时有一些故事会从最近故事列表转移到热门新闻列表。我们的算法(这个是保密的)通过查看用户的行为和故事内容的分类来决定选择哪些故事进入热门新闻。

我们是如何实现它的?

让我们从宏观的角度看下如果一个用户访问Digg的站点,做一些基于内容的操作。下面的图片显示了公众看到的内容及内部提供的页面、图片、API请求等服务。

我们内部系统的简单描述如上。我们的API服务代理想内部后端服务进行请求。前端的服务是被虚拟化的(与缓存是有区别的),并且放置在相同的服务层。CMS和广告系统将在此文章中不做详细说明,纵览整个系统,大致可以分为以下两类:同步和异步。

1、对用户进行即时响应的同步操作

同步操作主要表示对用户请求(包括API请求)的即时快速响应,包括一些在页面中通过AJAX方式进行的异步请求。这些操作通常要求最长一两秒的时间内就能完成。

2、离线批量进行的异步计算 除了实时响应的请求外,有时候还需要进行一些批量的计算任务,这些任务可能是间接的被用户启动的,但用户不会等待这些任务的完成。这些异步计算通常可能会花费数秒,数分钟甚至几小时。

上面所说的两部分如下图所示:

下面就更加深入的了解各个组成部分。

线上系统

提供页面和API请求服务的程序主要以PHP(前端Web页面,Drupal CMS)和使用的Python(API服务,Tornado)编写。前端通过Thrift protocol协议来调用后端的服务(Python)。很多数据会被如Memcached 和Redis 这样的内存缓存系统缓存。

消息和事件

线上和离线的信息通过主要数据存储transient / logging系统这种同步方式连接和使用 RabbitMQ 作队列系统,将不用同步响应的操作放到队列异步地进行。比如说”一个用户Dugg了一个故事“,”计算这个东西“。

批处理和异步系统

上面的消息系统是指队列,而这个指的是具体从队列取出任务执行的部分。此系统将任务从队列中取出,进行一定的计算后再对主存储进行操作,对主存储的操作在实时系统和异步批量系统中都是一样的。

当队列中发现信息时,一个“工作者”被调用来完成特定的动作。一些信息由事件触发,有点象cron机制。然后工作者对主存储设备或者离线存储设备的数据进行运算和操作,在HDFS中记录日志,然后把结果写回到主存储设备,这样在线服务就可以使用他们。举个例子:比如说索引新的故事,计算故事提升算法,运行分析工作。

数据存储

Digg根据数据的类型和使用方式的不同,将数据存储在不同的系统中,当然,有时候还避免不了有一些历史原因。

Cassandra:对诸如文章、用户、Digg操作记录等“类对象(Object-like)”的信息,都是使用Cassandra来存储的。我们使用的是Cassandra0.6版本,由于0.6版本并没有劫持二级索引,于是我们将数据通过应用层处理后再用它进行存储。比如我们的用户数据层提供通过用户名及Email地址来查询用户信息的接口。这样就允许了服务器能够查看,比如说,通过用户的用户名或者邮件而不是用户的用户ID来查询。这里我们使用了Python Lazyboy wrapper。 HDFS:来自站点和API事件,用户活动的日志都在这里。主要用到日志信息存储及分析计算,利用 Hive 操作 Hadoop,进行MapReduce计算。 MogileFS:是一个分布式文件存储系统,用以存储二进制的文件,比如用户头像,截屏图片等。当然,文件存储的上层还有统一的CDN。 […]

【多图慎入】自由门、HTTP劫持和浏览器缓存

首先交代一下事件发生背景:作为一只用不起收费VPN的穷屌丝,我在国内期间仍然使用免费的轮子系列翻墙代理软件(如,自由门)浏览墙外网站。(goagent不能看外链的youtube视频)

今天刷Tumblr的时候,发现自己刚发的帖子里好像混进去了神马奇怪的东西:

我第一想到的就是:曾经干净清新的Tumblr终于也沦陷为无良小广告的丧尸了么。

但是,在Dashboard里查看了我刚才发的原帖子的Markdown/HTML后,并没有找到任何可疑的内容。

轻博客自身的HTML模板是我自己亲手定制的,所以也不可能会成为植入广告的来源。

那么,这个无良小广告到底从何而来的呢?

第一件要做的事情当然就是检查源代码嗯。

起初我没有在HTML的前半部分发现任何异常(或者至少说,没有找到类似<iframe>这种可疑的最有可能植入广告的东西)……于是目光自然就定格到了页面的最后一部分,<!– BEGIN TUMBLR CODE –>后面的<iframe>元素上。

很显然,这个<iframe>只可能是Tumblr自身提供的工具栏,也就是当本人登录Tumblr之后页面右上角显示的“Customize” “Dashboard”导航按钮(因为这是页面上唯一能够识别出Tumblr的外观元素)

于是试着点开源链接之后,是怎样的效果呢……

果然是Tumblr的导航按钮,但是,正中莫名其妙地多出了一个硕大的Google Ads广告!

这个页面的源码想必很简单,现在来看一看……

感谢Tumblr前端工程师良好的缩进风格,我很快就找到了这么几行违和感强烈的代码。一个<center>居中标签包着一个Google Ads的script。恶心人的广告就是寄身在这里的。

这段总计11行没有缩进的代码怎么看都不可能来自于Tumblr,那么它到底又是从何而来的呢?

因为排除了是Tumblr的原因,我忽然想到去查一下自己的博客主页是不是也如此。果了个然,在页面里发现了同样的无良小广告元素:(类似地也是嵌入在Blogger自身导航栏<iframe>的内容里面的)

甚至在Blogger的编辑界面里也有这货:

和被污染的Tumblr页面对比一下,是完全相同的11行代码。这段天杀的代码如下:

而且比较一下就可以发现,这段<center>代码如出一辙,总是紧接在正常页面HTML的<body>元素后面出现,以达到任何网页一打开正上方居中皆是一个斗大的嵌入广告想看不到都不行的强烈视觉效果……

为了慎重起见,我把所有主流的浏览器试了一遍(嘛,对于前端开发来说这些是必须有的):Chrome,Firefox,Safari,IE,Opera,还有一个最干净的开发版Chromium。所有的都出现了无良小广告,基本上排除了是流氓软件插件篡改HTML的可能性。

好吧,你污染我的主页倒也罢了,竟然连大小姐的博客也不放过……不可饶恕!

HTTP劫持,我还真的完全没接触过。倒也不是说以前上网从来没遇到过,不过估计遇到的时候我还处于在家占着一根电话线拨号上网的时代,Win 98+IE上新浪雅虎21cn,哪里懂什么HTML什么HTTP劫持,反正一样是广告满天飞。之后就一直多年逍遥在教育网和国外ISP上了。

国内ISP现在已经无良到这种程度了?HTTP劫持嘛,依我的想象力最严重就是搞个<iframe>加个广告包上去,竟然还有功夫写个算法把<body>元素识别出来然后“人性化”地把广告代码居中再插到最前面好让用户一打开页面第一眼就能看到?

当然,我首先怀疑到的自然是一直开着的的自由门代理。关掉自由门之后再刷新Chrome和Safari,果然,Tumblr和主页(www.soimort.org)上镶嵌的无良小广告消失了。

但令人费解的是,Firefox和IE无论怎样刷新多少次,依然是返回被劫持之后受污染的页面。(注意到嵌入广告的大部分被我那个设置了z-index的导航栏压在下面了……垃圾广告程序员你们的技术水平还不够过硬啊残念残念lol)

乍一看有点略诡异。莫非这个流氓程序还会根据HTTP headers的User Agent选择性劫持HTML植入广告?

还有,既然关了自由门的代理还存在这种情况,难道说真的是无良ISP在某个环节劫持了HTTP?

自由门是通过127.0.0.1:8580这个SOCKS代理服务器访问外部网络的,像traceroute这类基于ICMP协议的工具压根查不出什么东西。(traceroute不走代理)

所以说想查到自由门用的外部服务器IP对于我这种网络小白来说压力略大……

嘛,我只是一个web designer而不是hacker,虽然对于网络方面一窍不通,不过以前做前端设计的经验告诉我很有可能是浏览器缓存的问题。

[…]

【译文】Linux的成功源于自私和信任

Original Article: Linus Torvalds: Linux succeeded thanks to selfishness and trust by Leo Kelion (Chinese Translation by Mort Yao)

Linux的创造者Linus Torvalds摘取了由芬兰技术科学院颁发的千禧年科技奖,以及作为奖金的600000欧元(相当于756000美元或486000英镑)支票。

他被授予该奖的理由是他创造了最初的Linux操作系统,并且长期以来决定着Linux内核应该做出哪些方面的修改——以通过代码让软件和硬件协同工作。

今天,各种各样基于Linux的操作系统驱动着世界上无数的服务器、TV机顶盒、智能电话、平板电脑、网络路由器、个人电脑以及超级电脑。

在该奖项宣布之前,Torvalds先生罕见地接受了一次BBC的采访。

当你1991年在Usenet新闻组上发布关于最初的系统内核的消息时,你当时预想到接下来会发生的事情是什么?

我想你的问题是假定我在这之前做好了某种程度的计划,但实际上那并不存在。在我公布原始的内核代码时,我对于未来并没有什么特别的预期;发布它的动力很大程度上只是想要告诉大家“嗨,来看看我做出了什么。”

我当时绝对没有奢望会有别人来帮助我完成这个项目,但我期望能得到一些针对项目完成度的意见反馈,并且能够搜集到一些在别人看来不错的想法。

Linux的成功很大程度上归功于它的开源本质。你认为是什么使得人们愿意在没有物质奖励的情况下投入时间参与其中?

实际上在许多方面,我认为开源的真正意义在于:允许每个人变得“自私”,而非试图让所有人都为了一致的公共利益来做贡献。

换言之,我从来都不把开源看作那种夸大其辞的“让我们围着篝火唱起兄弟之歌,让这个世界变得更美好。”不,开源只有当每个人都出于各自自私的目的而来为之付出努力时,才会真正地发展壮大起来。

话虽如此,在当下,这些自私的目的绝不仅仅是单纯地为了“经济奖赏”。

最早这些参与Linux开发的人,他们的“自私”目的无非就是为了满足自己捣鼓新奇玩意的爱好。这也曾经是我做Linux的理由——编程是我的乐趣——一种真正的激情——而学会怎样控制硬件则是我的“自私”目的。到后来我发现,并非只有我一个人抱有这种目的。

在那些规模较大的、开设了计算机科学系的大学里面,也会有不少人对类似的东西感兴趣。

对于那些人来说,完全从零开始编写自己的操作系统可能显得有点疯狂,但肯定会有人对摆弄、折腾硬件设备产生兴趣,如果他们足够兴致盎然的话,他们就会开始捣鼓这个操作系统,提出改进的建议,而且最终自行实现这些改进并回馈给我。

版权模式可以保护这一类人。假如你是一个操作系统的爱好者,你听说了这个项目,如果你感到自己贡献的劳动可能会从某种意义上成为“冤大头”,你肯定不会乐意加入,但是由于GPL v2许可证的采用,这就不是一个问题了。

GPL v2许可证的基本属性是一种非常简单明了的“以眼还眼”模式。我给予你我所做的改进成果,但作为回报,你必须承诺:你也会把你所做的改进成果给予他人。

它是一个从骨子里公平的许可证,你用不着担心别人会从你的劳动成果中“揩油”。

令许多人感到惊讶的是,这种“公平性”的概念实际适用的范围可以扩展到非常之广。

当然,很多公司最初对这种他们闻所未闻的许可证持强烈的怀疑态度,有时候这种怀疑甚至会翻上一番,个中缘由在于自由软件阵营的一部分人极端地反对商业化、恨不得那些公司一夜之间就把所有东西全部变成自由软件。

但是说真的,整个“以眼还眼”的模型并不只是适用于个人意义上的公平,它的公平性同样也适用于公司规模、乃至全球规模。

一旦个人和公司克服了这道障碍——改口将它称作“开放源码”,并且澄清了它绝非是某种反商业化行动这一事实——事态就开始欣欣向荣起来了。

事情最终演变成了这样,如果竞争对手不投入与你同等的努力,他们就不能获得和你同等的收益:如果他们不参与项目的贡献,他们就不能够影响项目前进的方向,并且他们在相应的对技术的认识和理解上将远远落在后面。

因此,积极地参与其中是大有好处的——你不能总是沿着别人的工作亦步亦趋。

来自80个国家的7800名开发者参与贡献了最近一个版本的Linux内核。由于它变得越来越复杂,这是否会导致新人要想加入开发变得愈加困难?

内核肯定是变得更加复杂了,而且绝对会有那种新的开发者不想一上来就碰到的难啃的核心部分。

当那些之前没有一定良好记录的新人向内核提交补丁时,社区里的人们会变得比较紧张——尤其是涉及那些复杂部分的、例如VM子系统的代码。

所以说,比起15年以前,如今要想成为一名合格的核心开发者肯定是变得更困难了。

与此同时,我认为参与内核开发其实还是比较容易的一件事,如果你不用一上来就直接去搞最复杂的核心部分的话。事实上,我差不多每三个月发布一个新版本的内核,每次发布通常都有1000人以上参与了开发,也就是说,我们肯定不缺少贡献者。

你之前提到过,你不可能亲自去把所有提交的代码在所有的硬件上都检查一遍——在这样的开源项目当中,信任所导致的问题可能会有多大?

哦,信任是最重要的东西。同时它也是条双行道。

并不只是我应当信任那些子部分的负责人能够把事情做对,相应地,他们也应该能够信任我会保持公平公正、做出正确的选择。

我们的意见并不总是一致,有时候争论会愈演愈烈,在一天的结束时,你甚至都可能感到不太喜欢对方,如果你至少相信别人不是故意要和你抬杠的话。

举个实际的例子,这种信任问题也正是我从来不曾想要为一个商业Linux公司工作的原因。

[…]

阿北:豆瓣的初衷

六年前,我开始写豆瓣第一行代码的时候,是想做一个关于生活发现的服务。也就是说,豆瓣想帮人发现真实生活里的好东西。今天豆瓣有一百多人的团队了,我们依然在做一个关于生活发现的服务。

这个想法可以在2005年以来一直没有改动过的一个页面里看到,就是“关于豆瓣”。其中两段如下:

“豆瓣的发起者发现,对多数人做选择最有效的帮助其实来自亲友和同事。随意的一两句推荐,不但传递了他们自己真实的感受,也包含了对你口味的判断和随之而行的筛选。他们不会向单身汉推荐育儿大全,也不会给老妈带回赤裸特工。遗憾的是,你我所有的亲友加起来,听过看过的仍然有限。而且,口味最类似的人却往往是陌路。”

“如果能不一一结交,却知道成千上万人的口味,能从中间迅速找到最臭味相投的,口口相传的魔力一定能放大百倍,对其中每一个人都多少会有帮助。豆瓣随着这一个愿望产生。豆瓣不针对任何特定的人群,力图包纳百味。无论高矮胖瘦,白雪巴人,豆瓣帮助你通过你喜爱的东西找到志同道合者,然后通过他们找到更多的好东西。”

六年没有改动也是因为豆瓣一直在这个方向上努力。因为世界上一直没有一个伟大的“生活发现”网站可以供我们参考,豆瓣一边做一边琢磨,希望可以成为一个这样的网站。每年我们都学到一些新的东西,也走过一些弯路。现在也许可以回顾一下。

2005和2006, 豆瓣对“发现”的理解是“个性化算法推荐”,就是“豆瓣猜你会喜欢”,包括后来的豆瓣电台。2007和2008, 豆瓣加强了“关于豆瓣”里提到的亲友和同事的口口相传,这就是”友邻广播“,今天叫作”豆瓣说“。2009和2010, 越来越多用户在群组活动里谈论生活的方方面面,于是我们把这部分单列出来,叫做“豆瓣社区”,也分化出了线上活动和豆瓣小站。所有以上的积累让豆瓣这个网站太复杂,开始给用户困扰,所以现在“www.douban.com”分成了几个子网站,每一个都可以更加简单专一。

豆瓣最先实践的三个生活领域是图书、电影、音乐,因为算法推荐在这三个领域最有效。“关于豆瓣”里也自然地用它们做例子。现在每个月几千万个人会用到豆瓣的图书电影音乐。我们觉得可以做得更好,依然在全力以赴。

但生活里除了图书电影音乐还有太多好东西在默默地等着你去发现,所以豆瓣也一直试着能在别的生活领域里帮到用户。2006年我们试了一下“我去”(旅行分享), 不是特别受欢迎。 2008年的同城活动却很受欢迎。今年我们在尝试生活类的小站、社区里的二手交易、“豆瓣猜你会喜欢的团购”,还有一些手机应用。我们希望当别人帮你娱乐游戏八卦的时候,我们可以帮到你的真实生活。我们希望你不上网的时候,豆瓣也是有用的。

豆瓣最终会由多个简单实用的生活服务组合而成。放在一起,是你的生活方式指南。这个指南不是任何编辑达人写的。它是你写的,给别人用,反之亦然。

我们在这个方向上坚持了六年,以后还会坚持下去,因为这是豆瓣的初衷。感谢你对豆瓣的耐心和支持,希望在对未来的方向上,我们想到了一起。

以上内容转自:http://blog.douban.com/douban/2011/06/01/1437/

最近一直有个想法,就是做一个发现知识的网站,让更多的人,更容易的发现知识。互联网将是最好的老师,在此勉励下自己!

Related posts:

豆瓣电台桌面软件:dbRadio Plus 旁敲侧击豆瓣电台的推荐系统 对当当网的分析【SEO每周一站】

Instagram的技术架构

Instagram 被 Facebook 以10亿美金收购。团队规模:13 人。而在被Facebook收购前的一个月,整个团队才7名员工。

2010年: 2位工程师 2011年: 3 位工程师 2012年: 5 位工程师

制胜法宝:

广泛的单元测试和功能测试 坚持DRY(Don’t Repeat Yourself)原则 使用通知/信号机制实现解耦 我们大部分工作使用Python来完成,只有逼不得已的时候,才会用C 频繁的代码复查,尽量保持“智慧共享”。(frequent code reviews, pull requests to keep things in the ‘shared brain’) 广泛的系统监控

Instagram的两个创始人

Mike Kriegerr:之前是一个颇为低调的工程师和用户体验设计师,他在一家名叫Meebo的创业公司工作了1年半。analytics & python @ meebo(在Meebo做分析,使用python ); Kevin Systrom:毕业后在Google的收购部门工作了一年,今年28岁,随后去到了一家从事旅行业务的创业公司Nextstop,没有计算机学位,没有接受过正式培训, 但他下班后坚持自学编程,在这家创业公司被Facebook以人才收购的方式收购后,Systrom又去早期的Twitter实习了一段时间。

下面一起来看下这个奇迹是怎样搭建的?Instagram的技术实现是什么?以下内容来自翻译。

当我们与其他工程师偶遇和交流的时候,有一个问题经常被问及,“你们的技术架构(technology stack)是怎么样的”?我们觉得从较高的层次来描述Instagram的所有构成系统是一件有趣的事情;未来你可能期待更深入的描述这些系统。这就是我们的系统,仅仅1年时间,并且我们活了下来,其中有一部分我们一直在修改。一个小型团队的初创公司,可以在一年多一点时间发展到1400多万用户规模。

Instagram 开发团队奉行的三个核心原则:

Keep it very simple (极简主义) Don’t […]

知乎技术方案初探

知乎的整个网站架构图如下:

知乎是国内很少的使用Python开发的一个网站,也很多值得我们学习的地方,从知乎让我们也可以了解到一些新的WEB技术。

一、Python框架

知乎目前使用的是Tornado 框架。Tornado 全称Tornado Web Server,是一个用Python 语言写成的Web 服务器兼Web 应用框架,由 FriendFeed 公司在自己的网站FriendFeed 中使用,被facebook 收购以后框架以开源软件形式开放给大众。

参考链接:http://zh.wikipedia.org/wiki/Tornado

学习文档:http://www.tornadoweb.cn/documentation

二、数据库

目前知乎采用的是MySQL作为主要的存储,使用SqlAlchemy 为ORM进行数据库的建模或者映射。

三、缓存技术

知乎使用Redis来进行缓存、队列、计数或者任务,使用Redis-Py为其连接客户端。

Redis参考链接:http://redis.readthedocs.org/en/latest/index.html

Redis-Py参考链接:http://redis-py.readthedocs.org/en/latest/index.html

四、Javascript框架

知乎使用Google的Closure Library作为前端的JavaScript 框架。

五、负载处理

目前知乎使用的是nginx做反向代理,用nginx来做静态文件等大数据量的I/O操作。

六、图片服务

知乎以前用到的Upyun,现在已经迁移到知乎自己建的图片服务上。

七、邮件服务

知乎的邮件发送一开始使用的是Amazon的SES,由于SES有些功能不能满足需求,目前已经转换成Mailgun。

八、消息系统

知乎消息系统采用的是comet实现,comet是基于http长连接的“服务器推”技术。

九、虚拟环境

作为一个Python网站,知乎很有可能采用Virtualenv来解决纯净的包环境问题。

中文文档地址:http://virtualenv-chinese-docs.readthedocs.org/en/latest/index.html

十、代码部署

常见的Python项目基本上采用Fabric进行部署,不知道知乎到底用的是哪一个。

十一、搜索实现

知乎使用mmseg做中文分词,对应的词根存在redis中作为key,数据库id作为value,每个数据项是一个zset集合。查询时根据key找到对应的value。

Related posts:

在Windows上安装配置Redis及Python使用 微格式:让网页更加语义化 Instagram的技术架构

[…]

代码之丑(十四)

代码评审,我对一个TreeSet产生了兴趣。

TreeSet configuration = new TreeSet();…Handler handler = new Handler(configuration);

“为什么要用TreeSet呢?”,我问道。“因为这是构造函数的参数决定的。”,有人回答。“可以打开源码看一下吗?”,对于这种处理,通常人们都会选择HashSet,好奇心驱使我要进一步专研一下这段代码。

我看到了这个构造函数的声明:public Handler(TreeSet configuration) {  …}

在我开始研究这个构造函数使用TreeSet的缘由之前,我看到了另外一个构造函数,或许它更能满足我的心理需求:public Handler(HashSet configuration) {  …}

“为什么会有一个用到HashSet构造函数?它和用到TreeSet的有什么不同”,我继续追问。“它们是分别处理两种情况的,在不同的配置下起作用。”

我终于知道为什么会有TreeSet,因为HashSet已经被人用了,为了支持另外一种情形,TreeSet被人从墙角了挖了出来。可是如果不深究代码,谁又能知道这其中的奥妙呢?显然,我们需要一个更具表达力的写法。

之所以陷入这样的坑,根源在于构造函数,因为构造函数只能有一个名字。其实,这里只是要解决构造的问题,而面对这个问题,解决方式几乎再直白不过了:工厂方法。

class HandlerFactory {  public static Handler createTrivialHandler(Set configuration) {    …  }

  public static Handler createFancyHandler(Set configuration) {    …  }}

这里,用两个名字上有更明确意义的函数替代之前的那两个需要强大理解力的构造函数。当然,这里的参数用了Set,连具体的类型都省了,真正的面向接口编程。

事实上,如果一个类有多于一个的构造函数,都是值得考虑的。我曾写过一篇《构造函数沉思录》专门讨论这个问题。

[…]

关于博客的悔忏

我的朋友月小刀的家与上班地点之间隔着一条钱塘江,他每天骑车上下班,加上路上等红绿灯的时间,单程大约要1个小时。这一个小时,他把自己汇入滚滚车流,吸着城市的废气,也嗅着人间的烟火。他在细雨中可以偷听来一个提亲故事,然后写到博客上。这种对生活充满求索和兴致的精神,让我佩服且惭愧。

我自2012年以来,博文的数量创下新低。目前固定专栏只有两个,还经常在截止期限前几分钟交稿。起初,我以为这是微博作祟,就戒了将近一个月的推特和微博。才发现微博真是无辜的。没有微博的日子,创作并没有任何进展,相反,连专栏也屡屡拖稿。肯写微博说明至少还有写作冲动,如果连这点冲动都没有了,写长文章就更困难了。

写作是一种靠消耗情感来维持的工程,在中国现阶段,主要是靠愤怒来维持。但是人的愤怒有一点神圣性和稀缺性,不应该像自来水,只要拧开笼头就流出来。写作最恶的状态是为了取悦读者而伪装愤怒,那比伪装高潮更为不堪。

对于大多数人来说,要想在这个国家生存需要学会麻木,对某些新闻麻木,对某些日子麻木,进而对某些情感麻木。保持清醒没什么问题,保持清醒并且说出来就会有麻烦。大概一个人成熟的过程,就是逐渐学会“识大体、不开口”的过程。

如果有什么话要送给2012年,那就是八个字:多事之秋,现金为王。不解释。

博客写作和专栏是不同的。专栏常窄急,博客宜宽缓。这一点我特别欣赏纳纳的博客。她的写法是一种中国古已有之、现已失传的“笔意闲闲”的写法。

影评家Roger Ebert评论《肖申克的救赎》时,认为这部电影有一种悠闲自得的气度,影片的节奏就像Red(摩根-弗里曼扮演)的叙述,慢条斯理,深思熟虑。这是大部分好莱坞电影都不敢采用的方法,因为传统电影理论认为,观众的注意力容易分散,需要用一个又一个小高潮激发他们的兴奋点。没有急赤白脸,没有演员抢戏,所有一切都按部就班,徐徐展开,一如高墙内近乎凝固的时间。

其实,我们何尝不在牢笼之内呢。卢梭说:人类生而自由,但枷锁无处不在。面对三面压迫的生活,博客也许是最后的逃难之所。

萝莉啰嗦说这么多,中心意思就是:以后要勇写博客,怒写博客,勤写博客。

Category

Archives