<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet href='http://feed.feedsky.com/styles/temp01.xsl' type='text/xsl' ?><!--这是一个由Feedsy提供技术支持的Feed，为了提高读者阅读的体验，以及满足用户美化自己Feed的需要，我们设计了多种精美的Feed模板，提供给大家选择，所有最终呈现出来的样式，皆由用户自愿选择使用，未经许可，任何团体和个人，请不要擅自修改样式或者盗用，这是对于用户选择权的尊重。--><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:fs="http://www.feedsky.com/namespace/feed" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link href="http://feed.fulin.org" type="application/rss+xml" rel="self"></atom:link><fs:self_link href="http://feed.feedsky.com/fulin" type="application/rss+xml"></fs:self_link><lastBuildDate>Tue, 24 Apr 2012 02:27:37 GMT</lastBuildDate><title>福林雨-博客</title><description>千帆过尽，我仍是寂寞海洋</description><image><url>http://www.feedsky.com/feed/fulin/sc/gif</url><title>福林雨-博客</title><link>http://blog.fulin.org</link></image><link>http://blog.fulin.org</link><sy:updatePeriod>hourly</sy:updatePeriod><sy:updateFrequency>1</sy:updateFrequency><language>en</language><pubDate>Mon, 07 May 2012 04:27:24 GMT</pubDate><item><title>转：通天塔导游</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248026/1234636/1/item.html</link><content:encoded>&lt;p&gt;(译注：圣经记载：在远古的时候，人类都使用一种语言，全世界的人决定一起造一座通天的塔，就是巴别塔，后来被上帝知道了，上帝就让人们使用不同的语言，这个塔就没能造起来。 巴别塔不建自毁，与其说上帝的分化将人类的语言复杂化，不如说是人类自身心灵和谐不再的分崩离析。之所以后来有了翻译，不仅是为了加强人类之间的交流，更寄达了一种愿望，希望能以此消除人际的隔阂，获求来自心灵的和谐及慰藉。真正的译者，把握血脉，抚平创痕，通传天籁，开启心门。)&lt;/p&gt;
&lt;p&gt;这是我写的旋风式的编程语言简介—我本来为亚马逊开发者杂志本月的期刊写的，但是发现我写的东西没法…见人。&lt;/p&gt;
&lt;p&gt;首先，我偶尔一不小心口出脏话，或者对上帝不恭的话，所以对很官方很正式的亚马逊上发表是不合适的; 所以我就把它塞到我的博客里了，我的博客反正没人看的。除了你以外。是的，只有你会看，你好啊。&lt;/p&gt;
&lt;p&gt;其次，这是一项进行中的工程，现在只是东打一耙西搞一下，还没有精加工过的。又一个把它写到博客里的很大的理由。不需要很好，或很完整。就是我今天想说的一些话。请随便！&lt;/p&gt;
&lt;p&gt;我的旋风式简介会讲C，C++，Lisp，Java，Perl，(我们在亚马逊用到的所有语言)，Ruby (我就是喜欢)，和Python，把Python加进来是因为—好吧，你看了就知道了，现在我可不说。&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;C&quot;&gt;&lt;/a&gt;C&lt;/h2&gt;
&lt;p&gt;你必须懂C。为哈? 因为出于所有现实的理由，这个世界上你过去，现在，将来会用到的每一台计算机都是一台冯·诺曼机器，而C是一种轻量级的，很有表达力的语法，能很好的展现冯·诺曼机器的能力。&lt;/p&gt;
&lt;p&gt;冯·诺曼架构就是你每天都用的计算机的架构的标准：一个CPU，内存，硬盘，一条总线。多核计算机并没有带来本质上的变化。冯·诺曼机是一个很方便，很便宜，上世纪五十年代的实现图灵机的技术，图灵机是执行计算的最知名的抽象模型。&lt;/p&gt;
&lt;p&gt;世上还有其他的计算的机器。比如，Lisp机器，是上世纪50年代对Lisp计算模型的实现。Lisp模型是基于lambda代数的一种计算语言表示法，后者是与图灵机同构的一种模型。不像图灵机，lambda代数能被人类读和写。但是这二者是同等能力的。它们同样精确的表示了计算机能干什么。&lt;/p&gt;
&lt;p&gt;Lisp机现在不是很流行了，除了在跳蚤市场里。从谁更受欢迎来说，冯·诺曼机器赢了。还有一些其他的计算机，比如神经网络计算机，译者也不知道怎么翻的计算机(cellular automata)，但是这些都不够大众化，至少现在是这样的。&lt;/p&gt;
&lt;p&gt;所以你必须知道C。&lt;/p&gt;
&lt;p&gt;还有一个你必须知道C的原因是，Unix是用C写的。巧的是，Windows也是。基本上所有的其他操作系统都是用C写的。因为这些操作系统都是冯·诺曼机的操作系统，你还能用别的吗? 任何跟C很不一样的东西都会跟硬件的实际能力相差太远而导致无法满足性能上的需要，至少对一个操作系统来说是这样—至少在上个世纪是这样，碰巧这些系统都是上个世纪的。&lt;/p&gt;
&lt;p&gt;你还应该知道Lisp。你不必用它来干实际工作，虽然它在很多GNU的软件里都会很用得着。尤其是，你应该学会Scheme，Lisp的一种小巧化的，纯洁的方言。GNU的版本叫Guile。&lt;/p&gt;
&lt;p&gt;他们在麻省理工和加州伯克利教新学生一到两个学期的Scheme，这些学生都对他们为哈要学这么奇怪的语言抓破脑袋。实话实说，作为第一门学习的语言，这是一个很烂的选择，第二门也是很烂。你应该学会它，最终，但不是作为第一门或第二门语言。&lt;/p&gt;
&lt;p&gt;这是很难的哦。这是很大的一步。学会怎么用Lisp写出像C语言的程序是不够的，那没有意义。C和Lisp一个就像红外线，一个就像紫外线，它们分布在光谱的最两端。它俩一个牛逼的地方刚好是另一个傻逼了的地方。&lt;/p&gt;
&lt;p&gt;如果说，C是最靠近计算机是如何工作的语言模型，Lisp就是最能反映计算(注意，这里没有了“机”字，计算机和计算是很不同的！译者注)是如何工作的模型。你不需要懂很多Lisp，真的。紧咬Scheme就哦了，因为它是最简单最干净的。其他的Lisp已经发展成了很大，很复杂(很好很强大? 译者：-)的编程环境，就像C++和Java，要有很多库啊，工具啊等等之类。那些，你不需要知道。但是你应该能用Scheme写程序。如果你能够做出The Little Schemer和The Seasoned Schemer这两本书里的所有习题，你懂得就够多了，我认为。&lt;/p&gt;
&lt;p&gt;但是对于你天天要做的编程工作，你应该基于以下条款选择你的语言：库，文档，工具支持，操作系统集成，资源，和一堆其他的东西。这些条款跟计算机如何工作关系很小，但是跟人类如何工作关系甚大。&lt;/p&gt;
&lt;p&gt;人们还在用很直白的C语言写东西。很多东西。你应该懂C！&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;C++&quot;&gt;&lt;/a&gt;C++&lt;/h2&gt;
&lt;p&gt;C++是地球上最蠢的语言，即使是从蠢这个字的真正意义上出发。C++很无厘头。它不知道自己是什么东西。它没有内视(面向对象里的一个概念，译者注)。C也没有，但是C不是“面向对象”的，而面向对象很大程度上是关于要让你的程序知道它自己。对象就像演员。所以面向对象语言应该有运行时的自省机制，知道自己是个什么类的对象。C++不是这样的，真的，你不会那样用它。&lt;/p&gt;
&lt;p&gt;关于C：写一个C的编译器是那么的简单，以至于你可以用C写一个关于C的工具，用起来就像是有内省机制。而C++呢，基本上是不可解析的，所以如果你想写一个很牛逼的工具用来—比如，告诉你你的虚函数的原型，或者帮你重构你的代码，你将不得不依赖别人的工具集，因为你自己在除非脑子进屎的情况下是根本不会去写一个C++的解析器的。而市面上所有的C++的解析器都很傻逼。&lt;/p&gt;
&lt;p&gt;C++很蠢，你不能用蠢语言创造一个好系统。语言决定世界，蠢语言决定蠢世界。&lt;/p&gt;
&lt;p&gt;所有的计算都基于抽象。你用低级的东西创造出高级的东西。但是你不能用分子创造出一个城市。尝试使用太低级别的抽象只会给你带来麻烦。&lt;/p&gt;
&lt;p&gt;我们就惹上麻烦了 (是指亚马逊的员工，还是所有C++的程序员? 我也不知道，译者注)。&lt;/p&gt;
&lt;p&gt;理智的情况下，你用C写的最大的东东就是一个操作系统。而操作系统其实不是很大的，真的。它们看起来很大，但那是因为它们有很多应用软件，操作系统本身的内核是蛮小的。&lt;/p&gt;
&lt;p&gt;你用C++能写的最大的东东是…也是操作系统。好吧，或许稍微再大点儿。让我们说，再大三倍吧。或者10倍吧。但是操作系统内核最多也就，那啥，一百万行代码? 所以我说你能用C++写的最大的系统大概也就是一千万行代码吧，再大的话就开始不行了，这玩意儿你没法控制了，就像恐怖片里的…&lt;/p&gt;
&lt;p&gt;我说的一千万行是指如果你那时候还能让你的系统编译通过的话。&lt;/p&gt;
&lt;p&gt;我们(在亚马逊，译者注)有五千万行C++代码。不，现在还要更多了。我已经不知道有多少行了。上个圣诞节是五千万行，那是九个月前，而它以每季度八百万行的规模增长。增长率本身也增长，妈呀。&lt;/p&gt;
&lt;p&gt;我们想这个系统里干点啥好像要一万年。一个亚马逊工程师有一次这样描述我们的代码库：“一座很大的屎山，你见过的最大的山，每次你想修正一个bug，你的工作就是爬到屎山的正中心去。”&lt;/p&gt;
&lt;p&gt;伙计们，那哥们可是在四年前说的这话。他现在已经到更环保绿色的牧场上去了。真是太可惜了，他可是个实实在在的高手啊。&lt;/p&gt;
&lt;p&gt;这都是C++的错。别跟我争论。就是的。我们用的是世上最蠢的语言。这简直有点老板级的蠢，你说呢? (译者注，meta在计算机术语里通常表示更高一个层次，比如，meta-language，比普通的language高一个层次，意思是关于语言的语言。哲学里应该会经常用到这个词。我不懂哲学，但是我觉得老板们总是比我们高一级，所以meta-dump我就翻译成老板级的蠢喽。：-)&lt;/p&gt;
&lt;p&gt;说了以上这些难听的话，话得说回来了。用C++写出漂亮的代码显然是可以的，我的意思是说，这样的代码应该大部分还是C，偶尔很有品味的，很有节制的用一点C++。但是这种代码几乎从来不会被写出来。C++是个很好玩的游乐场，而如果你把它玩儿得门儿清的话你会觉得自己特牛，所以你总是被诱惑把你知道的所有的东西都用上。但是那是很难做好的，因为从一开始这个语言就太狗屎了，最终，你会弄得一塌糊涂，即使你很能干。&lt;/p&gt;
&lt;p&gt;我知道，我说的都是异端邪说，该被钉到十字架上的。随便吧。我在大学里的时候老喜欢C++了，因为我那时候就只知道这一门语言。当我听到我的语言教授，Craig Chambers，绝对的厌憎C++，我想：“为啥呢? 我觉得它挺好的啊”。而当我听到STL(标准模板库)的发明者被采访时说他恨OOP(面向对象编程)时，我更是认为他肯定是磕药了。怎么会有人恨OOP呢，而这个人竟然还是STL的发明者?&lt;/p&gt;
&lt;p&gt;亲不敬，熟生厌(语出圣经，译者注)。说的是在大多数情况下，跟一件事物熟悉了之后你就失去对它的膜拜尊敬了; 在计算机语言里情况不是这样的。光对一门语言熟悉不会导致你看轻这门语言。你必须成为另一门更优秀的语言的专家(才能让你明白原来那门语言有多么多的问题)。&lt;/p&gt;
&lt;p&gt;所以如果你不喜欢我针对C++大放厥词，请你去学另一门语言并成为一个专家(我推荐Lisp)，只有那时你才有足够的武器与我争论。然而，那时你将不会跟我争了。你上了我的当了。你也会跟我一样变得不喜欢C++了，你或许会觉得我这个人很恶心，把你骗得不喜欢自己曾经的最爱了。所以或许你应该把我说的一切都忘了。C++挺好的其实，真的。它就是很棒棒(译者注，作者在这里用了ducky，这是一个女性喜欢用的夸某物好的词，近来也为玻璃们喜爱)。忘了我说的话。C++不错的。&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;Lisp&quot;&gt;&lt;/a&gt;Lisp&lt;/h2&gt;
&lt;p&gt;(我打赌这一节会让你觉得惊讶，即使你已经关注我的博客有一阵了 (译者注，作者也可能是说，即使你成为亚马逊的员工有一阵了)。)&lt;/p&gt;
&lt;p&gt;亚马逊创业之初，我们有很多明星级的工程师。我不认识他们所有人，但是我认识几个。&lt;/p&gt;
&lt;p&gt;比如? Shel Kaphan。大拿。Greg Linden。大拿。Eric Benson。即使在他加入亚马逊之前就已经有自己响亮的名气了。也是大拿。&lt;/p&gt;
&lt;p&gt;他们写了Obidos服务器。是Obidos让亚马逊成功的。只是后来那些生产大便很拿手的工程师，网页开发者，搞前端的人—这些人因为生产大便很拿手而总是能让经理们满意—只是在后来这些人把Obidos搞糟了。(他们的大便)把整条河都堵了，打个比方说的话。但是Obidos是亚马逊最初的成功的一块关键的基石。&lt;/p&gt;
&lt;p&gt;这些最早的牛人们在亚马逊神圣的代码库里只允许两种语言：C 和 Lisp。&lt;/p&gt;
&lt;p&gt;你自己去想吧。&lt;/p&gt;
&lt;p&gt;当然，他们所有人都使用Emacs。靠，Eric Benson是XEmacs的作者之一。这个世界上所有伟大的工程师都在用Emacs[注1]。那种世界因你而不同级别的伟大。不是坐在你旁边的格子里的那哥们那种伟大。也不是Fred，走廊尽头那哥们。我说的是我们这个行业里最伟大的软件开发者，那些能改变这个工业的面貌的人。像James Gosling们(Java语言设计者)，Donald Knuth们(这个人没有听说过的话赶紧改行吧，别搞计算机了)，Paul Graham们[注2]，Jamie Zawinski们，Eric Benson们。真正的工程师用Emacs。你必须很有点聪明才能把Emacs用好，而如果你能成为一个Emacs大师的话它会给你难以置信的牛力。有机会的话你应该站到Paul Nordstrom的肩后看看他是怎么工作的，如果你不相信我的话。对那些一辈子都在用烂Visual。Net之类的集成开发环境的人来说，一定会大开眼界的。&lt;/p&gt;
&lt;p&gt;Emacs是那种你可以用100年的编辑器。&lt;/p&gt;
&lt;p&gt;Shel，Eric，Greg，和其他像他们那样的人，我没有足够幸运能跟他们直接一起工作：他们禁止在这里使用C++，他们禁止使用Perl。(或者Java，为完整起见)。他们是明白人。&lt;/p&gt;
&lt;p&gt;现在我们都在用C++，Java和Perl了，所有的代码都用这些语言。我们的前辈们已经到更环保的牧场上去了 (指没有大便的牧场，译者注)。&lt;/p&gt;
&lt;p&gt;Shel用C写了Mailman，客服部的人把它用Lisp封装了一下。Emacs-Lisp。你不需要知道Mailman是什么东西。除非你是个Amazon的老员工，或许不是搞技术的，而且你曾经不得不让客户哈皮 (只有在这种情况下你才需要知道Mailman，译者注)。不是间接的，因为你用C++写的一个狗屎功能跑不起来了，让客户很生气，于是你不得不去搞定它以恢复客户的哈皮度。不，我是说直接的，意思是，你必须跟他们聊。我们可爱的，不识字的，呱呱其谈的，心地善良的，充满希望的，困惑的，能帮点小忙的，愤怒的，哈皮的客户们，真正的客户们，那些从咱们这里买东西的人，我们的客户们。(如果你必须跟他们打交道的话，)那你就会知道Mailman这个东西。&lt;/p&gt;
&lt;p&gt;Mailman是客服部的客户电子邮件处理软件，我们用了它有…四，五年? 反正是很长时间。它是用Emacs写的，所有人都爱死它了。&lt;/p&gt;
&lt;p&gt;人们现在还很爱它。直到今天，我依旧不得不听我们一些非技术员工跟我长篇大论的叨叨他们是多么的怀念Mailman。我可绝不是满嘴喷粪。上个圣诞节我参加了一个Amazon的派对，一个我不知道自己怎么会被邀请的派对，里面全是些西装笔挺的商务人士，谁都长得比我帅，比我光鲜。以及一些我在公司里曾经打过交道的人(这句不知道怎么译)。四个美女认出了我是在客服部里干的，把我包围了，跟我说了十五分钟她们是多么的怀念Mailman和Emacs，而现在的亚马逊(我们用JSP花了好多年准备换掉Mailman的那一套软件)是怎么的不能满足她们，让她们觉得跟以前一样爽。&lt;/p&gt;
&lt;p&gt;这一切都太梦幻了，我觉得她们可能是喝多了。&lt;/p&gt;
&lt;p&gt;Shel是个天才。Emacs是天才。连非技术人员都爱Emacs。我现在就是在Emacs里打这些文字。我绝不情愿在任何其他地方打字。这不只是关于让你的效率得到飞跃，通过那些地球上其他地方找不到的快捷键和文本编辑功能。我每分钟打一百三到一百四十个英文单词，在Emacs里，当我在写没有格式要求的文本的时候。我测过这个时间速度。自己写了一个测打字速度的Emacs应用。但我想跟你说的不只是这个。&lt;/p&gt;
&lt;p&gt;Emacs有的是一种你叫不出名字来的品质。&lt;/p&gt;
&lt;p&gt;我们现在不用Mailman了。那是因为我们有一种叫得出名字的品质—就是，烂。我们很烂。我们(当时)找不到Emacs-Lisp足够牛的人把Mailman继续搞下去。今天这应该不难了; 亚马逊现在到处都是Emacs Lisp的黑客。但是在那时候，客服部的人没法从别人那里得到帮助。于是他们就用他们当时手头有的资源去搞这件事。他们当时没有足够多的Emacs-Lisp的人。有一段时间，他们甚至找来Bob Glickstein当合同工，那个给O&amp;#8217;Reilly写了那本Gnu Emacs扩展的书的家伙，坐在一个小办公室里给Emacs写Mailman的扩展。&lt;/p&gt;
&lt;p&gt;客服应用部是Amazon的第一个两块比萨饼的团队(我也不知道什么意思，看下文)。这个团队是完全自立的。不管是那时还是现在。没人跟他们说话，没人帮他们。没有枪，没有炮，他们自己造。他们没有网页工程师，没有支持工程师。屁也没有。有的只是一堆骨灰级的工程师和一个能带新人的文化。这就是他们需要的一切了。&lt;/p&gt;
&lt;p&gt;但他们最终不得不让Mailman光荣退休。妈哎。而我呢今天还听到人们说他们是多么的怀念它。甚至在派对上。&lt;/p&gt;
&lt;p&gt;我想今天按人头比例来说，客服部仍然拥有比亚马逊任何其他团队更多的Lisp黑客。可能他们用到Lisp的机会不多了，但是Eric Raymond说过，即使你很少用Lisp写程序，学习Lisp会是意义深远的一个经历，能让你下辈子都成为一个更好的工程师。&lt;/p&gt;
&lt;p&gt;卡尔，宗教现在已经不是大众的精神鸦片了。现在鸦片是集成开发环境了。(卡尔。马克思。这个人不知道的话应该打屁屁)。&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;Java&quot;&gt;&lt;/a&gt;Java&lt;/h2&gt;
&lt;p&gt;Java是过去的10年中计算行业里发生过的最好的同时也是最坏的事。&lt;/p&gt;
&lt;p&gt;一方面，Java把你从C++编程的很多枯燥易错的细节中解救出来了。没有数组越界了，没有core dump了。抛出来的异常能让你精确定位到出错的那一行代码，而且99%的时候都是正确的那一行出错了的代码。对象们在需要的时候能智能地把它们自己打印出来。等等等等。&lt;/p&gt;
&lt;p&gt;另一方面，除了是一种语言，一个虚拟机，一个巨无霸的类库，一个安全模型，一个可移植的字节码格式，Java还是一个宗教。邪教。所以你不能太相信对它太虔诚的人。想要招一个好的Java工程师是一项很有技术挑战的活。&lt;/p&gt;
&lt;p&gt;但是总的来说，Java是软件工程史上的一大进步。&lt;/p&gt;
&lt;p&gt;从C++到Java不只是语法上的改变。这是一种需要一段时间去好好体会的一种震撼性的世界观的转变。这有点像突然你被配了一个执行助理。你知道老总们为什么总是好像有时间去开会，总是知道公司现在运行的情况，总是写出很酷酷的文档吗? 老总们常常忘记其实他们不是一个人在战斗，他们都是两个全职的人，他们和他们的执行助理们。有一个执行助理把你从琐事中解救出来让你有时间去思考那些真的需要你去解决的问题; 没有的话你将不得不花一半的时间在那些无聊的世俗的事情上。切换到Java编程语言就把你变成了两个程序员—一个处理那些你不需要关心的东西，另一个可以集中精力在问题本身上。这是一个很震人的改变，一个你应该很快就能习惯能喜欢上的改变。&lt;/p&gt;
&lt;p&gt;就像Jamie Zawinski(Netscape牛人，开发Mozilla浏览器，好像学历是高中毕业?)在他著名的“Java真烂”那篇文章里说的：“先说那些好东西：Java没有free()函数。我必须一开始就承认，其他的东西都没什么了不起。(没有free)是能让我原谅其他所有东西的特性，不管其他东西有多烂。讲完这一点后，我的文章里其他一切几乎都完全没有重要性了。”&lt;/p&gt;
&lt;p&gt;Jamie的文章写在1997年，按Java年来算的话是很早以前了，跟他写这篇文章时比Java已经有很大的改善; 一些他抱怨的东西甚至已经被fix了。&lt;/p&gt;
&lt;p&gt;但是大多数还是没有被fix。Java作为一门语言还是有点烂。但就如Jamie指出的，Java“是今天为止最好的语言。我的意思是说，它是今天市面上那些烂得底儿掉地一堆语言比起来有那么一点能被我接受。”&lt;/p&gt;
&lt;p&gt;真的，你应该读读他那篇文章。&lt;/p&gt;
&lt;p&gt;Java几乎每一方面都很好，除了它的语言本身，而这是JWZ抱怨的主要对象。但那是一个很大的抱怨。再好的库也救不了一个烂语言。相信我：你可能比我知道多得多的东西，但是我知道好兵救不了烂将。在Geoworks搞了五年汇编语言都会了我这个道理。&lt;/p&gt;
&lt;p&gt;跟C++比，Java作为一个语言还过得去。好吧，别扯了，Java要好很多。因为它有(内建)的字符串。哥们，你说一个没有内建的字符串的语言是人用的吗。&lt;/p&gt;
&lt;p&gt;但是Java跟C++比少了一些好东西，比如(函数调用时)传引用，栈上的对象，typedef，宏，以及运算符重载。一些时不时地会很称手的东西。&lt;/p&gt;
&lt;p&gt;哦，还有多重继承，我现在老了，反而挺欣赏了的多重继承。如果你认为我这个观点僵硬不灵活的家伙是多态教义很好的反例的话，我倒是可以给你举几个为什么你需要多态继承的好例子，或者至少像Ruby那样的mixin或者自动的派遣。下次问问我白龙马的事情。今天我要告诉你为什么Java的interface是个烂货。&lt;/p&gt;
&lt;p&gt;几年前Gosling自己都说，如果一切都能重来的话，他不会搞出个interface的概念。&lt;/p&gt;
&lt;p&gt;但是那正是Java的问题。当James说出那句话的时候，人们被雷到了。我甚至能感觉到那股雷劲儿，能感觉到Sun公司市场部和法务部的鸟人是多么想把James灭口，然后告诉大家他没那么说过。&lt;/p&gt;
&lt;p&gt;Java的问题就是人们都被那帮人搞的广告效应蒙住了眼。C++，Perl，任何流行语言都有这个问题。这是很严重的，因为如果没有一些说大话吹牛逼的广告，一个语言是不会流行起来的。所以如果一个语言的设计者说他的语言没有被设计得很完美的话，就是赶紧用麻醉枪射击这胡说八道的家伙并关闭会议的时候了。&lt;/p&gt;
&lt;p&gt;语言们需要放点儿卫星才能活，我只希望人们不要被卫星耀瞎了眼。&lt;/p&gt;
&lt;p&gt;我学了面向对象编程， 我自己也对此大吹大擂。当我加入亚马逊时，我不能告诉你我有什么智慧或者经验，但我可以给你背诵出所有关于OOP的魔咒。多重继承是邪恶的，因为大家都这么说; 运算符重载是邪恶的，诸如此类。我甚至有点模糊地知道为什么是邪恶的，但实际上不知道。后来我明白了，这些都不邪恶，不是烂玩意儿，烂的是开发者，是我。我现在还是烂，但是希望每年都不烂一点起来。&lt;/p&gt;
&lt;p&gt;上礼拜我碰到一个来面试的，他告诉我多继是邪恶的，因为，比如，你可以从头，胳膊，腿，躯干多重继承出一个人来。他既是对的，又是错的。那样的多继情形当然邪恶，但那都是因为他自己太邪恶了。那样继承出来的“东西”远远就能看见有多蠢，如果他还把这玩意儿弄进门来那就更邪恶了。&lt;/p&gt;
&lt;p&gt;不良开发者，占了这世上开发者的大多数，他们能用你扔给他们随便什么语言写出不良的代码。&lt;/p&gt;
&lt;p&gt;说了这些，还是得说回来，多继不是请客吃饭那么轻松的事儿; mixin看起来是更好的解决方案，但是还没人完美的解决这个问题。但我还是认为Java比C++好，即使它没有多继。因为我知道不管我的出发点是多么好，某一天我还是会被一堆不懂怎么写好代码的人包围，让他们用Java比用C++会带来更少的伤害。&lt;/p&gt;
&lt;p&gt;此外，Java除了语言本身外还有老多其他的重要有用的东西。且Java语言本身也在进化，虽然像冰川一样慢，所以我们还是能看到希望。Java正是我们应该在亚马逊推荐使用的语言。&lt;/p&gt;
&lt;p&gt;你就是得小心点儿，因为各其他任何语言一样，你能很容易找出一堆人，他们很懂一门语言及其编程环境，但对品味，计算或者其他任何重要的东西却一无所知。&lt;/p&gt;
&lt;p&gt;当你有怀疑时，还是雇那种会好几门语言的Java程序员，那种厌憎J2EE/EJB之类松松跨跨的所谓框架的，那种使用Emacs的。这都是一些实战经验。&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;Perl&quot;&gt;&lt;/a&gt;Perl&lt;/h2&gt;
&lt;p&gt;Perl，怎么说呢?&lt;/p&gt;
&lt;p&gt;Perl是个老朋友。老老朋友。我开始写Perl代码的时候，可能是1995年? 而它为我很好的服务了差不多10年的时间。&lt;/p&gt;
&lt;p&gt;它就像你骑了十万二十万英里的老自行车，你心里永远有一块地方装着它，虽然现在你已经换了一辆更加现代化的只有五磅重的自行车，而且这一辆也不像老的那辆顶得你屁眼疼了。&lt;/p&gt;
&lt;p&gt;Perl受欢迎原因有仨：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用Perl你很快就能搞定你的问题。而这是最终的衡量标准。&lt;/li&gt;
&lt;li&gt;Perl有世上最好的市场推广。你可以写一本介绍他们市场推广有多绝的书。Sun公司砸大笔钱给Java推市场，Perl在受欢迎程度来说能跟Java齐头并进，但Perl纯粹是依靠Larry Wall和他那帮哥们的三寸不烂之舌做市场。哈佛商学院的人应该去研究Perl的市场是怎么做出来的。真的让人瞠目结舌。&lt;/li&gt;
&lt;li&gt;直到差不多，呃，现在，Perl没有真正的竞争者。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有比Perl“好”的语言。操，有很多比Perl好的语言，如果你定义“好”为“不是给疯子用的”的话。Lisp，Smalltalk，Python，妈呀，我可能可以列出二三十种比Perl“好”的语言。从这些语言不像这个夏天在台湾街头爆了肚皮的抹香鲸这个角度来说。鲸鱼肠子到处都是，汽车上，机车上，行人身上。这就是Perl。让人着迷，真的。&lt;/p&gt;
&lt;p&gt;但是Perl有很多很多好的特性，直到最近，都是其他语言没有的。它们弥补了Perl肠子在外的不足。你可以从爆了肚皮的鲸鱼可以做很多有用的东西出来，比如香水。这很有用。Perl也是这样。&lt;/p&gt;
&lt;p&gt;当其他的那些语言(尤其是Lisp和Smalltalk)都想假装操作系统并不存在，列表(Lisp的)和对象(Smalltalk的)就是把屎搞出来的唯一存在，Perl却走了截然相反的路子。Larry说：Unix和字符串是搞出屎来的唯一存在。&lt;/p&gt;
&lt;p&gt;对很多任务来说，他绝对是正确的。所以Perl绝对是Unix系统管理和字符串处理的史上最强语言，除了一个，刚出来的一个，从哥斯拉(电影哥斯拉看过没)之地出来的一个。我一会儿会讲到那一个。&lt;/p&gt;
&lt;p&gt;可惜，Larry太太太太在意Unix系统管理和字符串处理以致他压根忘了列表和对象，等他明白过来想改正的时候已经晚了。实际上，在Perl早期的…好吧，对鲸鱼肠子我实在不想用“设计”这个词，就说生命周期中吧，他犯的几个关键错误让把列表和对象加进来变得如此尴尬，以致Perl已经进化成一个真正的Rube Goldberg机器，至少当你想在Perl里用列表和对象的时候。(Rube Goldberg是一漫画家，常画一些很复杂的机器，但只完成简单的工作，比如一个小球滚过很多关卡，最后把门打开。译者注)。&lt;/p&gt;
&lt;p&gt;列表和对象也他妈的是很重要的，Larry！(farging应该是作者不想说fucking那么直白，译者注)&lt;/p&gt;
&lt;p&gt;Perl没法表达列表因为Larry一早犯了一个悲剧性的愚蠢的错误，把列表全抹平。于是(1，2，(3，4))魔术般地变成(1，2，3，4)。不是说你会想让它这样工作，而是Larry刚好那天在搞一个这样会更方便的问题。于是Perl的数据结构从此就变得爆炸了的鲸鱼了。&lt;/p&gt;
&lt;p&gt;今天你看Perl的书，小教程或PPT的时候，不花三分之一的时间在“引用”上是不可能的。这就是Larry可怜的，坏了的，Goldberg(漫画家，想起来没? 译者注)式的对他那抹平列表的疯狂错误的解决方案。但是Perl的市场宣传做得那么难以置信地好以致它让你觉得这是你身上发生过的最好的东西。你可以对任何东西取它的引用。这很有趣！闻起来也很香（说肠子呢，译者注，呵呵）！&lt;/p&gt;
&lt;p&gt;Perl不能支持面向对象编程因为Larry压根不相信这玩意儿。这可能没什么大不了; 我也不是很确定我是不是信这个OOP。但是那么为啥他又要试着把对象加进Perl呢? Perl的面向对象是个半成品，且在Perl社区里没多少人重视。它就是不像字符串处理或Unix集成那样充满灵感。&lt;/p&gt;
&lt;p&gt;当然了，Perl还有其他很多怪怪的特性。比如它的“上下文”，这是Larry要有N个变量名字空间的喜剧式决定的一个恐怖片式的产物。这些空间由sigil来区分(就是Perl里变量名前面的‘$’，‘@’，‘%’字符)，看着像是从shell脚本里拷贝来的。在Perl里，所有的运算符，所有的函数，所有的操作其行为都是六取一的随机的，取决于当前的“上下文”。没有一些规则或助记法能帮你搞定这些特定操作在特定上下文里的特定行为。你得把它们全记在脑子里。&lt;/p&gt;
&lt;p&gt;想要个例子? 这儿有一个：在一个值量(scalar，对应于vector，向量)上下文里对一个哈希取值你得到一个字符串，里面是个分数，分子是目前已分配的键，分母是总共有多少个桶。鲸鱼肠子，我告诉你。&lt;/p&gt;
&lt;p&gt;但就像我说的—直到最近，没啥能像Perl那样把屎搞定。&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;Ruby&quot;&gt;&lt;/a&gt;Ruby&lt;/h2&gt;
&lt;p&gt;每过15年左右，一门语言就会被更好的代替。C被C++代替，至少对大应用开发而又需要性能和数据类型的人们来说。C++被Java代替，而Java无疑在7年后又会被更好的东西代替—好吧，我说的是完全代替C++的7年后，这到目前为止还没有发生，主要是因为微软能在Java霸占桌面系统之前狙击它。但是在服务器上的应用而言，C++的阵地已经慢慢让给Java了。&lt;/p&gt;
&lt;p&gt;Perl有一天也会消逝。那是因为一门新的语言Ruby刚刚终于被翻译成英语了。没错，它是在日本发明的，这么多地儿，没想到日本人搞出来了，还以为他们只是硬件和制造上占有名气，而不是他们的软件业，所以大家都跟你一样惊奇。为什么呢，大家可能都在想。但是我认为这都是跟打字有关。我根本不能想象他们以前能打字打得足够快，英文字母只有26个，他们却有上万个字。但是Emacs几年前支持多字节字符了，所以我猜他们现在打字速度他妈的快多了。(所以能搞出Ruby来了，译者猜作者是这个意思) (是的，他们也用Emacs—事实上日本人负责了Emacs多字节支持的大部工作，而且搞得坚不可摧。)&lt;/p&gt;
&lt;p&gt;不管怎么样，Ruby从Perl那里偷师了所有的好东西; 实际上，Matz，Ruby的作者(Yukihiro Matsumoto，如果我没记错的话，但是他外号“Matz”)，觉得他从Perl那里偷的有点太多了，他的鞋上也粘了些鲸鱼肠子。但是只是一丢丢。&lt;/p&gt;
&lt;p&gt;最重要的是，Ruby拿来了Perl的串处理和Unix集成，一点没改，就是说语法都是一样的，于是乎啥也不说了，你就拥有了Perl最好的那部分。这是个不错的开局，特别是如果你不把Perl剩下的东西也拿进来的话。&lt;/p&gt;
&lt;p&gt;但是之后Matz还从Lisp那里拿来的最好的列表处理，Smalltalk和其他语言那里拿来了最好的面向对象，CLU那里拿来了最好的迭代器，以及基本上是每个人每个事的最好的东西。&lt;/p&gt;
&lt;p&gt;而他让这些东西全部都跑起来，跑得那么顺，你都不会注意到这些东西在那儿。我比其他任何语言都快就学会了Ruby，我总共会三十到四十门语言; 而我花了大概三天时间就能用Ruby比Perl还流畅地工作了，当了八年的Perl黑客后。这些东西是这么的和谐你都能自己猜它们是怎么工作的，而且大多数时候你都能猜对。漂亮。有趣。靠谱。&lt;/p&gt;
&lt;p&gt;如果把语言比成自行车，那么AWK就是一辆粉系的儿童自行车，前面有个白色小框，还插块小旗，Perl就是沙滩车(还记得那有多酷吧? 唉。)，而Ruby则是一辆七千五美金的钛合金山地自行车。从Perl飞跃到Ruby意义不下于从C++到Java的飞跃。却没有任何缺陷，因为Ruby几乎是Perl功能的一个超集，而Java却拿掉了一些人们想要的东西，且没有真正的提供一个替代品。&lt;/p&gt;
&lt;p&gt;下次我会写更多关于Ruby的东西。我先需要灵感。去读读Lucky Stiff的(poignant) guide to Ruby吧。那本书是一本有灵感的书。真的，读一下。超赞。我不理解产生它的那种头脑，但它很有趣，很犀利，且全是关于Ruby的。好像。你会看到的。&lt;/p&gt;
&lt;h2&gt;&lt;a name=&quot;Python&quot;&gt;&lt;/a&gt;Python&lt;/h2&gt;
&lt;p&gt;啊，Python怎么说呢，一个不错的语言，这么多年来一直旁边在等待它的机会? Python社区很长时间以来是那些勇敢地吞下红药片从Perl骇客帝国中醒来的人的避难营。&lt;/p&gt;
&lt;p&gt;啊，有点像Smalltalk的人们，他们永远在等待替代C++，没想到半路杀出Java一下把它们操翻了，漂亮地，永久地。哎哟。Ruby正在对Python做着同样的事，现在，今天。可能会在一夜之间吧。&lt;/p&gt;
&lt;p&gt;Python本来可以统治世界，可惜它有两个致命缺陷：空格，和冷淡。&lt;/p&gt;
&lt;p&gt;空格很简单，就是说Python是用缩进来表达代码块之间的嵌套。它强制你必须按一定格式把所有的东西缩进，他们这样做是为了让所有人写的代码看上去一样。不料蛮多程序员讨厌这点，因为他们觉得自己的自由被拿走了; 感觉就像Python侵犯了宪法赋予他们的可以随便缩进格式和全写在一行上的权利。&lt;/p&gt;
&lt;p&gt;Python的作者，Guido Van Rossum，也在早期犯过一些很傻地技术错误—没有像Larry的失误那么严重，但是还是有几个。比如，最早Python没有字面变量范围，但它同时也没有动态变量范围，而动态变量范围可能会有它一些问题，但它还是有用的。Python却没有这些，只有全局的和本地(函数)的两种范围。所以即使它是一个真正的OO系统，类甚至不能访问它们自己的动态成员变量。你必须给成员函数传“self”参数，一大堆self参数很快就会把你搞疯掉，即使你不在意空格问题。&lt;/p&gt;
&lt;p&gt;等等之类。&lt;/p&gt;
&lt;p&gt;但在我看来，Python不行其实是因为冷淡。这阻止了它成为首选脚本语言，或者首选一切语言。靠，人们现在还在用Tcl作嵌入解释执行器，虽然Python比Tcl好得不要太多—除了，我说，这个冷淡问题。&lt;/p&gt;
&lt;p&gt;此处开始我不知所云。呵呵，这样吧，把原文贴在最后面。&lt;/p&gt;
&lt;p&gt;注1，Eric告诉我当时几乎全是Jamie Zawinski，当他们在Lucid工作的时候。&lt;/p&gt;
&lt;p&gt;注2，我写了这个之后很多人告诉我Paul Graham是用VI的，想不到。&lt;/p&gt;
&lt;p&gt;注3，为了有据可查，我个人根本不介意空格问题。我认为因为这个而不喜欢Python是很傻的。我只是说有一堆比例让人惊奇的&lt;strong&gt;其他&lt;/strong&gt;工程师讨厌空格问题。&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s the frost thing, you ask? Well, I used to have a lot of exceptionally mean stuff written here, but since Python&amp;#8217;s actually quite pleasant to work with (if you can overlook its warts), I no longer think it&amp;#8217;s such a great idea to bash on Pythonistas。The &amp;#8220;frost thing&amp;#8221; is just that they used to have a tendency to be a bit, well, frosty。Why?&lt;/p&gt;
&lt;p&gt;Because they were so tired of hearing about the whitespace thing！&lt;/p&gt;
&lt;p&gt;I think that&amp;#8217;s why Python never reached Perl&amp;#8217;s level of popularity, but maybe I&amp;#8217;m just imagining things。&lt;/p&gt;
&lt;p&gt;Coda&lt;/p&gt;
&lt;p&gt;That was the ADJ article I really wanted to write。Or at least something like it。For some reason, though, my true feelings only seem to come out during insomniac attacks between 3am and 6am。Time for bed！2 hours &amp;#8217;til my next meeting。&lt;/p&gt;
&lt;p&gt;这才是我真正想给亚马逊开发者杂志写的文章。或者至少是这样的。出于某些原因，我的真感情好像只有在我凌晨三点到六点失眠的时候都会流露。该睡觉了！我下个会议再过两小时就开始了。&lt;/p&gt;
&lt;p&gt;(发布于2004年9月，小小的更新在3/28/2006)&lt;/p&gt;
&lt;p&gt;原文：&lt;a href=&quot;https://sites.google.com/site/steveyegge2/tour-de-babel&quot; rel=&quot;nofollow&quot;&gt;https://sites.google.com/site/steveyegge2/tour-de-babel&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;译文：http://code.google.com/p/windows-config/wiki/TourDeBabel&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2012%2F04%2Ftour-de-babel.html&amp;title=%E8%BD%AC%EF%BC%9A%E9%80%9A%E5%A4%A9%E5%A1%94%E5%AF%BC%E6%B8%B8&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248026/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248026/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2012/04/tour-de-babel.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>(译注：圣经记载：在远古的时候，人类都使用一种语言，全世界的人决定一起造一座通天的塔，就是巴别塔，后来被上帝知道了，上帝就让人们使用不同的语言，这个塔就没能造起来。 巴别塔不建自毁，与其说上帝的分化将人类的语言复杂化，不如说是人类自身心灵和谐不再的分崩离析。之所以后来有了翻译，不仅是为了加强人类之间的交流，更寄达了一种愿望，希望能以此消除人际的隔阂，获求来自心灵的和谐及慰藉。真正的译者，把握血脉，抚平创痕，通传天籁，开启心门。) 这是我写的旋风式的编程语言简介—我本来为亚马逊开发者杂志本月的期刊写的，但是发现我写的东西没法…见人。 首先，我偶尔一不小心口出脏话，或者对上帝不恭的话，所以对很官方很正式的亚马逊上发表是不合适的; 所以我就把它塞到我的博客里了，我的博客反正没人看的。除了你以外。是的，只有你会看，你好啊。 其次，这是一项进行中的工程，现在只是东打一耙西搞一下，还没有精加工过的。又一个把它写到博客里的很大的理由。不需要很好，或很完整。就是我今天想说的一些话。请随便！ 我的旋风式简介会讲C，C++，Lisp，Java，Perl，(我们在亚马逊用到的所有语言)，Ruby (我就是喜欢)，和Python，把Python加进来是因为—好吧，你看了就知道了，现在我可不说。 C 你必须懂C。为哈? 因为出于所有现实的理由，这个世界上你过去，现在，将来会用到的每一台计算机都是一台冯·诺曼机器，而C是一种轻量级的，很有表达力的语法，能很好的展现冯·诺曼机器的能力。 冯·诺曼架构就是你每天都用的计算机的架构的标准：一个CPU，内存，硬盘，一条总线。多核计算机并没有带来本质上的变化。冯·诺曼机是一个很方便，很便宜，上世纪五十年代的实现图灵机的技术，图灵机是执行计算的最知名的抽象模型。 世上还有其他的计算的机器。比如，Lisp机器，是上世纪50年代对Lisp计算模型的实现。Lisp模型是基于lambda代数的一种计算语言表示法，后者是与图灵机同构的一种模型。不像图灵机，lambda代数能被人类读和写。但是这二者是同等能力的。它们同样精确的表示了计算机能干什么。 Lisp机现在不是很流行了，除了在跳蚤市场里。从谁更受欢迎来说，冯·诺曼机器赢了。还有一些其他的计算机，比如神经网络计算机，译者也不知道怎么翻的计算机(cellular automata)，但是这些都不够大众化，至少现在是这样的。 所以你必须知道C。 还有一个你必须知道C的原因是，Unix是用C写的。巧的是，Windows也是。基本上所有的其他操作系统都是用C写的。因为这些操作系统都是冯·诺曼机的操作系统，你还能用别的吗? 任何跟C很不一样的东西都会跟硬件的实际能力相差太远而导致无法满足性能上的需要，至少对一个操作系统来说是这样—至少在上个世纪是这样，碰巧这些系统都是上个世纪的。 你还应该知道Lisp。你不必用它来干实际工作，虽然它在很多GNU的软件里都会很用得着。尤其是，你应该学会Scheme，Lisp的一种小巧化的，纯洁的方言。GNU的版本叫Guile。 他们在麻省理工和加州伯克利教新学生一到两个学期的Scheme，这些学生都对他们为哈要学这么奇怪的语言抓破脑袋。实话实说，作为第一门学习的语言，这是一个很烂的选择，第二门也是很烂。你应该学会它，最终，但不是作为第一门或第二门语言。 这是很难的哦。这是很大的一步。学会怎么用Lisp写出像C语言的程序是不够的，那没有意义。C和Lisp一个就像红外线，一个就像紫外线，它们分布在光谱的最两端。它俩一个牛逼的地方刚好是另一个傻逼了的地方。 如果说，C是最靠近计算机是如何工作的语言模型，Lisp就是最能反映计算(注意，这里没有了“机”字，计算机和计算是很不同的！译者注)是如何工作的模型。你不需要懂很多Lisp，真的。紧咬Scheme就哦了，因为它是最简单最干净的。其他的Lisp已经发展成了很大，很复杂(很好很强大? 译者：-)的编程环境，就像C++和Java，要有很多库啊，工具啊等等之类。那些，你不需要知道。但是你应该能用Scheme写程序。如果你能够做出The Little Schemer和The Seasoned Schemer这两本书里的所有习题，你懂得就够多了，我认为。 但是对于你天天要做的编程工作，你应该基于以下条款选择你的语言：库，文档，工具支持，操作系统集成，资源，和一堆其他的东西。这些条款跟计算机如何工作关系很小，但是跟人类如何工作关系甚大。 人们还在用很直白的C语言写东西。很多东西。你应该懂C！ C++ C++是地球上最蠢的语言，即使是从蠢这个字的真正意义上出发。C++很无厘头。它不知道自己是什么东西。它没有内视(面向对象里的一个概念，译者注)。C也没有，但是C不是“面向对象”的，而面向对象很大程度上是关于要让你的程序知道它自己。对象就像演员。所以面向对象语言应该有运行时的自省机制，知道自己是个什么类的对象。C++不是这样的，真的，你不会那样用它。 关于C：写一个C的编译器是那么的简单，以至于你可以用C写一个关于C的工具，用起来就像是有内省机制。而C++呢，基本上是不可解析的，所以如果你想写一个很牛逼的工具用来—比如，告诉你你的虚函数的原型，或者帮你重构你的代码，你将不得不依赖别人的工具集，因为你自己在除非脑子进屎的情况下是根本不会去写一个C++的解析器的。而市面上所有的C++的解析器都很傻逼。 C++很蠢，你不能用蠢语言创造一个好系统。语言决定世界，蠢语言决定蠢世界。 所有的计算都基于抽象。你用低级的东西创造出高级的东西。但是你不能用分子创造出一个城市。尝试使用太低级别的抽象只会给你带来麻烦。 我们就惹上麻烦了 (是指亚马逊的员工，还是所有C++的程序员? 我也不知道，译者注)。 理智的情况下，你用C写的最大的东东就是一个操作系统。而操作系统其实不是很大的，真的。它们看起来很大，但那是因为它们有很多应用软件，操作系统本身的内核是蛮小的。 你用C++能写的最大的东东是…也是操作系统。好吧，或许稍微再大点儿。让我们说，再大三倍吧。或者10倍吧。但是操作系统内核最多也就，那啥，一百万行代码? 所以我说你能用C++写的最大的系统大概也就是一千万行代码吧，再大的话就开始不行了，这玩意儿你没法控制了，就像恐怖片里的… 我说的一千万行是指如果你那时候还能让你的系统编译通过的话。 我们(在亚马逊，译者注)有五千万行C++代码。不，现在还要更多了。我已经不知道有多少行了。上个圣诞节是五千万行，那是九个月前，而它以每季度八百万行的规模增长。增长率本身也增长，妈呀。 我们想这个系统里干点啥好像要一万年。一个亚马逊工程师有一次这样描述我们的代码库：“一座很大的屎山，你见过的最大的山，每次你想修正一个bug，你的工作就是爬到屎山的正中心去。” 伙计们，那哥们可是在四年前说的这话。他现在已经到更环保绿色的牧场上去了。真是太可惜了，他可是个实实在在的高手啊。 这都是C++的错。别跟我争论。就是的。我们用的是世上最蠢的语言。这简直有点老板级的蠢，你说呢? (译者注，meta在计算机术语里通常表示更高一个层次，比如，meta-language，比普通的language高一个层次，意思是关于语言的语言。哲学里应该会经常用到这个词。我不懂哲学，但是我觉得老板们总是比我们高一级，所以meta-dump我就翻译成老板级的蠢喽。：-) 说了以上这些难听的话，话得说回来了。用C++写出漂亮的代码显然是可以的，我的意思是说，这样的代码应该大部分还是C，偶尔很有品味的，很有节制的用一点C++。但是这种代码几乎从来不会被写出来。C++是个很好玩的游乐场，而如果你把它玩儿得门儿清的话你会觉得自己特牛，所以你总是被诱惑把你知道的所有的东西都用上。但是那是很难做好的，因为从一开始这个语言就太狗屎了，最终，你会弄得一塌糊涂，即使你很能干。 我知道，我说的都是异端邪说，该被钉到十字架上的。随便吧。我在大学里的时候老喜欢C++了，因为我那时候就只知道这一门语言。当我听到我的语言教授，Craig Chambers，绝对的厌憎C++，我想：“为啥呢? 我觉得它挺好的啊”。而当我听到STL(标准模板库)的发明者被采访时说他恨OOP(面向对象编程)时，我更是认为他肯定是磕药了。怎么会有人恨OOP呢，而这个人竟然还是STL的发明者? 亲不敬，熟生厌(语出圣经，译者注)。说的是在大多数情况下，跟一件事物熟悉了之后你就失去对它的膜拜尊敬了; 在计算机语言里情况不是这样的。光对一门语言熟悉不会导致你看轻这门语言。你必须成为另一门更优秀的语言的专家(才能让你明白原来那门语言有多么多的问题)。 所以如果你不喜欢我针对C++大放厥词，请你去学另一门语言并成为一个专家(我推荐Lisp)，只有那时你才有足够的武器与我争论。然而，那时你将不会跟我争了。你上了我的当了。你也会跟我一样变得不喜欢C++了，你或许会觉得我这个人很恶心，把你骗得不喜欢自己曾经的最爱了。所以或许你应该把我说的一切都忘了。C++挺好的其实，真的。它就是很棒棒(译者注，作者在这里用了ducky，这是一个女性喜欢用的夸某物好的词，近来也为玻璃们喜爱)。忘了我说的话。C++不错的。 Lisp (我打赌这一节会让你觉得惊讶，即使你已经关注我的博客有一阵了 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/635248026/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248026/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>技术资料</category><pubDate>Tue, 24 Apr 2012 10:27:37 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2012/04/tour-de-babel.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652726</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2012/04/tour-de-babel.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248026/1234636</fs:itemid></item><item><title>2012 dtcc 中数据库大会的讲稿分享</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248027/1234636/1/item.html</link><content:encoded>&lt;div id=&quot;__ss_12544337&quot; style=&quot;width: 425px&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;width: 425px&quot;&gt;2012年4月15号，中国数据库大会，&lt;a title=&quot;我在中国数据库大会，NoSQL专场的介绍&quot; href=&quot;http://dtcc.it168.com/3.html#tangfl&quot; target=&quot;_blank&quot;&gt;NoSQL 专场&lt;/a&gt;，我的《Redis 大数据之路》的分享讲稿。更多讨论，欢迎在微博上找我： http://weibo.com/tangfl&lt;/div&gt;
&lt;div style=&quot;width: 425px&quot;&gt;&lt;/div&gt;
&lt;div style=&quot;width: 425px&quot;&gt;&lt;strong&gt;&lt;a title=&quot;Redis大数据之路 dtcc-唐福林&quot; href=&quot;http://www.slideshare.net/tangfl/redis-dtcc&quot; target=&quot;_blank&quot;&gt;Redis大数据之路 dtcc-唐福林&lt;/a&gt;&lt;/strong&gt; &lt;iframe src=&quot;http://www.slideshare.net/slideshow/embed_code/12544337&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;div id=&quot;__ss_12544337&quot; style=&quot;width: 425px&quot;&gt;
&lt;div style=&quot;padding: 5px 0 12px&quot;&gt;View more &lt;a href=&quot;http://www.slideshare.net/&quot; target=&quot;_blank&quot;&gt;presentations&lt;/a&gt; from &lt;a href=&quot;http://www.slideshare.net/tangfl&quot; target=&quot;_blank&quot;&gt;fulin tang&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2012%2F04%2F2012dtcc_redis_bigdata.html&amp;title=2012+dtcc+%E4%B8%AD%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%A7%E4%BC%9A%E7%9A%84%E8%AE%B2%E7%A8%BF%E5%88%86%E4%BA%AB&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248027/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248027/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2012/04/2012dtcc_redis_bigdata.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>2012年4月15号，中国数据库大会，NoSQL 专场，我的《Redis 大数据之路》的分享讲稿。更多讨论，欢迎在微博上找我： http://weibo.com/tangfl Redis大数据之路 dtcc-唐福林 View more presentations from fulin tang&lt;img src=&quot;http://www1.feedsky.com/t1/635248027/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248027/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>工作日志</category><pubDate>Sun, 15 Apr 2012 15:00:10 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2012/04/2012dtcc_redis_bigdata.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652723</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2012/04/2012dtcc_redis_bigdata.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248027/1234636</fs:itemid></item><item><title>转：服务治理过程演进</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248028/1234636/1/item.html</link><content:encoded>&lt;p&gt;在大规模服务化之前，应用可能只是通过RMI或Hessian等工具，简单的暴露和引用远程服务，通过配置服务的URL地址进行调用，通过F5等硬件进行负载均衡。&lt;/p&gt;
&lt;p&gt;(1) 当服务越来越多时，服务URL配置管理变得非常困难，F5硬件负载均衡器的单点压力也越来越大。&lt;/p&gt;
&lt;p&gt;此时需要一个服务注册中心，动态的注册和发现服务，使服务的位置透明。&lt;/p&gt;
&lt;p&gt;并通过在消费方获取服务提供方地址列表，实现软负载均衡和Failover，降低对F5硬件负载均衡器的依赖，也能减少部分成本。&lt;/p&gt;
&lt;p&gt;(2) 当进一步发展，服务间依赖关系变得错踪复杂，甚至分不清哪个应用要在哪个应用之前启动，架构师都不能完整的描述应用的架构关系。&lt;/p&gt;
&lt;p&gt;这时，需要自动画出应用间的依赖关系图，以帮助架构师理清理关系。&lt;/p&gt;
&lt;p&gt;(3) 接着，服务的调用量越来越大，服务的容量问题就暴露出来，这个服务需要多少机器支撑？什么时候该加机器？&lt;/p&gt;
&lt;p&gt;为了解决这些问题，第一步，要将服务现在每天的调用量，响应时间，都统计出来，作为容量规划的参考指标。&lt;/p&gt;
&lt;p&gt;其次，要可以动态调整权重，在线上，将某台机器的权重一直加大，并在加大的过程中记录响应时间的变化，直到响应时间到达阀值，记录此时的访问量，再以此访问量乘以机器数反推总容量。&lt;/p&gt;
&lt;p&gt;(4) 规模继续扩大，应用之间不再是扁平的对应关系，开始分层，比如核心数据层，业务集成层等，就算没有出现循环依赖，也不允许从低层向高层依赖，以免后续被逼循环依赖。&lt;/p&gt;
&lt;p&gt;这时，需要在注册中心定义架构体系，列明有哪些层的定义，每个服务暴露或引用时，都必须声明自己应用属于哪一层，这样注册中心能更快的发现架构的腐化现象。&lt;/p&gt;
&lt;p&gt;(5) 服务多了，沟通成本也开始上升，调某个服务失败该找谁？服务的参数都有什么约定？&lt;/p&gt;
&lt;p&gt;这时就需要登记每个服务都是谁负责的，并建立一个服务的文档库，方便检索。&lt;/p&gt;
&lt;p&gt;(6) 慢慢一些敏感数据也都服务化了，安全问题开始变得重要，谁能调该服务？如何授权？&lt;/p&gt;
&lt;p&gt;这样的服务可能需要一个密码，访问时需带着此密码，但如果用密码，要改密码时，就会很不方便，所有的消费方都要改，所以动态生成令牌(Token)可能会更好，提供方将令牌告之注册中心，由注册中心决定是否告之消费方，这样就能在注册中心页面上做复杂的授权模型。&lt;/p&gt;
&lt;p&gt;(7) 就算是不敏感的服务，也不是能任意调用，比如某服务突然多了一个消费者，这个消费者的请求量直接把服务给拖跨了，其它消费者跟着一起故障。&lt;/p&gt;
&lt;p&gt;首先服务提供方需要流控，当流程超标时，能拒绝部分请求，进行自我保护。&lt;/p&gt;
&lt;p&gt;其次，消费者上线前和提供者约定《服务质量等级协定(SLA)》，SLA包括消费者承诺每天调用量，请求数据量，提供方承诺响应时间，出错率等，将SLA记录在监控中心，定时与监控数据对比，超标则报警。&lt;/p&gt;
&lt;p&gt;(8) 虽然有SLA约定，如果不能控制，就只是君子协定，如何确保服务质量？&lt;/p&gt;
&lt;p&gt;比如：一个应用很重要，一个不那么重要，它们调用同一个服务，这个服务就应该向重要应用倾斜，而不是一视同仁，当支撑不住时，应限制不重要应用的访问，保障重要应用的可用，如何做到这一点呢。这时，就需要服务路由，控制不同应用访问不同机器，比如：&lt;br /&gt;
应用分离：&lt;br /&gt;
consumer.application = foo =&amp;gt; provider.host = 1,2,3&lt;br /&gt;
consumer.application != foo =&amp;gt; provider.host = 5,6&lt;br /&gt;
读写分离：&lt;br /&gt;
method.name = find*,get* =&amp;gt; provider.host = 1,2,3&lt;br /&gt;
method.name != find*,get* =&amp;gt; provider.host = 5,6&lt;/p&gt;
&lt;p&gt;(9) 服务上线后，需要验证服务是否可用，但因防火墙的限制，线下是不能访问线上服务的，不得不先写好一个测试Main，然后放到线上去执行，非常麻烦，并且容易忘记验证。&lt;/p&gt;
&lt;p&gt;所以线上需要有一个自动运行的验证程序，用户只需在界面上填上要验证的服务方法，以及参数值和期望的返回值，当有一个服务提供者上线时，将自动运行该用例，并将运行结果发邮件通知负责人。&lt;/p&gt;
&lt;p&gt;(10) 服务应用和Web应用是有区别的，它是一个后台Daemon程序，不需要Tomcat之类的Web容器。但因公司之前以Web应用为主，规范都是按Web应用的，所以不得不把服务跑在一个根本用不上的Web容器里，而搭一个这样的Web工程也非常费事。&lt;/p&gt;
&lt;p&gt;所以需要实现一个非Web的容器，只需简单的Main加载Spring配置即可，并提供Maven模板工程，只需mvn dubbo:generate 即可创建一个五脏俱全的服务应用。&lt;/p&gt;
&lt;p&gt;(11) 开发服务的人越来越多，更注重开发效率，IDE的集成支持必不可少。&lt;/p&gt;
&lt;p&gt;通过插件，可以在Eclipse中直接运行服务，提供方可以直接填入测试数据测试服务，消费方可以直接Mock服务不依赖提供方开发。&lt;/p&gt;
&lt;p&gt;(12) 因为暴露服务很简单，服务的上线越来越随意，有时候负责服务化的架构师都不知道有人上线了某个服务，使得线上服务鱼龙混杂，甚至出现重复的服务，而服务下线比上线还困难。&lt;/p&gt;
&lt;p&gt;需要一个新服务上线审批流程，必须经过服务化的架构师审批过了，才可以上线。&lt;/p&gt;
&lt;p&gt;而服务下线时，应先标识为过时，然后通知调用方尽快修改调用，直到没有人调此服务，才能下线。&lt;/p&gt;
&lt;p&gt;(13) 因服务接口设计的经验一直在慢慢的积累过程中，很多接口并不能一促而蹴，在修改的过程中，如何保证兼容性，怎么判断是否兼容？另外，更深层次的，业务行为兼容吗？&lt;/p&gt;
&lt;p&gt;可以根据使用的协议类型，分析接口及领域模型的变更是否兼容，比如：对比加减字段，方法签名等。&lt;/p&gt;
&lt;p&gt;而业务上，可能需要基于自动回归测试用例，形成Technology Compatibility Kit (TCK)，确保兼容升级。&lt;/p&gt;
&lt;p&gt;(14) 随着服务的不停升级，总有些意想不到的事发生，比如cache写错了导致内存溢出，故障不可避免，每次核心服务一挂，影响一大片，人心慌慌，如何控制故障的影响面？服务是否可以功能降级？或者资源劣化？&lt;/p&gt;
&lt;p&gt;应用间声明依赖强度，哪些功能强依赖，哪些弱依赖，然后基于依赖强度，计算出影响面，并定期测试复查，加强关键路径上的服务的优化和容错，清理不该在关键路径上的服务。&lt;/p&gt;
&lt;p&gt;提供容错Mock数据，Mock数据也应可以在注册中心在运行时动态下发，当某服务不可用时，用Mock数据代替，可以减少故障的发生，比如某验权服务，当验权服务全部挂掉后，直接返回false表示没有权限，并打印Error日志报警。&lt;/p&gt;
&lt;p&gt;另外，前端的页面也应采用Portal进行降级，当该Portal获取不到数据时，直接隐藏，或替换为其它模块展示，并提供功能开关，可人工干预是否展示，或限制多少流量可以展示。&lt;/p&gt;
&lt;p&gt;(15) 当已有很多小服务，可能就需要组合多个小服务的大服务，为此，不得不增加一个中间层，暴露一个新服务，里面分别调其它小服务，这样的新服务业务逻辑少，却带来很多开发工作量。&lt;/p&gt;
&lt;p&gt;此时，需要一个服务编排引擎，内置简单的流程引擎，只需用XML或DSL声明如何聚合服务，注册中心可以直接下发给消费者执行聚合逻辑，或者部署通用的编排服务器，所有请求有编排服务器转发。&lt;/p&gt;
&lt;p&gt;(16) 并不是所有服务的访问量都大，很多的服务都只有一丁点访问量，却需要部署两台提供服务的机器，进行HA互备，如何减少浪费的机器。&lt;/p&gt;
&lt;p&gt;此时可能需要让服务容器支持在一台机器上部署多个应用，可以用多JVM隔离，也可以用ClassLoader隔离。&lt;/p&gt;
&lt;p&gt;(17) 多个应用如果不是一个团队开发的，部署在一台机器上，很有可以误操作，停掉了别人的服务。&lt;/p&gt;
&lt;p&gt;所以需要实现自动部署，所有的部署都无需人工干扰，最好是一键式部署。&lt;/p&gt;
&lt;p&gt;(18) 机器总是的闲时和忙时，或者冗余机器防灾，如何提高机器的利用率？&lt;/p&gt;
&lt;p&gt;即然已经可以自动部署了，那根据监控数据，就可以实现资源调度，根据应用的压力情况，自动添加机器并部署。&lt;/p&gt;
&lt;p&gt;如果你的应用是国际化的，有中文站，美国站之类，因为时差，美国站的机器晚上闲的时候，可能正是中文站的白天忙时，可以通过资源调度，分时段自动调配和部署双方应用。&lt;/p&gt;
&lt;p&gt;按关键词归纳为：&lt;/p&gt;
&lt;p&gt;1. 服务注册与发现&lt;/p&gt;
&lt;p&gt;2. 软负载均衡与容错&lt;/p&gt;
&lt;p&gt;3. 服务监控与统计&lt;/p&gt;
&lt;p&gt;4. 服务容量评估&lt;/p&gt;
&lt;p&gt;5. 服务上线审批&lt;/p&gt;
&lt;p&gt;6. 服务下线通知&lt;/p&gt;
&lt;p&gt;7. 服务负责人&lt;/p&gt;
&lt;p&gt;8. 服务文档&lt;/p&gt;
&lt;p&gt;9. 服务路由&lt;/p&gt;
&lt;p&gt;10. 服务编排&lt;/p&gt;
&lt;p&gt;11. 服务黑白名单&lt;/p&gt;
&lt;p&gt;12. 服务权限控制&lt;/p&gt;
&lt;p&gt;13. 服务依赖关系&lt;/p&gt;
&lt;p&gt;14. 服务分层架构&lt;/p&gt;
&lt;p&gt;15. 服务调用链跟踪&lt;/p&gt;
&lt;p&gt;16. 故障传导分析&lt;/p&gt;
&lt;p&gt;17. 服务降级&lt;/p&gt;
&lt;p&gt;18. 服务等级协定&lt;/p&gt;
&lt;p&gt;19. 服务自动测试&lt;/p&gt;
&lt;p&gt;20. 服务伪装容错&lt;/p&gt;
&lt;p&gt;21. 服务兼容性检测&lt;/p&gt;
&lt;p&gt;22. 服务使用情况报告&lt;/p&gt;
&lt;p&gt;23. 服务权重动态调整&lt;/p&gt;
&lt;p&gt;24. 服务负载均衡调整&lt;/p&gt;
&lt;p&gt;25. 服务映射&lt;/p&gt;
&lt;p&gt;26. 服务模板工程&lt;/p&gt;
&lt;p&gt;27. 服务开发IDE&lt;/p&gt;
&lt;p&gt;28. 服务健康检测&lt;/p&gt;
&lt;p&gt;29. 服务容器&lt;/p&gt;
&lt;p&gt;30. 服务自动部署&lt;/p&gt;
&lt;p&gt;31. 服务资源调度&lt;/p&gt;
&lt;p&gt;转自：http://javatar.iteye.com/blog/1345073&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2012%2F03%2Fservice-management.html&amp;title=%E8%BD%AC%EF%BC%9A%E6%9C%8D%E5%8A%A1%E6%B2%BB%E7%90%86%E8%BF%87%E7%A8%8B%E6%BC%94%E8%BF%9B&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248028/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248028/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2012/03/service-management.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>在大规模服务化之前，应用可能只是通过RMI或Hessian等工具，简单的暴露和引用远程服务，通过配置服务的URL地址进行调用，通过F5等硬件进行负载均衡。 (1) 当服务越来越多时，服务URL配置管理变得非常困难，F5硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心，动态的注册和发现服务，使服务的位置透明。 并通过在消费方获取服务提供方地址列表，实现软负载均衡和Failover，降低对F5硬件负载均衡器的依赖，也能减少部分成本。 (2) 当进一步发展，服务间依赖关系变得错踪复杂，甚至分不清哪个应用要在哪个应用之前启动，架构师都不能完整的描述应用的架构关系。 这时，需要自动画出应用间的依赖关系图，以帮助架构师理清理关系。 (3) 接着，服务的调用量越来越大，服务的容量问题就暴露出来，这个服务需要多少机器支撑？什么时候该加机器？ 为了解决这些问题，第一步，要将服务现在每天的调用量，响应时间，都统计出来，作为容量规划的参考指标。 其次，要可以动态调整权重，在线上，将某台机器的权重一直加大，并在加大的过程中记录响应时间的变化，直到响应时间到达阀值，记录此时的访问量，再以此访问量乘以机器数反推总容量。 (4) 规模继续扩大，应用之间不再是扁平的对应关系，开始分层，比如核心数据层，业务集成层等，就算没有出现循环依赖，也不允许从低层向高层依赖，以免后续被逼循环依赖。 这时，需要在注册中心定义架构体系，列明有哪些层的定义，每个服务暴露或引用时，都必须声明自己应用属于哪一层，这样注册中心能更快的发现架构的腐化现象。 (5) 服务多了，沟通成本也开始上升，调某个服务失败该找谁？服务的参数都有什么约定？ 这时就需要登记每个服务都是谁负责的，并建立一个服务的文档库，方便检索。 (6) 慢慢一些敏感数据也都服务化了，安全问题开始变得重要，谁能调该服务？如何授权？ 这样的服务可能需要一个密码，访问时需带着此密码，但如果用密码，要改密码时，就会很不方便，所有的消费方都要改，所以动态生成令牌(Token)可能会更好，提供方将令牌告之注册中心，由注册中心决定是否告之消费方，这样就能在注册中心页面上做复杂的授权模型。 (7) 就算是不敏感的服务，也不是能任意调用，比如某服务突然多了一个消费者，这个消费者的请求量直接把服务给拖跨了，其它消费者跟着一起故障。 首先服务提供方需要流控，当流程超标时，能拒绝部分请求，进行自我保护。 其次，消费者上线前和提供者约定《服务质量等级协定(SLA)》，SLA包括消费者承诺每天调用量，请求数据量，提供方承诺响应时间，出错率等，将SLA记录在监控中心，定时与监控数据对比，超标则报警。 (8) 虽然有SLA约定，如果不能控制，就只是君子协定，如何确保服务质量？ 比如：一个应用很重要，一个不那么重要，它们调用同一个服务，这个服务就应该向重要应用倾斜，而不是一视同仁，当支撑不住时，应限制不重要应用的访问，保障重要应用的可用，如何做到这一点呢。这时，就需要服务路由，控制不同应用访问不同机器，比如： 应用分离： consumer.application = foo =&amp;#62; provider.host = 1,2,3 consumer.application != foo =&amp;#62; provider.host = 5,6 读写分离： method.name = find*,get* =&amp;#62; provider.host = 1,2,3 method.name != find*,get* =&amp;#62; [...]&lt;img src=&quot;http://www1.feedsky.com/t1/635248028/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248028/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>技术资料</category><pubDate>Mon, 26 Mar 2012 17:44:33 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2012/03/service-management.html#comments</comments><guid isPermaLink="false">http://blog.fulin.org/?p=652719</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2012/03/service-management.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248028/1234636</fs:itemid></item><item><title>转：Tumblr：150亿月浏览量背后的架构挑战</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248029/1234636/1/item.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;导读：&lt;/strong&gt;和许多新兴的网站一样，著名的轻博客服务Tumblr在急速发展中面临了系统架构的瓶颈。每天5亿次浏览量，峰值每秒4万次请求，每天3TB新的数据存储，超过1000台服务器，这样的情况下如何保证老系统平稳运行，平稳过渡到新的系统，Tumblr正面临巨大的挑战。近日，HighScalability网站的Todd Hoff采访了该公司的分布式系统工程师Blake Matheny，&lt;a href=&quot;http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;撰文系统介绍了网站的架构&lt;/a&gt;，内容很有价值。&lt;/p&gt;
&lt;p&gt;Tumblr每月页面浏览量超过150亿次，已经成为火爆的博客社区。用户也许喜欢它的简约、美丽，对用户体验的强烈关注，或是友好而忙碌的沟通方式，总之，它深得人们的喜爱。&lt;/p&gt;
&lt;p&gt;每月超过30%的增长当然不可能没有挑战，其中可靠性问题尤为艰巨。每天5亿次浏览量，峰值每秒4万次请求，每天3TB新的数据存储，并运行于超过1000台服务器上，所有这些帮助Tumblr实现巨大的经营规模。&lt;/p&gt;
&lt;p&gt;创业公司迈向成功，都要迈过危险的迅速发展期这道门槛。寻找人才，不断改造基础架构，维护旧的架构，同时要面对逐月大增的流量，而且曾经只有4位工程师。这意味着必须艰难地选择应该做什么，不该做什么。这就是Tumblr的状况。好在现在已经有20位工程师了，可以有精力解决问题，并开发一些有意思的解决方案。&lt;/p&gt;
&lt;p&gt;Tumblr最开始是非常典型的LAMP应用。目前正在向分布式服务模型演进，该模型基于&lt;a href=&quot;http://www.scala-lang.org/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Scala&lt;/a&gt;、&lt;a href=&quot;http://hbase.apache.org/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;HBase&lt;/a&gt;、&lt;a href=&quot;http://redis.io/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Redis&lt;/a&gt;（著名开源K-V存储方案）、&lt;a href=&quot;http://incubator.apache.org/kafka/index.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Kafka&lt;/a&gt;（Apache项目，出自LinkedIn的分布式发布-订阅消息系统）、&lt;a href=&quot;http://twitter.github.com/finagle/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Finagle&lt;/a&gt;（由Twitter开源的容错、协议中立的RPC系统），此外还有一个有趣的基于Cell的架构，用来支持Dashboard（CSDN注：Tumblr富有特色的用户界面，类似于微博的时间轴）。&lt;/p&gt;
&lt;p&gt;Tumblr目前的最大问题是如何改造为一个大规模网站。系统架构正在从LAMP演进为最先进的技术组合，同时团队也要从小的创业型发展为全副武装、随时待命的正规开发团队，不断创造出新的功能和基础设施。下面就是Blake Matheny对Tumblr系统架构情况的介绍。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;网站地址&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.tumblr.com/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;http://www.tumblr.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;主要数据&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;▲每天5亿次PV（页面访问量）&lt;/p&gt;
&lt;p&gt;▲每月超过150亿PV&lt;/p&gt;
&lt;p&gt;▲约20名工程师&lt;/p&gt;
&lt;p&gt;▲ 峰值请求每秒近4万次&lt;/p&gt;
&lt;p&gt;▲每天超过1TB数据进入Hadoop集群&lt;/p&gt;
&lt;p&gt;▲ MySQL/HBase/Redis/memcache每天生成若干TB数据&lt;/p&gt;
&lt;p&gt;▲每月增长30%&lt;/p&gt;
&lt;p&gt;▲近1000硬件节点用于生产环境&lt;/p&gt;
&lt;p&gt;▲平均每位工程师每月负责数以亿计的页面访问&lt;/p&gt;
&lt;p&gt;▲每天上传大约50GB的文章，每天跟帖更新数据大约2.7TB（CSDN注：这两个数据的比例看上去不太合理，据&lt;a href=&quot;https://twitter.com/#!/adamlaiacano/status/169140791732740096&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Tumblr数据科学家Adam Laiacano在Twitter上解释&lt;/a&gt;，前一个数据应该指的是文章的文本内容和元数据，不包括存储在S3上的多媒体内容）&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;软件环境&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;▲开发使用OS X，生产环境使用Linux（CentOS/Scientific）&lt;/p&gt;
&lt;p&gt;▲Apache&lt;/p&gt;
&lt;p&gt;▲PHP, Scala, Ruby&lt;/p&gt;
&lt;p&gt;▲Redis, HBase, MySQL&lt;/p&gt;
&lt;p&gt;▲&lt;a href=&quot;https://www.varnish-cache.org/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Varnish&lt;/a&gt;, &lt;a href=&quot;http://haproxy.1wt.eu/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;HAProxy&lt;/a&gt;, nginx&lt;/p&gt;
&lt;p&gt;▲memcache, &lt;a href=&quot;http://gearman.org/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Gearman&lt;/a&gt;（支持多语言的任务分发应用框架）, Kafka, &lt;a href=&quot;https://github.com/robey/kestrel&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Kestrel&lt;/a&gt;（Twitter开源的分布式消息队列系统）, Finagle&lt;/p&gt;
&lt;p&gt;▲ Thrift, HTTP&lt;/p&gt;
&lt;p&gt;▲&lt;a href=&quot;http://func.et.redhat.com/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Func&lt;/a&gt;——一个安全、支持脚本的远程控制框架和API&lt;/p&gt;
&lt;p&gt;▲ Git, Capistrano（多服务器脚本部署工具）, Puppet, Jenkins&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;硬件环境&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲500台Web服务器&lt;/p&gt;
&lt;p&gt;▲200台数据库服务器（47 pool，20 shard）&lt;/p&gt;
&lt;p&gt;▲30台memcache服务器&lt;/p&gt;
&lt;p&gt;▲22台Redis服务器&lt;/p&gt;
&lt;p&gt;▲15台Varnish服务器&lt;/p&gt;
&lt;p&gt;▲25台HAproxy节点&lt;/p&gt;
&lt;p&gt;▲8台nginx服务器&lt;/p&gt;
&lt;p&gt;▲14台工作队列服务器（Kestrel + Gearman）&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;架构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt; 1. 相对其他社交网站而言，Tumblr有其独特的使用模式：&lt;/p&gt;
&lt;p&gt;▲每天有超过5千万篇文章更新，平均每篇文章的跟帖又数以百计。用户一般只有数百个粉丝。这与其他社会化网站里少数用户有几百万粉丝非常不同，使得Tumblr的扩展性极具挑战性。&lt;/p&gt;
&lt;p&gt;▲按用户使用时间衡量，Tumblr已经是排名第二的社会化网站。内容的吸引力很强，有很多图片和视频，文章往往不短，一般也不会太长，但允许写得很长。文章内容往往比较深入，用户会花费更长的时间来阅读。&lt;/p&gt;
&lt;p&gt;▲用户与其他用户建立联系后，可能会在Dashboard上往回翻几百页逐篇阅读，这与其他网站基本上只是部分信息流不同。&lt;/p&gt;
&lt;p&gt;▲用户的数量庞大，用户的平均到达范围更广，用户较频繁的发帖，这些都意味着有巨量的更新需要处理。&lt;/p&gt;
&lt;p&gt;2. Tumblr目前运行在一个托管数据中心中，已在考虑地域上的分布性。&lt;/p&gt;
&lt;p&gt;3. Tumblr作为一个平台，由两个组件构成：公共Tumblelogs和Dashboard&lt;/p&gt;
&lt;p&gt;▲公共Tumblelogs与博客类似（此句请Tumblr用户校正），并非动态，易于缓存&lt;/p&gt;
&lt;p&gt;▲Dashboard是类似于Twitter的时间轴,用户由此可以看到自己关注的所有用户的实时更新。与博客的扩展性不同，缓存作用不大，因为每次请求都不同，尤其是活跃的关注者。而且需要实时而且一致，文章每天仅更新50GB，跟帖每天更新2.7TB，所有的多媒体数据都存储在S3上面。&lt;/p&gt;
&lt;p&gt;▲大多数用户以Tumblr作为内容浏览工具，每天浏览超过5亿个页面，70%的浏览来自Dashboard。&lt;/p&gt;
&lt;p&gt;▲Dashboard的可用性已经不错，但Tumblelog一直不够好，因为基础设施是老的，而且很难迁移。由于人手不足，一时半会儿还顾不上。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;老的架构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Tumblr最开始是托管在Rackspace上的，每个自定义域名的博客都有一个A记录。当2007年Rackspace无法满足其发展速度不得不迁移时，大量的用户都需要同时迁移。所以他们不得不将自定义域名保留在Rackspace，然后再使用HAProxy和Varnish路由到新的数据中心。类似这样的遗留问题很多。&lt;/p&gt;
&lt;p&gt;开始的架构演进是典型的LAMP路线：&lt;/p&gt;
&lt;p&gt;▲最初用PHP开发，几乎所有&lt;a title=&quot;程序员的本质&quot; href=&quot;http://blog.jobbole.com/821/&quot;&gt;程序员&lt;/a&gt;都用PHP&lt;/p&gt;
&lt;p&gt;▲最初是三台服务器：一台Web，一台数据库，一台PHP&lt;/p&gt;
&lt;p&gt;▲为了扩展，开始使用memcache，然后引入前端cache，然后在cache前再加HAProxy，然后是MySQL sharding（非常奏效）&lt;/p&gt;
&lt;p&gt;▲采用“在单台服务器上榨出一切”的方式。过去一年已经用C开发了两个后端服务：&lt;a href=&quot;http://engineering.tumblr.com/post/10996371189/blake-matheny-id-generation-at-scale&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;ID生成程序&lt;/a&gt;和&lt;a href=&quot;http://engineering.tumblr.com/post/7819252942/staircar-redis-powered-notifications&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Staircar&lt;/a&gt;（用Redis支持Dashboard通知）&lt;/p&gt;
&lt;p&gt;Dashboard采用了“扩散-收集”方式。当用户访问Dashboard时将显示事件，来自所关注的用户的事件是通过拉然后显示的。这样支撑了6个月。由于数据是按时间排序的，因此sharding模式不太管用。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;新的架构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;▲由于招人和开发速度等原因，改为&lt;strong&gt;以JVM为中心&lt;/strong&gt;。目标是将一切从PHP应用改为服务，使应用变成请求鉴别、呈现等诸多服务之上的薄层。&lt;/p&gt;
&lt;p&gt;▲这其中，非常重要的是&lt;strong&gt;选用了Scala和Finagle&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;▲在团队内部有很多人具备Ruby和PHP经验，所以Scala很有吸引力。&lt;/p&gt;
&lt;p&gt;▲Finagle是选择Scala的重要因素之一。这个来自Twitter的库可以解决大多数分布式问题，比如分布式跟踪、服务发现、服务注册等。&lt;/p&gt;
&lt;p&gt;▲转到JVM上之后，Finagle提供了团队所需的所有基本功能（Thrift, ZooKeeper等），无需再开发许多网络代码，另外，团队成员认识该项目的一些开发者。&lt;/p&gt;
&lt;p&gt;▲Foursquare和Twitter都在用Finagle，Meetup也在用Scala。&lt;/p&gt;
&lt;p&gt;▲应用接口与Thrift类似，性能极佳。&lt;/p&gt;
&lt;p&gt;▲团队本来很喜欢&lt;a href=&quot;http://netty.io/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Netty&lt;/a&gt;（Java异步网络应用框架，2月4日刚刚发布3.3.1最终版），但不想用Java，Scala是不错的选择。&lt;/p&gt;
&lt;p&gt;▲选择Finagle是因为它很酷，还认识几个开发者。&lt;/p&gt;
&lt;p&gt;之所以&lt;strong&gt;没有选择Node.js&lt;/strong&gt;，是因为以JVM为基础更容易扩展。Node的发展为时尚短，缺乏标准、最佳实践以及大量久经测试的代码。而用Scala的话，可以使用所有Java代码。虽然其中并没有多少可扩展的东西，也无法解决5毫秒响应时间、49秒HA、4万每秒请求甚至有时每秒40万次请求的问题。但是，Java的生态链要大得多，有很多资源可以利用。&lt;/p&gt;
&lt;p&gt;内部服务从C/libevent为基础正在转向Scala/Finagle为基础。&lt;/p&gt;
&lt;p&gt;开始采用新的&lt;strong&gt;NoSQL存储方案&lt;/strong&gt;如HBase和Redis。但大量数据仍然存储在大量分区的MySQL架构中，并没有用HBase代替MySQL。HBase主要支持短地址生产程序（数以十亿计）还有历史数据和分析，非常结实。此外，HBase也用于高写入需求场景，比如Dashboard刷新时一秒上百万的写入。之所以还没有替换HBase，是因为不能冒业务上风险，目前还是依靠人来负责更保险，先在一些小的、不那么关键的项目中应用，以获得经验。MySQL和时间序列数据sharding（分片）的问题在于，总有一个分片太热。另外，由于要在slave上插入并发，也会遇到读复制延迟问题。&lt;/p&gt;
&lt;p&gt;此外，还开发了一个&lt;strong&gt;公用服务框架&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;▲花了很多时间解决分布式系统管理这个运维问题。&lt;/p&gt;
&lt;p&gt;▲为服务开发了一种Rails scaffolding，内部用模板来启动服务。&lt;/p&gt;
&lt;p&gt;▲所有服务从运维的角度来看都是一样的，所有服务检查统计数据、监控、启动和停止的方式都一样。&lt;/p&gt;
&lt;p&gt;▲工具方面，构建过程围绕&lt;a href=&quot;https://github.com/harrah/xsbt/wiki&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;SBT&lt;/a&gt;（一个Scala构建工具），使用插件和辅助程序管理常见操作，包括在Git里打标签，发布到代码库等等。大多数程序员都不用再操心构建系统的细节了。&lt;/p&gt;
&lt;p&gt;200台&lt;strong&gt;数据库服务器&lt;/strong&gt;中，很多是为了提高可用性而设，使用的是常规硬件，但MTBF（平均故障间隔时间）极低。故障时，备用充足。&lt;/p&gt;
&lt;p&gt;为了支持PHP应用有6个&lt;strong&gt;后端服务&lt;/strong&gt;，并有一个小组专门开发后端服务。新服务的发布需要两到三周，包括Dashboard通知、Dashboard二级索引、短地址生成、处理透明分片的memcache代理。其中在MySQL分片上耗时很多。虽然在纽约本地非常热，但并没有使用MongoDB，他们认为MySQL的可扩展性足够了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gearman&lt;/strong&gt;用于会长期运行无需人工干预的工作。&lt;/p&gt;
&lt;p&gt;可用性是以达到范围（reach）衡量的。用户能够访问自定义域或者Dashboard吗？也会用错误率。&lt;/p&gt;
&lt;p&gt;历史上总是解决那些最高优先级的问题，而现在会对故障模式系统地分析和解决，目的是从用户和应用的角度来定成功指标。（后一句原文似乎不全）&lt;/p&gt;
&lt;p&gt;最开始Finagle是用于Actor模型的，但是后来放弃了。对于运行后无需人工干预的工作，使用任务队列。而且Twitter的&lt;a href=&quot;http://twitter.github.com/util/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;util工具库&lt;/a&gt;中有Future实现，服务都是用Future（Scala中的无参数函数，在与函数关联的并行操作没有完成时，会阻塞调用方）实现的。当需要线程池的时候，就将Future传入Future池。一切都提交到Future池进行异步执行。&lt;/p&gt;
&lt;p&gt;Scala提倡无共享状态。由于已经在Twitter生产环境中经过测试，Finagle这方面应该是没有问题的。使用Scala和Finagle中的结构需要避免可变状态，不使用长期运行的状态机。状态从数据库中拉出、使用再写回数据库。这样做的好处是，开发人员不需要操心线程和锁。&lt;/p&gt;
&lt;p&gt;22台&lt;strong&gt;Redis&lt;/strong&gt;服务器，每台的都有8-32个实例，因此线上同时使用了100多个Redis实例。&lt;/p&gt;
&lt;p&gt;▲Redis主要用于Dashboard通知的后端存储。&lt;/p&gt;
&lt;p&gt;▲所谓通知就是指某个用户like了某篇文章这样的事件。通知会在用户的Dashboard中显示，告诉他其他用户对其内容做了哪些操作。&lt;/p&gt;
&lt;p&gt;▲高写入率使MySQL无法应对。&lt;/p&gt;
&lt;p&gt;▲通知转瞬即逝，所以即使遗漏也不会有严重问题，因此Redis是这一场景的合适选择。&lt;/p&gt;
&lt;p&gt;▲这也给了开发团队了解Redis的机会。&lt;/p&gt;
&lt;p&gt;▲使用中完全没有发现Redis有任何问题，社区也非常棒。&lt;/p&gt;
&lt;p&gt;▲开发了一个基于Scala Futures的Redis接口，该功能现在已经并入了Cell架构。&lt;/p&gt;
&lt;p&gt;▲短地址生成程序使用Redis作为一级Cache，HBase作为永久存储。&lt;/p&gt;
&lt;p&gt;▲Dashboard的二级索引是以Redis为基础开发的。&lt;/p&gt;
&lt;p&gt;▲Redis还用作Gearman的持久存储层，使用Finagle开发的memcache代理。&lt;/p&gt;
&lt;p&gt;▲正在缓慢地从memcache转向Redis。希望最终只用一个cache服务。性能上Redis与memcache相当。&lt;/p&gt;
&lt;div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内部的firehose&lt;/strong&gt;&lt;strong&gt;(通信管道)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲内部的应用需要活跃的信息流通道。这些信息包括用户创建/删除的信息，liking/unliking的提示，等等。挑战在于这些数据要实时的分布式处理。我们希望能够检测内部运行状况，应用的生态系统能够可靠的生长，同时还需要建设分布式系统的控制中心。&lt;/p&gt;
&lt;p&gt;▲以前，这些信息是基于Scribe(Facebook开源的分布式日志系统。)/Hadoop的分布式系统。服务会先记录在Scribe中，并持续的长尾形式写入，然后将数据输送给应用。这种模式可以立即停止伸缩，尤其在峰值时每秒要创建数以千计的信息。不要指望人们会细水长流式的发布文件和grep。&lt;/p&gt;
&lt;p&gt;▲内部的firehose就像装载着信息的大巴，各种服务和应用通过&lt;a href=&quot;http://thrift.apache.org/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Thrift&lt;/a&gt;与消防管线沟通。(一个可伸缩的跨语言的服务开发框架。)&lt;/p&gt;
&lt;p&gt;▲LinkedIn的Kafka用于存储信息。内部人员通过HTTP链接firehose。经常面对巨大的数据冲击，采用MySQL显然不是一个好主意，分区实施越来越普遍。&lt;/p&gt;
&lt;p&gt;▲firehose的模型是非常灵活的，而不像Twitter的firehose那样数据被假定是丢失的。&lt;/p&gt;
&lt;p&gt;▲firehose的信息流可以及时的回放。他保留一周内的数据，可以调出这期间任何时间点的数据。&lt;/p&gt;
&lt;p&gt;▲支持多个客户端连接，而且不会看到重复的数据。每个客户端有一个ID。Kafka支持客户群，每个群中的客户都用同一个ID，他们不会读取重复的数据。可以创建多个客户端使用同一个ID，而且不会看到重复的数据。这将保证数据的独立性和并行处理。Kafka使用ZooKeeper(Apache推出的开源分布式应用程序协调服务。)定期检查用户阅读了多少。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为Dashboard收件箱设计的Cell架构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲现在支持Dashboard的功能的分散-集中架构非常受限，这种状况不会持续很久。&lt;/p&gt;
&lt;p&gt;▲解决方法是采用基于Cell架构的收件箱模型，与&lt;a href=&quot;http://cloud.csdn.net/a/20120215/www.facebook.com/note.php?note_id=454991608919&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Facebook Messages&lt;/a&gt;非常相似。&lt;/p&gt;
&lt;p&gt;▲收件箱与分散-集中架构是对立的。每一位用户的dashboard都是由其追随者的发言和行动组成的，并按照时间顺序存储。&lt;/p&gt;
&lt;p&gt;▲就因为是收件箱就解决了分散-集中的问题。你可以会问到底在收件箱中放了些什么，让其如此廉价。这种方式将运行很长时间。&lt;/p&gt;
&lt;p&gt;▲重写Dashboard非常困难。数据已经分布，但是用户局部升级产生的数据交换的质量还没有完全搞定。&lt;/p&gt;
&lt;p&gt;▲数据量是非常惊人的。平均每条消息转发给上百个不同的用户，这比Facebook面对的困难还要大。大数据+高分布率+多个数据中心。&lt;/p&gt;
&lt;p&gt;▲每秒钟上百万次写入，5万次读取。没有重复和压缩的数据增长为2.7TB，每秒百万次写入操作来自24字节行键。&lt;/p&gt;
&lt;p&gt;▲已经流行的应用按此方法运行。&lt;/p&gt;
&lt;p&gt;▲cell&lt;/p&gt;
&lt;p&gt;▲每个cell是独立的，并保存着一定数量用户的全部数据。在用户的Dashboard中显示的所有数据也在这个cell中。&lt;/p&gt;
&lt;p&gt;▲用户映射到cell。一个数据中心有很多cell。&lt;/p&gt;
&lt;p&gt;▲每个cell都有一个HBase的集群，服务集群，Redis的缓存集群。&lt;/p&gt;
&lt;p&gt;▲用户归属到cell，所有cell的共同为用户发言提供支持。&lt;/p&gt;
&lt;p&gt;▲每个cell都基于&lt;a href=&quot;https://github.com/twitter/finagle&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Finagle&lt;/a&gt;（Twitter推出的异步的远程过程调用库），建设在HBase上，Thrift用于开发与firehose和各种请求与数据库的链接。(&lt;strong&gt;请纠错&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;▲一个用户进入Dashboard，其追随者归属到特定的cell，这个服务节点通过HBase读取他们的dashboard并返回数据。&lt;/p&gt;
&lt;p&gt;▲后台将追随者的dashboard归入当前用户的table，并处理请求。&lt;/p&gt;
&lt;p&gt;▲Redis的缓存层用于cell内部处理用户发言。&lt;/p&gt;
&lt;p&gt;▲请求流：用户发布消息，消息将被写入firehose，所有的cell处理这条消息并把发言文本写入数据库，cell查找是否所有发布消息追随者都在本cell内，如果是的话，所有追随者的收件箱将更新用户的ID。（&lt;strong&gt;请纠错&lt;/strong&gt;）&lt;/p&gt;
&lt;p&gt;▲cell设计的优点：&lt;/p&gt;
&lt;p&gt;▲大规模的请求被并行处理，组件相互隔离不会产生干扰。 cell是一个并行的单位，因此可以任意调整规格以适应用户群的增长。&lt;/p&gt;
&lt;p&gt;▲cell的故障是独立的。一个Cell的故障不会影响其他cell。&lt;/p&gt;
&lt;p&gt;▲cell的表现非常好，能够进行各种升级测试，实施滚动升级，并测试不同版本的软件。&lt;/p&gt;
&lt;p&gt;▲关键的思想是容易遗漏的：所有的发言都是可以复制到所有的cell。&lt;/p&gt;
&lt;p&gt;▲每个cell中存储的所有发言的单一副本。 每个cell可以完全满足Dashboard呈现请求。应用不用请求所有发言者的ID，只需要请求那些用户的ID。(&lt;strong&gt;“那些用户”所指不清，请指正。&lt;/strong&gt;)他可以在dashboard返回内容。每一个cell都可以满足Dashboard的所有需求，而不需要与其他cell进行通信。&lt;/p&gt;
&lt;p&gt;▲用到两个HBase table ：一个table用于存储每个发言的副本，这个table相对较小。在cell内，这些数据将与存储每一个发言者ID。第二个table告诉我们用户的dashboard不需要显示所有的追随者。当用户通过不同的终端访问一个发言，并不代表阅读了两次。收件箱模型可以保证你阅读到。&lt;/p&gt;
&lt;p&gt;▲发言并不会直接进入到收件箱，因为那实在太大了。所以，发言者的ID将被发送到收件箱，同时发言内容将进入cell。这个模式有效的减少了存储需求，只需要返回用户在收件箱中浏览发言的时间。而缺点是每一个cell保存所有的发言副本。令人惊奇的是，所有发言比收件箱中的镜像要小。(&lt;strong&gt;请纠错&lt;/strong&gt;)每天每个cell的发言增长50GB，收件箱每天增长2.7TB。用户消耗的资源远远超过他们制造的。&lt;/p&gt;
&lt;p&gt;▲用户的dashboard不包含发言的内容，只显示发言者的ID，主要的增长来自ID。(&lt;strong&gt;请Tumblr用户纠错&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;▲当追随者改变时，这种设计方案也是安全的。因为所有的发言都保存在cell中了。如果只有追随者的发言保存在cell中，那么当追随者改变了，将需要一些回填工作。&lt;/p&gt;
&lt;p&gt;▲另外一种设计方案是采用独立的发言存储集群。这种设计的缺点是，如果群集出现故障，它会影响整个网站。因此，使用cell的设计以及后复制到所有cell的方式，创建了一个非常强大的架构。&lt;/p&gt;
&lt;p&gt;▲一个用户拥有上百万的追随者，这带来非常大的困难，有选择的处理用户的追随者以及他们的存取模式（见&lt;a href=&quot;http://highscalability.com/blog/2012/1/17/paper-feeding-frenzy-selectively-materializing-users-event-f.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Feeding Frenzy&lt;/a&gt;）&lt;/p&gt;
&lt;p&gt;▲不同的用户采用不同并且恰当的存取模式和分布模型，两个不同的分布模式包括：一个适合受欢迎的用户，一个使用大众。&lt;/p&gt;
&lt;p&gt;▲依据用户的类型采用不同的数据处理方式，活跃用户的发言并不会被真正发布，发言将被有选择的体现。(果真如此？&lt;strong&gt;请Tumblr用户纠错&lt;/strong&gt;)&lt;/p&gt;
&lt;p&gt;▲追随了上百万用户的用户，将像拥有上百万追随者的用户那样对待。&lt;/p&gt;
&lt;p&gt;▲cell的大小非常难于决定。cell的大小直接影响网站的成败。每个cell归于的用户数量是&lt;a title=&quot;影响力&quot; href=&quot;http://www.amazon.cn/gp/product/B0044KME2E/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=vastwork-23&amp;amp;linkCode=as2&amp;amp;camp=536&amp;amp;creative=3200&amp;amp;creativeASIN=B0044KME2E&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;影响力&lt;/a&gt;之一。需要权衡接受怎样的用户体验，以及为之付出多少投资。&lt;/p&gt;
&lt;p&gt;▲从firehose中读取数据将是对网络最大的考验。在cell内部网络流量是可管理的。&lt;/p&gt;
&lt;p&gt;▲当更多cell被增添到网络中来，他们可以进入到cell组中，并从firehose中读取数据。一个分层的数据复制计划。这可以帮助迁移到多个数据中心。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;在纽约启动运作&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;纽约具有独特的环境，资金和广告充足。招聘极具挑战性，因为缺乏创业经验。&lt;/p&gt;
&lt;p&gt;在过去的几年里，纽约一直致力于推动创业。纽约大学和哥伦比亚大学有一些项目，鼓励学生到初创企业实习，而不仅仅去华尔街。市长建立了一所学院，侧重于技术。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;团队架构&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲团队：基础架构，平台，SRE，产品，web ops，服务；&lt;/p&gt;
&lt;p&gt;▲基础架构：5层以下，IP地址和DNS，硬件配置；&lt;/p&gt;
&lt;p&gt;▲平台：核心应用开发，SQL分片，服务，Web运营；&lt;/p&gt;
&lt;p&gt;▲SRE：在平台和产品之间，侧重于解决可靠性和扩展性的燃眉之急；&lt;/p&gt;
&lt;p&gt;▲服务团队：相对而言更具战略性，&lt;/p&gt;
&lt;p&gt;▲Web ops：负责问题检测、响应和优化。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;软件部署&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲开发了一套rsync脚本，可以随处部署PHP应用程序。一旦机器的数量超过200台，系统便开始出现问题，部署花费了很长时间才完成，机器处于部署进程中的各种状态。&lt;/p&gt;
&lt;p&gt;▲接下来，使用Capistrano（一个开源工具，可以在多台服务器上运行脚本）在服务堆栈中构建部署进程（开发、分期、生产）。在几十台机器上部署可以正常工作，但当通过SSH部署到数百台服务器时，再次失败。&lt;/p&gt;
&lt;p&gt;▲现在，所有的机器上运行一个协调软件。基于Redhat Func（一个安全的、脚本化的远程控制框架和接口）功能，一个轻量级的API用于向主机发送命令，以构建扩展性。&lt;/p&gt;
&lt;p&gt;▲建立部署是在Func的基础上向主机发送命令，避免了使用SSH。比如，想在组A上部署软件，控制主机就可以找出隶属于组A的节点，并运行部署命令。&lt;/p&gt;
&lt;p&gt;▲部署命令通过Capistrano实施。&lt;/p&gt;
&lt;p&gt;▲Func API可用于返回状态报告，报告哪些机器上有这些软件版本。&lt;/p&gt;
&lt;p&gt;▲安全重启任何服务，因为它们会关闭连接，然后重启。&lt;/p&gt;
&lt;p&gt;▲在激活前的黑暗模式下运行所有功能。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;展望&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲从哲学上将，任何人都可以使用自己想要的任意工具。但随着团队的发展壮大，这些工具出现了问题。新员工想要更好地融入团队，快速地解决问题，必须以他们为中心，建立操作的标准化。&lt;/p&gt;
&lt;p&gt;▲过程类似于Scrum（一种敏捷管理框架），非常敏捷。&lt;/p&gt;
&lt;p&gt;▲每个开发人员都有一台预配置的开发机器，并按照控制更新。&lt;/p&gt;
&lt;p&gt;▲开发机会出现变化，测试，分期，乃至用于生产。&lt;/p&gt;
&lt;p&gt;▲开发者使用VIM和TextMate。&lt;/p&gt;
&lt;p&gt;▲测试是对PHP程序进行代码审核。&lt;/p&gt;
&lt;p&gt;▲在服务方面，他们已经实现了一个与提交相挂钩的测试基础架构，接下来将继承并内建通知机制。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;招聘流程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲面试通常避免数学、猜谜、脑筋急转弯等问题，而着重关注应聘者在工作中实际要做什么。&lt;/p&gt;
&lt;p&gt;▲着重编程技能。&lt;/p&gt;
&lt;p&gt;▲面试不是比较，只是要找对的人。&lt;/p&gt;
&lt;p&gt;▲挑战在于找到具有可用性、扩展性经验的人才，以应对Tumblr面临的网络拥塞。&lt;/p&gt;
&lt;p&gt;▲在Tumblr工程博客（Tumblr Engineering Blog），他们对已过世的Dennis Ritchie和John McCarthy予以纪念。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;经验及教训&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;▲自动化无处不在&lt;/p&gt;
&lt;p&gt;▲MySQL（增加分片）规模，应用程序暂时还不行&lt;/p&gt;
&lt;p&gt;▲Redis总能带给人惊喜&lt;/p&gt;
&lt;p&gt;▲基于Scala语言的应用执行效率是出色的&lt;/p&gt;
&lt;p&gt;▲废弃项目——当你不确定将如何工作时&lt;/p&gt;
&lt;p&gt;▲不顾用在他们发展经历中没经历过技术挑战的人，聘用有技术实力的人是因为他们能适合你的团队以 及工作。&lt;/p&gt;
&lt;p&gt;▲选择正确的软件集合将会帮助你找到你需要的人&lt;/p&gt;
&lt;p&gt;▲建立团队的技能&lt;/p&gt;
&lt;p&gt;▲阅读文档和博客文章。&lt;/p&gt;
&lt;p&gt;▲多与同行交流，可以接触一些领域中经验丰富的人，例如与在Facebook、Twitter、LinkedIn的工程师 多交流，从他们身上可以学到很多&lt;/p&gt;
&lt;p&gt;▲对技术要循序渐进，在正式投入使用之前他们煞费苦心的学习HBase和Redis。同时在试点项目中使用 或将其控制在有限损害范围之内。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;翻译：包研，张志平，刘江；审校：刘江&lt;/p&gt;
&lt;p&gt;转自 http://blog.jobbole.com/13311/  英文原文出自&lt;a href=&quot;http://highscalability.com/blog/2012/2/13/tumblr-architecture-15-billion-page-views-a-month-and-harder.html&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;High Scalability&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2012%2F02%2Ftumblr-architecture.html&amp;title=%E8%BD%AC%EF%BC%9ATumblr%EF%BC%9A150%E4%BA%BF%E6%9C%88%E6%B5%8F%E8%A7%88%E9%87%8F%E8%83%8C%E5%90%8E%E7%9A%84%E6%9E%B6%E6%9E%84%E6%8C%91%E6%88%98&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248029/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248029/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2012/02/tumblr-architecture.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>导读：和许多新兴的网站一样，著名的轻博客服务Tumblr在急速发展中面临了系统架构的瓶颈。每天5亿次浏览量，峰值每秒4万次请求，每天3TB新的数据存储，超过1000台服务器，这样的情况下如何保证老系统平稳运行，平稳过渡到新的系统，Tumblr正面临巨大的挑战。近日，HighScalability网站的Todd Hoff采访了该公司的分布式系统工程师Blake Matheny，撰文系统介绍了网站的架构，内容很有价值。 Tumblr每月页面浏览量超过150亿次，已经成为火爆的博客社区。用户也许喜欢它的简约、美丽，对用户体验的强烈关注，或是友好而忙碌的沟通方式，总之，它深得人们的喜爱。 每月超过30%的增长当然不可能没有挑战，其中可靠性问题尤为艰巨。每天5亿次浏览量，峰值每秒4万次请求，每天3TB新的数据存储，并运行于超过1000台服务器上，所有这些帮助Tumblr实现巨大的经营规模。 创业公司迈向成功，都要迈过危险的迅速发展期这道门槛。寻找人才，不断改造基础架构，维护旧的架构，同时要面对逐月大增的流量，而且曾经只有4位工程师。这意味着必须艰难地选择应该做什么，不该做什么。这就是Tumblr的状况。好在现在已经有20位工程师了，可以有精力解决问题，并开发一些有意思的解决方案。 Tumblr最开始是非常典型的LAMP应用。目前正在向分布式服务模型演进，该模型基于Scala、HBase、Redis（著名开源K-V存储方案）、Kafka（Apache项目，出自LinkedIn的分布式发布-订阅消息系统）、Finagle（由Twitter开源的容错、协议中立的RPC系统），此外还有一个有趣的基于Cell的架构，用来支持Dashboard（CSDN注：Tumblr富有特色的用户界面，类似于微博的时间轴）。 Tumblr目前的最大问题是如何改造为一个大规模网站。系统架构正在从LAMP演进为最先进的技术组合，同时团队也要从小的创业型发展为全副武装、随时待命的正规开发团队，不断创造出新的功能和基础设施。下面就是Blake Matheny对Tumblr系统架构情况的介绍。 网站地址 http://www.tumblr.com/ &amp;#160; 主要数据 ▲每天5亿次PV（页面访问量） ▲每月超过150亿PV ▲约20名工程师 ▲ 峰值请求每秒近4万次 ▲每天超过1TB数据进入Hadoop集群 ▲ MySQL/HBase/Redis/memcache每天生成若干TB数据 ▲每月增长30% ▲近1000硬件节点用于生产环境 ▲平均每位工程师每月负责数以亿计的页面访问 ▲每天上传大约50GB的文章，每天跟帖更新数据大约2.7TB（CSDN注：这两个数据的比例看上去不太合理，据Tumblr数据科学家Adam Laiacano在Twitter上解释，前一个数据应该指的是文章的文本内容和元数据，不包括存储在S3上的多媒体内容） &amp;#160; 软件环境 ▲开发使用OS X，生产环境使用Linux（CentOS/Scientific） ▲Apache ▲PHP, Scala, Ruby ▲Redis, HBase, MySQL ▲Varnish, HAProxy, nginx ▲memcache, Gearman（支持多语言的任务分发应用框架）, Kafka, Kestrel（Twitter开源的分布式消息队列系统）, Finagle ▲ Thrift, HTTP ▲Func——一个安全、支持脚本的远程控制框架和API ▲ Git, Capistrano（多服务器脚本部署工具）, Puppet, Jenkins &amp;#160; 硬件环境 ▲500台Web服务器 ▲200台数据库服务器（47 pool，20 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/635248029/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248029/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>技术资料</category><pubDate>Fri, 17 Feb 2012 13:59:25 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2012/02/tumblr-architecture.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652713</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2012/02/tumblr-architecture.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248029/1234636</fs:itemid></item><item><title>用 redis 实现和保护 12306</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248030/1234636/1/item.html</link><content:encoded>&lt;p&gt;网上大家都在流传 &lt;a title=&quot;微博上关于12306的讨论&quot; href=&quot;http://weibo.com/10503/y13WCsSAu&quot; target=&quot;_blank&quot;&gt;如何更好的实现一个 12306&lt;/a&gt; ，作为一个技术人员，碰到如此难得的机会，忍不住也想跟着忽悠一把。&lt;/p&gt;
&lt;p&gt;纯粹从技术角度出发，来设计一个架构和实现方案是非常容易的。但我相信，真实的 12306 的架构师，需要考虑的不仅仅是技术实现，还有数不清的历史包袱，现实约束，甚至人为限制。所以，这里的描述，只是技术人员关起们来，自己的 YY ，大家姑且看看就行，别太当真。&lt;/p&gt;
&lt;p&gt;12306 当前的问题，无非是僧多粥少加定时放票引起秒杀效应，造成拥堵。只要解决了这个问题，大家的意见就不会那么强烈了。&lt;/p&gt;
&lt;p&gt;首先来看僧多粥少的问题。车票一共就那么多张，这个系统只需要考虑如何将这些票安全，公平的卖出去。至于是不是还有人没有买上票，这就不用技术人员考虑了。所以，我们的问题其实只有一个：如何解决拥堵问题。&lt;/p&gt;
&lt;p&gt;在这个神奇的国度，每个地方都有拥堵问题，公交站台，景区门口，银行柜台，甚至食堂窗口，大家都用同一种办法来解决这个问题：排队。所以我一直很纳闷，12306 为什么一开始没有实现排队的功能，是领导拍了脑袋？还是有其它不为人知的原因？&lt;/p&gt;
&lt;p&gt;废话少扯，还是说正经的吧。&lt;/p&gt;
&lt;p&gt;Redis 用在这里，不仅仅是一个 NoSQL 存储工具，简直是一个完美的解决方案。下面我就来详细描述一下我想象中的一个架构：&lt;/p&gt;
&lt;p&gt;1. LVS 接入，同时将 https 协议转成 http 协议。 按照网上流传的 2kw 的预算，F5 恐怕是用不起了，不过也没事，LVS 加硬件 SSL 卡，50w 预算绝对拿下。&lt;/p&gt;
&lt;p&gt;2. varnish 反向代理。cache 住大部分的静态资源，每台机器 3w/s 的 rps 应该可以比较轻松的应对。即使按照 30w/s 的峰值能力计算，也就 10 台机器，30w 预算&lt;/p&gt;
&lt;p&gt;3. Nginx 服务静态资源，有 2 台足够，6w 预算&lt;/p&gt;
&lt;p&gt;4. Tomcat 服务动态请求，这个量会比较大。但可以从这几个方面入手去减少资源消耗：第一，使用 ajax 请求，而不是页面刷新，减少单个请求的 size；第二，做好频率检测和控制，对于部分用工具来刷的用户，甚至可以采取惩罚措施，以减少无谓的资源消耗。保守估计，20 台机器左右，这个数字要看领导们对于“用户体验”的要求程度。&lt;/p&gt;
&lt;p&gt;5. Redis 服务器，96G / 台，价格也就 3w 出头。预算 10 台，将 2kw 注册用户全部加载到内存，将 2k 车次全部加载到内存，将每个车次的每个座位的状态都加载到内存，将每个在线用户都加载到内存，应该都还有内存剩余。为什么要写磁盘呢？大不了给 Redis 服务器配置双电源，再配一个电池！&lt;/p&gt;
&lt;p&gt;6. DB 服务器。最重要的 db 服务器，“铁道部”的系统，如果不是 DB2 那就应该是 Orcale 了，应该是连硬件到软件一起买的解决方案吧。这个我没有用过，甚至都没有见过，所以不好估计预算了。如果用我们比较熟悉的 mysql，用户系统应该是一个单独的库；车次信息应该是一个单独的库，而且基本上是只读；车票信息应该有区分当前库和历史库，当前库用来存未售出的车票信息，或者近期刚刚售出的车票信息，数据量小，支持快速读写，以及更新，历史库用来存历史上的车票信息，存档性质；订单信息单独一个库，读写量都不会太大。除了车票信息的当前库建议用 SSD ，其它的库采用普通的硬件就行，预算不会超过 5w/台，按照 1M3S 的标准配置，总体的机器台数在 20 以内，预算 100w 左右。值得一提的是，车票信息的当前库，需要按照车次（甚至是车次+日期）进行分库分表。想提高实时性，提升用户体验，减少投诉？增加当前库的机器投入即可。&lt;/p&gt;
&lt;p&gt;硬件设备应该就是这样了，接下来说说一些值得一提的实现细节。&lt;/p&gt;
&lt;p&gt;当前 12306 系统一个很受人诟病的实现就是无法登录。用户打开登录页，输入了用户名密码，还耐心的填好了验证码，点击提交，再耐心的等了 30 秒，结果，弹出一个无比丑陋的对话框，说“当前访问用户过多，请稍后尝试”，太坑人了！以至于某公司甚至给做了一个“12306登录助手”出来。让用户登录进来，给他们能买到票的希望，是减少投诉的一个很重要的方面。这个其实一点也不难：将用户信息都加载到 Redis 内存，简单点，key 就是 email，value 就是密码加密串（亲，不能是明文哦！），用 cookie 而不是 session 进行身份验证，用 ajax 而不是刷新页面的方式提交数据和返回应答，这么一来，即使 2 kw 用户同时都登录进来，也只需要三五台 tomcat ，20分钟就搞定了。&lt;/p&gt;
&lt;p&gt;用户登陆进来之后，不能立即就给出太多的输入框，让用户输入查询，那样对系统的消耗比较大，不划算。应该先让用户通过出发站和到站，查询好车次（单独的车次信息库，全部加载到内存供查询），选择好乘车日期，然后——点击“取号”按钮，拿一个号，进行排队。是不是很熟悉？去银行开卡，汇款啥的，不都是这么办的么！将每个“车次+发车日期”作为一个单独的队列进行排队，其实就是将火车站售票窗口给移动到互联网页面上而已！想提升用户体验？那就每个登录用户可以同时排 3 个队吧，比如我，想买 18 号或者 19 号的 K21，那我就同时在 “K21+18号发车” 和 “K21+19号发车” 2 个队伍里排着好了。&lt;/p&gt;
&lt;p&gt;用户既然已经在排队了，那后台处理就很灵活了：根据 db 的承载能力，将用户有序的带到查余票和下订单的页面（后面命名为 “售票厅” 吧）即可。用户在排队页，用 ajax 请求定期轮询，server 端返回有 3 种：当还没有轮到该用户时，返回当前队列前面还有多少人，这个车次还剩多少张卧铺，多少张硬座等等，当然，这些信息都不是实时更新的，而是定期由后台线程或进程进行更新。读取的时候，只是一个缓存 get 操作而已。另一种就是已经轮到该用户，这个时候，给一个30秒或者60秒的订票时间窗口，要求在这个时间内完成查询和下单操作：查询的时候并不做任何的 lock 操作，而是仅仅显示 db select 的结果（这个地方，可能需要 select master 库），填写完票数，点击提交的时候，才做真正的 lock，随机选择座位，update db，update redis 。这个步骤是直接操作 db，不做任何的缓存，但因为是根据 db 的能力放进来的量，所以性能风险反而最小。还有一种状态，就是该用户的号已经过期，或者订票时间窗口过期，很简单，重新取号，重新排队。&lt;/p&gt;
&lt;p&gt;具体到 Redis 操作，大约会是这样：&lt;/p&gt;
&lt;p&gt;用户：key 为 user:abc@test.com ，value 就是 md5(email + password) ，用户登陆的时候，只需要做一次 get ，即可验证登陆是否成功。&lt;/p&gt;
&lt;p&gt;用户参与排队的时候，给用户分配一个 token，token 中建议包含加入排队的时间。&lt;/p&gt;
&lt;p&gt;为每个“车次+日期”建立一个队列：key 为 train:queue:k21:20120118 , value 是一个 list ，用户点击“排队”按钮，加入队尾，用 lpush token，后台进程根据 db 负载，从队伍头取出一个用户带入查票和下单页面用 rpop token 即可。后台一个定时任务，定期扫描队伍，更新每个人前面的人数，供查询使用。&lt;/p&gt;
&lt;p&gt;为每个“车次+日期”建立一个“售票厅”：key 为 train:selling:k21:20120118 , value 是一个 hash ，field 即 token，value 为过期时间。后台进程定期从队列中 rpop 出一个或多个用户，hset 到 hash 里。并且还需要一个后台进程，定期从售票厅里清除出过期的 token&lt;/p&gt;
&lt;p&gt;用户在排队页面，使用 token 作为参数来查询自己的状态：首先 hget 售票厅，确认是否已经轮到自己了，如果没有，则再获取前面还有多少人，预估还需要排队多久，车次还剩下多少票等等信息。如果已经轮到自己，则显示“下一步”按钮，将用户带到售票厅。这一步需要做好安全验证，防止有人采取技术手段绕过排队，直接进入售票厅。&lt;/p&gt;
&lt;p&gt;如果不希望用户不停的按刷新按钮，消耗服务器资源？那就来一招狠的：用户每次刷新，则将他在排队中的位置往后排一个！不过采取这样的措施之前，别忘了在醒目位置提醒用户“注意节约我们的带宽资源”！&lt;/p&gt;
&lt;p&gt;用户真正下单买票，这是纯粹的业务逻辑，这里就不再细说。下单买票完成后，记得更新一下余票信息缓存即可。&lt;/p&gt;
&lt;p&gt;这样的系统很难做么？难，也不难。有的地方因为业务逻辑太复杂，不得不做一些改变，比如亚马逊为了应对圣诞购物季，建了一块云，比如淘宝为了双11双12的秒杀，买了一堆的机器；也有的地方因为各种其它的原因，无法做到完美，比如 12306，比如新浪微博。不过无论现实如何，在我们技术人员的心里，永远保留着一颗追求完美的心，永远保留一股追求更好的劲头，就够了。&lt;/p&gt;
&lt;p&gt;谨以此献给我在 12306 上失败的购票经历，和明天的 K21 旅程。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2012%2F01%2F12306_with_redis.html&amp;title=%E7%94%A8+redis+%E5%AE%9E%E7%8E%B0%E5%92%8C%E4%BF%9D%E6%8A%A4+12306&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248030/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248030/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2012/01/12306_with_redis.html/feed</wfw:commentRss><slash:comments>2</slash:comments><description>网上大家都在流传 如何更好的实现一个 12306 ，作为一个技术人员，碰到如此难得的机会，忍不住也想跟着忽悠一把。 纯粹从技术角度出发，来设计一个架构和实现方案是非常容易的。但我相信，真实的 12306 的架构师，需要考虑的不仅仅是技术实现，还有数不清的历史包袱，现实约束，甚至人为限制。所以，这里的描述，只是技术人员关起们来，自己的 YY ，大家姑且看看就行，别太当真。 12306 当前的问题，无非是僧多粥少加定时放票引起秒杀效应，造成拥堵。只要解决了这个问题，大家的意见就不会那么强烈了。 首先来看僧多粥少的问题。车票一共就那么多张，这个系统只需要考虑如何将这些票安全，公平的卖出去。至于是不是还有人没有买上票，这就不用技术人员考虑了。所以，我们的问题其实只有一个：如何解决拥堵问题。 在这个神奇的国度，每个地方都有拥堵问题，公交站台，景区门口，银行柜台，甚至食堂窗口，大家都用同一种办法来解决这个问题：排队。所以我一直很纳闷，12306 为什么一开始没有实现排队的功能，是领导拍了脑袋？还是有其它不为人知的原因？ 废话少扯，还是说正经的吧。 Redis 用在这里，不仅仅是一个 NoSQL 存储工具，简直是一个完美的解决方案。下面我就来详细描述一下我想象中的一个架构： 1. LVS 接入，同时将 https 协议转成 http 协议。 按照网上流传的 2kw 的预算，F5 恐怕是用不起了，不过也没事，LVS 加硬件 SSL 卡，50w 预算绝对拿下。 2. varnish 反向代理。cache 住大部分的静态资源，每台机器 3w/s 的 rps 应该可以比较轻松的应对。即使按照 30w/s 的峰值能力计算，也就 10 台机器，30w 预算 3. Nginx 服务静态资源，有 2 台足够，6w 预算 4. Tomcat 服务动态请求，这个量会比较大。但可以从这几个方面入手去减少资源消耗：第一，使用 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/635248030/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248030/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>工作日志</category><pubDate>Tue, 17 Jan 2012 12:20:40 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2012/01/12306_with_redis.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652706</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2012/01/12306_with_redis.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248030/1234636</fs:itemid></item><item><title>新年快乐</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248031/1234636/1/item.html</link><content:encoded>&lt;p&gt;新年快乐！&lt;/p&gt;
&lt;p&gt;第一次在公司过元旦。如果运气不好，真被要求值班，那么大年夜可能也要跟今晚一样，在公司守着了。&lt;/p&gt;
&lt;p&gt;2011 年过去了，2012 年到来了。2011 年总会过去的，2012 年总会到来的。&lt;/p&gt;
&lt;p&gt;这一年，见证了新浪微博从 v3 到 v4 ，从一个奇迹到另一个奇迹的变迁。从 &lt;a title=&quot;我在 Qcon 杭州的演讲&quot; href=&quot;http://qconhangzhou.com/Speaker.aspx?Id=26&quot; target=&quot;_blank&quot;&gt;Qcon hangzhou&lt;/a&gt; 回来后，把自己的微博（&lt;a title=&quot;我的新浪微博&quot; href=&quot;http://weibo.com/tangfl&quot; target=&quot;_blank&quot;&gt;@唐福林&lt;/a&gt;）签名改成了 “微博开放平台，伪架构师，兼职客服，负责 t.cn 短链，关注粉丝，分组和计数器。短链不能点击，关注，粉丝不对，分组错乱，数字不准都可以直接找我” ，从工程师到架构师，我终于能够跨过自己心里的那道坎。&lt;/p&gt;
&lt;p&gt;2012 年，我将要更多的承担起架构师的职责，从自己接需求，自己出方案，自己写代码，自己上线，自己维护模块，渐渐转变成：把控大的方向，维护整体架构，推行最佳实践，完善流程和工具链，营造总结分享的气氛，为整体系统和团队带来更大的价值。技术人员成长到一定程度，总要从“技”走向“术”，最终从“术”上升到“道”。&lt;/p&gt;
&lt;p&gt;这一年，与 &lt;a title=&quot;leeva 的微博&quot; href=&quot;http://weibo.com/leeyanva&quot; target=&quot;_blank&quot;&gt;@leeyanva&lt;/a&gt; 共同走过，有风雨，更有彩虹和阳光。清明&lt;a title=&quot;黄山旅游&quot; href=&quot;http://weibo.com/1723877915/zF4mJHEX1i&quot; target=&quot;_blank&quot;&gt;去了一趟黄山和婺源&lt;/a&gt;，夏天&lt;a title=&quot;游龙板&quot; href=&quot;http://weibo.com/1723877915/ezyucTF2sF9&quot; target=&quot;_blank&quot;&gt;学会了滑游龙板&lt;/a&gt; ，去了无数次后海，秋天的时候，在北戴河&lt;a title=&quot;婚纱&quot; href=&quot;http://weibo.com/1723877915/xoDWPCUTE&quot; target=&quot;_blank&quot;&gt;补了一个婚纱照&lt;/a&gt;（&lt;a title=&quot;北戴河海边&quot; href=&quot;http://weibo.com/1243233955/xnvQKni5N&quot; target=&quot;_blank&quot;&gt;海边&lt;/a&gt;），十一回家足足&lt;a title=&quot;玉米地&quot; href=&quot;http://weibo.com/1723877915/xrG83kMZZ&quot; target=&quot;_blank&quot;&gt;掰了6天的玉米&lt;/a&gt; （&lt;a title=&quot;玉米地&quot; href=&quot;http://weibo.com/1243233955/xrD3ysT1M&quot; target=&quot;_blank&quot;&gt;玉米地照片&lt;/a&gt;）。最后，春节，回湖南，到时候看看是一起去桂林转转，还是去舜皇山国家森林公园看看。&lt;/p&gt;
&lt;p&gt;这一年，进电影院看了不少电影，几乎包括了所有感兴趣的大片，有的是用工会发的电影卡，也有的是自己团购的电影票。&lt;/p&gt;
&lt;p&gt;这一年，公司组织去了一次&lt;a title=&quot;新浪微博白洋淀之行&quot; href=&quot;http://weibo.com/1243233955/eDff5a4Dran&quot; target=&quot;_blank&quot;&gt;白洋淀&lt;/a&gt;，还去了一次&lt;a title=&quot;新浪微博开放平台在坝上草原合影&quot; href=&quot;http://weibo.com/1243233955/xhKtYr9VK&quot; target=&quot;_blank&quot;&gt;坝上草原&lt;/a&gt; 。但因为都不许带家属，所以玩的都不是特别尽兴。三国杀，划船，骑马，晒太阳。&lt;/p&gt;
&lt;p&gt;一年了，在“&lt;a title=&quot;北京缓解拥堵&quot; href=&quot;http://www.bjhjyd.gov.cn/&quot; target=&quot;_blank&quot;&gt;北京还将拥堵&lt;/a&gt; ”系统里排队抽签，却一致没有抽中，所以一直没能拥有自己的车。&lt;/p&gt;
&lt;p&gt;一年了，终于攒出一点首付，再四处借一点，准备出手买房，然后准备要小孩。&lt;/p&gt;
&lt;p&gt;一年了，身边还发生了很多很多事情，有些记下了，也有些已经遗忘。&lt;/p&gt;
&lt;p&gt;那末，就这样吧。&lt;/p&gt;
&lt;p&gt;再见，2011 。&lt;/p&gt;
&lt;p&gt;你好，2012 。&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;我的 2010 总结&quot; href=&quot;http://blog.fulin.org/2011/01/my2010.html&quot; target=&quot;_blank&quot;&gt;2011 年 元旦时的对比&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2012%2F01%2Fhappy_new_year.html&amp;title=%E6%96%B0%E5%B9%B4%E5%BF%AB%E4%B9%90&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248031/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248031/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2012/01/happy_new_year.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>新年快乐！ 第一次在公司过元旦。如果运气不好，真被要求值班，那么大年夜可能也要跟今晚一样，在公司守着了。 2011 年过去了，2012 年到来了。2011 年总会过去的，2012 年总会到来的。 这一年，见证了新浪微博从 v3 到 v4 ，从一个奇迹到另一个奇迹的变迁。从 Qcon hangzhou 回来后，把自己的微博（@唐福林）签名改成了 “微博开放平台，伪架构师，兼职客服，负责 t.cn 短链，关注粉丝，分组和计数器。短链不能点击，关注，粉丝不对，分组错乱，数字不准都可以直接找我” ，从工程师到架构师，我终于能够跨过自己心里的那道坎。 2012 年，我将要更多的承担起架构师的职责，从自己接需求，自己出方案，自己写代码，自己上线，自己维护模块，渐渐转变成：把控大的方向，维护整体架构，推行最佳实践，完善流程和工具链，营造总结分享的气氛，为整体系统和团队带来更大的价值。技术人员成长到一定程度，总要从“技”走向“术”，最终从“术”上升到“道”。 这一年，与 @leeyanva 共同走过，有风雨，更有彩虹和阳光。清明去了一趟黄山和婺源，夏天学会了滑游龙板 ，去了无数次后海，秋天的时候，在北戴河补了一个婚纱照（海边），十一回家足足掰了6天的玉米 （玉米地照片）。最后，春节，回湖南，到时候看看是一起去桂林转转，还是去舜皇山国家森林公园看看。 这一年，进电影院看了不少电影，几乎包括了所有感兴趣的大片，有的是用工会发的电影卡，也有的是自己团购的电影票。 这一年，公司组织去了一次白洋淀，还去了一次坝上草原 。但因为都不许带家属，所以玩的都不是特别尽兴。三国杀，划船，骑马，晒太阳。 一年了，在“北京还将拥堵 ”系统里排队抽签，却一致没有抽中，所以一直没能拥有自己的车。 一年了，终于攒出一点首付，再四处借一点，准备出手买房，然后准备要小孩。 一年了，身边还发生了很多很多事情，有些记下了，也有些已经遗忘。 那末，就这样吧。 再见，2011 。 你好，2012 。 2011 年 元旦时的对比&lt;img src=&quot;http://www1.feedsky.com/t1/635248031/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248031/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>工作日志</category><category>个人隐私</category><pubDate>Sun, 01 Jan 2012 02:34:00 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2012/01/happy_new_year.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652698</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2012/01/happy_new_year.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248031/1234636</fs:itemid></item><item><title>转：三好学生Chris Lattner的LLVM编译工具链</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248032/1234636/1/item.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;2011年12月3日，LLVM 3.0正式版发布，完整支持所有ISO C++标准和大部分C++ 0x的新特性， 这对于一个短短几年的全新项目来说非常不易。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;开发者的惊愕&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在2011年WWDC（苹果全球开发者大会）的一场与Objective-C相关的讲座上，开发者的人生观被颠覆了。&lt;/p&gt;
&lt;p&gt;作为一个开发者，管理好自己程序所使用的内存是天经地义的事，好比人们在溜狗时必须清理狗的排泄物一样（美国随处可见“Clean up after your dogs”的标志）。在本科阶段上C语言的课程时，教授们会向学生反复强调：如果使用malloc函数申请了一块内存，使用完后必须再使用free函数把申请的内存还给系统——如果不还，会造成“内存泄漏”的结果。这对于Hello World可能还不算严重，但对于庞大的程序或是长时间运行的服务器程序，泄内存是致命的。如果没记住，自己还清理了两次，造成的结果则严重得多——&lt;a href=&quot;https://blog.delphij.net/2009/10/free.html&quot; target=&quot;_blank&quot;&gt;直接导致程序崩溃&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Objective-C有类似malloc/free的对子，叫alloc/dealloc，这种原始的方式如同管理C内存一样困难。所以Objective-C中的内存管理又增加了“引用计数”的方法，也就是如果一个物件被别的物件引用一次，则引用计数加一；如果不再被该物件引用，则引用计数减一；当引用计数减至零时，则系统自动清掉该物件所占的内存。具体来说，如果我们有一个字符串，当建立时，需要使用alloc方法来申请内存，引用计数则变成了一；然后被其他物件引用时，需要用retain方法去增加它的引用计数，变成二。当它和刚才引用的物件脱离关联时，需使release方法减少引用计数，又变回了一；最后，使用完这个字符串时，再用release方法减少其引用计数，这时，运行库发现其引用计数变为零了，则回收走它的内存。这是&lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-BAJHFBGH&quot; target=&quot;_blank&quot;&gt;手动的方式&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;这种方式自然很麻烦，所以又设计出一种叫做autorelease的机制（不是类似Java的自动垃圾回收）。在Objective-C中，设计了一个叫做NSAutoReleasePool的池，当开发者需要完成一个任务时（比如每开启一个线程，或者开始一个函数），可以手动创立一个这样的池子， 然后通过显式申明把物件扔进自动回收池中。NSAutoReleasePool内有一个数组来保存声明为autorelease的所有对象。如果一个对象声明为autorelease，则会自动加到池子里。如果完成了一个任务（结束线程了，或者退出那个函数），则开发者需对这个池子发送一个drain消息。这时，NSAutoReleasePool会对池子中所有的物件发送release消息，把它们的引用计数都减一 ——这就好比游泳池关门时通知所有客人都“滚蛋”一样。所以开发者无需显式声明release，所有的物件也会在池子清空时自动呼叫release函数，如果引用计数变成零了，系统才回收那块内存。所以这是个&lt;a href=&quot;http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI&quot; target=&quot;_blank&quot;&gt;半自动、半手动的方式&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Objective-C的这种方式虽然比起C来进了一大步，我刚才花了几分钟就和读者讲明白了。只要遵守上面这两个简单的规则，就可以保证不犯任何错误。但这和后来的Java自动垃圾回收相比则是非常繁琐的，哪怕是再熟练的开发者，一不小心就会弄错。而且，哪怕很简单的代码，比如物件的getter/setter函数，都需要用户写上一堆的代码来管理接收来的物件的内存。&lt;/p&gt;
&lt;p&gt;经典教材《Cocoa Programming for Mac OS X》用了整整一章节的篇幅，来讲解Objective-C中内存管理相关的内容，但初学者们看得还是一头雾水。所以，在2007年10.5发布时，Objective-C做出了有史以来最大的更新，最大的亮点是它的运行库libobjc 2.0正式支持自动垃圾回收，也就是由运行库在运行时随时侦测哪些物件需要被释放。听上去很不错，可惜使用这个技术的项目却少之又少。原因很简单，使用这个特性，会有很大的性能损失，使Objective-C的内存管理效率低得和Java一样，而且一旦有一个模块启用了这个特性，这个进程中所有的地方都要启用这个特性——因此如果你写了一个使用垃圾回收的库，那所有引用你库的程序就都得被迫使用垃圾回收。所以Apple自己也不使用这项技术，大量的第三方库也不使用它。&lt;/p&gt;
&lt;p&gt;这个问题随Apple在移动市场的一炮走红而变得更加严峻。不过这次，Apple和与会的开发者讲，他们找到了一个解决问题的终极方法，这个方法把从世界各地专程赶来聆听圣谕的开发者惊得目瞪口呆——你不用写任何内存管理代码，也不需要使用自动垃圾回收。因为我们的编译器已经学会了上面所介绍的内存管理规则，会自动在编译程序时把这些代码插进去。&lt;/p&gt;
&lt;p&gt;这个编译器，一直是Apple公开的秘密——LLVM。说它公开，是因为它自始至终都是一个开源项目；而秘密，则是因为它从来没公开在WWDC的Keynote演讲上亮相过 。&lt;/p&gt;
&lt;p&gt;一直关注这系列连载的读者一定还记得，在第二篇《Linus Torvalds的短视》介绍Apple和GPL社区的不合时，提到过“自以为是但代码又写得差的开源项目，Apple事后也遇到不少，比如GCC编译器项目组。虽然大把钞票扔进去，在先期能够解决一些问题，但时间长了这群人总和Apple过不去，并以自己在开源世界的地位恫吓之，最终Apple由于受不了这些项目组的态度、协议、代码质量，觉得还不如自己造轮子来得方便。”LLVM则是Apple造的这个轮子，它的目的是完全替代掉GCC那条编译链。它的主要作者，则是现在就职于Apple的Chris Lattner。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;编译器高材生Chris Lattner&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;2000年，本科毕业的Chris Lattner像中国多数大学生一样，按部就班地考了GRE，最终前往UIUC（伊利诺伊大学厄巴纳香槟分校），开始了艰苦读计算机硕士和博士的生涯。在这阶段，&lt;a href=&quot;http://photos.nondot.org/&quot; target=&quot;_blank&quot;&gt;他不仅周游美国各大景点&lt;/a&gt;，更是努力学习科学文化知识，翻烂了“龙书”（《Compilers: Principles, Techniques, and Tools》），&lt;a href=&quot;http://nondot.org/sabre/Resume.html&quot; target=&quot;_blank&quot;&gt;成了GPA牛人&lt;/a&gt;【注：最终学分积4.0满分】，以及不断地研究探索关于编译器的未知领域，发表了一篇又一篇的论文，是中国传统观念里的“三好学生”。他的&lt;a href=&quot;http://www.programmer.com.cn/9436/%E6%B3%A8%EF%BC%9ALLVM:%20An%20Infrastructure%20for%20Multi-Stage%20Optimization%EF%BC%8C%20http://llvm.org/pubs/2002-12-LattnerMSThesis.html&quot; target=&quot;_blank&quot;&gt;硕士毕业论文提出了一套完整的在编译时、链接时、运行时甚至是在闲置时优化程序的编译思想&lt;/a&gt;，直接奠定了LLVM的基础。&lt;br /&gt;
LLVM在他念博士时更加成熟，使用GCC作为前端来对用户程序进行语义分析产生IF（Intermidiate Format），然后LLVM使用分析结果完成代码优化和生成。这项研究让他在2005年毕业时，成为小有名气的编译器专家，他也因此早早地被Apple相中，成为其编译器项目的骨干。&lt;/p&gt;
&lt;p&gt;Apple相中Chris Lattner主要是看中LLVM能摆脱GCC束缚。Apple（包括中后期的NeXT） 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错，但Apple对编译工具会提出更高的要求。&lt;/p&gt;
&lt;p&gt;一方面，是Apple对Objective-C语言（甚至后来对C语言）新增很多特性，但GCC开发者并不买Apple的帐——不给实现，因此索性后来两者分成两条分支分别开发，这也造成Apple的编译器版本远落后于GCC的官方版本。另一方面，GCC的代码耦合度太高，不好独立，而且&lt;a href=&quot;http://www.thejemreport.com/more-on-openbsds-new-compiler/&quot; target=&quot;_blank&quot;&gt;越是后期的版本，代码质量越差&lt;/a&gt;，但Apple想做的很多功能（比如更好的IDE支持）需要模块化的方式来调用GCC，但GCC一直不给做。甚至最近，《&lt;a href=&quot;https://blog.delphij.net/2009/01/gcc.html&quot; target=&quot;_blank&quot;&gt;GCC运行环境豁免条款 （英文版）&lt;/a&gt;》从根本上限制了LLVM-GCC的开发。 所以，这种不和让Apple一直在寻找一个高效的、模块化的、协议更放松的开源替代品，Chris Lattner的LLVM显然是一个很棒的选择。&lt;/p&gt;
&lt;p&gt;刚进入Apple，Chris Lattner就大展身手：首先在OpenGL小组做代码优化，把LLVM运行时的编译架在OpenGL栈上，这样OpenGL栈能够产出更高效率的图形代码。如果显卡足够高级，这些代码会直接扔入GPU执行。但对于一些不支持全部OpenGL特性的显卡（比如当时的Intel GMA卡），&lt;a href=&quot;http://lists.cs.uiuc.edu/pipermail/llvmdev/2006-August/006492.html&quot; target=&quot;_blank&quot;&gt;LLVM则能够把这些指令优化成高效的CPU指令，使程序依然能够正常运行&lt;/a&gt;。这个强大的OpenGL实现被用在了后来发布的Mac OS X 10.5上。同时，LLVM的链接优化被直接加入到Apple的代码链接器上，而LLVM-GCC也被同步到使用GCC4代码。&lt;/p&gt;
&lt;p&gt;LLVM真正的发迹，则得等到Mac OS X 10.6 Snow Leopard登上舞台。可以说， Snow Leopard的新功能，完全得益于LLVM的技术。而这一个版本，也是将LLVM推向真正成熟的重大机遇。&lt;/p&gt;
&lt;p&gt;关于Snow Leopard的三项主推技术（64位支持、OpenCL，以及Grand Central Dispatch）的细节，我们会在下一次有整整一期篇幅仔细讨论，这次只是点到为止——我们告诉读者，这些技术，不但需要语言层面的支持（比如&lt;a href=&quot;http://lists.cs.uiuc.edu/pipermail/cfe-dev/2008-August/002670.html&quot; target=&quot;_blank&quot;&gt;Grand Centrual Dispatch所用到的“代码块”语法&lt;/a&gt;， 这被很多人看作是带lambda的C），也需要底层代码生成和优化（比如OpenCL是在运行时编译为GPU或CPU代码并发执行的）。而这些需求得以实现，归功于LLVM自身的新前端——Clang。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;优异的答卷——Clang&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前文提到，Apple吸收Chris Lattner的目的要比改进GCC代码优化宏大得多——GCC系统庞大而笨重，而Apple大量使用的Objective-C在GCC中优先级很低。此外GCC作为一个纯粹的编译系统，与IDE配合得很差。加之许可证方面的要求，Apple无法使用LLVM 继续改进GCC的代码质量。于是，Apple决定从零开始写 C、C++、Objective-C语言的前端 Clang，完全替代掉GCC。&lt;/p&gt;
&lt;p&gt;正像名字所写的那样，Clang只支持C，C++和Objective-C三种C家族语言。&lt;a href=&quot;http://lists.cs.uiuc.edu/pipermail/cfe-dev/2007-July/000000.html&quot; target=&quot;_blank&quot;&gt;2007年开始开发&lt;/a&gt;，C编译器最早完成，而由于Objective-C相对简单，只是C语言的一个简单扩展，很多情况下甚至可以等价地改写为C语言对Objective-C运行库的函数调用，因此在2009年时，已经完全可以用于生产环境。C++的支持也热火朝天地进行着。&lt;/p&gt;
&lt;p&gt;Clang的加入代表着LLVM真正走向成熟和全能，Chris Lattner以影响他最大的&lt;a href=&quot;http://en.wikipedia.org/wiki/Dragon_Book_(computer_science)&quot; target=&quot;_blank&quot;&gt;“龙书”封面&lt;/a&gt;【注：见http://en.wikipedia.org/wiki/Dragon_Book_(computer_science)】为灵感，为项目选定了图标——&lt;a href=&quot;http://llvm.org/img/DragonMedium.png&quot; target=&quot;_blank&quot;&gt;一条张牙舞爪的飞龙&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;Clang一个重要的特性是编译快速，占内存少，而代码质量还比GCC来得高。测试结果表明Clang编译Objective-C代码时速度为GCC的3倍【注：http://llvm.org/pubs/2007-07-25-LLVM-2.0-and-Beyond.pdf】，而语法树（AST）内存占用则为被编译源码的1.3倍，而&lt;a href=&quot;http://llvm.org/devmtg/2007-05/09-Naroff-CFE.pdf&quot; target=&quot;_blank&quot;&gt;GCC则可以轻易地可以超过10倍&lt;/a&gt;。Clang不但编译代码快，对于用户犯下的错误，也能够更准确地给出建议。使用过GCC的读者应该熟悉，GCC给出的错误提示基本都不是给人看的。&lt;/p&gt;
&lt;p&gt;比如最简单的：&lt;/p&gt;
&lt;p&gt;struct foo { int x; }&lt;br /&gt;
typedef int bar;&lt;/p&gt;
&lt;p&gt;如果使用GCC编译，它将告诉你：&lt;br /&gt;
t.c:3: error: two or more data types in declaration specifiers&lt;/p&gt;
&lt;p&gt;但是Clang给出的出错提示则显得人性化得多：&lt;br /&gt;
t.c:1:22: error: expected ‘;’ after struct&lt;/p&gt;
&lt;p&gt;甚至，Clang可以根据语境，像拼写检查程序一样地告诉你可能的替代方案。&lt;br /&gt;
比如这个程序：&lt;/p&gt;
&lt;p&gt;#include &amp;lt;inttypes.h&amp;gt;&lt;br /&gt;
int64 x;&lt;/p&gt;
&lt;p&gt;GCC一样给出乱码似的出错提示：&lt;/p&gt;
&lt;p&gt;t.c:2: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘x’&lt;/p&gt;
&lt;p&gt;而优雅的Clang则用彩色的提示告诉你是不是拼错了，并给出可能的变量名：&lt;/p&gt;
&lt;p&gt;t.c:2:1: error: unknown type name ‘int64′; did you mean ‘int64_t’?&lt;br /&gt;
int64 x;^~~~~int64_t&lt;/p&gt;
&lt;p&gt;更多的例子可以参考http://blog.llvm.org/2010/04/amazing-feats-of-clang-error-recovery.html。 而同时又因为Clang是高度模块化的一个前端，很容易实现代码的高度重用。所以比如Xcode 4.0的集成编程环境就使用Clang的模块来实现代码的自动加亮、代码出错的提示和自动的代码补全。开发者使用Xcode 4.0以后的版本，可以极大地提高编程效率，尽可能地降低编译错误的发生率。&lt;/p&gt;
&lt;p&gt;支持C++也是Clang的一项重要使命。C++是一门非常复杂的语言，大多编译器（如GCC、MSVC）用了十多年甚至二十多年来完善对C++的支持，但效果依然不很理想。Clang的C++支持却一直如火如荼地展开着。2010年2月4日，Clang已经成熟到能自举（即使用Clang编译Clang，到我发稿时，&lt;a href=&quot;http://clang.llvm.org/cxx_status.html&quot; target=&quot;_blank&quot;&gt;LLVM 3.0发布已完整支持所有ISO C++标准，以及大部分C++ 0x的新特性&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;这对于一个短短几年的全新项目来说是非常不易的。得益于本身健壮的架构和Apple的大力支持，Clang越来越全能，从&lt;a href=&quot;http://lists.freebsd.org/pipermail/freebsd-current/2009-February/003743.html&quot; target=&quot;_blank&quot;&gt;FreeBSD&lt;/a&gt;【注：http://lists.freebsd.org/pipermail/freebsd-current/2009-February/003743.html】 到&lt;a href=&quot;http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-October/011711.html&quot; target=&quot;_blank&quot;&gt;Linux Kernel&lt;/a&gt;【注：http://lists.cs.uiuc.edu/pipermail/cfe-dev/2010-October/011711.html】， 从&lt;a href=&quot;http://blog.llvm.org/2010/05/clang-builds-boost.html&quot; target=&quot;_blank&quot;&gt;Boost&lt;/a&gt;【注：http://blog.llvm.org/2010/05/clang-builds-boost.html】 到&lt;a href=&quot;http://weblogs.java.net/blog/simonis/archive/2011/02/10/compiling-hotspot-vm-clang&quot; target=&quot;_blank&quot;&gt;Java虚拟机&lt;/a&gt;， Clang支持的项目越来越多。&lt;/p&gt;
&lt;p&gt;Apple的Mac OS X以及iOS也成了Clang和LLVM的主要试验场——10.6时代，很多需要高效运行的程序比如OpenSSL和Hotspot就由LLVM-GCC编译来加速的。而10.6时代的Xcode 3.2诸多图形界面开发程序如Xcode、Interface Builder等，皆由Clang编译。到了Mac OS X 10.7，整个系统的的代码都由Clang或LLVM-GCC编译【注：http://llvm.org/Users.html】。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LLVM周边工具&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于受到Clang项目的威胁，GCC也不得不软下来，让自己变得稍微模块化一些，推出&lt;a href=&quot;http://gcc.gnu.org/wiki/plugins&quot; target=&quot;_blank&quot;&gt;插件的支持&lt;/a&gt;，而LLVM项目则顺水推舟，索性废掉了出道时就一直作为看家本领的LLVM-GCC，改为一个&lt;a href=&quot;http://dragonegg.llvm.org/&quot; target=&quot;_blank&quot;&gt;GCC的插件DragonEgg&lt;/a&gt;。 Apple也于Xcode 4.2彻底抛弃了GCC工具链。&lt;/p&gt;
&lt;p&gt;而Clang的一个重要衍生项目，则是&lt;a href=&quot;http://clang-analyzer.llvm.org/images/analyzer_html.png&quot; target=&quot;_blank&quot;&gt;静态分析工具&lt;/a&gt;，能够通过自动分折程序的逻辑，在编译时就找出程序可能的bug。在Mac OS X 10.6时，静态分析被集成进Xcode 3.2，帮助用户查找自己犯下的错误。其中一个功能，就是告诉用户内存管理的Bug，比如alloc了一个物件却忘记使用&lt;a href=&quot;http://clang-analyzer.llvm.org/images/analyzer_xcode.png&quot; target=&quot;_blank&quot;&gt;release回收&lt;/a&gt;。这已经是一项很可怕的技术，而Apple自己一定使用它来发现并改正Mac OS X整个系统各层面的问题。但许多开发者还不满足——既然你能发现我漏写了release，你为什么不能帮我自动加上呢？于是ARC被&lt;a href=&quot;http://www.programmer.com.cn/9436/Automatic%20Reference%20Counting%20http://clang.llvm.org/docs/AutomaticReferenceCounting.html&quot; target=&quot;_blank&quot;&gt;集成进Clang&lt;/a&gt;，发生了文章开头开发者们的惊愕——从来没有人觉得这件事是可以做成的。&lt;/p&gt;
&lt;p&gt;除LLVM核心和Clang以外，LLVM还包括一些重要的子项目，比如一个&lt;a href=&quot;http://lldb.llvm.org/&quot; target=&quot;_blank&quot;&gt;原生支持调试多线程程序的调试器LLDB&lt;/a&gt;，和一个&lt;a href=&quot;http://libcxx.llvm.org/&quot; target=&quot;_blank&quot;&gt;C++的标准库libstdc++&lt;/a&gt;，这些项目由于是从零重写的，因此要比先前的很多项目站得更高，比如先前GNU、Apache、STLport等C++标准库在设计时，C++0x标准还未公布，所以大多不支持这些新标准或者需要通过一些肮脏的改动才能支持，而libstdc++则原生支持C++0x。而且在现代架构上，这些项目能动用多核把事情处理得更好。&lt;/p&gt;
&lt;p&gt;不单单是Apple，诸多的项目和编程语言都从LLVM里取得了关键性的技术。&lt;a href=&quot;http://blog.llvm.org/2010/05/glasgow-haskell-compiler-and-llvm.html&quot; target=&quot;_blank&quot;&gt;Haskell语言编译器GHC使用LLVM作为后端&lt;/a&gt;，实现了高质量的代码编译。很多动态语言实现也使用LLVM作为运行时的编译工具，较著名的有Google的Unladen Swallow【注：&lt;a href=&quot;http://code.google.com/p/unladen-swallow/&quot; target=&quot;_blank&quot;&gt;Python实现，后夭折&lt;/a&gt;】、PyPy【注：&lt;a href=&quot;http://codespeak.net/pypy/dist/pypy/doc/index.html&quot; target=&quot;_blank&quot;&gt;Python实现&lt;/a&gt;】，以及MacRuby【注：&lt;a href=&quot;http://www.programmer.com.cn/9436/macruby.org/&quot; target=&quot;_blank&quot;&gt;Ruby实现&lt;/a&gt;】。&lt;a href=&quot;http://programmingzen.com/2009/03/29/why-macruby-matters/&quot; target=&quot;_blank&quot;&gt;例如 MacRuby 后端改为LLVM后，速度不但有了显著的提高&lt;/a&gt;，更是支持Grand Central Dispatch来实现高度的并行运行。由于LLVM高度的模块化，很方便重用其中的组件来作为一个实现的重要组成部分，因此类似的项目会越来越多。&lt;/p&gt;
&lt;p&gt;LLVM的成熟也给其他痛恨GCC的开发项目出了一口恶气。其中最重要的，恐怕是以FreeBSD为代表的BSD社区。BSD社区和Apple的联系一向很紧密，而且由于代码相似，很多Apple的技术如Grand Central Dispatch也是最早移植到FreeBSD上。&lt;a href=&quot;http://en.wikipedia.org/wiki/Portable_C_Compiler&quot; target=&quot;_blank&quot;&gt;BSD社区很早就在找GCC的替代品&lt;/a&gt;，无奈大多都很差（如Portable C Compiler产生的代码质量和gcc不能同日而语）。&lt;/p&gt;
&lt;p&gt;一方面是因为不满意GCC的代码品质【注：BSD代码整体要比GNU的高一些，GNU代码永无休止地出现各种严重的&lt;a href=&quot;https://blog.delphij.net/2007/01/gpl-gzip1.html&quot; target=&quot;_blank&quot;&gt;安全问题&lt;/a&gt;】，更重要的是协议问题。BSD开发者有洁癖的居多，大多都不喜欢GPL代码，尤其是&lt;a href=&quot;http://www.freebsdfoundation.org/press/2007Aug-newsletter.shtml&quot; target=&quot;_blank&quot;&gt;GPL协议第三版发布时，和FreeBSD的协议甚至是冲突的&lt;/a&gt;。这也正是为什么FreeBSD中包含的GNU的C++运行库还是2007年以GPLv2发布的老版本，而不是支持C++0x的但依GPLv3协议发布的新版本。 因此历时两年的开发后，2012年初发布的FreeBSD 9.0中，&lt;a href=&quot;http://wiki.freebsd.org/BuildingFreeBSDWithClang&quot; target=&quot;_blank&quot;&gt;Clang被加入到FreeBSD的基础系统&lt;/a&gt;。 但这只是第一步，因为FreeBSD中依然使用GNU的C++ STL 库、C++运行库、GDB调试器、libgcc/libgcc_s编译库都是和编译相关的重要底层技术，先前全被GNU垄断，而现在LLVM子项目lldb、libstdc++、compiler-rt等项目的出现，使BSD社区有机会向GNU说“不”，因此一个把&lt;a href=&quot;http://wiki.freebsd.org/GPLinBase&quot; target=&quot;_blank&quot;&gt;GNU组件移出FreeBSD的计划被构想出来&lt;/a&gt;，并完成了很大一部分。编写过《Cocoa Programming Developer’s Handbook》的著名Objective-C牛人David Chisnall也被吸收入FreeBSD开发组完成这个计划的关键部分。 预计在FreeBSD 10发布时，将不再包含GNU代码。&lt;/p&gt;
&lt;p&gt;LLVM在短短五年内取得的快速发展充分反映了Apple对于产品技术的远见和处理争端的决心和手腕，并一跃成为最领先的开源软件技术。而Chris Lattner在2010年也赢得了他应有的荣誉——Programming Languages Software Award（程序设计语言软件奖）。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.programmer.com.cn/9435/&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;本文选自《程序员》杂志2012年01期，更多精彩内容敬请关注01期杂志&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2011%2F12%2Fllvm.html&amp;title=%E8%BD%AC%EF%BC%9A%E4%B8%89%E5%A5%BD%E5%AD%A6%E7%94%9FChris+Lattner%E7%9A%84LLVM%E7%BC%96%E8%AF%91%E5%B7%A5%E5%85%B7%E9%93%BE&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248032/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248032/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2011/12/llvm.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>2011年12月3日，LLVM 3.0正式版发布，完整支持所有ISO C++标准和大部分C++ 0x的新特性， 这对于一个短短几年的全新项目来说非常不易。 开发者的惊愕 在2011年WWDC（苹果全球开发者大会）的一场与Objective-C相关的讲座上，开发者的人生观被颠覆了。 作为一个开发者，管理好自己程序所使用的内存是天经地义的事，好比人们在溜狗时必须清理狗的排泄物一样（美国随处可见“Clean up after your dogs”的标志）。在本科阶段上C语言的课程时，教授们会向学生反复强调：如果使用malloc函数申请了一块内存，使用完后必须再使用free函数把申请的内存还给系统——如果不还，会造成“内存泄漏”的结果。这对于Hello World可能还不算严重，但对于庞大的程序或是长时间运行的服务器程序，泄内存是致命的。如果没记住，自己还清理了两次，造成的结果则严重得多——直接导致程序崩溃。 Objective-C有类似malloc/free的对子，叫alloc/dealloc，这种原始的方式如同管理C内存一样困难。所以Objective-C中的内存管理又增加了“引用计数”的方法，也就是如果一个物件被别的物件引用一次，则引用计数加一；如果不再被该物件引用，则引用计数减一；当引用计数减至零时，则系统自动清掉该物件所占的内存。具体来说，如果我们有一个字符串，当建立时，需要使用alloc方法来申请内存，引用计数则变成了一；然后被其他物件引用时，需要用retain方法去增加它的引用计数，变成二。当它和刚才引用的物件脱离关联时，需使release方法减少引用计数，又变回了一；最后，使用完这个字符串时，再用release方法减少其引用计数，这时，运行库发现其引用计数变为零了，则回收走它的内存。这是手动的方式。 这种方式自然很麻烦，所以又设计出一种叫做autorelease的机制（不是类似Java的自动垃圾回收）。在Objective-C中，设计了一个叫做NSAutoReleasePool的池，当开发者需要完成一个任务时（比如每开启一个线程，或者开始一个函数），可以手动创立一个这样的池子， 然后通过显式申明把物件扔进自动回收池中。NSAutoReleasePool内有一个数组来保存声明为autorelease的所有对象。如果一个对象声明为autorelease，则会自动加到池子里。如果完成了一个任务（结束线程了，或者退出那个函数），则开发者需对这个池子发送一个drain消息。这时，NSAutoReleasePool会对池子中所有的物件发送release消息，把它们的引用计数都减一 ——这就好比游泳池关门时通知所有客人都“滚蛋”一样。所以开发者无需显式声明release，所有的物件也会在池子清空时自动呼叫release函数，如果引用计数变成零了，系统才回收那块内存。所以这是个半自动、半手动的方式。 Objective-C的这种方式虽然比起C来进了一大步，我刚才花了几分钟就和读者讲明白了。只要遵守上面这两个简单的规则，就可以保证不犯任何错误。但这和后来的Java自动垃圾回收相比则是非常繁琐的，哪怕是再熟练的开发者，一不小心就会弄错。而且，哪怕很简单的代码，比如物件的getter/setter函数，都需要用户写上一堆的代码来管理接收来的物件的内存。 经典教材《Cocoa Programming for Mac OS X》用了整整一章节的篇幅，来讲解Objective-C中内存管理相关的内容，但初学者们看得还是一头雾水。所以，在2007年10.5发布时，Objective-C做出了有史以来最大的更新，最大的亮点是它的运行库libobjc 2.0正式支持自动垃圾回收，也就是由运行库在运行时随时侦测哪些物件需要被释放。听上去很不错，可惜使用这个技术的项目却少之又少。原因很简单，使用这个特性，会有很大的性能损失，使Objective-C的内存管理效率低得和Java一样，而且一旦有一个模块启用了这个特性，这个进程中所有的地方都要启用这个特性——因此如果你写了一个使用垃圾回收的库，那所有引用你库的程序就都得被迫使用垃圾回收。所以Apple自己也不使用这项技术，大量的第三方库也不使用它。 这个问题随Apple在移动市场的一炮走红而变得更加严峻。不过这次，Apple和与会的开发者讲，他们找到了一个解决问题的终极方法，这个方法把从世界各地专程赶来聆听圣谕的开发者惊得目瞪口呆——你不用写任何内存管理代码，也不需要使用自动垃圾回收。因为我们的编译器已经学会了上面所介绍的内存管理规则，会自动在编译程序时把这些代码插进去。 这个编译器，一直是Apple公开的秘密——LLVM。说它公开，是因为它自始至终都是一个开源项目；而秘密，则是因为它从来没公开在WWDC的Keynote演讲上亮相过 。 一直关注这系列连载的读者一定还记得，在第二篇《Linus Torvalds的短视》介绍Apple和GPL社区的不合时，提到过“自以为是但代码又写得差的开源项目，Apple事后也遇到不少，比如GCC编译器项目组。虽然大把钞票扔进去，在先期能够解决一些问题，但时间长了这群人总和Apple过不去，并以自己在开源世界的地位恫吓之，最终Apple由于受不了这些项目组的态度、协议、代码质量，觉得还不如自己造轮子来得方便。”LLVM则是Apple造的这个轮子，它的目的是完全替代掉GCC那条编译链。它的主要作者，则是现在就职于Apple的Chris Lattner。 编译器高材生Chris Lattner 2000年，本科毕业的Chris Lattner像中国多数大学生一样，按部就班地考了GRE，最终前往UIUC（伊利诺伊大学厄巴纳香槟分校），开始了艰苦读计算机硕士和博士的生涯。在这阶段，他不仅周游美国各大景点，更是努力学习科学文化知识，翻烂了“龙书”（《Compilers: Principles, Techniques, and Tools》），成了GPA牛人【注：最终学分积4.0满分】，以及不断地研究探索关于编译器的未知领域，发表了一篇又一篇的论文，是中国传统观念里的“三好学生”。他的硕士毕业论文提出了一套完整的在编译时、链接时、运行时甚至是在闲置时优化程序的编译思想，直接奠定了LLVM的基础。 LLVM在他念博士时更加成熟，使用GCC作为前端来对用户程序进行语义分析产生IF（Intermidiate Format），然后LLVM使用分析结果完成代码优化和生成。这项研究让他在2005年毕业时，成为小有名气的编译器专家，他也因此早早地被Apple相中，成为其编译器项目的骨干。 Apple相中Chris Lattner主要是看中LLVM能摆脱GCC束缚。Apple（包括中后期的NeXT） 一直使用GCC作为官方的编译器。GCC作为开源世界的编译器标准一直做得不错，但Apple对编译工具会提出更高的要求。 一方面，是Apple对Objective-C语言（甚至后来对C语言）新增很多特性，但GCC开发者并不买Apple的帐——不给实现，因此索性后来两者分成两条分支分别开发，这也造成Apple的编译器版本远落后于GCC的官方版本。另一方面，GCC的代码耦合度太高，不好独立，而且越是后期的版本，代码质量越差，但Apple想做的很多功能（比如更好的IDE支持）需要模块化的方式来调用GCC，但GCC一直不给做。甚至最近，《GCC运行环境豁免条款 （英文版）》从根本上限制了LLVM-GCC的开发。 所以，这种不和让Apple一直在寻找一个高效的、模块化的、协议更放松的开源替代品，Chris Lattner的LLVM显然是一个很棒的选择。 刚进入Apple，Chris Lattner就大展身手：首先在OpenGL小组做代码优化，把LLVM运行时的编译架在OpenGL栈上，这样OpenGL栈能够产出更高效率的图形代码。如果显卡足够高级，这些代码会直接扔入GPU执行。但对于一些不支持全部OpenGL特性的显卡（比如当时的Intel GMA卡），LLVM则能够把这些指令优化成高效的CPU指令，使程序依然能够正常运行。这个强大的OpenGL实现被用在了后来发布的Mac OS X 10.5上。同时，LLVM的链接优化被直接加入到Apple的代码链接器上，而LLVM-GCC也被同步到使用GCC4代码。 LLVM真正的发迹，则得等到Mac [...]&lt;img src=&quot;http://www1.feedsky.com/t1/635248032/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248032/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>技术资料</category><pubDate>Wed, 14 Dec 2011 12:43:54 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2011/12/llvm.html#comments</comments><guid isPermaLink="false">http://blog.fulin.org/?p=652701</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2011/12/llvm.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248032/1234636</fs:itemid></item><item><title>转：腾讯的核心竞争力是什么</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248033/1234636/1/item.html</link><content:encoded>&lt;p&gt;&lt;strong&gt;内部人士的解读：&lt;/strong&gt;&lt;br /&gt;
&lt;strong&gt;@Andy Pan&lt;/strong&gt; &lt;strong&gt;腾讯无线国际业务产品总监, 腾讯国际业务部&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我决定在国外出差的最后一晚晚点休息,在酒店静静的认真的回答这个问题。我尽量客观的负责的回答，不愤青，不炫耀，不攻击，用朴实的语言。只代表我个人的思考，不代表公司。&lt;/p&gt;
&lt;p&gt;腾讯最出名的是PC端的即时通信(IM)，有一种普遍的认识是即时通信IM（用户关系链）是整个腾讯竞争力的基础，平台和核心。在PC互联网端的后续出现的很多产 品，特别是一些细分市场的产品（由其他公司先发），腾讯通常能够后来居上。这一点也最为人诟病。主要批评是两点：1.依赖绑定 2.扼杀新兴公司&lt;/p&gt;
&lt;p&gt;我之前服务的公司是微软，和腾讯非常非常相似，也是构建一个巨大的平台，然后在后续的新兴领域不断超越已领先公司（从Borland,到 Wordperfect,到Netscape),被诟病的点也极其类似:1.依赖绑定 2.扼杀新兴公司&lt;/p&gt;
&lt;p&gt;因为这些,我非常认真的思考过这个问题。我有一个想法，算不上结论，只代表我目前的考虑：有些公司，他们的产品模式决定了商业模式，尤其是平台性产品公 司，注定是先期在搭建平台的努力和投入，在后期的应用上才得到回报。在微软做DOS, Windows的时候，为了赢得一个平台的努力和所冒的风险，如果只算当时Windows本身的回报也许会是不值得的。因为平台产品市场基本是一个零和游 戏，你赌整个公司在上边，做不赢就消失。如果只算那个平台产品本身的收益，聪明生意人都不会投资的。那么冒了巨大风险而万幸成功的企业，所有的努力将会这 个平台后续应用的回报获得，因为这是之前的努力的回报的一部分，属于分期还款加利息。举一个不恰当的例子，一个从艺20年终于成功的名角儿，拍广告30分 钟挣100万。如果单从这回报看，是不公平的暴利。但是事实上，商家购买的是角儿的影响力，这影响力是之前20年不停积累的结果。也就是说这100万从他 20年前就开始挣了，这30分钟只是最后的兑现。&lt;/p&gt;
&lt;p&gt;同样的道理，也适用于腾讯的即时通信IM。算上当时做即时通信IM，无收入，竞争对手多，创始人还在继续坚持做。这所有的投入是为了打造一个平台，而这个平台怎么挣钱当时 也不清楚。但是后来在这个平台上各项赢利的产品，其实有相当一部分是当时做即时通信IM的劳动回报，只是延期而已。&lt;/p&gt;
&lt;p&gt;同样的模式也适用于其他平台级厂商，比如Facebook,360等等等等。&lt;/p&gt;
&lt;p&gt;多说几句: 这样的模式就注定了有些平台级公司，随着时间的推移，会进入到各个细分领域。这个说实话，无可厚非。之所以有细分领域，是因为用户有需求，平台的用户也是 用户，作为平台加应用厂商，为平台用户提供自己在该细分领域的服务也是正常。不举IT界的例子,最早的DIET软饮料是1952年的NO-CAL,新兴公 司,只在地方销售;然后是DIET RITE,取得较大成功;引起大公司关注这个市场,1960年百事推出DIET PEPSI，DR.PEPPER在1962年推出自己的DIET饮料。1963年终于可口可乐公司进入这个市场,推出TAB,取得巨大成功,后来演变为 DIET COKE. 这是细分市场的新兴公司必然会遇到的一个挑战,更大型的公司认为这个需求成为一个大众需求就会进入这个领域,新兴公司可以选择被投资被收购从而延续自己的 价值(比如ZAPPOS被AMAZON收购,YOUTUBE被GOOGLE收购),这也是新兴公司的一个成功。当然如果这个新兴公司认为这个细分领域可以 成就一家更大规模的公司,即便大型公司进入这个领域也无法与之竞争,这就是公司领导人对产业和对自己的判断了,有成功的案例,也有失败的案例.这是领导人 的GUTS,愿赌服输. DROPBOX的创始人拒绝苹果的收购,他要为他以后的成功失败担负荣耀或责任。大公司进入细分领域也有失败的案例，微软进入消费领域很少有成功案例，腾 讯在进入电商，搜索领域后也不是所谓的“大兵所至，片甲不留”。&lt;/p&gt;
&lt;p&gt;回到主题: 所以，对的，我相信即时通信IM平台是核心竞争力之一。&lt;/p&gt;
&lt;p&gt;从即时通信IM出发，我觉得衍生出来的竞争力就变成了，信息双向传递而产生的独特的竞争力，这个竞争力包括：信息实时直接触达最大范围用户的能力,用户反馈回收的 能力。有了第一种能力，使得平台上的应用产品对于用户的discoverability直接增强,从而使得用户对新产品有快速的认知；有了第二种能力，使 得产品在滚动，迭代的过程中，会越来越成为一个好的产品。因此,两者配合,使得腾讯公司在用户的新需求出现后,可以迅速的跟上新产品,并且快速的使得新产 品达到相当的品质.&lt;/p&gt;
&lt;p&gt;于是，这种公司与海量用户之间信息双向沟通的能力也是核心竞争力之一。&lt;/p&gt;
&lt;p&gt;再往后衍生，海量用户服务能力，海量用户架构，运营能力都成为竞争优势。我就不详细说了。&lt;/p&gt;
&lt;p&gt;最后,我想再说一下我看到的另外一个核心竞争力, 就是员工的群体性努力，群体性指的是几乎所有的员工,从CEO，总裁到基层。你可能会说，每个公司的人都会说自己员工努力啦。我要说的是，无论是微软，还 是腾讯，员工_真的_很努力，工作的负荷远远超过我工作过的其他公司，也超过我身边认识的其他公司的员工。在微软，我觉得几乎每个人都或主动或被驱动的常 年维持大负荷的工作。当时和Nokia合作项目，Nokia总部的人对我们说，印象最深的就是他们不论什么时候发电邮，我们都会马上回，似乎没有时差一 般。一次半夜一点左右，他们的一个邮件需要三个职能的同事回信写工作细节，10分钟之内，我看到我和我们几个同事的邮件全部发出来了。在腾讯，晚上门口长 长的的士趴活的队伍早就是一道风景线了，一次我带IT界另外几个著名公司的朋友在很晚的时候到腾讯，他们的反应几乎是惊呼。我几乎经常性的在晚上1点钟左 右还不停的收到同事的运营报告，数据分析。我认识的经理也差不多都是这样。这种努力为什么是一种核心竞争力呢？因为这其实反映的是一家公司管理庞大知识型 工作者群体的能力。我记得我在微软时，和一个美国的资深的开发主管聊微软的竞争力，他的回答就是，微软的竞争力在于自己管理这么大规模的一间公司，虽然不 能说管理的多好，但是至少还OK，不太会犯致命的错误，持久战中等对手犯错误。那么竞争对手你要小心，新兴公司随着业务进步，公司变大，会面临很多必然的 问题，如果人性弱点浮现（因初期成功骄傲自满，组织变大无序的政治斗争），一个错误就会被这种从上到下很努力的公司超越，变成灭顶之灾。他举了 NESCAPE的例子,一个灾难性的烂版本出来,终于被IE超过。（说到这里，我想起来乔布斯97年回归苹果，介绍微软投资时，对应台下嘘声说，你们要搞 清楚一件事情，苹果没做好，是我们自己搞砸了，不是因为别人。我有时看到业界一些公司的公关稿时，经常会想起这段话。）一家全员都非常努力的公司，犯巨大 错误的机会可能会比较少，因为如果价值观走歪，策略愚蠢，员工会考虑一个问题，我这么拼命是值得的吗？我觉得格外努力的员工群体会帮助整个公司在出现问题 的时候立即察觉，无论是从优秀员工离职率还是别的调查。&lt;/p&gt;
&lt;p&gt;写这段文字的时候，我不停的脑子里面浮现出来我部门的几个同事深夜工作的样子。&lt;/p&gt;
&lt;p&gt;因此，我觉得这种非常努力的员工和工作氛围，而导致的一种竞争力，也应该是核心竞争力吧。&lt;/p&gt;
&lt;p&gt;以上就是我长期思考的一点想法。感谢知乎的周源发了问题邀请，促使我把这些想法整理出来。腾讯当然有缺点有不足，不过我还是觉得看同行的时候，见贤思齐，见不贤而自省是应有的态度吧。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;@李丹华 &lt;strong&gt;，腾讯产品经理，从事无线,关注电商&lt;/strong&gt;&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p&gt;一直以来知乎里面对行业，公司的看法都比较冷静客观，也尝试从以下几个小关键词来看腾讯的核心竞争力，仅供参考。&lt;/p&gt;
&lt;p&gt;1、QQ以及用户体验&lt;/p&gt;
&lt;p&gt;@Andy Pan大致上谈了腾讯业务扩展中QQ的关系，所以我这边的视角从产品层面解开。&lt;/p&gt;
&lt;p&gt;创 意来自ICQ，体验更符合国人。很多人说QQ山寨ICQ，其实从IM产品的用户视角来看，第一版的QQ确实跟ICQ差异不大。但是假设每个版本都模仿 ICQ,那么腾讯也就不复存在了。至少目前在欧美市场，MSN和ICQ的份额完全不是一个量级。以微博为例，也有人骂新浪，腾讯微博抄袭Twitter 的，但抛开产品和业界，回到普通用户的视角，现在新浪微博的体验，功能跟Twitter相比，谁更符合用户体验？很多击中用户痛点，让普通用户们“爽”的 产品是新浪做的。&lt;/p&gt;
&lt;p&gt;早期QQ的快速版本迭代，bug修复，关系链的存储，Q群这种泛社群概念产品的推出，到后面的视频，语音，确实集中了用户需求。而同类型的竞争产品，没熬 得住0收入的压力，于是就只剩下腾讯了。认识一个当年做IM的哥们，当年就是钱烧光了，也想不出怎么挣钱，于是放弃掉。&lt;/p&gt;
&lt;p&gt;如果把QQ当作是在线生活的入口，可能更符合一个美好产品的理想状态，后续的业务其实也是跟随这这个理念而产生，但也因为这样，衍生的业务会被人骂抄袭骂得更厉害。&lt;br /&gt;
以邮箱为例，是的，通过即时通信IM捆绑能拉动用户。但本质上邮箱是把很多细致的用户场景和需求点覆盖了。完全web化的邮箱体验，一站式的多邮箱内容管理，邮件 跟IM同步快速触达等等，这里面有即时通信IM的优势，至少我更欣赏内在逻辑和对用户场景的细致把握。然后有了微信，其实跟邮箱的理念确实一致：跨平台信息的管理 入口 ，一个是更偏向业务的长信息，一个是基于个人的信息集合。&lt;/p&gt;
&lt;p&gt;你说是不是山寨了ICQ，至少我个人认为是的，但它现在跟ICQ完全不同。那么是不是比ICQ好用，我想大部分普通用户会说是的。&lt;/p&gt;
&lt;p&gt;2、加班，内在驱动以及其他&lt;/p&gt;
&lt;p&gt;每次加班超过晚上10点，打车都变得很痛苦：队伍太长，人太多。一方面是加班打车的报销政策，但更大程度上确实业务层面承担并且消化了很多业务压力，需要加班。加班不是什么光荣的事情，也不会以加班为荣。相信没人喜欢加班，加班会挤压生活时间。不过当整个组织被灌注了高效的节奏，组织内的个人也会被驱动，然后驱 动着别人。这跟强制加班没啥关系。当你身边的人高效率地处理事情，而且极致地追求用户体验，自然也会被感染。那么当产品追求更快更敏捷，研发需要陪着加 班。当运营想更细致地看效果，市场，营销，产品，甚至开发都要加班。&lt;/p&gt;
&lt;p&gt;好吧，需求是无尽的，为啥不少人不讨厌加班。&lt;/p&gt;
&lt;p&gt;满足感：“我”做的事情，开发的东西，产品反馈了效果，“我”知道做的事情有价值。&lt;/p&gt;
&lt;p&gt;责任感：大家在期待，要把事情做好。&lt;/p&gt;
&lt;p&gt;氛围：大家都很明晰自己的责任，都愿意为结果负责。&lt;/p&gt;
&lt;p&gt;回到问题本身，腾讯有着对产品体验的极致追求，驱动着产品经理做得更好。产品经理有着明确的信息周知传统，这传统正向激励着项目相关人员。至于是否加班，这跟内在驱动没关系，顶多是在某种状态下的表现而已。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;非内部人士的解读，代表性回答：&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;@张亮 &lt;strong&gt;，风险投资新兵&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;1. 马化腾。&lt;br /&gt;
2. QQ 这款史无前例成功的即时通信 IM。它不仅连接了数亿中国用户，还成为了中国最主流的生活方式、娱乐手段、虚拟财产、个人成就系统。&lt;br /&gt;
3. 长期布局获得的交叉推广能力，说穿了，中国互联网业绝无仅有的流量能力。&lt;br /&gt;
4. 自 2003 年起在游戏领域积累的变现能力。中国互联网最赚钱的市场是游戏，最大的游戏公司是腾讯。&lt;br /&gt;
5. 2、3、4 三者相加而成的生态系统。百度有流量平台和收入平台，但缺乏用户平台。阿里系有自成一体的卖家网络、交易系统和活跃用户群，但对这体系之外的流量无控制力。&lt;br /&gt;
6. 极早布局于无线，且拥有产品和收入两套人马。无线领域的成就让它在移动互联网时代难以撼动。&lt;br /&gt;
7. 全公司长期积累的技术实力、产品能力。腾讯内部很少说某个技术是实现不了的，以至于腾讯的不少产品经理出去创业时发现有这么多以前意识不到的难搞的技术问题。产品能力不说了。&lt;br /&gt;
8. 心态上，没有因为公司变大而放不下身段，市值五百亿美元的腾讯较好的保持了其危机感和血性。虽然也让 360、新浪微博、迅雷、淘米、YY 夹缝中成长起来，但从未出现过微软对 Google、Google 对 Facebook 那种严重忽视。&lt;br /&gt;
9. 微信。个人认为，微信相当于腾讯到二次创业，至少确保了它的根基基本无人能撼动。&lt;br /&gt;
10. 你懂的。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;@pansz &lt;strong&gt;，自由软件开发者&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;腾讯的核心竞争力，可能是曾经的运气和机遇。&lt;/p&gt;
&lt;p&gt;在腾讯发力 即时通信IM 的时候，MSN 还不存在，世界上唯一的流行的即时通信 IM 是 ICQ。但是腾讯跟 ICQ 的用户体验相比，强得太多太多了，以至于我这个当时的铁杆 ICQ 用户立即跳槽了。如果当年腾讯的定位不是国内而是全世界，那么恐怕 MSN 就永远没有出现的机会了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;而大家应当知道，腾讯当年发力即时通信 IM 的时候，还根本没有所谓互联网管制这回事。。。所以腾讯最初并不是靠国内的互联网壁垒而发家的。&lt;/p&gt;
&lt;p&gt;此后的事情，只要没犯太大的错误，就没什么差错了。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;当然，我个人现在其实不怎么用 QQ，那纯粹是因为这种形式的通讯对我来说没有必要而已，我自然也属于“不用腾讯”的一族。虽然我觉得腾讯的产品并非不可缺少，但是纯粹从设计的角度来讲，腾讯的产品在国内产品中设计得算是不错的。&lt;/p&gt;
&lt;p&gt;不过为什么腾讯的抄袭行为依然受到很多诟病呢？这在知识产权不完整的国度可能是必然的，在发达国家，象腾讯这种级别的大公司如果去做别人已经有的事情，可能优先会采取收购而不是抄袭。——如果采用收购的办法，那么腾讯可能获得的骂名会少很多很多很多。&lt;/p&gt;
&lt;p&gt;但 是腾讯偏偏采用了抄袭的办法，其原因我觉得可能是：首先在这个特定的环境，抄袭并不存在太大的法律风险，而且腾讯对自己的用户体验设计能力有足够信心，认 为自己可以设计出一款不输于对手的产品。这后面的结果就很多了，我们看到腾讯在某些产品上确实达到了打压甚至超越竞争对手的程度。但是在很多产品上，他仍 然只是一个追赶者。——究其原因，也许因为：用户体验并不是产品成败的唯一决定因素。&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;@陈宾文 &lt;strong&gt;，程序员&lt;/strong&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;庞大的QQ用户群。最核心的一个。tx致广大用户一封信之后，身边的QQ好友都想删掉QQ，但是因为QQ用户群太大，大到我们的亲朋好友 都在上面，没办法还是照常用，tx几天后股价回升就是证明。有了庞大用户群（6亿多），腾讯的即时通讯（QQ，企业QQ，邮箱，浏览器，影音），网络媒体 （综合腾讯网），娱乐业务（各种游戏，QQ音乐），增值服务（各种级别的会员，QQ空间），还有电子商务（QQ网购，腾讯拍拍）哪个不是依赖于这个庞大用 户群（6亿）搭建起来的，故而腾讯很多细分市场的产品很快的能赶上甚至超越同行公司或小公司（暂且不谈抄袭），这一点可以从QQ弹窗看出（腾讯每发布新产 品都会弹窗折磨我们一下）&lt;/li&gt;
&lt;li&gt;财力宏厚，人强马壮。财大好办事（废话），吸引的牛人自然多，加上在现在“没钱没车就没老婆”的现实时代，谁不想到一个平均月薪2.7万（好像又升了）的大公司工作？首先腾讯的管理层，技术层随便一抓就是行业牛，牛人多了，各种人才都会聚集过去。&lt;/li&gt;
&lt;li&gt;用户群有了，财力有了，人才也有了，那就开始谈工作的激情、细节。作为一个程序员，我觉得腾讯用户体验很好，很注重细节。&lt;/li&gt;
&lt;li&gt;国内一些关于版权、创新的一些法律漏洞造就腾讯的抄袭无懈可击。面对腾讯的抄袭行为，尽管很多人大骂腾讯没创新，但它还是合法的，没办法！&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;总结性结论（&lt;strong&gt;@Shi.k&lt;/strong&gt; &lt;strong&gt;@胡东海 &lt;strong&gt; &lt;/strong&gt;&lt;/strong&gt;）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;即时通信IM积累的深厚用户基础&lt;/li&gt;
&lt;li&gt;以用户为中心的价值观 ，在pony领导下，深入每个员工，在这个价值观认同下，对用户、产品的态度非常一致，员工有自豪感和认同感，工作价值感强，有工作热情 （局外人看，这条不一定对）&lt;/li&gt;
&lt;li&gt;高层战略方向把握到位，公司管理不错&lt;/li&gt;
&lt;li&gt;腾讯抓住了人们线上社交需求，并维系了这种社交圈，形成了强大的生态链，这很难破坏，同时也因为这让他推出附加产品时推广起来变得更加便利；&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;转载自：http://www.mysqlops.com/2011/11/20/tt.html&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2011%2F11%2Fwhat-makes-tencent-succ.html&amp;title=%E8%BD%AC%EF%BC%9A%E8%85%BE%E8%AE%AF%E7%9A%84%E6%A0%B8%E5%BF%83%E7%AB%9E%E4%BA%89%E5%8A%9B%E6%98%AF%E4%BB%80%E4%B9%88&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248033/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248033/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2011/11/what-makes-tencent-succ.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>内部人士的解读： @Andy Pan 腾讯无线国际业务产品总监, 腾讯国际业务部 我决定在国外出差的最后一晚晚点休息,在酒店静静的认真的回答这个问题。我尽量客观的负责的回答，不愤青，不炫耀，不攻击，用朴实的语言。只代表我个人的思考，不代表公司。 腾讯最出名的是PC端的即时通信(IM)，有一种普遍的认识是即时通信IM（用户关系链）是整个腾讯竞争力的基础，平台和核心。在PC互联网端的后续出现的很多产 品，特别是一些细分市场的产品（由其他公司先发），腾讯通常能够后来居上。这一点也最为人诟病。主要批评是两点：1.依赖绑定 2.扼杀新兴公司 我之前服务的公司是微软，和腾讯非常非常相似，也是构建一个巨大的平台，然后在后续的新兴领域不断超越已领先公司（从Borland,到 Wordperfect,到Netscape),被诟病的点也极其类似:1.依赖绑定 2.扼杀新兴公司 因为这些,我非常认真的思考过这个问题。我有一个想法，算不上结论，只代表我目前的考虑：有些公司，他们的产品模式决定了商业模式，尤其是平台性产品公 司，注定是先期在搭建平台的努力和投入，在后期的应用上才得到回报。在微软做DOS, Windows的时候，为了赢得一个平台的努力和所冒的风险，如果只算当时Windows本身的回报也许会是不值得的。因为平台产品市场基本是一个零和游 戏，你赌整个公司在上边，做不赢就消失。如果只算那个平台产品本身的收益，聪明生意人都不会投资的。那么冒了巨大风险而万幸成功的企业，所有的努力将会这 个平台后续应用的回报获得，因为这是之前的努力的回报的一部分，属于分期还款加利息。举一个不恰当的例子，一个从艺20年终于成功的名角儿，拍广告30分 钟挣100万。如果单从这回报看，是不公平的暴利。但是事实上，商家购买的是角儿的影响力，这影响力是之前20年不停积累的结果。也就是说这100万从他 20年前就开始挣了，这30分钟只是最后的兑现。 同样的道理，也适用于腾讯的即时通信IM。算上当时做即时通信IM，无收入，竞争对手多，创始人还在继续坚持做。这所有的投入是为了打造一个平台，而这个平台怎么挣钱当时 也不清楚。但是后来在这个平台上各项赢利的产品，其实有相当一部分是当时做即时通信IM的劳动回报，只是延期而已。 同样的模式也适用于其他平台级厂商，比如Facebook,360等等等等。 多说几句: 这样的模式就注定了有些平台级公司，随着时间的推移，会进入到各个细分领域。这个说实话，无可厚非。之所以有细分领域，是因为用户有需求，平台的用户也是 用户，作为平台加应用厂商，为平台用户提供自己在该细分领域的服务也是正常。不举IT界的例子,最早的DIET软饮料是1952年的NO-CAL,新兴公 司,只在地方销售;然后是DIET RITE,取得较大成功;引起大公司关注这个市场,1960年百事推出DIET PEPSI，DR.PEPPER在1962年推出自己的DIET饮料。1963年终于可口可乐公司进入这个市场,推出TAB,取得巨大成功,后来演变为 DIET COKE. 这是细分市场的新兴公司必然会遇到的一个挑战,更大型的公司认为这个需求成为一个大众需求就会进入这个领域,新兴公司可以选择被投资被收购从而延续自己的 价值(比如ZAPPOS被AMAZON收购,YOUTUBE被GOOGLE收购),这也是新兴公司的一个成功。当然如果这个新兴公司认为这个细分领域可以 成就一家更大规模的公司,即便大型公司进入这个领域也无法与之竞争,这就是公司领导人对产业和对自己的判断了,有成功的案例,也有失败的案例.这是领导人 的GUTS,愿赌服输. DROPBOX的创始人拒绝苹果的收购,他要为他以后的成功失败担负荣耀或责任。大公司进入细分领域也有失败的案例，微软进入消费领域很少有成功案例，腾 讯在进入电商，搜索领域后也不是所谓的“大兵所至，片甲不留”。 回到主题: 所以，对的，我相信即时通信IM平台是核心竞争力之一。 从即时通信IM出发，我觉得衍生出来的竞争力就变成了，信息双向传递而产生的独特的竞争力，这个竞争力包括：信息实时直接触达最大范围用户的能力,用户反馈回收的 能力。有了第一种能力，使得平台上的应用产品对于用户的discoverability直接增强,从而使得用户对新产品有快速的认知；有了第二种能力，使 得产品在滚动，迭代的过程中，会越来越成为一个好的产品。因此,两者配合,使得腾讯公司在用户的新需求出现后,可以迅速的跟上新产品,并且快速的使得新产 品达到相当的品质. 于是，这种公司与海量用户之间信息双向沟通的能力也是核心竞争力之一。 再往后衍生，海量用户服务能力，海量用户架构，运营能力都成为竞争优势。我就不详细说了。 最后,我想再说一下我看到的另外一个核心竞争力, 就是员工的群体性努力，群体性指的是几乎所有的员工,从CEO，总裁到基层。你可能会说，每个公司的人都会说自己员工努力啦。我要说的是，无论是微软，还 是腾讯，员工_真的_很努力，工作的负荷远远超过我工作过的其他公司，也超过我身边认识的其他公司的员工。在微软，我觉得几乎每个人都或主动或被驱动的常 年维持大负荷的工作。当时和Nokia合作项目，Nokia总部的人对我们说，印象最深的就是他们不论什么时候发电邮，我们都会马上回，似乎没有时差一 般。一次半夜一点左右，他们的一个邮件需要三个职能的同事回信写工作细节，10分钟之内，我看到我和我们几个同事的邮件全部发出来了。在腾讯，晚上门口长 长的的士趴活的队伍早就是一道风景线了，一次我带IT界另外几个著名公司的朋友在很晚的时候到腾讯，他们的反应几乎是惊呼。我几乎经常性的在晚上1点钟左 右还不停的收到同事的运营报告，数据分析。我认识的经理也差不多都是这样。这种努力为什么是一种核心竞争力呢？因为这其实反映的是一家公司管理庞大知识型 工作者群体的能力。我记得我在微软时，和一个美国的资深的开发主管聊微软的竞争力，他的回答就是，微软的竞争力在于自己管理这么大规模的一间公司，虽然不 能说管理的多好，但是至少还OK，不太会犯致命的错误，持久战中等对手犯错误。那么竞争对手你要小心，新兴公司随着业务进步，公司变大，会面临很多必然的 问题，如果人性弱点浮现（因初期成功骄傲自满，组织变大无序的政治斗争），一个错误就会被这种从上到下很努力的公司超越，变成灭顶之灾。他举了 NESCAPE的例子,一个灾难性的烂版本出来,终于被IE超过。（说到这里，我想起来乔布斯97年回归苹果，介绍微软投资时，对应台下嘘声说，你们要搞 [...]&lt;img src=&quot;http://www1.feedsky.com/t1/635248033/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248033/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>休闲转载</category><pubDate>Mon, 28 Nov 2011 10:48:59 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2011/11/what-makes-tencent-succ.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652695</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2011/11/what-makes-tencent-succ.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248033/1234636</fs:itemid></item><item><title>Qcon杭州的演讲文稿</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248034/1234636/1/item.html</link><content:encoded>&lt;div style=&quot;width:425px&quot; id=&quot;__ss_9894400&quot;&gt;&lt;strong&gt;&lt;a href=&quot;http://www.slideshare.net/tangfl/redis-9894400&quot; title=&quot;新浪微博开放平台中的 Redis 实践&quot;&gt;新浪微博开放平台中的 Redis 实践&lt;/a&gt;&lt;/strong&gt;&lt;object width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=redis-111026151707-phpapp01&amp;amp;stripped_title=redis-9894400&amp;amp;userName=tangfl&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot; /&gt;&lt;embed name=&quot;__sse9894400&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=redis-111026151707-phpapp01&amp;amp;stripped_title=redis-9894400&amp;amp;userName=tangfl&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;div style=&quot;padding:5px 0 12px&quot;&gt;View more &lt;a href=&quot;http://www.slideshare.net/&quot;&gt;presentations&lt;/a&gt; from &lt;a href=&quot;http://www.slideshare.net/tangfl&quot;&gt;fulin tang&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;主题：http://qconhangzhou.com/ShowNews.aspx?id=7&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2011%2F10%2Fqcon-hangzhou.html&amp;title=Qcon%E6%9D%AD%E5%B7%9E%E7%9A%84%E6%BC%94%E8%AE%B2%E6%96%87%E7%A8%BF&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248034/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248034/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2011/10/qcon-hangzhou.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>新浪微博开放平台中的 Redis 实践 View more presentations from fulin tang. 主题：http://qconhangzhou.com/ShowNews.aspx?id=7&lt;img src=&quot;http://www1.feedsky.com/t1/635248034/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248034/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>技术资料</category><pubDate>Thu, 27 Oct 2011 04:25:33 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2011/10/qcon-hangzhou.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652689</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2011/10/qcon-hangzhou.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248034/1234636</fs:itemid></item><item><title>redis 坑</title><link>http://item.feedsky.com/~feedsky/fulin/~8140614/635248035/1234636/1/item.html</link><content:encoded>&lt;div style=&quot;width:425px&quot; id=&quot;__ss_9371197&quot;&gt;&lt;strong&gt;&lt;a href=&quot;http://www.slideshare.net/tangfl/redis-9371197&quot; title=&quot;Redis 坑&quot;&gt;Redis 坑&lt;/a&gt;&lt;/strong&gt;&lt;object width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=redis-110922024828-phpapp01&amp;amp;stripped_title=redis-9371197&amp;amp;userName=tangfl&quot; /&gt;&lt;param name=&quot;allowFullScreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot; /&gt;&lt;embed name=&quot;__sse9371197&quot; src=&quot;http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=redis-110922024828-phpapp01&amp;amp;stripped_title=redis-9371197&amp;amp;userName=tangfl&quot; type=&quot;application/x-shockwave-flash&quot; allowscriptaccess=&quot;always&quot; allowfullscreen=&quot;true&quot; width=&quot;425&quot; height=&quot;355&quot;&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;div style=&quot;padding:5px 0 12px&quot;&gt;View more &lt;a href=&quot;http://www.slideshare.net/&quot;&gt;presentations&lt;/a&gt; from &lt;a href=&quot;http://www.slideshare.net/tangfl&quot;&gt;fulin tang&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;http://www.bshare.cn/share?url=http%3A%2F%2Fblog.fulin.org%2F2011%2F09%2Fredis_keng.html&amp;title=redis+%E5%9D%91&quot; title=&quot;用bShare分享或收藏本文&quot;&gt;&lt;img src=&quot;http://static.bshare.cn/frame/images/button_custom1-zh.gif&quot; alt=&quot;用bShare分享或收藏本文&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;img src=&quot;http://www1.feedsky.com/t1/635248035/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248035/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</content:encoded><wfw:commentRss>http://blog.fulin.org/2011/09/redis_keng.html/feed</wfw:commentRss><slash:comments>0</slash:comments><description>Redis 坑 View more presentations from fulin tang.&lt;img src=&quot;http://www1.feedsky.com/t1/635248035/fulin/feedsky/s.gif?r=http://item.feedsky.com/~feedsky/fulin/~8140614/635248035/1234636/1/item.html&quot; border=&quot;0&quot; height=&quot;0&quot; width=&quot;0&quot; style=&quot;position:absolute&quot; /&gt;</description><category>工作日志</category><pubDate>Thu, 22 Sep 2011 15:53:55 +0800</pubDate><author>唐福林</author><comments>http://blog.fulin.org/2011/09/redis_keng.html#comments</comments><guid isPermaLink="false">http://fulin.juziyue.com/?p=652685</guid><dc:creator>唐福林</dc:creator><fs:srclink>http://blog.fulin.org/2011/09/redis_keng.html</fs:srclink><fs:srcfeed>http://blog.fulin.org/feed</fs:srcfeed><fs:itemid>feedsky/fulin/~8140614/635248035/1234636</fs:itemid></item></channel></rss>
