机器学习概述

机器学习作为一门交叉学科,目前为止没有非常权威的定义,或者说堪称权威的人下的定义太多,目前没有一个被大家公认的定义标准。最经典的也是T.Mitchell在他的那本《machine learning》中提到的:“利用经验改善系统自身的性能。”经典到过于简短。中科院的王珏研究员给出了如下说明:“令W是这个给定世界的有限或无限所有对象的集合,由于我们观察能力的限制,我们只能获得这个世界的一个有限的子集Q∈W。机器学习的任务就是根据这个世界的对象子集Q,计算这个世界的统计分布。这样,在统计意义下,这个分布对这个世界的绝大多数对象是正确的。这就是这个世界的一个模型。”其实,人类认识的世界的方法就是通过有限的特征去猜测和拟合无限维特征构成的真实世界。所以以上的描述相对于机器学习可能又太大了一些。不过从其本质出发,机器学习其实就是人类研究世界、认识世界的方法得到机器更强的计算和存储能力扩展后的延伸。从这个角度来说之前的说明倒也贴近机器学习的最终追求。

机器学习研究的问题大体可以分为以下几类:分类、回归、聚类。这些其实也是人类认识世界主要通过的一些途径。

分类很好理解,生物学上把生物分为动物、植物、微生物,动物之下又分脊椎动物和无脊椎动物,脊椎动物又可以分为哺乳动物、鸟类、爬行动物、两栖类、鱼类……通过一层层的划分,将拥有更多共性的对象放到一起,可以方便知识的积累和研究的深入……而在机器学习上所说的分类问题,与平时说的分类问题类似,就是将一个对象分入事先划分好的类别中。比如对一个新的物种,判断它是属于动物还是植物,这就可以算一个机器学习上的分类问题。

而回归则是数学上的一个概念,学过统计学的同学应该都接触过。简单的说就是确定两种或两种以上变量间相互依赖的定量关系的一种统计方法。最简单的就是以前书本上的一元线性函数回归分析:已知y=ax+b,并且知道一系列的样本点(x1,y1)(x2,y2)……要求通过这些样本点推出a和b的值,从而得到y根据x变化的规律。回归分析的特点是要事先知道几个变量中服从哪一种大致规律(比如一元线性函数,或者一元二次函数,或者多元一次函数等等),如果这个大致的规律没有猜对,之后无论用什么方法对参数进行拟合都不会得到合适的结果。

聚类是将物理或抽象对象的集合分成由类似的对象组成的多个类的过程。它有点像分类,它和分类不同的地方在于,分类是已经事先有了分好的类别,这就意味着这些类别也已经有大量已知的特征去刻画。而聚类则是事先不知道这些分类的特征,只拿到一堆混杂的样本,利用这些样本之间的关系,自动划分出几个类别。然后如果有需要可能会再对这些类别进行分析,对于稳定的聚类的结果可以作为之后分类方法的输入。类似于一杯水里混合了许多互不相溶的液体,这时可以用滤纸、分液法等方法对里面的液体进行分离,但是在分离之前,你并不知道最后会分出几种液体,分出的液体应该是什么样的你也不会知道。但是聚类之后的结果,你可以再进行研究,去定义这些新的分类。

机器学习的大部分问题就都可以归结到这三类问题中,比如排序问题、最后可以归结到分类上。而分类、回归、聚类的方法之间也不存在排他的界限,比如回归的结果可以作为分类的依据。聚类的方法可以作为分类的一个输入。等等。

Posted in machine learning | Tagged | Leave a comment

何谓真爱?

在果壳网上看到一篇用获今年诺贝尔奖的稳定匹配理论分析的所谓“最优速配法”的文章。被无数人追捧和转载,里面纯粹是出于娱乐者有之,也有半信半疑,甚至信以为真的。可惜真从科学的角度分析,这篇文章也是漏洞百出,让人忍不住吐槽。不过这篇文章倒也引出了一个问题:何谓真爱?

对于爱情的本源,大家应该不会有异议,不管怎么样的描述,“荷尔蒙”也好,“出于繁衍后代的原始本能”也罢。爱情最初的出发点也许真得非常简单。但是在人类社会进化到足够复杂而发明出“爱情”这个词之后,男女之间的吸引似乎也不再仅仅只是原始欲望那么简单。或者说原始的繁衍更优质后代的欲望的表现变得更加复杂。看看现在征友征婚的标准,可以列出的清单,有得甚至可以长达好几页。

还好人类在把社会和自己变得复杂的同时也发明出了许多对付这些复杂情况的分析工具。几千年来,我们已经逐渐习惯于用因果的逻辑工具来分析和理解我们周围的一切的事情。所以男女之间互相吸引总是能找出这样那样的理由。比如外貌、气质、身材、品德、性格、学识、才艺、地位、金钱……这几年发达的网络更是发挥集体的智慧成功总结出了言简意赅的“高帅富”和“白富美”(是否表明这些是择偶标准里最为大多数看重的前三位?)

在这里面,最有意思的是“拜金”这个似乎一直有些争议的选项。一方面批判者、鄙夷者众多,另一方面追捧、献身者不停。其实说句公道话一个人因为金钱的因素而喜欢上另一个人,和因为品德或者外貌喜欢上另一个人没有多大区别,只是特征维度的权重不同而已。不过“金钱”的一个特殊的地方在于你的身高可能只有到年老时才会由于龟背而有所降低,但是你的财富就不一定了,哪怕是富甲一方的豪门,也不能保证不在什么时候突然家道中落(当然豪门可能稳定性还好一些,那些没有太久财富积累的暴发户,财富值发生突变的可能更大),那么你曾经吸引他/她的因素可能就不在了。另外,如果他/她只是因为金钱才喜欢上你的,那么由于金钱的一般等价物属性,而且可以量化,所以它不像性格、才艺这类略显复杂的特征,比较起来简单直接明了,一旦有一个比你更有钱的人出现,你的他/她看起来似乎没有太多的理由不变心。所以即使拜金的女孩们不在乎,那些手头有金子的高富帅们可能也会比较介意,如果她们仅仅只看重了高富帅中的“富”这个字,而既然世界首富又只有一个,有些人难保会有一些不安全感,总担心哪天遇上一个更有钱的,可能怀中佳人就要和别人跑了。

所以如果真从变与不变的角度来分析,一个男生只是因为你的相貌而喜欢上你肯定不如因为你的性格而喜欢上你来得更可靠一些,不是说喜欢内在美就伟大,喜欢外在美就肤浅,两者其实都是很美好的东西,更看重哪一个只是萝卜青菜各有所爱(而且据我所知,其实看重后者的似乎更多一些……)。只不过性格可能随时间变坏的几率毕竟要比外貌随时间变差的几率小得多,即使在现代化妆和保养技术日新月异的情况下。所以这条已经足以反驳果壳的那篇文章了:由于个人的条件因素会随时间改变,你当时喜欢的他/她,二三十年后就未必还是你最喜欢的。而你当时不喜欢的他/她,也不一定不会在几年后上升排序。

这还只是其一,因为既然是爱情那就是双方互动的游戏,不光要考虑对方的条件,还要考虑自己感觉和心情。我们都知道人是会变的,不仅仅是那些可以明码标价的条件,一个人的兴趣、品味、要求也可能发生变化,可能有人小时候喜欢吃萝卜,长大后喜欢吃白菜。可能一二十岁时喜欢帅哥美女、三四十时喜欢成熟温柔的。有的人可能一辈子就喜欢二十岁年轻漂亮的女子,有的人可能小时候喜欢成绩好的,大一些喜欢长得帅的,再大一些喜欢事业有成的,再大一些喜欢性格成熟能照顾她的。所以,很杯具的,就算你的他/她的外在条件一直不变,或者一直在向好的方向发展。也难保你个人的口味不会发生一些转变。

这样看来似乎要保持一段长久稳定的感情就成了一件很困难的事,似乎只剩下两个例外:一个是你的口味和你的他/她吸引你的地方基本保持不变。还有一个是你的他/她吸引你的地方的变化能恰好跟得上你口味的变化。

我们先来看前者,这个在古代可能还是可以做到的,比如你种一辈子的地,本来身上的feature就不多,人家妹子要求的东西也不多,几十年就这么稀里糊涂地过去了(啊?你说这是过日子?不是轰轰烈烈的“真爱”?- -)。或者隐居深山,过着年复一年日复一日的简单生活。因为我们知道虽然人自己喜欢胡思乱想,但是如果切断人和外界的信息联系的话,这种胡思乱想导致的口味改变是可以约束和控制的(除了可能的乏味……),而简单规律的生活,与外界较少的联系会使得个人条件里面能变化的东西大约就是随时间而来的衰老了,只要你们当初互相吸引的因素不是会被衰老打败的(可能相貌至少要排除了,当然一定要严谨的说的话,长期只能见到一个异性倒可能带来口味上的改变,使你对外貌的在意程度可以大大降低),就可以安然得在其中渡过晚年(当然问题是离群索居的生活在现在看来肯定是很辛苦的……)。这倒也能解释为什么现代社会离婚率越来越高(传说北京的离婚率已经到了40%,成功接近发达国家的门槛50%……),用一句世俗的话说就是这个世界变得太快,面对的诱惑太多……翻译过来就是两点,一:个人条件变化和个人口味变化越来越快(看看微博上那些短命的,兴起一时“热点”,比如曾经红极一时之后只剩清水荡漾的度娘,和现在估计很难火过半年的江南style)。二:随着信息时代的信息爆炸,你能接触到的潜在对象和可比对象越来越多,而且更糟糕的是这些对象还不是一开始就排在你面前让你挑的,而是随着时间流逝,先后进入你的生活的。对于这一点,可以参考类比互联网电子交易系统引入股票二级交易市场之后导致换手率的爆炸性增长的情况……

那么后者呢?那种联动的变化带来的动态稳定似乎比消极的静态稳定状态要靠谱得多。但是可惜的是,我们都知道概率论里的乘法公式,能撞上的我觉得都可以认为有相当好的运气,不比彩票中个几十万差。所以要对后者有所期待,那只能平时多去烧香了。

那么看完以上这些,是否会让人有一种绝望的感觉呢?稳定的感情是否就只是个小概率事件呢?其实不然,上面的这些分析都是出自于果壳那篇文章的假设,而果壳那篇文章最大的问题在于它在模型抽象的时候忘记了,人是一种有状态的系统。人是有回忆的。而回忆将是一道坚固的护城河,一般的欲望很难飞过这个城池(当然因人对欲望的抗性和回忆在该人脑海中印象的深刻程度而异)。这时你的那个他/她,就已经不仅仅是一样你所追求的艺术品了,或者哪怕他/她已经不再是你所追求的那个艺术品,他/她的身上也已经承载了太多过去的信息,可能已经是你青春的一个大大的纪念品,一个过去时光留下的烙印,一个关联着太多曾经的活的礼物。外貌、气质、身材、品德、性格、学识、才艺、地位、金钱……有太多的条件可以拿出来比较,但是那些承载了太多时光的回忆,却是你们独一无二的财富。只要你们还在意这一个理由或者说属性,那在这一点上就没有其它人能超得过你们。 我们再回过头看那些经常作为真爱典型范例的例子,比如热恋的中的一方因为某次大病或者车祸,导致常年卧病在床,另一方不离不弃,这基本可以看成是一种对回忆的忠诚。还有,女方在男方一无所有时爱上男方,男方在发达后不忘“糟糠之妻”,这基本上也是一种忠于回忆的例子,当然女方在一开始可能看重的也不是事业,可能是男方身上别的特质,而男方在发达之后也可能未必会碰上更吸引他的女人(感觉把回忆脱离出来,赤裸裸的讨论因果,太伤害那些文艺烂漫的故事了,就此打住……)……而这些例子之所以显得特别,得到大家的歌颂,恰恰说明了大部分其实做不到,大部分故事不会这样演,从大多数人的“平常心”出发,可能回忆的份量并没有上述例子中显示的那么重。当然现实生活中回忆也一般不会遭到如上述例子中那样严峻得考验。

所以真爱是什么?也许现实中存活着的那些其实不过是1%的最初的冲动和互相吸引包装下的99%的回忆的变体吧。

Posted in Uncategorized | 1 Comment

Google Spanner简介(ZZ)

原帖转自http://qing.weibo.com/2294942122/88ca09aa3300221n.html 最近spanner很火啊,这篇文章感觉写得不错。大致介绍了一个概貌。

====================转载分割线========================

Spanner 是Google的全球级的分布式数据库 (Globally-Distributed Database) 。Spanner的扩展性达到了令人咋舌的全球级,可以扩展到数百万的机器,数已百计的数据中心,上万亿的行。更给力的是,除了夸张的扩展性之外,他还能同时通过同步复制和多版本来满足外部一致性,可用性也是很好的。冲破CAP的枷锁,在三者之间完美平衡。

 

Google Spanner原理- 全球级的分布式数据库

 

Spanner是个可扩展,多版本,全球分布式还支持同步复制的数据库。他是Google的第一个可以全球扩展并且支持外部一致的事务。Spanner能做到这些,离不开一个用GPS和原子钟实现的时间API。这个API能将数据中心之间的时间同步精确到10ms以内。因此有几个给力的功能:无锁读事务,原子schema修改,读历史数据无block。

EMC中国研究院实时紧盯业界动态,Google最近发布的一篇论文《Spanner: Google’s Globally-Distributed Database》, 笔者非常感兴趣,对Spanner进行了一些调研,并在这里分享。由于Spanner并不是开源产品,笔者的知识主要来源于Google的公开资料,通过现有公开资料仅仅只能窥得Spanner的沧海一粟,Spanner背后还依赖有大量Google的专有技术。

下文主要是Spanner的背景,设计和并发控制。

 

Spanner背景

要搞清楚Spanner原理,先得了解Spanner在Google的定位。

 

Google Spanner原理- 全球级的分布式数据库

 

 

 

从上图可以看到。Spanner位于F1和GFS之间,承上启下。所以先提一提F1和GFS。

 

F1

和众多互联网公司一样,在早期Google大量使用了Mysql。Mysql是单机的,可以用Master-Slave来容错,分区来扩展。但是需要大量的手工运维工作,有很多的限制。因此Google开发了一个可容错可扩展的RDBMS——F1。和一般的分布式数据库不同,F1对应RDMS应有的功能,毫不妥协。起初F1是基于Mysql的,不过会逐渐迁移到Spanner。

F1有如下特点:

·        7×24高可用。哪怕某一个数据中心停止运转,仍然可用。

·        可以同时提供强一致性和弱一致。

·        可扩展

·        支持SQL

·        事务提交延迟50-100ms,读延迟5-10ms,高吞吐

众所周知Google BigTable是重要的NoSql产品,提供很好的扩展性,开源世界有HBase与之对应。为什么Google还需要F1,而不是都使用BigTable呢?因为BigTable提供的最终一致性,一些需要事务级别的应用无法使用。同时BigTable还是NoSql,而大量的应用场景需要有关系模型。就像现在大量的互联网企业都使用Mysql而不愿意使用HBase,因此Google才有这个可扩展数据库的F1。而Spanner就是F1的至关重要的底层存储技术。

 

Colossus(GFS II)

Colossus也是一个不得不提起的技术。他是第二代GFS,对应开源世界的新HDFS。GFS是著名的分布式文件系统。

 

Google Spanner原理- 全球级的分布式数据库

 

 

 

初代GFS是为批处理设计的。对于大文件很友好,吞吐量很大,但是延迟较高。所以使用他的系统不得不对GFS做各种优化,才能获得良好的性能。那为什么Google没有考虑到这些问题,设计出更完美的GFS ?因为那个时候是2001年,Hadoop出生是在2007年。如果Hadoop是世界领先水平的话,GFS比世界领先水平还领先了6年。同样的Spanner出生大概是2009年,现在我们看到了论文,估计Spanner在Google已经很完善,同时Google内部已经有更先进的替代技术在酝酿了。笔者预测,最早在2015年才会出现Spanner和F1的山寨开源产品。

Colossus是第二代GFS。Colossus是Google重要的基础设施,因为他可以满足主流应用对FS的要求。Colossus的重要改进有:

·        优雅Master容错处理 (不再有2s的停止服务时间)

·        Chunk大小只有1MB (对小文件很友好)

·        Master可以存储更多的Metadata(当Chunk从64MB变为1MB后,Metadata会扩大64倍,但是Google也解决了)

Colossus可以自动分区Metadata。使用Reed-Solomon算法来复制,可以将原先的3份减小到1.5份,提高写的性能,降低延迟。客户端来复制数据。具体细节笔者也猜不出。

 

与BigTable, Megastore对比

Spanner主要致力于跨数据中心的数据复制上,同时也能提供数据库功能。在Google类似的系统有BigTable和Megastore。和这两者相比,Spanner又有什么优势呢。

BigTable在Google得到了广泛的使用,但是他不能提供较为复杂的Schema,还有在跨数据中心环境下的强一致性。Megastore有类RDBMS的数据模型,同时也支持同步复制,但是他的吞吐量太差,不能适应应用要求。Spanner不再是类似BigTable的版本化 key-value存储,而是一个“临时多版本”的数据库。何为“临时多版本”,数据是存储在一个版本化的关系表里面,存储的时间数据会根据其提交的时间打上时间戳,应用可以访问到较老的版本,另外老的版本也会被垃圾回收掉。

Google官方认为 Spanner是下一代BigTable,也是Megastore的继任者。

 

Google Spanner设计

功能

从高层看Spanner是通过Paxos状态机将分区好的数据分布在全球的。数据复制全球化的,用户可以指定数据复制的份数和存储的地点。Spanner可以在集群或者数据发生变化的时候将数据迁移到合适的地点,做负载均衡。用户可以指定将数据分布在多个数据中心,不过更多的数据中心将造成更多的延迟。用户需要在可靠性和延迟之间做权衡,一般来说复制1,2个数据中心足以保证可靠性。

作为一个全球化分布式系统,Spanner提供一些有趣的特性。

·        应用可以细粒度的指定数据分布的位置。精确的指定数据离用户有多远,可以有效的控制读延迟(读延迟取决于最近的拷贝)。指定数据拷贝之间有多远,可以控制写的延迟(写延迟取决于最远的拷贝)。还要数据的复制份数,可以控制数据的可靠性和读性能。(多写几份,可以抵御更大的事故)

·        Spanner还有两个一般分布式数据库不具备的特性:读写的外部一致性,基于时间戳的全局的读一致。这两个特性可以让Spanner支持一致的备份,一致的MapReduce,还有原子的Schema修改。

这写特性都得益有Spanner有一个全球时间同步机制,可以在数据提交的时候给出一个时间戳。因为时间是系列化的,所以才有外部一致性。这个很容易理解,如果有两个提交,一个在T1,一个在T2。那有更晚的时间戳那个提交是正确的。

这个全球时间同步机制是用一个具有GPS和原子钟的TrueTime API提供了。这个TrueTime API能够将不同数据中心的时间偏差缩短在10ms内。这个API可以提供一个精确的时间,同时给出误差范围。Google已经有了一个TrueTime API的实现。笔者觉得这个TrueTimeAPI 非常有意义,如果能单独开源这部分的话,很多数据库如MongoDB都可以从中受益。

体系结构

Spanner由于是全球化的,所以有两个其他分布式数据库没有的概念。

·        Universe。一个Spanner部署实例称之为一个Universe。目前全世界有3个。一个开发,一个测试,一个线上。因为一个Universe就能覆盖全球,不需要多个。

·        Zones. 每个Zone相当于一个数据中心,一个Zone内部物理上必须在一起。而一个数据中心可能有多个Zone。可以在运行时添加移除Zone。一个Zone可以理解为一个BigTable部署实例。

 

Google Spanner原理- 全球级的分布式数据库

 

 

 

 

如图所示。一个Spanner有上面一些组件。实际的组件肯定不止这些,比如TrueTime API Server。如果仅仅知道这些知识,来构建Spanner是远远不够的。但Google都略去了。那笔者就简要介绍一下。

·        Universemaster: 监控这个universe里zone级别的状态信息

·        Placement driver:提供跨区数据迁移时管理功能

·        Zonemaster:相当于BigTable的Master。管理Spanserver上的数据。

·        Location proxy:存储数据的Location信息。客户端要先访问他才知道数据在那个Spanserver上。

·        Spanserver:相当于BigTable的ThunkServer。用于存储数据。

可以看出来这里每个组件都很有料,但是Google的论文里只具体介绍了Spanserver的设计,笔者也只能介绍到这里。下面详细阐述Spanserver的设计。

 

Spanserver

本章详细介绍Spanserver的设计实现。Spanserver的设计和BigTable非常的相似。参照下图

 

Google Spanner原理- 全球级的分布式数据库

 

从下往上看。每个数据中心会运行一套Colossus (GFS II) 。每个机器有100-1000个tablet。Tablet概念上将相当于数据库一张表里的一些行,物理上是数据文件。打个比方,一张1000行的表,有10个tablet,第1-100行是一个tablet,第101-200是一个tablet。但和BigTable不同的是BigTable里面的tablet存储的是Key-Value都是string,Spanner存储的Key多了一个时间戳:

(Key: string, timestamp: int64) ->string。

因此spanner天生就支持多版本,tablet在文件系统中是一个B-tree-like的文件和一个write-ahead日志。

每个Tablet上会有一个Paxos状态机。Paxos是一个分布式一致性协议。Table的元数据和log都存储在上面。Paxos会选出一个replica做leader,这个leader的寿命默认是10s,10s后重选。Leader就相当于复制数据的master,其他replica的数据都是从他那里复制的。读请求可以走任意的replica,但是写请求只有去leader。这些replica统称为一个paxos group。

每个leader replica的spanserver上会实现一个lock table还管理并发。Lock table记录了两阶段提交需要的锁信息。但是不论是在Spanner还是在BigTable上,但遇到冲突的时候长时间事务会将性能很差。所以有一些操作,如事务读可以走lock table,其他的操作可以绕开lock table。

每个leader replica的spanserver上还有一个transaction manager。如果事务在一个paxos group里面,可以绕过transaction manager。但是一旦事务跨多个paxos group,就需要transaction manager来协调。其中一个Transactionmanager被选为leader,其他的是slave听他指挥。这样可以保证事务。

 

Directories and Placement

之所以Spanner比BigTable有更强的扩展性,在于Spanner还有一层抽象的概念directory, directory是一些key-value的集合,一个directory里面的key有一样的前缀。更妥当的叫法是bucketing。Directory是应用控制数据位置的最小单元,可以通过谨慎的选择Key的前缀来控制。据此笔者可以猜出,在设计初期,Spanner是作为F1的存储系统而设立,甚至还设计有类似directory的层次结构,这样的层次有很多好处,但是实现太复杂被摒弃了。

Directory作为数据放置的最小单元,可以在paxos group里面移来移去。Spanner移动一个directory一般出于如下几个原因:

·        一个paxos group的负载太大,需要切分

·        将数据移动到access更近的地方

·        将经常同时访问的directory放到一个paxos group里面

Directory可以在不影响client的前提下,在后台移动。移动一个50MB的directory大概需要的几秒钟。

那么directory和tablet又是什么关系呢。可以理解为Directory是一个抽象的概念,管理数据的单元;而tablet是物理的东西,数据文件。由于一个Paxos group可能会有多个directory,所以spanner的tablet实现和BigTable的tablet实现有些不同。BigTable的tablet是单个顺序文件。Google有个项目,名为Level DB,是BigTable的底层,可以看到其实现细节。而Spanner的tablet可以理解是一些基于行的分区的容器。这样就可以将一些经常同时访问的directory放在一个tablet里面,而不用太在意顺序关系。

在paxos group之间移动directory是后台任务。这个操作还被用来移动replicas。移动操作设计的时候不是事务的,因为这样会造成大量的读写block。操作的时候是先将实际数据移动到指定位置,然后再用一个原子的操作更新元数据,完成整个移动过程。

Directory还是记录地理位置的最小单元。数据的地理位置是由应用决定的,配置的时候需要指定复制数目和类型,还有地理的位置。比如(上海,复制2份;南京复制1分) 。这样应用就可以根据用户指定终端用户实际情况决定的数据存储位置。比如中国队的数据在亚洲有3份拷贝, 日本队的数据全球都有拷贝。

前面对directory还是被简化过的,还有很多无法详述。

 

数据模型

Spanner的数据模型来自于Google内部的实践。在设计之初,Spanner就决心有以下的特性:

·        支持类似关系数据库的schema

·        Query语句

·        支持广义上的事务

为何会这样决定呢?在Google内部还有一个Megastore,尽管要忍受性能不够的折磨,但是在Google有300多个应用在用它,因为Megastore支持一个类似关系数据库的schema,而且支持同步复制 (BigTable只支持最终一致的复制) 。使用Megastore的应用有大名鼎鼎的Gmail, Picasa, Calendar, Android Market和AppEngine。 而必须对Query语句的支持,来自于广受欢迎的Dremel,笔者不久前写了篇文章来介绍他。 最后对事务的支持是比不可少了,BigTable在Google内部被抱怨的最多的就是其只能支持行事务,再大粒度的事务就无能为力了。Spanner的开发者认为,过度使用事务造成的性能下降的恶果,应该由应用的开发者承担。应用开发者在使用事务的时候,必须考虑到性能问题。而数据库必须提供事务机制,而不是因为性能问题,就干脆不提供事务支持。

数据模型是建立在directory和key-value模型的抽象之上的。一个应用可以在一个universe中建立一个或多个database,在每个database中建立任意的table。Table看起来就像关系型数据库的表。有行,有列,还有版本。Query语句看起来是多了一些扩展的SQL语句。

Spanner的数据模型也不是纯正的关系模型,每一行都必须有一列或多列组件。看起来还是Key-value。主键组成Key,其他的列是Value。但这样的设计对应用也是很有裨益的,应用可以通过主键来定位到某一行。

 

Google Spanner原理- 全球级的分布式数据库

 

上图是一个例子。对于一个典型的相册应用,需要存储其用户和相册。可以用上面的两个SQL来创建表。Spanner的表是层次化的,最顶层的表是directory table。其他的表创建的时候,可以用interleave in parent来什么层次关系。这样的结构,在实现的时候,Spanner可以将嵌套的数据放在一起,这样在分区的时候性能会提升很多。否则Spanner无法获知最重要的表之间的关系。

 

TrueTime

 

Google Spanner原理- 全球级的分布式数据库

 

TrueTime API 是一个非常有创意的东西,可以同步全球的时间。上表就是TrueTime API。TT.now()可以获得一个绝对时间TTinterval,这个值和UnixTime是相同的,同时还能够得到一个误差e。TT.after(t)和TT.before(t)是基于TT.now()实现的。

那这个TrueTime API实现靠的是GFS和原子钟。之所以要用两种技术来处理,是因为导致这两个技术的失败的原因是不同的。GPS会有一个天线,电波干扰会导致其失灵。原子钟很稳定。当GPS失灵的时候,原子钟仍然能保证在相当长的时间内,不会出现偏差。

实际部署的时候。每个数据中心需要部署一些Master机器,其他机器上需要有一个slave进程来从Master同步。有的Master用GPS,有的Master用原子钟。这些Master物理上分布的比较远,怕出现物理上的干扰。比如如果放在一个机架上,机架被人碰倒了,就全宕了。另外原子钟不是并很贵。Master自己还会不断比对,新的时间信息还会和Master自身时钟的比对,会排除掉偏差比较大的,并获得一个保守的结果。最终GPS master提供时间精确度很高,误差接近于0。

每个Slave后台进程会每个30秒从若干个Master更新自己的时钟。为了降低误差,使用Marzullo算法。每个slave还会计算出自己的误差。这里的误差包括的通信的延迟,机器的负载。如果不能访问Master,误差就会越走越大,知道重新可以访问。

 

Google Spanner并发控制

Spanner使用TrueTime来控制并发,实现外部一致性。支持以下几种事务。

·        读写事务

·        只读事务

·        快照读,客户端提供时间戳

·        快照读,客户端提供时间范围

例如一个读写事务发生在时间t,那么在全世界任何一个地方,指定t快照读都可以读到写入的值。

 

Google Spanner原理- 全球级的分布式数据库

 

上表是Spanner现在支持的事务。单独的写操作都被实现为读写事务 ; 单独的非快照被实现为只读事务。事务总有失败的时候,如果失败,对于这两种操作会自己重试,无需应用自己实现重试循环。

时间戳的设计大大提高了只读事务的性能。事务开始的时候,要声明这个事务里没有写操作,只读事务可不是一个简单的没有写操作的读写事务。它会用一个系统时间戳去读,所以对于同时的其他的写操作是没有Block的。而且只读事务可以在任意一台已经更新过的replica上面读。

对于快照读操作,可以读取以前的数据,需要客户端指定一个时间戳或者一个时间范围。Spanner会找到一个已经充分更新好的replica上读取。

还有一个有趣的特性的是,对于只读事务,如果执行到一半,该replica出现了错误。客户端没有必要在本地缓存刚刚读过的时间,因为是根据时间戳读取的。只要再用刚刚的时间戳读取,就可以获得一样的结果。

 

读写事务

正如BigTable一样,Spanner的事务是会将所有的写操作先缓存起来,在Commit的时候一次提交。这样的话,就读不出在同一个事务中写的数据了。不过这没有关系,因为Spanner的数据都是有版本的。

在读写事务中使用wound-wait算法来避免死锁。当客户端发起一个读写事务的时候,首先是读操作,他先找到相关数据的leader replica,然后加上读锁,读取最近的数据。在客户端事务存活的时候会不断的向leader发心跳,防止超时。当客户端完成了所有的读操作,并且缓存了所有的写操作,就开始了两阶段提交。客户端闲置一个coordinator group,并给每一个leader发送coordinator的id和缓存的写数据。

leader首先会上一个写锁,他要找一个比现有事务晚的时间戳。通过Paxos记录。每一个相关的都要给coordinator发送他自己准备的那个时间戳。

Coordinatorleader一开始也会上个写锁,当大家发送时间戳给他之后,他就选择一个提交时间戳。这个提交的时间戳,必须比刚刚的所有时间戳晚,而且还要比TT.now()+误差时间 还有晚。这个Coordinator将这个信息记录到Paxos。

在让replica写入数据生效之前,coordinator还有再等一会。需要等两倍时间误差。这段时间也刚好让Paxos来同步。因为等待之后,在任意机器上发起的下一个事务的开始时间,都比如不会比这个事务的结束时间早了。然后coordinator将提交时间戳发送给客户端还有其他的replica。他们记录日志,写入生效,释放锁。

 

只读事务

对于只读事务,Spanner首先要指定一个读事务时间戳。还需要了解在这个读操作中,需要访问的所有的读的Key。Spanner可以自动确定Key的范围。

如果Key的范围在一个Paxos group内。客户端可以发起一个只读请求给group leader。leader选一个时间戳,这个时间戳要比上一个事务的结束时间要大。然后读取相应的数据。这个事务可以满足外部一致性,读出的结果是最后一次写的结果,并且不会有不一致的数据。

如果Key的范围在多个Paxos group内,就相对复杂一些。其中一个比较复杂的例子是,可以遍历所有的group leaders,寻找最近的事务发生的时间,并读取。客户端只要时间戳在TT.now().latest之后就可以满足要求了。

 

最后的话

本文介绍了GoogleSpanner的背景,设计和并发控制。希望不久的将来,会有开源产品出现。

Posted in reprint | Tagged , , | 1 Comment

浅议社会融资方式的选择

又有一个多月没更新博客了,想想几个月前刚续了两年黑山共和国的域名就觉得肉疼。所以还是尽量逼自己写点啥吧。

========================牢骚分割线=====================

几个月前很巧地和一个同学聊起了东亚自贸区的事,聊着聊着就说到投资手段上,当时这位同学情绪激动,说股票都是投机的玩意儿,骗钱圈钱投资效率低下,只有美国这样能吸收全世界投资又能随意印钞的超级大国才玩得动。中国的投资市场应该学习德国,以银行放贷和企业债券为主,融资靠谱,较少投机,真正把钱用在扩大再生产的刀刃上,而不是落入那些投机商人和赌徒的腰包中。于是争论主要就落在了股票还是银行贷款,容忍投机还是完全不容忍投机上了。

当时因为主要的见识都来自于书本和理论,总觉得再多的意见和争论也都是脱离实际的空谈,所以也不以为意。后来由于机缘巧合,在国泰君安开了个户,于是投了点小钱到了股市,正好赶上传说中的“钻石底”,经历了一个月的起起落落,对股市总算也有了点感性的认识。股市融资为生产企业输血一般只有两个办法,一个是IPO,也就是企业刚上市的时候拿出股份到公开市场上贩卖。另一种是增发,也就是在IPO之后,公司增加股本,将增加的股份在市场上再次进行售卖,募集资金。不管是那种方式,都是依靠售卖自己的股份(或者说是质押)来获取投资。

和银行贷款以及企业债券比,通过发行股票融资对企业而言有几大好处:1、和银行贷款比,无需抵押物,或者说公司的全部资产就是公司的抵押物,而IPO的价格其实不光考虑了公司的资产还考虑公司成长的预期,所以比直接的抵押贷款要划算许多。2、企业融资成本较低,且可控。这个不考虑IPO给券商的承销费及手续费等,单单考虑与贷款及债券利息相对应的股息。对于企业来说股票分红的主动权是掌握在自己手上,赚得多则多分,赚得少少分,不赚不分,当然赚了也不可以不分(像苹果已经好几年不分红了)。实际上相当于最大化地把企业经营的利润风险转移到了股民身上。3、融资规模大,银行给贷款一般是比较小气的,企业发行债券也要充分考虑自己的偿还能力和付息成本,但是发行股票就不一样了,融资对象除了各大机构还有广大散户,定价估值一般还综合考虑了企业未来的成长性,这个规模是不可同日而语的。

以上根据个人体会列举了三个优点,相对应的上市融资相比贷款、债券对企业而言也有如下短板:1、企业自主经营权的部分丧失。由于股份制企业是由股东大会说了算的。而上市企业股本分散,经营权就容易分散到几个大股东手里。而对于这些股东来说,最关心的是手中的股票和他们自身资产的增值及利益最大化,至于企业本身作为一个整体的未来和前景却一般不是他们首要考虑的地方。所以经常会看到一些上市企业在股东压力下短视的表现,或者甚至被股东逼着打包优质资产零碎拆分卖给其他公司。这些都是股东利益和企业利益不完全一致的后果。2、上市融资的门槛较贷款、债券略高,特别在国内更加明显,A股不是你想上就能上的。虽然A股三年前推出了创业板,但是门槛仍然不低(创业板要求最近两年连续盈利、最近两年净利润累计不少于1000万元且持续增长或者最近一年盈利且净利润不少于500万元。最近一年营业收入不少于5000万元并且最近两年营业收入增长率均不低于30%)。对于一般起步阶段的中小企业来说无法指望。增发的门槛也比较高,虽然每次增发的量可以很大,但是一般企业一年都难得增发一次。

综合以上优缺点,再加上股权本身在上市前可以做为一种激励和质押的资本,反而方便了一些中小企业的融资(比如VC、比如天使投资人)。总的来说,如果是企业,肯定更喜欢股票募资的形式。这可能也是我们为什么要不断扩大提升A股市场融资能力的原因。

但是有其利必有起弊,虽然股市对企业是利大于弊的,但是这种福利更多的是由于将企业融资和经营的风险转嫁到了市场上,使得这一部分风险由投资者来共同承担的方式实现的。投资者如果将钱存入银行,则基本可以认为毫无风险,如果将钱用来购买企业债券,也一般有一个最低的保底还款。而唯独在股市,投资者的投资几乎可以认为是毫无保障,损失的下限就是投资的全部。另外,之前提到企业有自由分红的权利,这些也使得投资者在回报方面不能得到很好的担保。而这还只是一个方面。更重要的是,由于IPO和增发其实在股票的二级市场只能算一种少数行为。这就使得股票的二级市场天生就具有很强的投机属性。每天在二级市场的巨额交易几乎都可以归入投机的范畴。(因为正常投资一支股票,除非企业经营状况有较大滑落或者生产有重大变故,股票是不会易手的,单纯追涨杀跌的交易都可以认为是对股价的投机)。这就意味着有大量的资金并没有通过IPO等渠道进入到真正需要资金的企业手中,而是落入了投机者和所谓庄家机构的腰包里。(当然这里有不少是投机者之间的零和博弈,在赚彼此的钱罢了,如果这些钱不在股市上流通,估计也不会进入企业而是会在某个类似赌场的机构或者市场出现)。如果将募集到却未流入生产企业的资金记为募集资本的社会成本的话。股市融资的社会成本毫无疑问是最高的。而银行贷款的社会成本不过是银行固定的存贷款利息差罢了。而且大量的投机性很容易带来市场的不稳定。蛮目地追涨和蛮目地杀跌都会带来股价的不正常波动。股市每一次泡沫的聚集和破裂都是一群赌徒收割另一群赌徒的狂欢。虽然要让赌徒拿自己的钱来干正经事不容易,但是当你看到如此巨量的资金流动时应该还是会忍不住可惜:“要是这么多钱都投到生产领域该多好。”在这里市场的威力和野蛮都表现得淋漓尽致。

那么回到最初争论的问题,究竟需不需要投机,投机究竟好不好?初看之下投机是往投资里掺了沙子,甚至发展起来可能喧宾夺主,将投资的戏份全抢光。但是从整个结果来看,在市场较理性的时机里,投机还是很好地起到了投资的润滑剂的作用。从另一个角度来看,投机的巨大利益,也吸引了许多可能本来根本不可能把钱进行投资的“赌徒”到投资的市场上来,在豪赌的同时也流了一些钱进入真正的投资市场。从这个角度来看,股市还是有保留和发展的必要的。这些收益足以让人忘记市场可能潜在的巨大风险和惊涛骇浪。而且资本的市场是有周期的,下行总会触底,而不至于万劫不复,也许这就是人们愿意忍受将经济世界交给赌徒去操控的原因吧。本来世界就在被无穷无尽的不确定性包围着,也许从上帝到人天生其实都是好赌之徒,只是赌的勇气有大小罢了:-)

Posted in essay | Leave a comment

linux下etc文件夹的含义

今天忽然想到一个问题,我们一般都知道usr文件夹是user的缩写,sys文件夹是system的缩写,dev文件夹是device的缩写……那么/etc文件夹是什么的缩写呢?

在Hi群里问了同事,一时也没有很官方的答案,不过很快有同学从wikipedia上搜到了权威的结果:

Host-specific system-wide configuration files

There has been controversy over the meaning of the name itself. In early versions of the UNIX Implementation Document from Bell labs, /etc is referred to as the etcetera directory, as this directory historically held everything that did not belong elsewhere (however, the FHS restricts /etc to static configuration files and may not contain binaries). Since the publication of early documentation, the directory name has been re-designated in various ways. Recent interpretations include Backronyms such as “Editable Text Configuration” or “Extended Tool Chest”.

之前也搜到了一篇中文的说明,不过没有这篇详细,而且维基百科上还标注了详细的引用。于是又不禁有了一丝感慨:网络上中文信息不论数量和质量都比英文差了一大截啊,和现实中的地位倒也相称,要赶上去还有非常长的一段路要走……

 

=====================================================

为什么有一种博客微博化的感觉,这篇太水了= =

Posted in linux | Tagged | 2 Comments

那就讲得远一点,从金字塔说起吧——续年轻程序员的追求

其实上一篇文章只是因为读研期间遇到这方面问题的争论,当时没想清楚,觉得现在想得比较清楚了,所以把自己考虑的答案总结了一下,只是针对计算机纯技术方向的内容,没有更多的引申,也没有个人的倾向。可能因为题目取得太大,发现大家对这个问题还蛮感兴趣的。有些人也误解了我的意思,那就趁热打铁一下,顺便把自己的观点说说。

世界上的一些事情我一直很难理解。

 

比如修金字塔,现在让你来负责整个工程,给你提供所有人类所能调动的资源,你会怎么做?当时的设计师没有多么高深的理论,没有多么高级的辅助工具就画出了一张张的图纸(也许连像样的图纸都没有),当时的工头仔细地研究揣摩设计师的意思,建立了严密的组织,让当时的工人能打磨出大小合适,表面光滑的石头,当时的工人们能在指挥下精确地将石头搬运到该运的地方,甚至可能在都不知道自己拖的这些石头将要垒出什么的情况下,一点一点、一层一层,从无到有地把一个奇迹堆了出来。当然一些列金字塔的工程本身可能也是一个不断迭代的过程,最早的金字塔也许修建得很粗糙,也许石头并不规整,形状也没有后来美观,结构也不牢固,可能还塌过几个,最早的石块也许都已早已混入滚滚黄沙之中。是一代一代的人不断借鉴,吸取之前的经验教训,在工艺方面、工程方面、组织方面不断地进步,最后才终于得出了让世人惊叹的作品。

 

想象一下,你是当时的一个工人,你每天的工作就是和身边的同事们,用各种器械拖着巨大的石块,在工地间穿梭,听着工头的指挥,将石块搬运到规定的地方,没有一丝偏差。也许在工作时你会想出一些省力的方法,琢磨出一些有趣的技巧,有一天你还好心把这些告诉了你的工友们,就像当年一个老工友把他的经验传授给大家时一样。年复一年,日复一日,时间就这样一天一天过去,一年一年的流逝,有一天你突然发现,眼前的地基慢慢“长高”长大了,当你忽然老去的那一天,你也忽然发现眼皮下多出了一栋雄伟建筑的半成品,那么地突然,那么地耀眼,虽然它的每一步成长,每一个石块其实都来自于你和你同事的手掌和足迹。

 

再想象一下,你是当时的一个设计师,你可能受过良好的教育和培训,或者是祖传的技巧,或者考察过很多同类建筑,拜访过很多老设计师,当过学徒,懂得设计一个金字塔所应该考虑的,应该交代的,应该表达的。你可能还有一些自己的想法,觉得这个流传下来的方子在某些方面还有改进的空间,于是你把这些大胆的改进揉进了你的设计里。你找到了几个富有经验的工程师和项目经理,把你的意思用尽量准确而浅显的语言向他们描述,或是图纸,或是文字,甚至手势比划。这些老员工聆听了你的描述,看过了你的材料,提出了几个问题,消化了你的想法,觉得你要做的和之前所为没有太大的不同,只有一些看起来挺有趣的小改进,要把这些活执行下去并不太难,他们已经有了丰富的经验,当然其中的一些可能是第一次做这个项目,但是他们已经向周围的老人请教过,觉得既然大家都是这么过来的,那么自己胜任这样的工作不会有问题。于是在材料和人力到位、预算无忧之后,工程开始了。接下来你可能会继续接下一个项目,也可能就一直在工地跟进,检查工程质量,看看自己的想法有没有在执行时遇到了偏差。

 

这时你可以想象一下你是当时的一个工程师,也许你的上面还有一个总工程师,他把任务分解之后,把修建东面地基的任务交给了你。你找来几个这方面德高望重的学者,请教他们要修好这样体积的建筑,地基需要打多深,需要挖多少土方,需要多少石块。然后利用你多年的经验,估算出了需要多少人来完成这项工作,他们如何分工?需要哪些人去拖运石块?哪些人负责挖土?哪些人负责运走土方?于是你根据估算的结果,找到了几个工头,交代了具体的任务,来参加这种大项目的工头一般也都富有经验,他们觉得这个任务不难,大致估计了一下工期就召集人手开工了。接下来你就得天天去工地检查,督促进度,保证质量。同时看看自己当初的安排是否合理,有没有需要调整的地方(加人、减人、改变分组和分工)。

 

现在可以想象你是一个工头,你天天扬着鞭子,喊着号子,驱使着那些卖力工作的奴隶,这些人来自五湖四海,有的天生就是奴隶,有的可能是北方的哪个国家战败被俘的平民或者贵族,有的可能是城里家境衰落的市民,还不起欠款的可怜人。你把鞭子高高地挥起来,看着他们不同的表情,有的漠然、有的愤怒、有的痛苦、有的迷茫,当然也不排除还有一些燃烧着斗志的眼神,虽然你不知道这种斗志可能来自哪里。你就这样日复一日,年复一年地矗立在工地上,看着身边的奴隶走过。驱使他们和你的都不是什么伟大的梦想而可能只是活命的欲望。但是在你面前慢慢矗立起来的建筑却可能给你朴素的心灵带来一种直接的冲击和震撼——一座用你手下的人的血汗平地垒成的大山(即使你不是第一次参与金字塔项目,我想这种冲击还是会留存的)……

 

以上的想象肯定和实际的情况相去甚远,但不妨碍我要表达的意思。即使有现代优秀的经验传承系统,有数学、有科学、有工程经验、有书本、有电脑、有网络,即使强大的辅助工具,有巨大的起重机、卡车、推土机、混凝土搅拌机……我还是觉得把几百乃至上千号人聚在一起,在工地上乒乒乓乓365天,就可以平地拔起一栋高达几十米乃至上百米,形状各异却和图纸完全一致的高楼实在是一件很神奇的事。首先一个人,哪怕给你一百年的时间,光靠一个人的知识储备和体力,是不可能完成这样的工程的。哪怕是一千个人,如果不是各自具有相应的专业知识,严密的流程控制,合理的组织方式,也不可能盖出一栋像样的楼房。人类的高度分工和亲密协作完美地完成了量变和质变的过程,而强大的知识传承体系,又使这一玄妙的催化剂在一个又一个的项目中成功生效,失败率低得让人难以置信。

 

现在这个时代,人越来越多,物质越来越丰富,个体的实力也越来越强,同时大生产大协作也几乎渗透到了所有领域。大家反而越来越关注个性,关注自己对世界的影响。“改变世界”成为越来越经常被喊出的口号,只不过有的喊在口头,有的喊在心里,可惜大多数人只能做一颗颗可有可无的螺丝钉……而且真的只是大多数么?其实我们都是人类社会这个具大机器的螺丝钉,就是这一颗颗在精密的系统上准确或者不准确工作的螺丝钉在真正地体现人类的意志,实现着人们心目中的那个“改变世界”的含义。也许你是可以取代的,或许没有人是不能被取代的,但是不是所有的人都能取代你。理想的人类系统也不应该有单点,依赖于某一个不可替换的零件,事实上到目前为止的人类历史也还没真正出现过这样传奇的部件。在历史上和金字塔一起留下的也许只有当时法老的名字,他下令建造,利用他手中的权力和权威调动资源,驱使人力。但是留下他的名字不过因为他是法老,他站在那样的位置上,那样的位置只需要一颗特殊的螺丝,但是不等于他的无可替代。对于整个工程来说,少了一个工人同样可怕,需要及时找到人力补充上去或者让其它人加班弥补工作量的损失,少了设计师也同样需要相同的职能的人来代替。也许区别只是找到替代品的难易度而已。而这些人类其实在不断的进化学习摸索中已经自然调整了不同工种的训练产出量。就好像大学根据就业情况调整招生数一样。也许要在一些领域做到极致需要许多必然的训练和偶然的天赋,但是要胜任大多数职位,只要大量合理的训练也许就足够了。当你需要大量劳工时,整个社会就会调整,导致大量的人去上技校或者直接去当民工。人类社会的组织模式是遵循稳定的金字塔形状的,所以在最初分工的时候它就注意到要把工作进行合理的拆分、归并和调整,使得最后的分工一定是遵循从金字塔顶端到低端学习成本逐步降低的一个分层。这样就可以和社会的其它层次体系最好地匹配。使得工程可以顺利地执行和传承。

 

回到追求这个话题上来,要全部写完,可能篇幅就太长了,可以拆成好几篇写。不过我想读到这里,聪明的朋友应该都能明白我的观点了。“改变世界”这个目标可以看起来很大也可以看起来很小,如果你想要的只是“改变世界”而不是青史留名,那么做一颗螺丝钉,做一颗在合适岗位上合适工作的螺丝钉(当然如果出了重大失误也可以从另一个方向改变世界),就足以达到目的。而至于在后人的小册子上留下你的名字,其实和做螺丝钉没有必然的联系。要让史学家注意到你,并且记录下来,有很多种方法。而且当你真得努力去show的时候,也许你会发现,这事可能还没有拉着石头从日出拉到日落来得有趣……

Posted in Uncategorized | Leave a comment

年轻程序员的追求

题目可能有点大。毕业一年多,我其实只是想写写自己对刚从学校毕业的码农对自己所做的事的追求的看法。

这一年多亲眼见识了IT业的高度流动性,人们来来往往,放弃着、追求着。舍彼而去的原因有很多,慕名而来的牵挂无非有这么几样:薪水、氛围、前景,还有就是对也许很多刚刚毕业还没有完全洗去学校那带着淡淡理想主义香味的学术气的年轻应届生们来说最为重要的——那就是所做的实际工作。

打杂之类的就不用多说了。对于年轻码农来说,什么才是最有技术含量,最有吸引力的工作呢?这个问题可能不同的人会有不同的答案,过去我一直想不太清楚。很多时候一些看起来很有含金量的工作,真得走近了,也不过尔尔。读研的时候一直觉得自己做的项目技术含量不高,工作以后有机会接触到许多新鲜的事物,新鲜归新鲜,倒也不觉得自己所做就有多高的门槛。但是对这个问题的思考倒是慢慢有了一些比较清晰的答案,下面就说说个人到目前为止的一些想法吧。

在我看来,在互联网时代,最有吸引力的(也许不是最有技术含量的),最能让年轻的码农们热血沸腾的工作大致可以分为以下四种:(之所以强调年轻,是因为年长又没有转行的码农一般有了妻儿子女,更多的精力可能就放在经营自己的生活和职业发展上,不大会再去考虑这种虚的东西)

1、设计能支持某些海量数据、高并发要求的系统架构。这一类活可能和DBA、运维关系紧密,接近底层,甚至可能涉及到硬件的组织选型,需要一定的级别和经验才能做,也有一定门槛,不是在家里抱一本书自学就能学会的,需要大量知识和实践的积累。

2、编写能提供高吞吐、快速响应或者支持大数据量、联机处理的服务程序。这一类往往要求一些奇技淫巧,熟练使用各种数据结构和算法,在限定硬件条件的情况下将系统的潜能发挥到极致,颇有些智力题的味道,有比较大的发挥空间,应该是典型程序员的最爱,而且门槛较1低,挑战却可能胜过1。可惜现在硬件发展速度太快,这段时期算是这类工作的相对低潮期(程序运行太慢?加机器呗。吃内存太多?加机器呗。实在不行,直接写几个脚本扔到hadoop集群上,搞几千上万个节点,怎么也能满足一般的需求了)。但是人类需求的增长是无限,硬件的高速发展却总会有瓶颈期,而且即使是在低谷,也只是相对的低谷,还是有许多地方要用到一些复杂的算法的。

3、高可用性、能伸缩、可复用的编程框架。这一类活的机会比1、2都少得多,一般越成功就越是一锤子买卖,这类活可能涉及到一些设计模型和软件工程的思想。虚的地方比较多,编写某个基础框架的乐趣应该远不如最后看到全公司人都在用这个基础框架时得到的那种满足感更大,(当然如果再“恰巧”赶上维护和开发都由你来负责,那整个活就完全变成了一部喜忧参半的悲喜剧了)是一种结果大于过程的享受。

4、学习、接触、应用时下最流行最炫最新潮的技术。4的门槛最低,同时新技术对每一个工程师而言,应该就像新的电子产品对年轻人的吸引力一样,没有几个人能说对新技术完全没有感觉和好奇。应用也分深浅,但因为限定于最新的技术,所以很难钻得很深。不过4和前三类活倒不冲突,可以在干上面那些活的时候应用最新的技术,站在浪潮的前面。但是如果完全被各种五光十色的新玩意所吸引,只是一味地弄潮,玩久了也就只剩一身咸湿而积累不足了,害处也是蛮大的。

从以上来看,除了4以外,另外3种活正常情况下都不是太容易碰到,但是偏巧我们正处在一个互联网起步的时代,赶上了许多小公司飞速发展的时期,所以能做的机会也是有的。但是如果自身准备不足,就算有了这样的机会,也未必能真正做好,而如果不能做好,反而会使很多人迷惑而怀疑其自己的追求。

Posted in essay | 1 Comment

日本之行小结

从尼轰国回来刚好一个月,除了传几张照片,游记没写,感想没写,实在有点过意不去,这里简单地记录一些吧。

1、  日本号称是全世界物价最高的国家。我们在日本吃的最便宜的是吉野家(估计相当于国内最便宜的快餐店),一碗牛肉饭350日元(100日元约合7.5元人民币)。其他拉面、中华料理之类的很容易就超过了4、500日元,而想吃一顿寿司之类的“正餐”,至少需要1000日元以上(最便宜的回转寿司,一盘要120日元)。而日本东京的房租均价基本在70000日元左右(普通一居室),而且东京的房子普遍都很小,这里所谓的一居室其实就是个10几平米的小开间。这样一比不禁感慨,国内的物价确实赶上来了,现在在帝都吃一顿饭,10几20元也是稀松平常,出去吃一顿人均上5、60也是很正常的事,房租由于历史原因和收入限制,和东京比还是低一些的,但是看来房租随着收入的上涨还有很高的提升空间(目前东京的房租可以占到普通个人收入的1/3到1/2左右)。

2、  我们在路上看到了许多招聘广告,都是招聘一些比较低端的职位:商场销售员、柜台服务员等,月薪基本在10几万日元。Sony的RD月薪 大约在40万日元左右,算高薪了。看来日本的劳动力确实比较贵,不过工资上的收入差距不大。帝都去年平均工资是4000多元,东京的平均工资估计在20多万日元(合人民币1万多元),帝都的平均工资是东京的1/3,考虑到实际购买力因素(其实从饮食来看,现在国内已经大有赶超之势了,真怀念几年前10元以下的便当……),再扣掉高昂的房租,现在帝都的收入水平应该大体已经超过东京的一半了,许多北京中等收入的普通百姓已经可以过上东京中等偏下收入市民的生活了(单纯从货币角度考虑)。

3、  平时的一些花销东京还是贵出不少的,一罐可乐要150日元(相当于人民币10元,酸奶倒也差不多这个价),路边摊的小吃动辄达到300、500日元(可能和在一些景区有关系)。衣服的价格和国内差不太远,最令人震惊的是levi’s在日本的价格相当便宜,在一家奥特莱斯,我们看到了大量只要1000日元出头的levi’s牛仔裤(合人民币70多元……)。还有就是化妆品和电子产品会比较便宜,但是文化产品很贵,应该和版税比较高有关系,一本书超过人民币100元是很正常的事。

4、  东京到处都遍布着自动贩卖机,买东西很方便(附带一提,日本最大的钞票面额也就10000元,1000元以下的全是硬币没有纸钞,自动售货机一般能接受的最大面额就是1000元)。甚至一些拉面店也是直接在自动贩卖机上买票,然后凭票去取面。

5、  东京的地铁是类似魔都的按站收费,最低起步价要160日元,公交我们没坐,听说也不便宜。不过作为游客可以在成田机场以优惠的价格买到两日券和一日券,可以当日随便坐,对于游客来说可以省不少钱。另外东京的地铁系统是由好几家公司运营不同的线路,所以在有些站换乘不同公司运营的线的时候需要先出站再入站。不知道那个一日券的优惠是不是就是这种竞争带来的。另外,由于很多地铁修建的时间较长,因此看起来比国内破旧得多,而且老的地铁站里面很低矮,给人一种压抑的感觉。最后,报站mm的声音很好听,比国内的好听多了:)

6、  东京的周围有不少卫星城,感觉规划得比帝都好,中央城区基本就是商业区和办公区,当然里面也错落着一些老房子。工作日的时候日本的上班族就穿着正装打着领带,从千叶等卫星城(感觉像回龙观,但是比回龙观离市区的距离远多了),挤着几个小时的地铁来上班(据说日本的女生都是利用在地铁上的时间来化妆)。在工作日的地铁站基本见不到不穿正装的人,让人感觉到一种很职业的严肃。工作日的晚上我们去银座之类的繁华的商业区也看不到多少人,但是周末的时候人就突然涌了出来,挤满了各个角落,不知道这个是不是可以说明日本的就业率比较高,并且大部分的就业岗位都是比较规律的双休工作制。

7、  还有就是化妆文化和露大腿文化。我们在东京街头见到的日本女人都是化着较浓的妆(到哪都有一种到国贸的感觉=_+),而且从小学生到中年工作者无一例外地裙子都不长(可能是因为他们女性的正装都是短裙)。当时天气还有些凉,经常看到一些小孩腿上被冻得青一块紫一块。不过大人基本就没事了,应该是锻炼出来了……据说日本的男人也普遍化妆,只是没化得那么浓……在早稻田大学,不知道是不是因为正好赶上春季新生入学,整个校园里全部都是穿着校服(校服也就是正装……)的学生,显得我们几个真的是非常民工……

8、  在东京迪斯尼我们也见识了日本人和来日本旅游的人强大的消费能力。有意思的是基本所有的玩具都是made in china的。还有不少手工艺品也基本都是made in china的。

9、  东京人的热情、礼貌和好客也是让人很震惊的。在路上问路的时候,基本上每一个行人,不管他们当时手上有什么急事,都会立刻停下来帮你解答,而且一般都要弄到你懂为止,如果实在说不清楚,他们中的大多数还会要求亲自带你去……服务场所就更不用说了,我在日本邮局体会到的真的是五星级的服务,等到我快走的时候才发现其中一个服务员抱着个字典,仔细一看原来是日英词典……之前原来她一直在边查边和我交流-_-(顺带一提,普通日本人的英语水平和国内普通大学生的水平差不多,大部分人口音还蛮重的……如果是4、50岁以上的则基本就都不会讲了)。

10、  东京的街道确实像传说中的一样干净卫生,一尘不染,虽然经常穿过几条街道都见不到一个垃圾桶……据说由于日本垃圾分类严格,沿街不设置垃圾桶,大家都把垃圾带回家再送到社区垃圾站回收……

11、 日本的大学都不提供宿舍,这意味着许多留学生要拿出奖学金的一半来交房租。据一个日本当地的大学生说,在日本边读书边打工是很正常的事,而且很多从高中就开始了,不这么做基本就不会有零花钱(其实国内大学现在兼职打零工的越来越多了)。麦当劳里基本都是学生在提供服务。

12、 日本的乡下小镇感觉挺有味道的,到处都是修得很精致的小洋楼,楼下的智能车库里停着一些大排量的SUV之类的车,和平时东京街道上跑的火材盒式的小车(真得大部分都像QQ那么大,感觉都是缩水的车型)形成鲜明的对比。

13、 中国游客这几年在日本的影响力还是很惊人的,日本许多店里都放上了银联的牌子,有的刷银联卡还有退税和折扣的优惠。有一些店(包括拉面店=_=)的宣传广播、海报和店内菜单都有中文的样式,秋叶原的电子城里甚至干脆在各柜台设置了中文导购。确实是有点小钱了啊……要知道我们还没看到哪家店有英文广播或者英文导购的……

14、总的来说,感觉发达国家确实是发达国家,虽然这几年中国在经济上确实是跨越式地前进了几个时期,但是很多地方的差距还是比较明显的。最大的感觉就是食品的安全感上,去日本便利店买酸奶,买面包,基本不用担心吃到问题食品,而在国内目前估计已经很找到没有问题的食品了。另外去店里交易,也一般不用担心遇到奸商,明码实价,这种信任蔓延的感觉很好。宾馆虽然不大,但是收拾得很干净,让人住得很舒服……感觉整个社会每个人对自己的产出都是很负责的。要达到这种水平,需要全国的普遍发展,还有很长的路要走。还有就是平均的文化素质,这些倒是可以在大城市率先接近东京的水平。(至少从英语水平来看,现在应该很接近了,甚至有反超的感觉:))

15、精致的化妆、礼貌的举止、急人之所急的热情,这就是东京市民给人的印象。但是感觉这样活着也挺累的,就像天天戴着一个厚厚的面具生活。去旅游还是很不错的,去生活,估计在许多地方的压力要比帝都大……

Posted in Uncategorized | Leave a comment

近期小结

这周没安排好时间,又没能好好写一篇文章,真心惭愧,只能希望每次都惭愧一下,总有一天能良心发现,好好做人……

就随便写点小结吧,总结一下这两周干得各种蠢事,和一些小tip吧。

首先是关于hadoop streaming的。

1、千万不要把注释加在几个参数项之间,结果你懂的。(这当然要2到一定程度才会这样做)
2、有一个很实用的二次排序功能。使用:
-partitioner org.apache.hadoop.mapred.lib.KeyFieldBasedPartitioner \
-jobconf stream.num.map.output.key.fields=2 \
-jobconf num.key.fields.for.partition=1 \
这些选项,可以实现reduce的二次排序,具体的说就是设置的num.key.fields.for.partition将表示分桶的key,相当于主键。比如这里是1,就表示从第一个分隔符往前的内容都作为key来分到不同的reduce里,这里默认分隔符为’/t’,当然也可以在配置里改,不过不是很实用,因为用别的分隔符最后输出的时候hadoop还是会把分隔符替换为’/t’(我看的官方文档的例子好像没体现这一点,但是我自己实际操作的时候发现是会被替换掉的……),而map的输出其实我们是可控的,所以还是养成良好习惯就用默认的比较靠谱,如果需要用别的,可以在reduce阶段接收输入时再换回来。stream.num.map.output.key.fields按字面看这个值就是指以第几个分隔符之前的值作为map输出的key,在这里是2,那就是从第二个’/t’之前都作为map输出的key,而map的输出是会按key排序的,这就意味着在主键相同的情况下,不同的value值就会按照第一个分隔符和第二分隔符之间的内容(相当于辅键)进行排序,这样就实现了二次排序。这个功能在很多场合还是很有用的,不仅省去了在reduce中做二次排序的工作,预排序也可以节省很多reduce的资源。
3、在编写reduce程序时一定要时刻牢记处理的数据是已经预排序过的,这样可以很容易使用一些节省内存和计算资源的算法。避免137错误。
4、在配置中要注意hadoop streaming的配置项中使用转义符是无效的(原因可能和echo中直接使用转义符是无效的一样),所以遇到’\t’的时候还是直接敲tab键吧,如果在命令行状态下,记得先ctrl+v,再敲tab键……(我在这个坑里爬了好久T_T,开始的时候一直不明白,为什么切分的分隔符不是用预想的分隔符……现在想来真是不可思议,弱爆了)。

补充一条刚回忆起来的:用map_input_file这个环境变量可以获取到map输入文件的名字,当map有不同格式的输入时,这个变量还是很有用的。

其次是关于sqlite的,sqlite的效率还是不错的,我开始的时候有点冤枉它了,不过要最快还是要直接调c的api,并且使用事务批量提交(如果数据量很大的话),另外在一次传入多条语句的时候,一定要记得在语句中间加换行,不然如果传入的语句较多,sqlite会慢得让你怀疑上帝(我真心错了,一开始怀疑的是sqlite的性能不行=_+)

第三,少在脚本里面用grep和管道,特别是本来就有逐行处理的逻辑的时候,能用截断解析就截断解析,能用awk就用awk(据说用awk比直接cat速度还快)。发现这些还要拜上面那个sqlite的坑所赐,我把一个脚本前前后后的速度都测了一遍,优化了一下,还是快了不少了(虽然后来发现改掉sqlite的那个换行问题才是让速度飞起来的关键=_=)

第四,送给那些像我一样对gdb心怀敬畏和恐惧的人,其实gdb调多线程程序也并不是非常麻烦,当然如果总在多个线程间跳来跳去可能是挺让人头大的,但是如果只是想调一个被多线程调用的模块,且逻辑完整简单的话,还是很方便的,直接在那个模块代码那里打上断点,然后一个run就能到你想要去的地方~当然在编写代码阶段,养成良好的习惯,把日志打全,从根本上避免调试才是王者之道,不过有的时候维护别人的代码或者编译时间太长的时候,调试还是有它存在的价值的。

Posted in Uncategorized | Leave a comment

shell下的printf

这几周都在百度旅游上写游记,博客上长的草都快枯死了,游记还没写完,估计短时间也很难完成了,先在博客上来篇搞笑的吧。

前两天用shell的printf用出了一个笑话。一般可能大家更习惯printf里面带变量的用法是printf XXXX${XXXX}XXX吧(或者直接用echo),但是因为我比较圡,所以那天用C的用法用了一下(printf XXX%sXXX $XXX)然后发现了一个“惊天大秘密”!那就是如果$XXX里面含有\t(tab键)的时候,你在$XXX后跟的每一个字符都会自动替换掉$XXX中的\t!!而更诡异的是如果我不用$XXX,而直接把$XXX里面的值作为第二个参数传入时就没有这个问题。当时我是百思不得其解啊,差点就想写到周报的issue里去了(当时居然没想到写博客!!可见这个站点的草是有多高了)。但是后来细想一试,才发现其实是因为$XXX外面没有引号,在SHELL里面是直接展开的,而\t把$XXX里面的变量全拆成一个个参数了&-___-b……发现这个问题之后的第一个反应就是过了个年果然又老了一岁啊!!~

唉,新年第一篇就这么水。在这祝大家新年快乐了!~^_^

Posted in Uncategorized | Leave a comment