Hadoop背后的数学

自从Nathan Marz同学写了那篇著名的How to beat the CAP theorem的Blog,以及Storm发布之后,俨然成为了技术界新偶像。顺着他本人的blog,翻了一下他过去几年的写的技术文章,发现老美的牛人们都爱总结,能够把技术实践提升到理论高度,然后抽象出新的设计和产品,比起我等只能每天苦逼苦逼应对实际需求的人来说,还是强出很多。我自己觉得那么多年,虽然觉得做什么都能做了,但是现在还是只能谈到模仿,做不到提炼总结和超越。

和著名的CAP的那篇Blog,Nathan Marz还有很多其他非常有料值得一读的博客,与其在国内的各种Hadoop大会上听大家泛泛而谈架构,还不如多看看老外们总结下来的技术博呢,比如这篇The mathematics behind Hadoop-based systems,比起大家简单列列机器数字来说,有价值得多。

我曾经写过,数学对于称为一名优秀的程序员是很重要的,但这不一定意味着一定要是多高深的数学。Nathan的这篇Blog用到的数学只有初中难度,但是的确写明白了我们遇到的很多Estimation以及集群数量预估的实际问题,我想一定也有很多人用hadoop但是和我们一样,对于很多机器数量或者workflow的管理是很粗放的,相信这篇blog对很多人都会有用,所以把它翻译成中文,全文如下


基于Hadoop的系统背后的数学

我希望一年之前我就知道这些。现在,根据一些简单的数学,我就可以回答:

  • 为什么在我将处理能力翻倍之后,我的workflow的速度没有翻倍?
  • 为什么10%的任务失败率会导致我的运行时间上升到原来的300%?
  • 如果通过优化了我的workflow的运行时间的30%导致运行时间下降了80%?
  • 我的集群中到底需要多少机器可以满足性能和容错的需要?

所有这些问题都可以通过这样一个简单的等式干净地回答:

运行时间(Runtime) = 额外开销(Overhead) / (1-{处理一小时数据需要的时间})

我们很快就可以推导出这个等式。首先,让我们简单地讨论一下什么是我所说的“基于Hadoop的系统”1。Hadoop的一个常见的用例,就是通过运行一个workflow来处理来连续进入的流数据。这个工作流运行一个”while(true)”的循环,然后每个workflow的迭代,都处理自从上个迭代依赖累积的数据。

下面的这些分析的灵感可以在一个简单的示例中概括出来。假如说你有一个workflow需要运行12小时,然后它会在每个迭代中处理12个小时的数据。然后假如说你加强了这个workflow去做一些额外的分析,然后你估计你在当前的这个workflow中需要多花两个小时来处理。然后麻烦来了。你的workflow增加的运行时间可能远超过两小时。它可能增加了10个小时,100个小时,或者这个workflow可能呈螺旋式上升地在每个迭代中花费越来越多的时间知道无限。

为什么?

问题在于,你将处理12个小时数据的workflow的运行时间增加到了14个小时。这意味着当下一次workflow运行的时候,有14小时的数据需要处理。既然下一个迭代有更多的数据,他要花费更多时间运行。这意味着下一个迭代会有更多的数据,等等。

为了确定什么时候运行时间,让我们做一些简单的算术。首先,让我们写下一个只有一个迭代的workflow的运行时间的等式

运行时间 = 额外开销 + {处理一小时数据的时间} * {多少小时的数据}

额外开销(Overhead)指的是花费在workflow上的任何常数项时间。例如,开始一个job需要的时间会计入额外开销。使用distributed cache来分发文件的时间会计入额外开销。你会把任何独立于数据规模的时间花费放到“额外开销”的分类中去。

“处理一小时数据的时间”指的是workflow中的动态时间。这是你忽视那些额外开销,花费在处理实际数据上的时间。如何一小时的数据会增加你半小时的运行时间上,这个值应该是0.5。如果一小时的数据会增加你一小时的运行时间,这是值就是2。

为了简洁,让我们把上面那个等式通过变量来重新写一下:

T = O + P * H

为了确定workflow的稳定的运行时间,我们需要找到workflow的运行时间在哪个点上正好等于累积了的需要处理的数据量。为了做这个,我们可以简单地插入 T=H 来求解T:

T = O + P * T
T = O / (1 - P)

这就是我之前展示的等式。你可以看到,一个workflow的稳定的运行时间是和workflow中的额外开销呈线性比例的。所以如果你可以将额外开销减少25%,那么你的workflow运行时间就会减少25%。然而,一个workflow的稳定运行时间和动态处理的速率“P”不是呈线性比例的。这背后的隐含含义就是每为集群加入一台机器带来的性能提升是在减少的。

通过这个等式,我们可以回答我在文章开始时候写下的问题了。让我们一起来过一些这些问题:

为什么在我将处理能力翻倍之后,我的workflow的速度没有翻倍?

将你的机器数翻倍,会将你的“处理一小时数据需要的时间”减少50%2。这个的效果和你的运行时间的关系是完全依赖于之前的P值的。让我们用数学来展示一下。假如说你的workflow在集群的机器数量翻倍之前的运行时间是“T1”,翻倍之后是“T2”。这给了我们两个等式:

T1 = O / (1-P)
T2 = O / (1 - P/2)

那么性能加速就会是 T2/T2,新的运行时间和旧的运行时间的比值。这给到我们

T2 / T1 = (1 - P) / (1 - P/2)
T2 / T1 = 1 - P / (2 - P)

对这个式子作图,我们可以得到如下的图,其中原始的P在x轴上,性能加速在y轴3上:

这个图说明了一切。如果你的P非常高,比如说,需要54分钟来处理一小时的数据,那么将你的集群数量翻倍会使得你新的运行时间是原来的18%,足足有82%的性能加速!这是一个非常违背直觉的结论 —— 我强烈推荐读者们仔细思考这种情况出现的背后的机制。

然后,如果你之前的P没有那么高(例如,需要6分钟的动态运行时间来处理1小时的数据),那么将集群数量翻倍对于运行时间几乎没有效果 —— 可能只有类似6%。由于运行时间被额外开销所主导,这是很合乎情理的,动态运行时间在运行时间中占得很小。

为什么10%的任务失败率会导致我的运行时间上升到原来的300%?

这个问题解释了workflow稳定性的属性。在一个大集群中,你总是会有不同的机器故障,所以任务失败率的峰值不会干掉mission critical系统的性能是非常重要的。关于这个问题的分析会和上一个问题看起来非常相似,除了我们会将动态运行时间变差而不是提高它之外。10%的任务失败率意味着我们需要多运行11%的任务来处理完我们的数据4。由于任务依赖于我们所拥有的数据量,这意味着,我们的“处理一小时数据需要的时间”会上升11%。类似于上一个问题,让我们将T1作为没有任务失败所需要的运行时间,T2作为有任务失败的运行时间

T1 = O / (1 - P)
T2 = O / (1 - 1.11*P)
T2 / T1 = (1 - P) / (1 - 1.11*P)

对此作图,我们得到:


(译著: 上图中X轴为P值,Y轴为花费时间增加的比例)

你可以看到,任务失败对于运行时间的影响在你的集群有“额外容量”减少的情况下戏剧性地增长。所以让保持你的P低是非常重要的。我们可以看到你的P越高,由于任务失败率的增加,你就更有可能进入“毁灭循环”的风险5

如果通过优化掉我的workflow的运行时间的30%而导致运行时间下降了80%?

这个问题是使得我真正找出workflow的运行时间的模型。我曾在一个workflow中有一个荒谬的瓶颈,导致了大概10小时的额外开销6,然后整个workflow的运行时间大概是30小时。在我优化了这个瓶颈(大约占据了30%的运行时间)之后,运行时间像石头一样坠落,最终稳定在6小时(减少了80%)。使用我们的模型,我们可以确定为什么这发生了:

30 = O / (1 - P)
6 = (O - 10) / (1 - P)
O = 12.5, P = 0.58

所以那10小时,占据了workflow中的80%的额外开销,这解释了整个的性能提升。

我的集群中到底需要多少机器可以满足性能和容错的需要?

这基本上是一个费效比分析的练习。我们可以看到,通过增加集群中机器数据来提高性能到回报在减少,而一旦P(“处理一小时数据需要的时间”)下降到30分钟以下(0.5),通过增加机器获得的性能提升是次线性的7。我们也同样看到将P保持得低是很重要得,不然任务失败的增加或者其他的任务使用集群,会严重影响你的运行时间。所以,你需要运行一些数据来确定对你的应用最佳的机器数量8

你应该在Twitter上follow

更新:看看本文的后续内容



1 事实上,这个等式适用于任何批量处理连续数据流的系统。
2 这里假设你的处理是完全分布式的,并且没有持有任何中心点,这对于一个基于Hadoop的workflow来说通常是真的。一个可能的例外是,你所有的tasks都通过一个中心的数据库进行通信。事实上,增加更多的机器会在额外开销(更多的机器去处理)以及数据处理速率(mapper需要将数据分发到更多的reducer中去)有少量的不利影响。对于这个分析的目的来说,我们可以忽略这些。
3 该图通过FooPlot生成。
4 比如说我们通过100个task来处理数据,现在,当你运行这些task的时候,其中有10个会失败。当你重新运行这10个的时候,9个会成功,还有1一个会失败。所以你实际运行了111个task而不是100个,这意味着task的数量增加了11%。
5 或者其他的运行在集群上的东西,比如一次性的查询或者其他的workflow。
6 这是由于Berkeley DB在ext3的文件系统上会生成很多碎片。
7 事实上,我没有展示这个,但是你可以通过模型来自己推导。我把这个作为一个练习留给读者。
8 如果你需要的话,你可以让这个模型变得更加全面。比如,这个模型没有区分新进入的数据和已经存在需要被查询的数据(并且在每个迭代中都会增加)。这个变量必然会影响到你的长期扩展需求,记住它是非常重要的。对于那些知识对于这些workflow的性能有获得一个直觉的目的来说,这不是必须的。


运营一个系统比开发一个系统更重要

互联网公司和软件公司最大的不同在于,即使对于技术团队来说,开发工作也只是一小部分工作,如何使得整个系统运营起来,才是重头戏,这是过去一年感悟最深的一点;而对于像广告质量这样的技术团队来说,运营和开发可以说是完全不可分离的。过去一年,在这点上,走了很多弯路,犯了很多错误,有很多可以总结的地方。从Quora上看到这样一个问题,“What are the keys to operationalizing a machine learning ranking system from an organization / engineering management point of view?”

觉得唯一的一个回答就很好,翻译一下以记之,虽然做不到信达雅,但是基本意思应该能描述对。

这个问题的大概内容是这样的:


如果从组织管理/工程管理的角度来看,什么是将一个机器学习的Ranking系统运营起来的关键点?
对于那些有基于机器学习或者其他方式有Ranking系统的组织,可以保证他们运行平稳,并且随着时间的推移慢慢进步?哪些监控是重要的?如何定义目标,目标由谁来定义?如何分辨效果的提升来自于Feature工程团队还是核心算法上的提升?哪些严重依赖于Ranking的组织如何为这些来构造他们的流程?


目前唯一可见的回答,来自前Google的工程师Brandon Ballinger:


我之前在Google做语音识别和广告,这两者都以机器学习作为他们的核心。下面是我从“野外”学到的如何运营一个机器学习系统的一些重要的经验和教训

  • 将你的成功的指标定义为让用户高兴。传统的精确性的指标,比如precision, square error, ROC等等并不能捕捉到那些你真正关心的——用户对于你的模型是如何反应的。例如,如果你运营一个广告系统,你的指标应该是每个PV的收入以及点击率。完全有可能,由于辛普森悖论,你有一个error rate减少了的模型,但是他带来的收入却降低了。
  • 核心指标下降是很严重的问题。你需要把核心指标的大幅下降当成和一个服务器当机或者数据库中数据损坏一样严重的问题。Oncall的人需要尝试尽快诊断问题,并且必要时把别人拉进来一起解决问题
  • 对每次Model的Launch做A/B测试。你应当始终并行运行两个模型,给不同的用于用不同的模型,然后比较用户行为。这是唯一可以确保你知道你在做正确的事情的办法。
  • 小心丑小鸭效应。机器学习系统会在从自己的错误中学习的过程中变得更加准确。这意味着,新的模型有一个与生固来的缺陷:你的历史训练数据包含着过去模型中的错误,但不是你新训练的模型的错误。导致你的新模型一开始可能像一个丑小鸭,但是如果你用他来决策用户看到的内容,他最后会变成一个漂亮的天鹅。你可以通过将一小部分流量切给新模型,来部分抵消丑小鸭效应,然后慢慢随时间提高这个百分比。
  • 使得算法对于噪声Feature健壮。类似于L1 regularization这样的技术可以使得你的机器学习算法对Feature进行剪枝,修剪掉那些对于预测的准确性贡献很小的Feature。这可以帮助你很好地拆分你的团队:一些人专注于算法,另一些人写Feature喂给算法。那些寻找Feature的人,可以直接“把东西扔进锅里”,然后让算法找出他们究竟好还是不好。(类似的,你应该通过确保合理的收敛性来选择一个算法)
  • 你可以部分地将架构和算法团队解耦合。基本上,大部分机器学习算法都是在累计一个分布式的hash table的统计信息,然后将这些统计信息合并成一个分数。开发一个分布式的hash table是和开发一个用于累计的算法不同的任务,可以由不同的子Team完成。然后,让这些人一起工作仍然是很重要的。例如,一些算法在写入和写入可用之前延时的“最终一致”的系统中(例如Dynamo),会有所波动。所以这只是一个部分解耦合,你仍然需要团队中有连接架构和算法的“桥梁”人员。
  • 在在线系统和批处理系统之间选择的时候要小心。一个在线系统可以实时学习,对于新的用户行为,可以在发生之后的几分钟内有所反应。但是这回带来巨大的开销,一个在线系统需要2-3倍的时间区开发和维护,而且他对瞬间的变化更加敏感。举个例子,如果你突然接收到了很多垃圾信息,这些噪声会立刻被吸收进你的系统并且开始降低用户的体验。类似的,一台机器如果没有可运行的内容了,如果网络连接中断了,或者一个特定的机器变慢了(导致Feature“歪了”),模型的某个输入开始生产垃圾,等等。
  • 为所有东西打上版本。一个训练过的模型依赖于稳定的标识,如果你更改了某个标识,模型立刻就过时了。例如,如果你将用户的语言(“en-us”)作为一个feature。那么当有些人提交了一个一行的修改,用下划线替换了短横线(“en_us”)。这使得模型立刻“忘记”了所有从”en-us”中学到的,使得所有的语言看起来都是一样的。所以为所有会在你模型中生成标识的代码和数据的变更都打上版本。
  • 你需要咬碎100-1000倍于实时的数据。如果你的训练数据来自于整整一年的历史数据,然后你的学习过程是10倍于实时,那他需要一个月来测试一个新Feature。把所有的东西都写成Map-Reduce或者Storm Topology使得你可以在数据变得足够大的时候仍然可以扩展。

看了一下,里面有不少错误我们都犯过,包括过去一个Q我们觉得由于团队小应该快点冲而省略掉的东西,现在看来也还是省略不掉的,而之前做对的部分也都是来自老大们的经验,希望今年少走弯路效果好啊。


支持Ruby1.9的MRToolkit

虽然最近的工作整天用Java写各类数据处理代码,但是去年大半年用惯了Ruby的我每每要写个测试或者临时计算的MapReduce都觉得真是太麻烦了,于是又念叨起Ruby的好来了。

先看了看利用Hadoop Streaming和Ruby来写MapReduce,发现还是有些麻烦,一是mapper和reducer要分开两个文件,二是每个任务都要重复写从stdin读取数据解析,以及输出的代码,一点不符合DRY原则,于是就找到了mrtoolkit,然后一连串杯具开始发生了。

麻烦LJ同学先给所有的机器装了Ruby1.9,然后一跑,杯具地发现没跑起来,然后发现部分代码不兼容1.9……好吧,反正没多少源代码,改之,再跑,发现虽然每台机器都下载了mrtoolkit而且都设好了RUBYLIB但还是没能成功require mrtoolkit;于是,上github抄了个别人更改的mrtoolkit版本的gemspec和Rakefile,然后打包成gem,然后安装,于是MapReduce任务在各个node上跑起来了,但是,有一部分失败了,杯具地发现Ruby1.9开始对于字符串encoding有了很多限制,使用split通过正则分割字符串的时候居然还检查整个字符串的encoding的合法性,而我们要处理的日志里会存在GBK和UTF-8混在一行编码的可能性……试了好多种方法都不行,只好再跑到邮件组上去问,得高人指点先把字符串转成BINARY的encoding进行分割,然后再转回来,终于……能用了。

所以现在就有了这个支持Ruby1.9的mrtoolkit的版本啦,首个release包含以下变更:

  • 支持Ruby1.9
  • 将hadoop streaming中deprecated的-jobconf参数改成了-D
  • 单行的文本编码可以是混合编码的不合法的Ruby1.9的字符串
  • 可以打包成gem安装(抄袭自jashmenn的版本)

还准备做个小改动是默认output目录存在时输出警告,并且不提交任务不删除输出目录,直接删除现有的输出目录这种方法太容易搞出事情来了。


建议的程序员学习LDA算法的步骤

这一阵为了工作上的关系,花了点时间学习了一下LDA算法,说实话,对于我这个学CS而非学数学的人来说,除了集体智慧编程这本书之外基本没怎么看过机器学习的人来说,一开始还真是摸不太到门道,前前后后快要四个月了,算是基本了解了这个算法的实现,记录一下,也供后来人快速入门做个参考。

一开始直接就下了Blei的原始的那篇论文来看,但是看了个开头就被Dirichlet分布和几个数学公式打倒,然后因为专心在写项目中的具体的代码,也就先放下了。但是因为发现完全忘记了本科学的概率和统计的内容,只好回头去看大学时候概率论的教材,发现早不知道借给谁了,于是上网买了本,花了几天时间大致回顾了一遍概率论的知识,什么贝叶斯全概率公式,正态分布,二项分布之类的。
后来晚上没事儿的时候,去水木的AI版转了转,了解到了Machine Learning的圣经PRML,考虑到反正也是要长期学习了,搞了电子版,同时上淘宝买了个打印胶装的版本。春节里每天晚上看一点儿,扫了一下前两章,再次回顾了一下基本数学知识,然后了解了下贝叶斯学派那种采用共轭先验来建模的方式。于是再次尝试回头去看Blei的那篇论文,发现还是看不太懂,于是又放下了。然后某天Tony让我准备准备给复旦的同学们share一下我们项目中LDA的使用,为了不露怯,又去翻论文,正好看到Science上这篇Topic Models Vs. Unstructured Data的科普性质的文章,翻了一遍之后,再去PRML里看了一遍Graphic Models那一张,觉得对于LDA想解决的问题和方法了解了更清楚了。之后从search engine里搜到这篇文章,然后根据推荐读了一部分的Gibbs Sampling for the Uninitiated。之后忘了怎么又搜到了Mark Steyvers和Tom Griffiths合著的Probabilistic Topic Models,在某个周末往返北京的飞机上读完了,觉得基本上模型训练过程也明白了。再之后就是读了一下这个最简版的LDA Gibbs Sampling的实现,再回过头读了一下PLDA的源码,基本上算是对LDA有了个相对清楚的了解。

这样前前后后,也过去了三个月,其实不少时间都是浪费掉的,比如Blei的论文在没有任何相关知识的情况下一开始读了好几次,都没读完而且得到到信息也很有限,如果重新总结一下,我觉得对于我们这些门外汉程序员来说,想了解LDA大概需要这些知识:

  • 有基本的概率论的知识,这个拿个大学的课本大概翻一下就好了
  • PRML的前两章和Graphic Model那部分需要浏览一下,了解一下所谓的贝叶斯学派的方法论,然后理解共轭先验的概念,以及Graphic Model的图形表达的意思。
  • 了解一下Gibbs Sampling的概念
  • 直接读Steyvers的Probabilistic Topic Models,没必要一定去读Blei的论文,开创性的论文不一定好读,最典型的例子就是Paxos了,30多页里多少都是希腊人名,对于英文不够精通,学术训练比较少的工程师来说,其实很痛苦,意义也不大。
  • 对照着Probabilistic Topic Models直接看LdaGibbsSampling.java的源码

基本上这样一圈下来,基本概念和算法实现都应该搞定了,当然,数学证明其实没那么容易就搞定,但是对于工程师来说,先把这些搞定就能干活了,这个步骤并不适合各位读博士发论文的同学们,但是这样先看看也比较容易对于这些数学问题的兴趣,不然,成天对这符号和数学公式,没有整块业余时间的我是觉得还是容易退缩放弃的。

发现作为工程师来说,还是看代码比较有感觉,看实际应用的实例比较有感觉,看来不能把大部分时间花在PRML上,还是要多对照着代码看。


作为一个程序员,数学对你到底有多重要

每个计算机系毕业的人,大都学过不少数学课,而且不少学校的计算机系的数学课,通常比一般的其他工科专业的数学要难一些,比如不上高等数学,而是学数学分析,不上线性代数而去上高等代数。但是,大部分毕业了后去做程序员的人,即使是所谓的名校计算机系毕业的,大都工作中也基本完全用不上学的那些数学,基本上,一半时间在CRUD,另一半时间在处理各类字符串、链表、Hash表,知道在面试中回答各种排序的时间复杂度是他们需要的数学的上线了。

而在念书的时候,虽然上大学之前,有不少内行的外行的,年老的年轻的人告诉你,数学很重要啊。但是,通常来说,各个学校的计算机系的同学么,爱好学习的,可能重视的也是Thinking in Java,C++ Primer之类的语言书,或者设计模式之类的架构书,抑或是算法与数据结构这些玩意儿;而像我这样天天偷懒放羊的,也不会把数学当作是什么重要的课程好好学习。所以,“数学真重要”,这句话,似乎对于大家来说,始终只是飘在天上的一句话,随风飘逝了。

于是,五年过去了,程序员们都有了不少的工作经验了,如果不是对工作毫无追求混吃等死的程序员的话,对于天天干活的语言,不论是Java还是C++应该都熟能生巧了,所谓的设计模式、重构、自动化测试等等也手到擒来了,大部分人的title上都加上了Senior了,牛一点的后面大概还跟上了一个Manager,然而,大家都开始考虑一个新的问题——“30岁以后怎么半?”,于是,转PM的转PM,考公务员的考公务员,像我这样仍然抱定——“你看人家美国Rohit都50了还不是天天写程序,别人想请还请不到的”的单纯想法的人越来越少了。然后,就算这些人,时不时也会觉得,自己天天干的超越CRUD的,所谓写点OO的框架,不也是很无聊的体力活么,写程序的人干两年谁都会干。于是,又有不少人下海创业了,多年以后,这些人中的大部分都会和我一样悲催的没有挣到前继续回来给大大小小的公司写程序。

其实,杯具往往发生在一开始,其实,要是咱们当年好好学习,才会发现,也许数学对于你当个不错的程序员来说,没那么重要,但是要再往上走一步,有一点点技术上的创新,就都是数学的事儿了。两年前,我在T公司,用Configurator处理某个程序的时候,开始有点儿意识到这一点了,于是,那阵子还花了不少时间重新翻了翻数理逻辑。今年,换了新工作后为了工作看点儿机器学习的东西的时候,终于发现,这全都是数学啊。当你要超越CRUD,做任何一点点有创新性的技术的时候(不说产品),最有机会遇到的问题,其实是数学问题。虽然从Spring到Hibernate到Rails之类的框架,或者Hadoop,HBase之类的分布式计算框架,也都是技术上的重大革新,但是这些框架类的程序,完善都是阶段性的,一旦出现后,很快都会有相应的Best Practice,又会成为熟练工种的活。而真正针对问题域的解答,反是每天都可以有些新鲜的想法、思路和方案的,这些,往往有个数学的门槛。所以如果你真是挺喜欢写程序的,而且希望自己一直能写更好玩更难的程序,总有一天,你要过了这一道坎儿。

所以我很是同意不知道是谁说得,如果你只想当个good programmer,那么数学不重要。但是如果你想当个great programmer,那么数学很重要。在你手里只有锤子的时候,你看什么东西都会是个钉子,想想你如果没有学过算法和数据结构,可能你的大部分程序需要自己写排序的话,都会是傻傻地冒泡吧,反正对于大部分程序来说,在现在这么快的PC下,这点时间差别,大部分情况下,也就是让你等程序执行测试的时候,多个倒杯水的时间。但是很多新鲜,好玩,有挑战的问题,很多数学的概念没有的话,恐怕不是多等个倒水的时间了。而如果你过了这个门槛,你又会发现,一个崭新的世界,又到了你的面前。

回过头来,我说数学重要的话,那么重要的是哪些呢?大家常说的通常是离散数学,不过最近比较热门的机器学习这个方向,我目前看到的相关资料都大量依赖于线性代数和概率论,以及一点点微积分。所以,如果你和我一样,希望做点有追求的技术工作的话,开始花点时间学习数学吧。其实万事开头难,也许你和我一样,对着一堆公式符号,感到头晕眼花,但是如果真得按下心来,看上一个小时,这么坚持个一周,其实就会发现,这没啥难的,就当学门新的编程语言得了。

PS:如果在google中搜索程序员 数学的话,第一个链接是程序员怎样学数学,我觉得这篇文章写得相当不错。我也非常同意,广度有限比较有效,容易激发学习的兴趣,而且能和实际的工作和现实世界的问题、项目相结合。


我的IT环境

科技越来越发达,工具越来越多,每天的生活都要和你的电脑、软件还有互联网服务打交道。这篇,就来说说我现在常用的软硬件工具和服务:

笔记本一之N610c:毕业没几个月买了台二手的N610c,然后抛弃了原来的拼装台式机。可惜我买二手的东西寿命都不长,现在这台机器通常作为我的第二显示器在写东西需要参考的时候开着,干活是已然不行了,因为南桥主板芯片出了问题,USB口不工作了,电池也充不进电了。
这台机器系统是XP,基本只装了Firefox和Adobe Reader,因为主要用来看看东西啦。

笔记本二之Macbook 466:去年底离职之后把工作电脑上交了,然后立马去买了台新的铝壳麦书,很好用啊很好用,虽然从价格上来说不便宜,摄像头蓝牙都有,多点触控很方便,用惯了改用windows有时候还真有点不习惯……
这台现在是日常工作机了,每天开机自启动的是Skype和Adium,Adium的好处是可以整合多个IM,不用再MSN+ICQ+QQ+Gtalk开四个IM浪费内存了,而且Adium可以让你整合多个IM的分组,同时将不同IM上的同一人的多个帐号合并在一起,非常方便,不用再一个个IM看某人是否在线了。然后浏览器日常用的是Firefox,当然也装了Safari和Opera测试的时候用用,Firefox里的插件装得不多,发现其实天天要用的也就那么一点,目前只有Adblock Plus,Firebug,Google Gears,Google Toolbar,GreaseMonkey,Remember the Milk for Gmail,Web Developer,wmlbrowser和Zotero。写代码目前主要在玩Ruby和Rails,所以找了个Textmate用用,一直在考虑要不要花钱买下license,当然Eclipse和Netbeans也都装了,自带的Xcode也在,不过Netbeans和Xcode基本没用过;装了Subversion和Git作为SCM的客户端,当然,慢慢习惯用Git之后我觉得SVN可以抛弃了。日常的照片音乐都交给了自带的iLife,看PDF也是用的Preview,反正对我来说已经足够好了。看片用Mplayer 1.0,下载各大盗版则是Amule+Transmission。常常会用到自带的Stickies来记录点东西,自带的Dictionary也很好用,虽然装了QuickSilver,但是我还是更习惯Spotlight,不过貌似这玩意儿有越用越慢的趋势。当然,为了上网上银行,还是搞了个VMWare的Windows虚拟机的。

手机一之Nokia 6630:也是毕业没多久买的,到现在还正常工作。手机有强烈的诺基亚风格,就是难看,但是皮实经摔好用,电话短信不会有问题,也不会死机重启之类,电池也能撑三四天。买的时候也算是当时的牛机了,现在看上去则是连山寨也不如了。刚买那会儿装了不少软件折腾,还拿这个看电影听MP3啥的,现在上面只有三个非自带的软件,分别是A4输入法,MSN和UCWeb。意欲装Frings在手机上控制所有IM可惜它不卖面子始终没法用,而UCWeb则是战胜了Opera Mini占据了手机上的位置,常常用它在老婆逛街的时候看看Google Readers里订阅的内容。还值得一提的是,这台机器通过Google Sync可以把Gmail里的Contacts和手机上的双向同步,方便了备份和转移电话本了。

手机二之Blackberry 8310:去年买的号称全新机,看到号称这两个字你就知道是翻新机了,在不长的时间里已经出了两次问题,这不前两天又拿到JS那里去修了,每次买二手的东西,我的RP都很差,所以下定决心以后不碰二手的东西了。虽然常常不能好好用,但是不可否认Blackberry是设计优良的机器,虽然用不上push mail费了一半,但是这台机器通过Google Sync可以同步联系人之外,还能同步Calendar,然后买了Remember the Milk的Pro服务还能同步Todo list,就可以完全把PIM的功能随身携带。另外,上面的Gmail的客户端也很不错,因为是全键盘,通过快捷键操作还是非常方便的。还有个好处是开软件不像其他机器那么费电,机器的按键和滚轮手感也不错,现在我就希望这台机器这回修好别再出问题了。

MP3之iPod shuffle 2:一台银色的夹子shuffle,不该买的,话说这其实也是台二手的,新蛋上买的,不过用的实在不多,浪费了,话说二手真是我的诅咒啊。

互联网服务:Mail自然毫无疑问是Gmail。然后是一系列的Google服务,因为Google Reader的分享功能用它替代了Bloglines;用Google Docs做读书笔记或者整理各种零散的笔记;用Google Calendar做日程表,虽然最近没什么计划性。然后Todo list因为Google自带的实在是不太好用,所以用的是Remember the Milk,装了Firefox的插件所以可以和Gmail很好地整合。Blog是host在Dreamhost上的,然后代码则是用Github取代了不稳定的Google Code

看了看,发现自己用的东西还是很简单的,同学们也来分享一下自己用的软硬件和服务吧。


在新macbook上安装Rails+MySQL

嗯,嗯,嗯,这个问题前一阵来来回回折腾过不少时间,主要的问题在于

  • Macbook 466是64位的CPU
  • Leopard自带的Ruby是32位的版本
  • 如果安装的MySQL是64位版本的,就需要自己编译个Ruby
  • 要不你就像我这样还是装个32位的MySQL吧

MySQL安装的注意事项

  • 建议安装Startup Item,这样就开机自启动了
  • 如果装了Startup Item但是不想开机自启动,那就修改/etc/hostconfig,把MYSQLCOM=-YES-改成MYSQLCOM=-NO-
  • 默认的encoding是latin1,所以要改一下配置文件,按下面这么办就行了
   $ sudo cp /usr/local/mysql/support-files/my-small.cnf /etc/my.cnf
   $ sudo vim /etc/my.cnf
   # 在对应的节点添加如下信息
   [client]
   default-character-set = utf8
   [mysqld]
   character-set-server = utf8
   default-table-type = innodb 

记得数据库创建要在改完配置重启mysqld之后,不然创建的数据库默认还是latin1的

然后就是gem安装mysql的驱动了,抛弃掉Rails自带的过时的ruby版本的驱动了

sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

如果您装的是64位的Ruby和MySQL那么改一个参数吧

sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config

折腾了一下午

遇上了n个bug,本来是想下个FM2009的Mac版,结果transmission罢工,一开始以为是种子过期了,可是换了一个还是一样的毛病,始终报Tracker request failed。研究了一下,发现是一个1.40版的已知bug,于是只好去下了个nightly build的版本,结果……没罢工但是完全没速度啊。

接下来是准备开工写个rails的app,看了一眼官方站点,貌似Leopard是自带ruby,rails,gem等等等,结果又是一堆错,好在这个提示还比较明确,告诉我rake版本太低,于是sudo gem update。然后又是一堆错,看了一眼,发现又是一个bug,可耻的是,居然还没fix,更可耻的是,居然这个bug已经发现有一年了……提供的work around方案就是删了重装而不要update,边考虑边顺手update了过时的rubygem版本。出问题的都是update好的lib后generate的doc,本来想忍了,想想还是继续折腾吧,搞彻底了以防以后再出sb的问题。所以谁也在Leopard下用ror,如果发现update的时候console出现下面这样的出错提示:

ERROR:  While generating documentation for net-sftp-2.0.1

… MESSAGE:   Unhandled special: Special: type=33, text=”Net::SFTP”

… RDOC args: –ri –op /Library/Ruby/Gems/1.8/doc/net-sftp-2.0.1/ri –line-numbers –inline-source –title Net-sftp –main README.rdoc –quiet lib CHANGELOG.rdoc lib/net/sftp/constants.rb lib/net/sftp/errors.rb lib/net/sftp/operations/dir.rb lib/net/sftp/operations/download.rb lib/net/sftp/operations/file.rb lib/net/sftp/operations/file_factory.rb lib/net/sftp/operations/upload.rb lib/net/sftp/packet.rb lib/net/sftp/protocol/01/attributes.rb lib/net/sftp/protocol/01/base.rb lib/net/sftp/protocol/01/name.rb lib/net/sftp/protocol/02/base.rb lib/net/sftp/protocol/03/base.rb lib/net/sftp/protocol/04/attributes.rb lib/net/sftp/protocol/04/base.rb lib/net/sftp/protocol/04/name.rb lib/net/sftp/protocol/05/base.rb lib/net/sftp/protocol/06/attributes.rb lib/net/sftp/protocol/06/base.rb lib/net/sftp/protocol/base.rb lib/net/sftp/protocol.rb lib/net/sftp/request.rb lib/net/sftp/response.rb lib/net/sftp/session.rb lib/net/sftp/version.rb lib/net/sftp.rb README.rdoc

(continuing with the rest of the installation)

就麻烦你自己把旧版本的rdoc删了重生吧……

Gmail的新Feature

不知道是不是过时新闻了,不过今天发现gmail左上角多了个“New! Video Chat”的红色链接,原来,史上最强大的Web Mail,现在更加强大了,可以直接通过Gmail页面里使用Google Talk的Video Chat了。好吧好吧,虽然Google App还没有把我希望的PIM完全结合到Gmail中,但是我不得不承认,Google实在是太强大了,事实上,我都不曾想过他们可以把Video Chat集成到网页中,但是……他们居然真得这么做了,好吧好吧,我现在要把他们家当成我得dream company了。

我还没能找到人试验一把他们得Web Video Chat质量怎么样,所以如果有人愿意尝试得话,可以Call我Blog右边得Google Talk帐号。

PS:他们的宣传视频里用的机器也是Mac。


ant版本兼容性的问题

折腾了大半天,跑ADI的时候,到一半就抛错

unknown argument: -cp
-usage ant [options] [target [target2]

google了一把,一般都说啥cmd和bat脚本不对啦,删掉/etc/下的config文件啦,最后发现是,ant1.6.3以下版本不支持-cp参数而只有-lib参数。我在copy项目依赖的ant相关的jar的时候,用1.6.2的jar覆盖了1.6.5版本的,导致cmd和bat脚本都是1.6.5的,而实际用的jar是1.6.2的。