linux之awk用法

Posted on

linux之awk用法

awk是一个非常棒的数字处理工具。相比于sed常常作用于一整行的处理,awk则比较倾向于将一行分为数个“字段”来处理。运行效率高,而且代码简单,对格式化的文本处理能力超强。先来一个例子: 文件a,统计文件a的第一列中是浮点数的行的浮点数的平均值。用awk来实现只需要一句话就可以搞定 $cat a 1.021 33 1/#.ll 44 2.53 6 ss 7 awk 'BEGIN{total = 0;len = 0} {if($1~/^[0-9]+.[0-9]//){total += $1; len++}} END{print total/len}' a (分析:$1~/^[0-9]+.[0-9]//表示$1与“/ /”里面的正则表达式进行匹配,若匹配,则total加上$1,且len自增,即数目加1.“^[0-9]+.[0-9]/”是个正则表达式,“^[0-9]”表示以数字开头,“.”是转义的意思,表示“.”为小数点的意思。“[0-9]/”表示0个或多个数字)

awk的一般语法格式为: awk [-参数 变量] 'BEGIN{初始化}条件类型1{动作1}条件类型2{动作2}。。。。END{后处理}' 其中:BEGIN和END中的语句分别在开始读取文件(in_file)之前和读取完文件之后发挥作用,可以理解为初始化和扫尾。 (1)参数说明: -F re:允许awk更改其字段分隔符 -v var=$v 把v值赋值给var,如果有多个变量要赋值,那么就写多个-v,每个变量赋值对应一个-v e.g. 要打印文件a的第num行到num+num1行之间的行, awk -v num=$num -v num1=$num1 'NR==num,NR==num+num1{print}' a -f progfile:允许awk调用并执行progfile程序文件,当然progfile必须是一个符合awk语法的程序文件。

(2)awk内置变量: ARGC 命令行参数的个数 ARGV 命令行参数数组 ARGIND 当前被处理文件的ARGV标志符 e.g 有两个文件a 和b awk '{if(ARGIND==1){print "处理a文件"} if(ARGIND==2){print "处理b文件"}}' a b 文件处理的顺序是先扫描完a文件,再扫描b文件

NR   已经读出的记录数 FNR  当前文件的记录数 上面的例子也可以写成这样: awk 'NR==FNR{print "处理文件a"} NR > FNR{print "处理文件b"}' a b 输入文件a和b,由于先扫描a,所以扫描a的时候必然有NR==FNR,然后扫描b的时候,FNR从1开始计数,而NR则接着a的行数继续计数,所以NR > FNR

e.g 要显示文件的第10行至第15行 awk 'NR==10,NR==15{print}' a

FS   输入字段分隔符(缺省为:space:),相当于-F选项 awk -F ':' '{print}' a 和 awk 'BEGIN{FS=":"}{print}' a 是一样的

OFS输出字段分隔符(缺省为:space:) awk -F ':' 'BEGIN{OFS=";"}{print $1,$2,$3}' b 如果cat b为 1:2:3 4:5:6 那么把OFS设置成";"后就会输出 1;2;3 4;5;6 (小注释:awk把分割后的第1、2、3个字段用$1,$2,$3...表示,$0表示整个记录(一般就是一整行))

NF:当前记录中的字段个数 awk -F ':' '{print NF}' b的输出为 3 3 表明b的每一行用分隔符":"分割后都3个字段 可以用NF来控制输出符合要求的字段数的行,这样可以处理掉一些异常的行 awk -F ':' '{if (NF == 3)print}' b

RS:输入记录分隔符,缺省为"\n" 缺省情况下,awk把一行看作一个记录;如果设置了RS,那么awk按照RS来分割记录 例如,如果文件c,cat c为 hello world; I want to go swimming tomorrow;hiahia 运行 awk 'BEGIN{ RS = ";" } {print}' c 的结果为 hello world I want to go swimming tomorrow hiahia 合理的使用RS和FS可以使得awk处理更多模式的文档,例如可以一次处理多行,例如文档d cat d的输出为 1 2 3 4 5 6 7 8 9 10 11 12

hello 每个记录使用空行分割,每个字段使用换行符分割,这样的awk也很好写 awk 'BEGIN{ FS = "\n"; RS = ""} {print NF}' d 输出 2 3 1

ORS:输出记录分隔符,缺省为换行符,控制每个print语句后的输出符号 awk 'BEGIN{ FS = "\n"; RS = ""; ORS = ";"} {print NF}' d 输出 2;3;1 (3)awk读取shell中的变量 可以使用-v选项实现功能 $b=1 $cat f apple $awk -v var=$b '{print var, $var}' f 1 apple 至于有没有办法把awk中的变量传给shell呢,这个问题我是这样理解的。shell调用awk实际上是fork一个子进程出来,而子进程是无法向父进程传递变量的,除非用重定向(包括管道) a=$(awk '{print $b, '$b'}' f) $echo $a apple 1

**(4)输出重定向**

awk的输出重定向类似于shell的重定向。重定向的目标文件名必须用双引号引用起来。 $awk '$4 >=70 {print $1,$2 > "destfile" }' filename $awk '$4 >=70 {print $1,$2 >> "destfile" }' filename

(5)awk中调用shell命令:

1)使用管道 awk中的管道概念和shell的管道类似,都是使用"|"符号。如果在awk程序中打开了管道,必须先关闭该管道才能打开另一个管道。也就是说一次只能打开一个管道。shell命令必须被双引号引用起来。“如果打算再次在awk程序中使用某个文件或管道进行读写,则可能要先关闭程序,因为其中的管道会保持打开状态直至脚本运行结束。注意,管道一旦被打开,就会保持打开状态直至awk退出。因此END块中的语句也会收到管道的影响。(可以在END的第一行关闭管道)” awk中使用管道有两种语法,分别是: awk output | shell input shell output | awk input

对于awk output | shell input来说,shell接收awk的输出,并进行处理。需要注意的是,awk的output是先缓存在pipe中,等输出完毕后再调用shell命令 处理,shell命令只处理一次,而且处理的时机是“awk程序结束时,或者管道关闭时(需要显式的关闭管道)” $awk '/west/{count++} {printf "%s %s\t\t%-15s\n", $3,$4,$1 | "sort +1"} END{close "sort +1"; printf "The number of sales pers in the western"; printf "region is " count "." }' datafile (解释:/west/{count++}表示与“wes”t进行匹配,若匹配,则count自增) printf函数用于将输出格式化并发送给管道。所有输出集齐后,被一同发送给sort命令。必须用与打开时完全相同的命令来关闭管道(sort +1),否则END块中的语句将与前面的输出一起被排序。此处的sort命令只执行一次。

在shell output | awk input中awk的input只能是getline函数。shell执行的结果缓存于pipe中,再传送给awk处理,如果有多行数据,awk的getline命令可能调用多次。 来源: [http://www.cnblogs.com/dong008259/archive/2011/12/06/2277287.html](http://www.cnblogs.com/dong008259/archive/2011/12/06/2277287.html)

hadoop

Posted on

hadoop

hadoop

Table of Contents

1 hadoop

参考资源

1.1 FAQ

1.1.1 Hadoop可以用来做什么

Why Hadoop? http://www.cloudera.com/why-hadoop/

TODO(dirlt):translate it!!!

Simply put, Hadoop can transform the way you store and process data throughout your enterprise. According to analysts, about 80% of the data in the world is unstructured, and until Hadoop, it was essentially unusable in any systematic way. With Hadoop, for the first time you can combine all your data and look at it as one.

  • Make All Your Data Profitable. Hadoop enables you to gain insight from all the data you already have; to ingest the data flowing into your systems 24/7 and leverage it to make optimizations that were impossible before; to make decisions based on hard data, not hunches; to look at complete data, not samples; to look at years of transactions, not days or weeks. In short, Hadoop will change the way you run your organization.
  • Leverage All Types of Data, From All Types of Systems. Hadoop can handle all types of data from disparate systems: structured, unstructured, log files, pictures, audio files, communications records, email– just about anything you can think of. Even when different types of data have been stored in unrelated systems, you can dump it all into your Hadoop cluster before you even know how you might take advantage of it in the future.
  • Scale Beyond Anything You Have Today. The largest social network in the world is built on the same open-source technology as Hadoop, and now exceeds 100 petabytes. It’s unlikely your organization has that much data. As you need more capacity, you just add more commodity servers and Hadoop automatically incorporates the new storage and compute capacity.

1.1.2 Hadoop包括哪些组件

TODO(dirlt):translate it!!!

Apache Hadoop包括了下面这些组件:

和Apache Hadoop相关的组件有:

  • Avro A data serialization system.
  • Cassandra A scalable multi-master database with no single points of failure.
  • Chukwa A data collection system for managing large distributed systems.
  • HBase A scalable, distributed database that supports structured data storage for large tables.
  • Hive A data warehouse infrastructure that provides data summarization and ad hoc querying.
  • Mahout A Scalable machine learning and data mining library.
  • Pig A high-level data-flow language and execution framework for parallel computation.
  • ZooKeeper A high-performance coordination service for distributed applications.

    1.1.3 CDH和Apache Hadoop的关系

CDH Hadoop FAQ https://ccp.cloudera.com/display/SUPPORT/Hadoop+FAQ

TODO(dirlt):translate it!!!

  • What exactly is included in CDH? / Cloudera's Distribution Including Apache Hadoop (CDH) is a certified release of Apache Hadoop. We include some stable patches scheduled to be included in future releases, as well as some patches we have developed for our supported customers, and are in the process of contributing back to Apache.
  • What license is Cloudera's Distribution Including Apache Hadoop released under? / Just like Hadoop, Cloudera's Distribution Including Apache Hadoop is released under the Apache Public License version 2.
  • Is Cloudera forking Hadoop? / Absolutely not. Cloudera is committed to the Hadoop project and the principles of the Apache Software License and Foundation. We continue to work actively with current releases of Hadoop and deliver certified releases to the community as appropriate.
  • Does Cloudera contribute their changes back to Apache? / We do, and will continue to contribute all eligible changes back to Apache. We occasionally release code we know to be stable even if our contribution to Apache is still in progress. Some of our changes are not eligible for contribution, as they capture the Cloudera brand, or link to our tools and documentation, but these do not affect compatibility with core project.

1.1.4 CDH产品组件构成

http://www.cloudera.com/content/cloudera/en/products/cdh.html

从这里可以下载CDH4组件 http://www.cloudera.com/content/cloudera-content/cloudera-docs/CDHTarballs/3.25.2013/CDH4-Downloadable-Tarballs/CDH4-Downloadable-Tarballs.html

./images/cloudera-enterprise-diagram.png

1.1.5 CDH产品组件端口分布和配置

The CDH4 components, and third parties such as Kerberos, use the ports listed in the tables that follow. Before you deploy CDH4, make sure these ports are open on each system.

1.1.5.1 Hadoop HDFS

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentDataNode50010TCPExternaldfs.datanode.addressDataNode HTTP server portDataNodeSecure1004TCPExternaldfs.datanode.addressDataNode50075TCPExternaldfs.datanode.http.addressDataNodeSecure1006TCPExternaldfs.datanode.http.addressDataNode50020TCPExternaldfs.datanode.ipc.addressNameNode8020TCPExternalfs.default.name or fs.defaultFSfs.default.name is deprecated (but still works)NameNode50070TCPExternaldfs.http.address or dfs.namenode.http-addressdfs.http.address is deprecated (but still works)NameNodeSecure50470TCPExternaldfs.https.address or dfs.namenode.https-addressdfs.https.address is deprecated (but still works)Sec NameNode50090TCPInternaldfs.secondary.http.address or dfs.namenode.secondary.http-addressdfs.secondary.http.address is deprecated (but still works)Sec NameNodeSecure50495TCPInternaldfs.secondary.https.addressJournalNode8485TCPInternaldfs.namenode.shared.edits.dirJournalNode8480TCPInternal

1.1.5.2 Hadoop MRv1

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentJobTracker8021TCPExternalmapred.job.trackerJobTracker50030TCPExternalmapred.job.tracker.http.addressJobTrackerThrift Plugin9290TCPInternaljobtracker.thrift.addressRequired by Hue and Cloudera Manager Activity MonitorTaskTracker50060TCPExternalmapred.task.tracker.http.addressTaskTracker0TCPLocalhostmapred.task.tracker.report.addressCommunicating with child (umbilical)

1.1.5.3 Hadoop YARN

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentResourceManager8032TCPyarn.resourcemanager.addressResourceManager8030TCPyarn.resourcemanager.scheduler.addressResourceManager8031TCPyarn.resourcemanager.resource-tracker.addressResourceManager8033TCPyarn.resourcemanager.admin.addressResourceManager8088TCPyarn.resourcemanager.webapp.addressNodeManager8040TCPyarn.nodemanager.localizer.addressNodeManager8042TCPyarn.nodemanager.webapp.addressNodeManager8041TCPyarn.nodemanager.addressMapReduce JobHistory Server10020TCPmapreduce.jobhistory.addressMapReduce JobHistory Server19888TCPmapreduce.jobhistory.webapp.address

1.1.5.4 HBase

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentMaster60000TCPExternalhbase.master.portIPCMaster60010TCPExternalhbase.master.info.portHTTPRegionServer60020TCPExternalhbase.regionserver.portIPCRegionServer60030TCPExternalhbase.regionserver.info.portHTTPHQuorumPeer2181TCPhbase.zookeeper.property.clientPortHBase-managed ZK modeHQuorumPeer2888TCPhbase.zookeeper.peerportHBase-managed ZK modeHQuorumPeer3888TCPhbase.zookeeper.leaderportHBase-managed ZK modeRESTREST Service8080TCPExternalhbase.rest.portThriftServerThrift Server9090TCPExternalPass -p on CLIAvro server9090TCPExternalPass –port on CLI

1.1.5.5 Hive

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentMetastore9083TCPExternalHiveServer10000TCPExternal

1.1.5.6 Sqoop

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentMetastore16000TCPExternalsqoop.metastore.server.portSqoop 2 server12000TCPExternal

1.1.5.7 Zookeeper

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentServer (with CDH4 and/or Cloudera Manager 4)2181TCPExternalclientPortClient portServer (with CDH4 only)2888TCPInternalX in server.N=host:X:YPeerServer (with CDH4 only)3888TCPInternalY in server.N=host:X:YPeerServer (with CDH4 and Cloudera Manager 4)3181TCPInternalX in server.N=host:X:YPeerServer (with CDH4 and Cloudera Manager 4)4181TCPInternalY in server.N=host:X:YPeerZooKeeper FailoverController (ZKFC)8019TCPInternalUsed for HAZooKeeper JMX port9010TCPInternal

As JMX port, ZooKeeper will also use another randomly selected port for RMI. In order for Cloudera Manager to monitor ZooKeeper, you must open up all ports when the connection originates from the Cloudera Manager server.

1.1.5.8 Hue

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentServer8888TCPExternalBeeswax Server8002InternalBeeswax Metastore8003Internal

1.1.5.9 Ozzie

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentOozie Server11000TCPExternalOOZIE_HTTP_PORT in oozie-env.shHTTPOozie Server11001TCPlocalhostOOZIE_ADMIN_PORT in oozie-env.shShutdown port

1.1.5.10 Ganglia

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentganglia-gmond8649UDP/TCPInternalganglia-web80TCPExternalVia Apache httpd

1.1.5.11 Kerberos

ServiceQualifierPortProtocolAccess RequirementConfigurationCommentKRB5 KDC ServerSecure88UDP/TCPExternalkdc_ports and kdc_tcp_ports in either the [kdcdefaults] or [realms] sections of kdc.confBy default only UDPKRB5 Admin ServerSecure749TCPInternalkadmind_port in the [realms] section of kdc.conf

1.2 观点

1.2.1 Hadoop即将过时了吗?

http://www.kuqin.com/database/20120715/322528.html

google提出的三个东西都是解决hadoop的软肋,最终目的还是需要解决大数据上面的实时性问题。

  • 增量索引过滤器(Percolator for incremental indexing)和频繁变化数据集分析。Hadoop是一台大型“机器”,当启动并全速运转时处理数据的性能惊人,你唯一需要操心的就是硬盘的传输速度跟不上。但是每次你准备启动分析数据时,都需要把所有的数据都过一遍,当数据集越来越庞大时,这个问题将导致分析时间无限延长。那么Google是如何解决让搜索结果返回速度越来越接近实时的呢?答案是用增量处理引擎Percolator代替GMR。通过只处理新增的、改动过的或删除的文档和使用二级指数来高效率建目录,返回查询结果。Percolator论文的作者写道:“将索引系统转换成增量系统…将文档处理延迟缩短了100倍。”这意味着索引web新内容的速度比用MapReduce快100倍!类似大型强子对撞机产生的数据将不断变大,Twitter也是如此。这也是为什么HBase中会新增触发流程,而Twitter Storm正在成为实时处理流数据的热门技术。
  • 用于点对点分析的Dremel。Google和Hadoop生态系统都致力于让MapReduce成为可用的点对点分析工具。从Sawzall到Pig和Hive,创建了大量的界面层,但是尽管这让Hadoop看上去更像SQL系统,但是人们忘记了一个基本事实——MapReduce(以及Hadoop)是为组织数据处理任务开发的系统,诞生于工作流内核,而不是点对点分析。今天有大量的BI/分析查询都是点对点模式,属于互动和低延迟的分析。Hadoop的Map和Reduce工作流让很多分析师望而却步,而且工作启动和完成工作流运行的漫长周期对于很多互动性分析来说意味着糟糕的用户体验。于是,Google发明了Dremel(业界也称之为BigQuery产品)专用工具,可以让分析师数秒钟内就扫描成PB(Petabyte)的数据完成点到点查询,而且还能支持可视化。Google在Dremel的论文中声称:“Dremel能够在数秒内完成数万亿行数据的聚合查询,比MapReduce快上100倍!”
  • 分析图数据的Pregel。Google MapReduce的设计初衷是分析世界上最大的数据图谱——互联网。但是在分析人际网络、电信设备、文档和其他一些图数据时就没有那么灵光了,例如MapReduce在计算单源最短路径(SSSP)时效率非常低下,已有的并行图算法库Parallel BGL或者CGMgraph又没有容错。于是Google开发了Pregel,一个可以在分布式通用服务器上处理PB级别图数据的大型同步处理应用。与Hadoop经常在处理图数据时产生指数级数据放大相比,Pregel能够自然高效地处理SSSP或PageRank等图算法,所用时间要短得多,代码也简洁得多。目前唯一能与Pregel媲美的开源选择是Giraph,这是一个早期的Apache孵化项目,调用了HDFS和Zookeeper。Githb上还有一个项目Golden Orb可用。

1.2.2 Best Practices for Selecting Apache Hadoop Hardware

http://hortonworks.com/blog/best-practices-for-selecting-apache-hadoop-hardware/

RAID cards, redundant power supplies and other per-component reliability features are not needed. Buy error-correcting RAM and SATA drives with good MTBF numbers. Good RAM allows you to trust the quality of your computations. Hard drives are the largest source of failures, so buy decent ones.(不需要选购RAID,冗余电源或者是一些满足高可靠性组件,但是选择带有ECC的RAM以及good MTBF的SATA硬盘却是非常需要的。ECC RAM可以让你确保计算结果的正确性,而SATA故障是大部分故障的主要原因)

  • On CPU: It helps to understand your workload, but for most systems I recommend sticking with medium clock speeds and no more than 2 sockets. Both your upfront costs and power costs rise quickly on the high-end. For many workloads, the extra performance per node is not cost-effective.(没有特别要求,普通频率,dual-socket???)
  • On Power: Power is a major concern when designing Hadoop clusters. It is worth understanding how much power the systems you are buying use and not buying the biggest and fastest nodes on the market.In years past we saw huge savings in pricing and significant power savings by avoiding the fastest CPUs, not buying redundant power supplies, etc. Nowadays, vendors are building machines for cloud data centers that are designed to reduce cost and power and that exclude a lot of the niceties that bulk up traditional servers. Spermicro, Dell and HP all have such product lines for cloud providers, so if you are buying in large volume, it is worth looking for stripped-down cloud servers. (根据自己的需要尽量减少能耗开销,撇去一些不需要的部件。而且现在很多厂商也在尽量减少不必要的部件)
  • On RAM: What you need to consider is the amount of RAM needed to keep the processors busy and where the knee in the cost curve resides. Right now 48GB seems like a pretty good number. You can get this much RAM at commodity prices on low-end server motherboards. This is enough to provide the Hadoop framework with lots of RAM (~4 GB) and still have plenty to run many processes. Don’t worry too much about RAM, you’ll find a use for it, often running more processes in parallel. If you don’t, the system will still use it to good effect, caching disk data and improving performance.(RAM方面的话越大越好,对于48GB的RAM来说普通的主板也是支持的。如果RAM用的上的话那么允许多个进程并行执行,如果暂时永不上的话可以做cache来提高速度)
  • On Disk: Look to buy high-capacity SATA drives, usually 7200RPM. Hadoop is storage hungry and seek efficient but it does not require fast, expensive hard drives. Keep in mind that with 12-drive systems you are generally getting 24 or 36 TB/node. Until recently, putting this much storage in a node was not practical because, in large clusters, disk failures are a regular occurrence and replicating 24+TB could swamp the network for long enough to really disrupt work and cause jobs to miss SLAs. The most recent release of Hadoop 0.20.204 is engineered to handle the failure of drives more elegantly, allowing machines to continue serving from their remaining drives. With these changes, we expect to see a lot of 12+ drive systems. In general, add disks for storage and not seeks. If your workload does not require huge amounts of storage, dropping disk count to 6 or 4 per box is a reasonable way to economize.(高容量SATA硬盘,最好是7.2KRPM,并且最好单机上面挂在12个硬盘。对于hadoop之前这种方式并不实际,因为磁盘非常容易损坏并且备份这24TB的数据非常耗时。而hadoop可以很好地解决这个问题。

小集群来说的话,通常单个机器上面挂在4-6个disk即可)

  • On Network: This is the hardest variable to nail down. Hadoop workloads vary a lot. The key is to buy enough network capacity to allow all nodes in your cluster to communicate with each other at reasonable speeds and for reasonable cost. For smaller clusters, I’d recommend at least 1GB all-to-all bandwidth, which is easily achieved by just connecting all of your nodes to a good switch. With larger clusters this is still a good target although based on workload you can probably go lower. In the very large data centers the Yahoo! built, they are seeing 2/10GB per 20 node rack going up to a pair of central switches, with rack nodes connected with two 1GB links. As a rule of thumb, watch the ratio of network-to-computer cost and aim for network cost being somewhere around 20% of your total cost. Network costs should include your complete network, core switches, rack switches, any network cards needed, etc. We’ve been seeing InfiniBand and 10GB Ethernet networks to the node now. If you can build this cost effectively, that’s great. However, keep in mind that Hadoop grew up with commodity Ethernet, so understand your workload requirements before spending too much on the network.(这个主要还是看需求。通常来说网络整体开销占据所有开销的20%,包括核心交换机,机架之间的交换机以及网卡设备等。yahoo大集群的部署方式是rack之间使用2/10GB的核心交换机工作,而20个节点的rack之间内部使用1GB链路)。

    1.2.3 The dark side of Hadoop - BackType Technology

http://web.archive.org/web/20110510125644/http://tech.backtype.com/the-dark-side-of-hadoop

谈到了一些在使用hadoop出现的一些问题,而这些问题是hadoop本身的。

  • Critical configuration poorly documented 一些关键的参数和配置并没有很好地说明清楚。
  • Terrible with memory usage 内存使用上面存在问题。hadoop里面有一些非常sloppy的实现,比如chmod以及ln -s等操作,并没有调用fs API而是直接创建一个shell进程来完成。因为fork出一个shell进程需要申请同样大小的内存(虽然实现上是COW),但是这样造成jvm出现oom。解决的办法是开辟一定空间的swap The solution to these memory problems is to allocate a healthy amount of swap space for each machine to protect you from these memory glitches. We couldn't believe how much more stable everything became when we added swap space to our worker machines.

  • Thomas Jungblut's Blog: Dealing with "OutOfMemoryError" in Hadoop http://codingwiththomas.blogspot.jp/2011/07/dealing-with-outofmemoryerror-in-hadoop.html 作者给出的解决办法就是修改hadoop的代码,通过调用Java API而不是使用ProcessBuilder来解决。

  • NOTE(dirlt):出现OOM的话必须区分JVM还是Linux System本身的OOM。JVM出现OOM是抛出异常,而Linux出现OOM是会触发OOM killer
  • Zombies hadoop集群出现一些zombie进程,而这些进程会一直持有内存直到大量zombie进程存在最后需要重启。造成这些zombie进程的原因通常是因为jvm oom(增加了swap之后就没有出现这个问题了),但是奇怪的是tasktracker作为这些process的parent,并不负责cleanup这些zombie进程而是依赖这些zombie进程的自己退出,这就是hadoop设计方面的问题。

Making Hadoop easy to deploy, use, and operate should be the /#1 priority for the developers of Hadoop.

1.3 使用问题

1.3.1 CDH3u3搭建单节点集群

搭建单节点集群允许我们在单机做一些模拟或者是测试,还是非常有意义的。如何操作的话可以参考链接 http://localhost/utils/hadoop-0.20.2-cdh3u3/docs/single_node_setup.html

这里稍微总结一下:

  • 首先安装ssh和rsync /# sudo apt-get install ssh && sudo apt-get install rsync
  • 本机建立好信任关系 /# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
  • 将{hadoop-package}/conf配置文件修改如下:
  • conf/core-site.xml

    fs.default.name hdfs://localhost:9000

  • conf/hdfs-site.xml

    dfs.replication 1

  • conf/mapred-site.xml

    mapred.job.tracker localhost:9001

1.3.2 CDH4.2.0搭建单节点集群

基本流程和CDH3u3是相同的,但是有一些差异我记录下来。

  • 配置文件

  • 配置文件在etc/hadoop,包括环境配置脚本比如hadoop-env.sh

  • bin/sbin目录下面有hadoop集群启动停止工具 NOTE(dirlt):不要使用它们
  • libexec目录下面是公用的配置脚本
  • mapred-site.xml中jobtracker地址配置key修改为 mapred.jobtracker.address NOTE(dirlt):this for yarn.如果是mr1那么不用修改,依然是mapred.job.tracker
  • hadoop-daemons.sh会使用/sbin/slaves.sh来在各个节点启动,但是 /不知道什么原因,很多环境变量没有设置/ ,所以在slaves.sh执行ssh命令部分最开始增加了 source ~/.shrc; 来强制设置我的环境变量
  • NOTE(dirlt):不要使用shell脚本来启动,而是直接使用类似hadoop namenode这种方式来启动单个机器上的实例
  • 公共组件

  • CDH4.2.0 native-library都放在了目录lib/native下面,而不是CDH3u3的lib/native/Linux-amd64-64下面,这点需要注意。

  • CDH4.2.0 没有自带libhadoop.so, 所以启动的时候都会出现 ”Unable to load native-hadoop library for your platform… using builtin-java classes where applicable“ 这个警告。需要自己编译放到lib/native目录下面。
  • CDH4.2.0 lib下面没有任何文件,所有的lib都在share/hadoop//*/lib下面,比如share/hadoop/common/lib. 这点和CDH3有差别,CDH3所有的jar都放在lib目录下面。使用 hadoop classpath 命令可以察看
  • 环境变量

  • JAVA_LIBRARY_PATH用来设置native library path

  • HADOOP_CLASSPATH可以用来设置hadoop相关的classpath(比如使用hadoop-lzo等)
  • 准备工作

  • 使用hdfs namenode -format来做格式化 注意如果使用sudo apt-get来安装的话,是其他用户比如hdfs,impala,mapred,yarn来启动的,所以必须确保目录对于这些用户是可写的

  • 使用命令 hadoop org/apache/hadoop/examples/QuasiMonteCarlo 1 1 确定集群是否可以正常运行。

    1.3.3 CDH4.3.0

基本流程和CDH4.2.0是相同的,但是存在一些差异我记录下来的。从4.3.0开始将mr1和mr2分开存放,还是一个比较大的区别的。这里我以使用mr1为例。

  • 在libexec/hadoop-config.sh添加source ~/.shrc 来强制设置环境变量。
  • mr1和mr2分开存放主要有

  • etc目录,hadoop and hadoop-mapreduce1

  • bin目录,bin and bin-mapreduce1
  • lib目录。如果需要使用mr1的话,那么将cp -r share/hadoop/mapreduce1/ .

  • NOTE(dirlt):似乎只需要最顶层的一些jar文件即可

  • 在bin/hadoop-config.sh添加source ~/.shrc 来强制设置环境变量。
  • NOTE(dirlt):不要使用start-dfs.sh这些脚本启动,似乎这些脚本会去读取master,slaves这些文件然后逐个上去ssh启动。直接使用hadoop namenode这种方式可以只启动单个机器上的实例

1.3.4 Configuration

1.3.4.1 .bash_profile

export HADOOP_HOME=$HOME/dirlt/hadoop-2.0.0-cdh4.3.0/

export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop export HBASE_HOME=/home/alium_zhanyinan/dirlt/hbase-0.94.6-cdh4.3.0

export HBASE_CLASSPATH=$HBASE_HOME/hbase-0.94.6-cdh4.3.0-security.jar:$HBASE_HOME/conf export ZK_HOME=/home/alium_zhanyinan/dirlt/zookeeper-3.4.5-cdh4.3.0

export ZK_CLASSPATH=$ZK_HOME/zookeeper-3.4.5-cdh4.3.0.jar export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:$HBASE_CLASSPATH:$ZK_CLASSPATH

export JAVA_HOME=/usr/java/default/

1.3.4.2 core-site.xml

fs.default.name hdfs://umengds1.mob.cm3:8020 fs.trash.interval 1440

1.3.4.3 hdfs-site.xml

dfs.name.dir /disk1/data/dfs/nn dfs.data.dir /disk1/data/dfs/dn fs.checkpoint.dir /disk1/data/dfs/snn dfs.replication 3 dfs.block.size 134217728 dfs.datanode.max.xcievers 8192 dfs.datanode.du.reserved 21474836480 dfs.namenode.handler.count 64 dfs.datanode.handler.count 32 dfs.client.read.shortcircuit true

1.3.4.4 mapred-site.xml

mapred.job.tracker umengds2.mob.cm3:8021 mapred.system.dir /tmp/mapred/system mapreduce.jobtracker.staging.root.dir /user mapred.local.dir /disk1/data/mapred/local mapred.submit.replication 3 true mapred.tasktracker.map.tasks.maximum 6 mapred.tasktracker.reduce.tasks.maximum 8 mapred.child.java.opts -Xmx2048M -XX:-UseGCOverheadLimit mapred.job.tracker.handler.count 64 io.sort.mb 256 io.sort.factor 64

1.3.4.5 hadoop-env.sh

/# The maximum amount of heap to use, in MB. Default is 1000.

export HADOOP_HEAPSIZE=6000

/# Extra Java runtime options. Empty by default. /# if ["$HADOOP_OPTS" == "" ]; then export HADOOP_OPTS=-server; else HADOOP_OPTS+=" -server"

; fi

/# Command specific options appended to HADOOP_OPTS when specified export HADOOP_NAMENODE_OPTS="-Xmx12000m $HADOOP_NAMENODE_OPTS"export HADOOP_SECONDARYNAMENODE_OPTS="-Xmx12000m $HADOOP_SECONDARYNAMENODE_OPTS"export HADOOP_DATANODE_OPTS="-Xmx6000m $HADOOP_DATANODE_OPTS"export HADOOP_BALANCER_OPTS="-Xmx3000m $HADOOP_BALANCER_OPTS"export HADOOP_JOBTRACKER_OPTS="-Xmx12000m $HADOOP_JOBTRACKER_OPTS"

1.3.4.6 hbase-site.xml

hbase.cluster.distributed true hbase.rootdir hdfs://umengds1.mob.cm3:8020/hbase hbase.zookeeper.quorum umengds1.mob.cm3,umengds2.mob.cm3 hbase.hregion.memstore.mslab.enabled true hbase.regionserver.handler.count 128 hbase.client.write.buffer 4194304 hbase.hregion.memstore.block.multiplier 8 hbase.server.thread.wakefrequency 1000 hbase.regionserver.lease.period 600000 hbase.hstore.blockingStoreFiles 15 hbase.hregion.max.filesize 2147483648 hbase.ipc.client.tcpnodelay true ipc.ping.interval 10000 hbase.hregion.majorcompaction 0 hbase.regionserver.checksum.verify true

1.3.4.7 hbase-env.sh

/# The maximum amount of heap to use, in MB. Default is 1000.

export HBASE_HEAPSIZE=14000

/# Extra Java runtime options. /# Below are what we set by default. May only work with SUN JVM.

/# For more on why as well as other possible settings, /# see http://wiki.apache.org/hadoop/PerformanceTuning

/# export HBASE_OPTS= "-ea -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalMode"export HBASE_OPTS="-ea -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=90"

1.4 Hadoop权威指南

1.4.1 初识Hadoop

古代,人们用牛来拉中午,当一头牛拉不动一根圆木的时候,他们不曾想过培育更大更壮的牛。同样,我们也不需要尝试开发超级计算机,而应试着结合使用更多计算机系统。

1.4.2 关于MapReduce

  • 设置HADOOP_CLASSPATH就可以直接使用hadoop CLASSNAME来在本地运行mapreduce程序。
  • hadoop jar $HADOOP_HOME/contrib/streaming/hadoop-streaming-0.20.2-cdh3u3.jar 可以用来启动streaming任务

  • 使用stdin/stdout来作为输入和输出

  • NOTE(dirlt):倒是可以探索一下如何使用,但是觉得能力有限

  • Input/Output Format

  • 外围环境的访问比如访问hdfs以及hbase
  • 程序打包。比如使用很多第三方库的话在其他机器上面没有部署。
  • hadoop pipes 可以用来启动pipes任务

  • Hadoop的Pipes是Hadoop MapReduce的C++接口代称

  • 使用Unix Domain Socket来作为输入和输出
  • NOTE(dirlt):可能使用上面还是没有native mr或者是streaming方式方便

    1.4.3 Hadoop分布式文件系统

  • 使用hadoop archive能够将大量小文档打包,存档文件之能够只读访问

  • 使用hadoop archive -archiveName .har -p src dst

  • 存档过程使用mapreduce完成,输出结果为目录

  • part-0 表示存档内容文件,应该是使用一个reduce做聚合。

  • _index,_masterindex 是对存档内容文件的索引文件。
  • har(hadoop archive)文件系统是建立在其他文件系统上面的,比如hdfs或者是local fs.

  • hadoop fs -ls har:///file.har 那么访问的是默认的文件系统上面的file.har

  • 如果想显示地访问hdfs文件系统的话,那么可以hadoop fs -ls har://hdfs-localhost:9000/file.har
  • 如果想显示地访问本地文件系统的话,那么可以使用hadoop fs -ls har://file-localhost/file.har
  • hadoop fs -ls har://schema-/ 是通用的访问方式

1.4.4 Hadoop IO

  • 文件系统

  • ChecksumFileSystem

  • 使用decorator设计模式,底层filesystem称为RawFileSystem

  • 对于每个文件filename都会创建.filename.crc文件存储校验和
  • 计算crc的单位大小通过io.bytes.per.checksum来进行控制
  • 读取文件如果出现错误的话,那么会抛出ChecksumException
  • 考虑到存在多副本的情况,如果读取某个副本出错的话,期间那么会调用reportChecksumFailure方法

  • NOTE(dirlt):这个部分的代码不太好读,非常绕

  • RawLocalFileSystem

  • 本地文件系统

  • LocalFileSystem

  • RawLocalFileSystem + ChecksumFileSystem

  • reportChecksumFailure实现为将校验和存在问题的文件移动到bad_files边际文件夹(side directory)
  • DistributedFileSystem

  • 分布式文件系统

  • ChecksumDistributedFileSystem

  • DistributedFileSystem + ChecksumFileSystem

  • 压缩解压

  • DEFLATE org.apache.hadoop.io.compress.DefaultCodec 扩展名.defalte

  • Gzip org.apache.hadoop.io.compress.GzipCodec 扩展名.gz 使用DEFLATE算法但是增加了额外的文件头。
  • bzip2 org.apache.hadoop.io.compress.BZip2Codec 扩展名.bz2 自身支持文件切分,内置同步点。
  • LZO com.hadoop.compression.lzo.LzopCodec 扩展名.lzo 和lzop工具兼容,LZO算法增加了额外的文件头。

  • LzopCodec则是纯lzo格式的codec,使用.lzo_deflate作为文件扩展名

  • 因为LZO代码库拥有GPL许可,因此没有办法包含在Apache的发行版本里面。
  • 运行MapReduce时候可能需要针对不同压缩文件解压读取,就需要构造CompressionCodec对象,我们可以通过CompressionCodecFactory来构造这个对象

  • CompressionCodecFactory读取变量io.compression.codecs

  • 然后根据输入文件的扩展名来选择使用何种codec.
  • getDefaultExtension
  • 压缩和解压算法可能同时存在Java实现和原生实现

  • 如果是原生实现的话通常是.so,那么需要设置java.library.path或者是在环境变量里面设置LD_LIBRARY_PATH

  • 如果同时有原生实现和Java实现,我们想只是使用原生实现的话,那么可以设置hadoop.native.lib = false来禁用原生实现。
  • 压缩算法涉及到对应的InputFormat,也就涉及到是否支持切分

  • 对于一些不支持切分的文件,可能存在一些外部工具来建立索引,从而支持切分。

  • 下面这些选项可以针对map结果以及mapreduce结果进行压缩

  • mapred.output.compress = true 将mapreduce结果做压缩

  • mapred.output.compression.codec mapreduce压缩格式
  • mapred.output.compress.type = BLOCK/RECORD 如果输出格式为SequenceFile的话,那么这个参数可以控制是块压缩还是记录压缩
  • NOTE(dirlt):我现在强烈感觉MR的中间结果存储格式为SequenceFile
  • NOTE(dirlt):应该是IFile,但是是否共享了这个配置呢?
  • mapred.compress.map.output = true 将map结果做压缩
  • mapred.map.output.compression.codec map压缩格式

  • 序列化

  • Hadoop的序列化都是基于Writable实现的,WritableComparable则是同时继承Writable,Comparable.

  • 序列化对象需要实现RawComparator,接口为public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2)进行二进制比较。

  • WritableComparator简化了这个实现,继承WritableComparator就实现了这个接口

  • 但是这个接口实现起来非常naive,就是将两个byte stream反序列化然后调用对象的compareTo实现
  • 如果想要提高效率的话,可以考虑通过直接比较两个byte stream来做优化。
  • 基于文件的数据结构

  • SequenceFile 主要用来存储KV数据结构,多条记录之间会穿插一些同步标记,因此允许进行切分。

  • 使用SequenceFileInputFormat和SequenceFileOutputFormat来读取和输出SequenceFile

  • hadoop fs -text 可以用来读取文件
  • mapred.output.compress.type = BLOCK/RECORD 可以用来控制压缩方式

  • 如果没有使用压缩的话,那么格式为 recordLength(4byte) + keyLength(4byte) + key + value

  • 如果使用记录压缩的话,那么格式为 recordLnegth(4byte) + keyLength(4byte) + key + compressedValue
  • 如果使用块压缩的话,那么格式为 numberRecord(1-5byte) + keyLength(4byte) + compressedKeys + valueLength(4byte) + compressedValues.每个block之间会插入sync标记
  • 块压缩大小可以使用io.seqfile.compress.blocksize来控制,默认1MB
  • MapFile 也是用来存储KV数据结构,但是可以认为已经按照了Key进行排序 NOTE(dirlt):要求添加顺序就按照Key排序

  • 存储格式实际上也是SequenceFile,data,index都是。

  • 底层会建立index,index在搜索的时候会加载到内存里面,这样可以减少data上的随机查询次数。
  • 使用io.map.index.interval可以控制多少个item在index里面创建一个条目
  • 使用io.map.index.skip = 0/1/2/n 可以控制skip几个index的item,如果为1的话那么表示只是使用1/2的索引。
  • 从SequenceFile创建MapFile非常简单

  • 首先使用sort将SequenceFile进行排序(可以使用hadoop example的sort)

  • 然后调用hadoop MapFileFixer来建立索引

    1.4.5 MapReduce应用开发

  • Configuration用来读取配置文件,功能还是比较强大的,有变量替换的功能

  • 如果使用true标记的话那么这个变量不允许被重置
  • 变量替换可以使用${variable}
  • 通过addResource来添加读取的配置文件

  • Hadoop集群有三种工作方式,分别为

  • standalone 使用单个JVM进程来模拟

  • 如果不进行任何配置的话默认使用这个模式 NOTE(dirlt):这个模式确实不错

  • fs.default.name = file 本地文件系统
  • mapred.job.tracker = local
  • pseudo-distributed 本地启动单节点集群

  • fs.default.name = hdfs://localhost

  • mapred.job.tracker = localhost:8021
  • fully-distributed 完全分布式环境

  • fs.default.name = hdfs://

  • mapred.job.tracer = :8021

  • 使用hadoop启动MapReduce任务的常用参数

  1. -D property=value 覆盖默认配置属性
  2. -conf filename 添加配置文件
  3. -fs uri 设置默认文件系统
  4. -jt host:port 设置jobtracker
  5. -files file,file2 这些文件可以在tasktracker工作目录下面访问
  6. -archives archive,archive2 和files类似,但是是存档文件
  • 突然觉得这个差别在files只能是平级结构,而archive可以是层级结构。
  • -libjars jar1,jar2 和files类似,通常这些JAR文件是MapReduce所需要的。

如果希望运行时候动态创建集群的话,可以通过这几个类来创建

  • MiniDFSCluster
  • MiniMRCluster
  • MiniHBaseCluster
  • MiniZooKeeperClutser
  • NOTE(dirlt):都称为Mini???Cluster?

另外还有自带的ClusterMapReduceTestCase以及HBaseTestingUtility来帮助进行mapreduce的testcase. 这些类散步在hadoop,hbase,hadoop-test以及hbase-test里面。

NOTE(dirlt):但是个人觉得可能还是没有本地测试方便,不过倒是可以试试

job,task and attempt

  • jobID常见格式为 job_200904110811_0002

  • 其中200904110811表示jobtracker从2009.04.11的08:11启动的

  • 0002 表示第三个job,从0000开始计数。超过10000的话就不能够很好地排序
  • taskID常见格式为 task_200904110811_0002_m_000003

  • 前面一串数字和jobID匹配,表示从属于这个job

  • m表示map任务,r表示reduce任务
  • 000003表示这是第4个map任务。顺序是在初始化时候指定的,并不反应具体的执行顺序。
  • attemptID常见格式为 attempt_200904110811_0002_m_000003_0

  • 前面一串数字和taskID匹配,表示从属与这个task

  • attempt出现的原因是因为一个task可能会因为失败重启或者是预测执行而执行多次
  • 如果jobtracker重启而导致作业重启的话,那么做后面id从1000开始避免和原来的attempt冲突。

作业调试

  • 相关配置

  • mapred.jobtracker.completeuserjobs.maximum 表示web页面下面展示completed jobs的个数,默认是100,超过的部分放到历史信息页。

  • mapred.jobtracker.restart.recover = true jobtracker重启之后自动恢复作业
  • hadoop.job.history.location 历史作业信息存放位置,超过30天删除,默认在_logs/history
  • hadoop.job.history.user.location 如果不为none那么历史作业信息在这里也会存在一份,不会删除。
  • 相关命令

  • hadoop fs -getmerge 能够将hdfs的src下面所有的文件merge合并成为一份文件并且copy到本地

  • hadoop job -history 察看作业历史
  • hadoop job -counter 察看作业计数器
  • 相关日志

  • 系统守护进程日志 写入HADOOP_LOG_DIR里面,可以用来监控namenode以及datanode的运行情况

  • MapReduce作业历史日志 _logs/history
  • MapReduce任务日志 写入HADOOP_LOG_DIR/userlogs里面,可以用来监控每个job的运行情况
  • 分析任务

  • JobConf允许设置profile参数 NOTE(dirlt):新的接口里面JobConf->JobContext->Job,Job没有这些接口,但是可以通过Configuration来设置

  • setProfileEnabled 打开profile功能,默认false,属性 mapred.task.profile

  • setProfileParams 设置profile参数

  • 属性 mapred.task.profile.params

  • 默认使用hprof -agentlib:hprof=cpu=samples,heap=sites,force=n,thread=y,verbose=n,file=%s"
  • 其中%s会替换成为profile输出文件
  • NOTE(dirlt):其实这里似乎也可以设置成为jmxremote来通过jvisualvm来调试
  • setProfileTaskRange(boolean,String)

  • 参数1表示针对map还是reduce task做profile, true表示map, false表示reduce

  • 参数2表示针对哪些tasks做优化,"0-2"表示针对0,1,2三个任务,默认也是"0-2"
  • map task对应属性mapred.task.profile.maps,reduce task对应属性mapred.task.profile.reduces
  • 任务重现

  • 首先将keep.failed.task.files设置为true,这样如果任务失败的话,那么这个任务的输入和输出都会保留下来

  • 如果是map任务的话,那么输入分别会在本地保留

  • 如果是reduce任务的话,那么对应的map任务输出会在本地保留
  • 然后我们使用hadoop IsolationRunner job.xml来重新运行这个任务
  • 可以修改HADOOP_OPTS添加远程调试选项来启动这个任务。
  • 如果希望任务都保留而不仅仅是失败任务保留的话,那么可以设置 keep.task.files.pattern 为正则表达式(与保留的任务ID匹配)

1.4.6 MapReduce的工作机制

Hadoop运行MapReduce作业的工作原理

./images/mapreduce-workflow-architecture.png

其中有几点需要注意的:

  • 计算分片信息是在本地完成的,分片信息和其他resouce(包括jars,files,archives等)一起copy到HDFS上面,然后jobtracker直接读取分片信息。
  • 提交的资源可以设置replication数目,高副本数目可以缓解tasktracker获取resource的压力。参数是mapred.submit.replication.
  • 对于streaming以及pipes的实现,无非就是task并不直接执行任务,而是开辟另外一个子进程来运行streaming或者是pipes的程序。

./images/mapreduce-streamming-pipes.jpg

进度和状态的更新

  • map任务进度是已经处理输入的比例
  • reduce任务进度分为三个部分

  • shuffle 1/3

  • sort 1/3
  • reduce 1/3
  • 也就是说如果刚运行完成sort的话,那么进度是2/3
  • 状态的更新

  • 触发事件

  • 读取记录

  • 输出记录
  • 修改状态 reporter的setStatus
  • 计数器修改
  • reporter的progress
  • 子进程有单独线程每隔3秒检查progress位是否设置,如果设置的话那么和tasktracker发起心跳

  • 通过mapred.task.timeout控制

  • tasktracker每隔5秒和jobtracker做心跳

  • 心跳时间通过 mapred.tasktracker.expircy.interval 设置

  • jobClient定期会去jobtracker询问job是否完成

  • jobClient也可以设置属性job.end.notification.url,任务完成jobtracker会调用这个url

  • 可以认为就是推拉方式的结合。

失败检测和处理

  • 任务失败

  • 子进程抛出异常的话,tasktracker将异常信息记录到日志文件然后标记失败

  • 对于streaming任务的话非0退出表示出现问题,也可以使用stream.non.zero.exit.is.failure = false来规避( 这样是否就没有办法判断是否正常退出了?
  • 如果长时间没有响应的话,没有和tasktracker有交互,那么也会认为失败。这个时间使用mapred.task.timeout控制,默认10min
  • 如果任务失败的话,jobtracker会尝试进行多次重试

  • map重试次数通过 mapred.map.max.attempts 配置

  • reduce重试次数通过 mapre.reduce.max.attempts 配置
  • 任何任务重试超过4次的话那么会认为整个job失败
  • 另外需要区分KILLED状态和FAILED状态,对于KILLED状态可能是因为推测执行造成的,不会记录到failed attempts里面
  • 如果我们希望允许少量任务失败的话,那么可以配置

  • mapred.max.map.failures.percent 允许map失败的最大比率

  • mapred.max.reduce.failures.percent 允许reduce失败的最大比率
  • 如果一个job超过一定的task在某个tt上面运行失败的话,那么就会将这个tt加入到这个job的blacklist. mapred.max.tracker.failures = 4
  • 如果job成功的话,检查运行task失败的tt并且标记,如果超过一定阈值的话,那么会将tt加入到全局的blacklist. mapred.max.tracker.blacklists = 4

作业的调度

  • fifo scheduler

  • 可以通过mapred.job.priority或者是setJobPriority设置

  • 当队列中有空闲的槽位需要执行任务时,从等待队列中选择优先级最高的作业
  • fair scheduler
  • capacity scheduler

shuffle和排序

./images/mapreduce-shuffle-sort.jpg

./images/mapreduce-shuffle-sort-2.png

有下面这些参数控制shuffle和sort的过程 NOTE(dirlt):书上倒是有很多参数,但是好多还是不太理解

  • io.sort.mb map输出缓存空间大小,默认是100MB. 建议设置10/* io.sort.factor.
  • io.sort.spill.percent 如果map输出超过了缓存空间大小的这个阈值的话,那么就会spill,默认是0.8

  • 每次spill之前先会对这个文件进行排序,如果有combiner的话那么会在上面调用combiner

  • 写磁盘是按照轮询的方式写到mapred.local.dir属性指定的目录下面
  • 如果spill速度太慢的话,那么往缓存空间写入进程就会阻塞,直到spill腾出空间。
  • io.sort.factor 多路归并的数量,默认是10. 建议设置在25-32.

  • 在map阶段,因为最终会存在多个spill文件,所以需要做多路归并。 TODO(dirlt):如果归并数量少的话是否可能会多次merge?

  • 在reduce阶段的话,因为可能存在多路map输出的结果,所以需要做多路归并。
  • min.num.spill.for.combine 如果指定combiner并且spill次数超过这个值的话就会调用combine,默认为3
  • tasktracker.http.threads reduce通过HTTP接口来发起数据请求,这个就是HTTP接口相应线程数目,默认为40。 mapper as server
  • mapred.reduce.parallel.copies reduce启动多少个线程去请求map输出,默认为5。 reducer as client

  • NOTE(dirlt):如果reduce和每个map都使用一个线程去请求输出结果的话,只要shuffle阶段没有出现network congestion,那么提高线程数量是有效果的

  • NOTE(dirlt):可以设置到15-50
  • mapred.reduce.copy.backoff = 300(s) reduce下载线程最大等待时间
  • mapred.job.shuffle.input.buffer.percent = 0.7 用来缓存shuffle数据的reduce task heap百分比
  • mapred.job.shuffle.merge.percent = 0.66 缓存的内存中多少百分比后开始做merge操作
  • mapred.job.reduce.input.buffer.percent = 0.0 sort完成后reduce计算阶段用来缓存数据的百分比. 默认来说不会使用任何内存来缓存,因此完全从磁盘上进行读取。

任务的执行

  • 推测执行参数

  • 如果某个任务执行缓慢的话会执行另外一个备份任务

  • mapred.map.tasks.speculative.execution true
  • mapred.reduce.tasks.speculative.execution true
  • JVM重用

  • 一个JVM实例可以用来执行多个task.

  • mapred.job.reuse.jvm.num.tasks/setNumTasksToExecutePerJvm 单个JVM运行任务的最大数目
  • -1表示没有限制
  • 任务执行环境

  • 程序自身可以知道执行环境对于开发还是比较有帮助的

  • 这些属性对于streaming可以通过环境变量获得

  • 对于streaming来说.替换成为_

  • mapred.job.id string jobID
  • mapred.tip.id string taskID
  • mapred.task.id string attemptID
  • mapred.task.partition int 作业中任务编号
  • mapred.task.is.map boolean 是否为map
  • mapred.work.output.dir / FileOutputFormat.getWorkOutputPath 当前工作目录
  • 杂项 NOTE(dirlt):from misc articles

  • mapred.job.map.capacity /# 最大同时运行map数量

  • mapred.job.reduce.capacity /# 最大同时运行reduce数量
  • mapred.job.queue.name /# 选择执行queue

    1.4.7 MapReduce的类型与格式

MapReduce的类型

老API里面还有MapRunner这个类,这个类主要的作用是可以用来控制Mapper运行的方法,比如可以多线程来控制Mapper的运行。 但是在新API里面已经完全集成到Mapper实现里面来了,用户可以重写两个方法来完全控制mapper的运行

  • map 如何处理kv
  • run 如何从context里面读取kv protected void map(KEYIN key, VALUEIN value,

                 Context context) throws IOException, InterruptedException {
    

    context.write((KEYOUT) key, (VALUEOUT) value);

} public void run(Context context) throws IOException, InterruptedException {

setup(context); while (context.nextKeyValue()) {

map(context.getCurrentKey(), context.getCurrentValue(), context);

}

cleanup(context); }

NOTE(dirlt):觉得这个特性不是特别有用

  • mapred.input.format.class setInputFormat
  • mapred.mapoutput.key.class setMapOutputKeyClass
  • mapred.mapoutput.value.class setMapOutputValueClass
  • mapred.output.key.class setOutputKeyClass
  • mapred.output.value.class setOutputValueClass
  • mapred.mapper.class setMapperClass
  • mapred.map.runner.class setMapRunnerClass
  • mapred.combiner.class setCombinerClass
  • mapred.partitioner.class setPartitionerClass
  • mapred.output.key.comparator.class setOutputKeyComparatorClass
  • mapred.output.value.groupfn.class setOutputValueGroupingComparator
  • mapred.reducer.class setReducerClass
  • mapred.output.format.class setOutputFormat

输入格式

对于InputFormat来说包含两个任务

  • 根据job描述来对输入进行切片(InputSplit)
  • 根据切片信息来读取记录(RecordReader) public abstract class InputFormat {

    public abstract List getSplits(JobContext context

                             ) throws IOException, InterruptedException;
    

public abstract RecordReader createRecordReader(InputSplit split,

                                     TaskAttemptContext context
                                    ) throws IOException,

                                             InterruptedException;

}

public abstract class InputSplit { public abstract long getLength() throws IOException, InterruptedException;

public abstract

String[] getLocations() throws IOException, InterruptedException;

}

public abstract class RecordReader implements Closeable {

public abstract void initialize(InputSplit split, TaskAttemptContext context

                              ) throws IOException, InterruptedException;

public abstract boolean nextKeyValue() throws IOException, InterruptedException;

public abstract

KEYIN getCurrentKey() throws IOException, InterruptedException;

public abstract VALUEIN getCurrentValue() throws IOException, InterruptedException;

public abstract float getProgress() throws IOException, InterruptedException;

public abstract void close() throws IOException;

}

下面是一些常见的InputFormat实现

  • FileInputFormat

  • addInputPath或者是setInputPaths修改输入路径 mapred.input.dir

  • setInputPathFilter可以修改过滤器 mapred.input.path.Filter.class

  • 基本实现会排除隐藏.或者是_开头文件。

  • 自定义的过滤器是建立在默认过滤器的基础上的。
  • 分片大小由下面三个参数控制

  • mapred.min.split.size 1

  • mapred.max.split.size MAX
  • dfs.block.size 64MB
  • 算法是max(minSplitSize,min(maxSplitSize,blockSize))
  • isSplitable可以控制输入文件是否需要分片
  • CombineFileInputFormat 可以处理多个小文件输入,抽象类需要继承实现。
  • TextInputFormat

  • 输入单位是行,key是LongWritable表示行偏移,value是Text表示行内容

  • KeyValueTextInputFormat

  • 输入单位是行,按照key.value.seperator.in.input.line来进行分隔默认是\t

  • key和value的格式都是Text
  • NLineInputFormat

  • 和TextInputFormat非常类似,大师使用多行输入默认为1行

  • 通过mapred.line.input.format.linespermap来控制行数
  • XML

  • InputFormat使用StreamInputFormat,

  • 设置RecordReader使用stream.recordreader.class来设置
  • RecordReader使用org.apache.hadoop.streaming.StreamXmlRecordReader
  • NOTE(dirlt):也有现成的XmlInputFormat的实现
  • SequenceFileInputFormat
  • SequenceFileAsTextInputFormat

  • 将输入的kv转换成为text对象适合streaming处理方式

  • SequenceFileAsBinaryInputFormat NOTE(dirlt):似乎没有什么用!
  • MultipleInputs
  • DBInputFormat/DBOutputFormat JDBC数据库输入输出
  • TableInputFormat/TableOutputFormat HBase输入输出

输出格式

  • TextOutputFormat

  • 使用mpared.textoutputformat.seperator来控制kv的分隔,默认是\t

  • 对应的输入格式为KeyValueTextInputFormat
  • 可以使用NullWritable来忽略输出的k或者是v
  • SequenceFileOutputFormat
  • SequenceFileAsBinaryOutpuFormat NOTE(dirlt):似乎没有什么用!
  • MapFileOutputFormat
  • MultipleOutputFormat
  • MultipleOutputs

  • 如果不像生成那写part-r-00000这些空文件的话,那么可以将OutputFormat设置成为NullOutputFormat

  • 但是使用NullOutputFormat的话会没有输出目录,如果想保留目录的话那么可以使用LazyOutputFormat

1.4.8 MapReduce的特性

  • 计数器

  • streaming计数器和可以通过写stderr来提交

  • reporter:counter:,,

  • reporter:status:
  • 连接

  • map端连接

  • 必须确保多路输入文件的reduce数量相同以及键相同。

  • 使用CompositeInputFormat来运行map端连接。
  • NOTE(dirlt);不过我稍微看了一下代码,实现上其实也是针对输入文件对每条记录读取,然后进行join包括inner或者是outer。感觉场景会有限,而且效率不会太高
  • 分布式缓存

  • 使用-files以及-archives来添加缓存文件

  • 也可以使用DistributedAPI来完成之间事情

  • addCacheFile/addCacheArchive

  • 然后在task里面通过configuration的getLocalCacheFiles以及getLocalCacheArchives来获得这些缓存文件
  • 工作原理

  • 缓存文件首先被放到hdfs上面

  • task需要的话那么会尝试下载,之后会对这个缓存文件进行引用计数,如果为0那么删除

  • 这也就意味着缓存文件可能会被多次下载

  • 但是运气好的话多个task在一个node上面的话那么就不用重复下载
  • 缓存文件存放在${mapred.local.dir}/taskTracker/archive下面,但是通过软连接指向工作目录
  • 缓存大小通过local.cache.size来配置
  • MapReduce库类

  • ChainMapper/ChainReducer 能够在一个mapper以及reducer里面运行多次mapper以及reducer

  • ChainMapper 允许在Map阶段,多个mapper组成一个chain,然后连续进行调用

  • ChainReducer 允许在Reuduce阶段,reducer完成之后执行一个mapper chain.
  • 最终达到的效果就是 M+ -> R -> M/* (1个或者是多个mapper, 一个reducer,然后0个或者是多个mapper)
  • TODO(dirlt):这样做倒是可以将各个mapper组合起来用作adapter.

    1.4.9 构建Hadoop集群

  • 很多教程说hadoop集群需要配置ssh,但是配置这个前提是你希望使用start-all.sh这个脚本来启动集群

  • 我现在的公司使用apt-get来安装,使用cssh来登陆到所有的节点上面进行配置,因此没有配置这个信任关系

  • Hadoop配置

  • 配置文件

  • hadoop-env.sh 环境变量脚本

  • core-site.xml core配置,包括hdfs以及mapred的IO配置等
  • hdfs-site.xml hadoop进程配置比如namenode以及datanode以及secondary namenode
  • mapred-site.xml mapred进程配置比如jobtracker以及tasktracker
  • masters 运行namenode(secondary namenode)的机器列表,每行一个, 无需分发到各个节点

  • 在本地启动primary namenode

  • slaves 运行datanode以及tasktracker的机器列表,每行一个 无需分发到各个节点

  • 在本地启动jobtracker

  • hadoop-metrics.properties 对hadoop做监控的配置文件
  • log4j.properties 日志配置文件
  • 这些文件在conf目录下面有,如果想使用不同的文件也可以使用-config来另行指定
  • NOTE(dirlt):所以从上面这个脚本来看,还是具有一定的局限性的
  • hadoop-env.sh

  • HADOOP_HEAPSIZE = 1000MB 守护进程大小

  • HADOOP_NAMENODE_OPTS
  • HADOOP_SECONDARYNAMENODE_OPTS
  • HADOOP_IDENT_STRING 用户名称标记,默认为${USER}
  • HADOOP_LOG_DIR hadoop日志文件,默认是HADOOP_INSTALL/logs
  • core-site.xml

  • io.file.buffer.size IO操作缓冲区大小,默认是4KB 这个需要提高

  • hdfs-site.xml

  • fs.default.name

  • hadoop.tmp.dir hadoop临时目录,默认是在/tmp/hadoop-${user.name}
  • dfs.name.dir namenode数据目录,一系列的目录,namenode内容会同时备份在所有指定的目录中。默认为${hadoop.tmp.dir}/dfs/name
  • dfs.data.dir datanode数据目录,一系列的目录,循环将数据写在各个目录里面。默认是${hadoop.tmp.dir}/dfs/data
  • fs.checkpoint.dir secondarynamenode数据目录,一系列目录,所有目录都会写一份。默认为${hadoop.tmp.dir}/dfs/namesecondary
  • dfs.namenode.handler.count namenode上用来处理请求的线程数目
  • dfs.datanode.ipc.address 0.0.0.0:50020 datanode的RPC接口,主要和namenode交互
  • dfs.datanode.address 0.0.0.0:50010 datanode的data block传输接口,主要和client交互
  • dfs.datanode.http.address 0.0.0.0:50075 datanode的HTTP接口,和user交互
  • dfs.datanode.handler.count datanode上用来处理请求的线程数目
  • dfs.datanode.max.xcievers datanode允许最多同时打开的文件数量
  • dfs.http.address 0.0.0.0:50070 namenode的HTTP接口
  • dfs.secondary.http.address 0.0.0.0:50090 secondard namenode的HTTP接口
  • dfs.datanode.dns.interface default 绑定的NIC,默认是绑定默认的NIC比如eth0
  • dfs.hosts / dfs.hosts.exclude 加入的datanode以及排除的datanode
  • dfs.replication = 3 副本数目
  • dfs.block.size = 64MB
  • dfs.datanode.du.reserved 默认datanode会使用目录所在磁盘所有空间,这个值可以保证有多少空间被reserved的
  • fs.trash.interval 单位分钟,如果不为0的话,那么删除文件会移动到回收站,超过这个单位时间的文件才会完全删除。

  • 回收站位置/home/${user]/.Trash NOTE(dirlt):回收站这个功能只是对fs shell有效。fs shell remove时候会构造Trash这个类来处理删除文件的请求。如果调用Java API的话那么会直接删除文件

  • haddop fs -expunge 强制删除
  • NOTE(dirlt):grep代码发现只有NameNode在TrashEmptier里面构造了Trash这个类,因此这个配置之需要在nn上配置即可,决定多久定期删除垃圾文件
  • fs.trash.checkpoint.interval 单位分钟,namenode多久检查一次文件是否需要删除。

  • NOTE(dirlt):似乎没有这个参数。如果没有这个参数的话,那么两次检查时长应该是由参数fs.trasn.interval来决定

  • mapred-site.xml

  • mapred.job.tracker

  • mapred.local.dir MR中间数据存储,一系列目录,分散写到各个目录下面,默认为${hadoop.tmp.dir}/mapred/local
  • mapred.system.dir MR运行期间存储,比如存放jar或者是缓存文件等。默认${hadoop.tmp.dir}/mapred/system
  • mapred.tasktracker.map.tasks.maximum = 2 单个tasktracker最多多少map任务
  • mapred.tasktracker.reduce.tasks.maximum = 2 单个tasktracker最多多少个reduce任务
  • mapred.tasktracker.dns.interface default 绑定的NIC,默认是绑定默认的NIC比如eth0
  • mapred.child.ulimit 单个tasktracker允许子进程占用的最大内存空间。通常为2-3/* mapred.child.java.opts.
  • mapred.child.java.opts = -Xmx200m 每个子JVM进程200M. NOTE(dirlt):这个是在提交机器上面设置的,而不是每个tasktracker上面设置的,每个job可以不同

  • 不一定支持将map/reduce的jvm参数分开设置 http://hadoop-common.472056.n3.nabble.com/separate-JVM-flags-for-map-and-reduce-tasks-td743351.html

  • NOTE(dirlt):个人折中思路是限制内存大小为1G,然后大内存机器允许同时执行map/reduce数量上限提高,通过增加job的map/reduce数量来提高并发增加性能
  • NOTE(dirlt):我grep了一下cdh3u3的代码,应该是将map/reduce的jvm参数分开进行了设置

  • mapred.map.child.java.opts

  • mapred.reduce.child.java.opts
  • mapred.task.tracker.report.address 127.0.0.1:0 tasktracker启动子进程通信的端口,0表示使用任意端口
  • mapred.task.tracker.expiry.interval 600(sec) tt和jt之间的心跳间隔
  • mapred.job.tracker.handler.count. jobtracker用来处理请求的线程数目。
  • mapred.job.tracker.http.address 0.0.0.0:50030 jobtracker的HTTP接口
  • mapred.task.tracker.http.address 0.0.0.0:50060 tasktrackder的HTTP接口
  • mapred.hosts / mapred.hosts.exclude 加入的tasktracker以及排除的tasktracker.
  • Hadoop Benchmark NOTE(dirlt):try it out

  • 在hadoop安装目录下面有jar可以来做基准测试

  • TestDFSIO测试HDFS的IO性能
  • Sort测试MapReduce性能
  • MRBench多次运行一个小作业来检验小作业能否快速相应
  • NNBench测试namenode硬件的负载

1.4.10 管理Hadoop

  • 永久性数据结构

  • namenode的目录结构

  • current表示当前的namenode数据(对于辅助节点上这个数据并不是最新的)

  • previous.checkpoint表示secondarynamenode完成checkpoint的数据(和current可能存在一些编辑差距)

  • hadoop dfsadmin -saveNamespace 可以强制创建检查点,仅仅在安全模式下面运行

  • 辅助namenode每隔5分钟会检查

  • 如果超过fs.checkpoint.period = 3600(sec),那么会创建检查点

  • 如果编辑日志大小超过fs.checkpoint.size = 64MB,同样也会创建检查点
  • 除了将文件copy到namenode之外,在辅助节点上面可以使用选项-importCheckpoint来载入
  • VERSION Java属性文件

  • namespaceID 每次格式化都会重新生成一个ID,这样可以防止错误的datanode加入

  • cTime namenode存储系统创建时间,对于刚格式化的存储系统为0.对于升级的话会更新到最新的时间戳
  • storageType NAME_NODE or DATA_NODE
  • layoutVersion 负整数表示hdfs文件系统布局版本号,对于hadoop升级的话这个版本号可能不会变化
  • edits 编辑日志文件
  • fsimage 镜像文件
  • fstime ???
  • datanode的目录结构

  • blk以及blk.meta 表示块数据以及对应的元信息,元数据主要包括校验和等内容

  • 如果datanode文件非常多的话,超过dfs.datanode.numblocks = 64的话,那么会创建一个目录单独存放,最终结果就是形成树存储结构。
  • dfs.data.dir目录是按照round-robin的算法选择的。
  • 安全模式

  • namenode启动的时候会尝试合并edit数据并且新建一个checkpoint,然后进入安全模式,在这个模式内文件系统是只读的

  • 可以通过hadoop dfsadmin -safemode来操作安全模式
  • 当达到下面几个条件的时候会离开安全模式

  • 整个系统的副本数目大于某个阈值的副本数目比率超过一个阈值之后,然后继续等待一段时间就会离开安全模式

  • dfs.replication.min = 1 副本数目阈值
  • dfs.safemode.threshold.pct = 0.999 比率阈值
  • dfs.safemode.extension = 30000(ms) 等待时间
  • 工具

  • dfsadmin

  • fsck
  • scanner

  • DataBlockScanner每隔一段时间会扫描本地的data block检查是否出现校验和问题

  • 时间间隔是dfs.datanode.scan.period.hours = 504默认三周
  • 可以通过页面访问每个datanode的block情况 http://localhost:50075/blockScannerReport
  • 加上listblocks参数可以看每个block情况 http://localhost:50075/blockScannerReport?listblocks NOTE(dirlt):可能会很大
  • balancer

  • 通过start-balancer.sh来启动,集群中只允许存在一个均衡器

  • 均衡的标准是datanode的利用率和集群平均利用率的插值,如果超过某个阈值就会进行block movement
  • -threshold可以执行阈值,默认为10%
  • dfs.balance.bandwidthPerSec = 1024 /* 1024 用于balance的带宽上限。
  • 监控

  • 日志

  • jobtracker的stack信息(thread-dump)http://localhost:50030/stacks

  • 度量

  • 度量从属于特性的上下文(context),包括下面几个

  • dfs

  • mapred
  • rpc
  • jvm
  • 下面是几种常见的context

  • FileContext 度量写到文件

  • GangliaContext 度量写到ganglia (这个似乎比较靠谱)
  • CompositeContext 组合context
  • 度量可以从hadoop-metrics.properties进行配置

1.5 Benchmark

1.5.1 TestDFSIO

测试hdfs吞吐 hdfs@hadoop1:~$ hadoop jar /usr/lib/hadoop/hadoop-test-0.20.2-cdh3u3.jar TestDFSIO

Usage: TestDFSIO [genericOptions] -read | -write | -append | -clean [-nrFiles N] [-fileSize Size[B|KB|MB|GB|TB]] [-resFile resultFileName] [-bufferSize Bytes] [-rootDir]%

  • read / write / append / clean 操作类型 append和write执行效率差别不大,但是write会创建新文件所以使用比较方便 (default read)
  • nrFiles 文件数目(default 1) 启动相同数量的map
  • fileSize 每个文件大小(1MB)
  • resFile 结果报告文件(TestDFSIO_results.log)
  • bufferSize write buffer size(单次write写入大小)(1000000 bytes)
  • rootDir 操作文件根目录(/benchmarks/TestDFSIO/) ----- TestDFSIO ----- : write

         Date & time: Thu Apr 25 19:14:21 CST 2013
     Number of files: 2
    

Total MBytes processed: 2.0 Throughput mb/sec: 7.575757575757576

Average IO rate mb/sec: 7.61113977432251 IO rate std deviation: 0.5189420757292891

Test exec time sec: 14.565

----- TestDFSIO ----- : read Date & time: Thu Apr 25 19:15:13 CST 2013

   Number of files: 2

Total MBytes processed: 2.0

 Throughput mb/sec: 27.77777777777778

Average IO rate mb/sec: 28.125

IO rate std deviation: 3.125 Test exec time sec: 14.664

  • throughtput = sum(filesize) / sum(time)
  • avaerage io rate = sum(filesize/time) / n
  • io rate std deviation

    1.5.2 TeraSort

通过排序测试MR执行效率 我看了一下代码map/reduce都有CPU操作,并且这个也非常依靠shuffle/copy.因此这个测试应该会是比较全面的 hdfs@hadoop1:~$ hadoop jar /usr/lib/hadoop/hadoop-examples-0.20.2-cdh3u3.jar

  • teragen 产生排序数据

  • 10 bytes key(random characters)

  • 10 bytes rowid(right justified row id as a int)
  • 78 bytes filler
  • \r\n
  • terasort 对数据排序

  • teravalidate 对排序数据做验证

可以使用hadoop job -history all 来观察程序运行数据,也可以通过web page来分析。

1.5.3 nnbench

测试nn负载能力 ➜ ~HADOOP_HOME hadoop jar hadoop-test-0.20.2-cdh3u3.jar nnbench

NameNode Benchmark 0.4 Usage: nnbench

Options: -operation

     /* NOTE: The open_read, rename and delete operations assume that the files they operate on, are already available. The create_write operation must be run before running the other operations.
    -maps <number of maps. default is 1. This is not mandatory>

    -reduces <number of reduces. default is 1. This is not mandatory>
    -startTime <time to start, given in seconds from the epoch. Make sure this is far enough into the future, so all maps (operations) will start at the same time>. default is launch time + 2 mins. This is not mandatory

    -blockSize <Block size in bytes. default is 1. This is not mandatory>
    -bytesToWrite <Bytes to write. default is 0. This is not mandatory>

    -bytesPerChecksum <Bytes per checksum for the files. default is 1. This is not mandatory>
    -numberOfFiles <number of files to create. default is 1. This is not mandatory>

    -replicationFactorPerFile <Replication factor for the files. default is 1. This is not mandatory>
    -baseDir <base DFS path. default is /becnhmarks/NNBench. This is not mandatory>

    -readFileAfterOpen <true or false. if true, it reads the file and reports the average time to read. This is valid with the open_read operation. default is false. This is not mandatory>
    -help: Display the help statement
  • startTime 作用是为了能够让所有的map同时启动以便对nn造成压力 ➜ ~HADOOP_HOME hadoop jar hadoop-test-0.20.2-cdh3u3.jar nnbench -operation create_write -bytesToWrite 0 -numberOfFiles 1200

➜ ~HADOOP_HOME hadoop jar hadoop-test-0.20.2-cdh3u3.jar nnbench -operation open_read

结果报告文件是 NNBench_results.log

-------------- NNBench -------------- :

                           Version: NameNode Benchmark 0.4
                       Date & time: 2013-04-25 19:41:02,873


                    Test Operation: create_write

                        Start time: 2013-04-25 19:40:21,70
                       Maps to run: 1

                    Reduces to run: 1
                Block Size (bytes): 1

                    Bytes to write: 0
                Bytes per checksum: 1

                   Number of files: 1200
                Replication factor: 1

        Successful file operations: 1200


    /# maps that missed the barrier: 0
                      /# exceptions: 0


           TPS: Create/Write/Close: 75

Avg exec time (ms): Create/Write/Close: 26.526666666666667 Avg Lat (ms): Create/Write: 13.236666666666666

               Avg Lat (ms): Close: 13.164166666666667


             RAW DATA: AL Total /#1: 15884
             RAW DATA: AL Total /#2: 15797

          RAW DATA: TPS Total (ms): 31832
   RAW DATA: Longest Map Time (ms): 31832.0

               RAW DATA: Late maps: 0
         RAW DATA: /# of exceptions: 0

-------------- NNBench -------------- :

                           Version: NameNode Benchmark 0.4
                       Date & time: 2013-04-25 19:44:42,354


                    Test Operation: open_read

                        Start time: 2013-04-25 19:44:31,921
                       Maps to run: 1

                    Reduces to run: 1
                Block Size (bytes): 1

                    Bytes to write: 0
                Bytes per checksum: 1

                   Number of files: 1
                Replication factor: 1

        Successful file operations: 1


    /# maps that missed the barrier: 0
                      /# exceptions: 0


                    TPS: Open/Read: 500

     Avg Exec time (ms): Open/Read: 2.0
                Avg Lat (ms): Open: 2.0


             RAW DATA: AL Total /#1: 2

             RAW DATA: AL Total /#2: 0
          RAW DATA: TPS Total (ms): 2

   RAW DATA: Longest Map Time (ms): 2.0
               RAW DATA: Late maps: 0

         RAW DATA: /# of exceptions: 0
  • maps that missed the barrier 从代码上分析是,在等待到start time期间中,如果sleep出现异常的话。
  • exceptions 表示在操作文件系统时候的exception数量
  • TPS transactions per second
  • exec(execution) 执行时间
  • lat(latency) 延迟时间
  • late maps 和 maps missed the barrier是一个概念。

对于后面RAW DATA部分的话,从代码上看,就是为了计算出上面那些指标的,所以没有必要关注。

1.5.4 mrbench

测试运行small mr jobs执行效率,主要关注响应时间。 MRBenchmark.0.0.2

Usage: mrbench [-baseDir ] [-jar ] [-numRuns ] [-maps ] [-reduces ] [-inputLines ] [-inputType ] [-verbose]

  • baseDir 输入输出目录
  • jar 通常不需要指定,用默认即可。
  • inputLines 输入条数
  • inputType 输入是否有序 hdfs@hadoop1:~$ hadoop jar /usr/lib/hadoop/hadoop-test-0.20.2-cdh3u3.jar mrbench -verbose

结果直接输出在终端上面,

Total MapReduce jobs executed: 1

Total lines of data per job: 1 Maps per job: 2

Reduces per job: 1 Total milliseconds for task: 1 = 16452

DataLines Maps Reduces AvgTime (milliseconds) 1 2 1 16452

可以看到每个任务平均执行时间在16.452s.

1.5.5 hbase.PerformanceEvaluation

hdfs@hadoop1:~$ hbase org.apache.hadoop.hbase.PerformanceEvaluation

Usage: java org.apache.hadoop.hbase.PerformanceEvaluation \ [--miniCluster] [--nomapred] [--rows=ROWS]

Options:

miniCluster Run the test on an HBaseMiniCluster nomapred Run multiple clients using threads (rather than use mapreduce)

rows Rows each client runs. Default: One million flushCommits Used to determine if the test should flush the table. Default: false

writeToWAL Set writeToWAL on puts. Default: True

Command: filterScan Run scan test using a filter to find a specific row based on it's value (make sure to use --rows=20)

randomRead Run random read test randomSeekScan Run random seek and scan 100 test

randomWrite Run random write test scan Run scan test (read every row)

scanRange10 Run random seek scan with both start and stop row (max 10 rows) scanRange100 Run random seek scan with both start and stop row (max 100 rows)

scanRange1000 Run random seek scan with both start and stop row (max 1000 rows) scanRange10000 Run random seek scan with both start and stop row (max 10000 rows)

sequentialRead Run sequential read test sequentialWrite Run sequential write test

Args:

nclients Integer. Required. Total number of clients (and HRegionServers) running: 1 <= value <= 500

Examples: To run a single evaluation client:

$ bin/hbase org.apache.hadoop.hbase.PerformanceEvaluation sequentialWrite 1

从参数上看还是比较直接的。benchmark每个client通常对应10个mapper, 每个client操作个row,因此每个mapper操作/10个row,每个row大约1000bytes.

  • filterScan 随机生成value,然后从头开始scan直到equal
  • randomRead 随机选取key读取
  • randomSeekScan 从某个随机位置开始scan最多100个
  • randomWrite 随即生成key写入
  • scan 每次scan 1个row,start随机
  • scan 每次scan num个row,start随机
  • seqRead 顺序地读取每个key
  • seqWrite 顺序地写入每个key
  • NOTE(dirlt):这里的key都非常简单,10个字符的数字,printf("%010d",row) hdfs@hadoop1:~$ time hbase org.apache.hadoop.hbase.PerformanceEvaluation --rows=1000 sequentialWrite 2

13/04/25 23:47:56 INFO mapred.JobClient: HBase Performance Evaluation 13/04/25 23:47:56 INFO mapred.JobClient: Row count=2000

13/04/25 23:47:56 INFO mapred.JobClient: Elapsed time in milliseconds=258

输出结果是在counter里面,这里面row count = 2000, 占用时间为258 ms. Date: 2013-12-15T10:28+0800

Org version 7.9.2 with Emacs version 24 Validate XHTML 1.0 来源: [http://dirlt.com/hadoop.html/#sec-1-1-4](http://dirlt.com/hadoop.html#sec-1-1-4)

Vim命令合集

Posted on

Vim命令合集

命令历史

以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令。

启动vim

在命令行窗口中输入以下命令即可

vim 直接启动vim

vim filename 打开vim并创建名为filename的文件

文件命令

打开单个文件

vim file

同时打开多个文件

vim file1 file2 file3 ...

在vim窗口中打开一个新文件

:open file

在新窗口中打开文件

:split file

切换到下一个文件

:bn

切换到上一个文件

:bp

查看当前打开的文件列表,当前正在编辑的文件会用[]括起来。

:args

打开远程文件,比如ftp或者share folder

:e ftp://192.168.10.76/abc.txt

:e \qadrive\test\1.txt

vim的模式

正常模式(按Esc或Ctrl+[进入) 左下角显示文件名或为空 插入模式(按i键进入) 左下角显示--INSERT-- 可视模式(不知道如何进入) 左下角显示--VISUAL--

导航命令

% 括号匹配

插入命令

i 在当前位置生前插入

I 在当前行首插入

a 在当前位置后插入

A 在当前行尾插入

o 在当前行之后插入一行

O 在当前行之前插入一行

查找命令

/text  查找text,按n健查找下一个,按N健查找前一个。

?text  查找text,反向查找,按n健查找下一个,按N健查找前一个。

vim中有一些特殊字符在查找时需要转义  ./*[]^%/?~$

:set ignorecase  忽略大小写的查找

:set noignorecase  不忽略大小写的查找

查找很长的词,如果一个词很长,键入麻烦,可以将光标移动到该词上,按/*或/#键即可以该单词进行搜索,相当于/搜索。而/#命令相当于?搜索。

:set hlsearch  高亮搜索结果,所有结果都高亮显示,而不是只显示一个匹配。

:set nohlsearch  关闭高亮搜索显示

:nohlsearch  关闭当前的高亮显示,如果再次搜索或者按下n或N键,则会再次高亮。

:set incsearch  逐步搜索模式,对当前键入的字符进行搜索而不必等待键入完成。

:set wrapscan  重新搜索,在搜索到文件头或尾时,返回继续搜索,默认开启。

替换命令

ra 将当前字符替换为a,当期字符即光标所在字符。

s/old/new/ 用old替换new,替换当前行的第一个匹配

s/old/new/g 用old替换new,替换当前行的所有匹配

%s/old/new/ 用old替换new,替换所有行的第一个匹配

%s/old/new/g 用old替换new,替换整个文件的所有匹配

:10,20 s/^/ /g 在第10行知第20行每行前面加四个空格,用于缩进。

ddp 交换光标所在行和其下紧邻的一行。

移动命令

h 左移一个字符 l 右移一个字符,这个命令很少用,一般用w代替。 k 上移一个字符 j 下移一个字符 以上四个命令可以配合数字使用,比如20j就是向下移动20行,5h就是向左移动5个字符,在Vim中,很多命令都可以配合数字使用,比如删除10个字符10x,在当前位置后插入3个!,3a!,这里的Esc是必须的,否则命令不生效。

w 向前移动一个单词(光标停在单词首部),如果已到行尾,则转至下一行行首。此命令快,可以代替l命令。

b 向后移动一个单词 2b 向后移动2个单词

e,同w,只不过是光标停在单词尾部

ge,同b,光标停在单词尾部。

^ 移动到本行第一个非空白字符上。

0(数字0)移动到本行第一个字符上,

移动到本行第一个字符。同0健。

$ 移动到行尾 3$ 移动到下面3行的行尾

gg 移动到文件头。 = [[

G(shift + g) 移动到文件尾。 = ]]

f(find)命令也可以用于移动,fx将找到光标后第一个为x的字符,3fd将找到第三个为d的字符。

F 同f,反向查找。

跳到指定行,冒号+行号,回车,比如跳到240行就是 :240回车。另一个方法是行号+G,比如230G跳到230行。

Ctrl + e 向下滚动一行

Ctrl + y 向上滚动一行

Ctrl + d 向下滚动半屏

Ctrl + u 向上滚动半屏

Ctrl + f 向下滚动一屏

Ctrl + b 向上滚动一屏

撤销和重做

u 撤销(Undo) U 撤销对整行的操作 Ctrl + r 重做(Redo),即撤销的撤销。

删除命令

x 删除当前字符

3x 删除当前光标开始向后三个字符

X 删除当前字符的前一个字符。X=dh

dl 删除当前字符, dl=x

dh 删除前一个字符

dd 删除当前行

dj 删除上一行

dk 删除下一行

10d 删除当前行开始的10行。

D 删除当前字符至行尾。D=d$

d$ 删除当前字符之后的所有字符(本行)

kdgg 删除当前行之前所有行(不包括当前行)

jdG(jd shift + g) 删除当前行之后所有行(不包括当前行)

:1,10d 删除1-10行

:11,$d 删除11行及以后所有的行

:1,$d 删除所有行

J(shift + j)  删除两行之间的空行,实际上是合并两行。

拷贝和粘贴

yy 拷贝当前行

nyy 拷贝当前后开始的n行,比如2yy拷贝当前行及其下一行。

p 在当前光标后粘贴,如果之前使用了yy命令来复制一行,那么就在当前行的下一行粘贴。

shift+p 在当前行前粘贴

:1,10 co 20 将1-10行插入到第20行之后。

:1,$ co $ 将整个文件复制一份并添加到文件尾部。

正常模式下按v(逐字)或V(逐行)进入可视模式,然后用jklh命令移动即可选择某些行或字符,再按y即可复制

ddp交换当前行和其下一行

xp交换当前字符和其后一个字符

剪切命令

正常模式下按v(逐字)或V(逐行)进入可视模式,然后用jklh命令移动即可选择某些行或字符,再按d即可剪切

ndd 剪切当前行之后的n行。利用p命令可以对剪切的内容进行粘贴

:1,10d 将1-10行剪切。利用p命令可将剪切后的内容进行粘贴。

:1, 10 m 20 将第1-10行移动到第20行之后。

退出命令

:wq 保存并退出

ZZ 保存并退出

:q! 强制退出并忽略所有更改

:e! 放弃所有修改,并打开原来文件。

窗口命令

:split或new 打开一个新窗口,光标停在顶层的窗口上

:split file或:new file 用新窗口打开文件

split打开的窗口都是横向的,使用vsplit可以纵向打开窗口。

Ctrl+ww 移动到下一个窗口

Ctrl+wj 移动到下方的窗口

Ctrl+wk 移动到上方的窗口

关闭窗口

:close 最后一个窗口不能使用此命令,可以防止意外退出vim。

:q 如果是最后一个被关闭的窗口,那么将退出vim。

ZZ 保存并退出。

关闭所有窗口,只保留当前窗口

:only

录制宏

按q键加任意字母开始录制,再按q键结束录制(这意味着vim中的宏不可嵌套),使用的时候@加宏名,比如qa。。。q录制名为a的宏,@a使用这个宏。

执行shell命令

:!command

:!ls 列出当前目录下文件

:!perl -c script.pl 检查perl脚本语法,可以不用退出vim,非常方便。

:!perl script.pl 执行perl脚本,可以不用退出vim,非常方便。

:suspend或Ctrl - Z 挂起vim,回到shell,按fg可以返回vim。

注释命令

perl程序中/#开始的行为注释,所以要注释某些行,只需在行首加入/#

3,5 s/^//#/g 注释第3-5行

3,5 s/^/#//g 解除3-5行的注释

1,$ s/^//#/g 注释整个文档。

:%s/^//#/g 注释整个文档,此法更快。

帮助命令

:help or F1 显示整个帮助 :help xxx 显示xxx的帮助,比如 :help i, :help CTRL-[(即Ctrl+[的帮助)。 :help 'number' Vim选项的帮助用单引号括起 :help 特殊键的帮助用<>扩起 :help -t Vim启动参数的帮助用- :help i 插入模式下Esc的帮助,某个模式下的帮助用模式主题的模式 帮助文件中位于||之间的内容是超链接,可以用Ctrl+]进入链接,Ctrl+o(Ctrl + t)返回

其他非编辑命令

. 重复前一次命令

:set ruler?  查看是否设置了ruler,在.vimrc中,使用set命令设制的选项都可以通过这个命令查看

:scriptnames  查看vim脚本文件的位置,比如.vimrc文件,语法文件及plugin等。

:set list 显示非打印字符,如tab,空格,行尾等。如果tab无法显示,请确定用set lcs=tab:>-命令设置了.vimrc文件,并确保你的文件中的确有tab,如果开启了expendtab,那么tab将被扩展为空格。

Vim教程 在Unix系统上 $ vimtutor 在Windows系统上 :help tutor :syntax 列出已经定义的语法项 :syntax clear 清除已定义的语法规则 :syntax case match 大小写敏感,int和Int将视为不同的语法元素 :syntax case ignore 大小写无关,int和Int将视为相同的语法元素,并使用同样的配色方案

一直都在注意Oracle的招聘信息

Posted on

一直都在注意Oracle的招聘信息

一直都在注意Oracle的招聘信息,毕竟是世界第二大软件公司呀。可是,奇怪的是观察了很长的时间都没有发现任何招聘广告。并且,从我对它的初步了解来看,与微软,Google中国研发中心比起来,它显得那样的无声无息。终于有一天的早上,打开zhaopin.com,第一次发现了Oracle的招聘信息。高兴的是,里边包括若干个测试的职位。马上把简历投了过去。下午接到了电话,一听果然就是Oracle的,要跟我安排面试。Oracle的招聘比较奇怪,没有recruiter,都是hiring manager跟你联系。 面试当天,早了几分钟来到公司,被前台领到一间会议室里面,给了一套试题来做。同屋已经有好几个人在做题了,心理顿感不爽。本来以为是要单独给我面试的,没想到竟然会跟大家一起做题。更没想到的是,当我打开试题的时候,我好像基本都不会做。实话实说,我并没有什么Oracle的技术背景,可是我觉得做测试也不需要懂这么多试题上的知识吧?硬着头皮做了两道,实在做不下去了,起身就走。到了前台,告诉他们我感觉这个面试不对劲。他们才反应过来给搞错了。忙着给我的hiring manager打电话,让我去了她那里。 Hiring manager是个中年女士,看起来人就很nice。面试也是在一间会议室进行的,做了一屋子的人。看来对一个测试人员的面试也搞得挺隆重。Hiring manager并没有提问,第一个提问的是个技术大拿。他面试的场面我还从来没经历过。简单的说就是,他看着你简历问你问题,问得肯定是你做过的东西,但是,问得深度是特别的深,一般你还回答不上来。这种知识面,深度的人,到任何地方都是大拿。我是挺佩服的。第二个面试的可能是一个香港人,他主要是考察我的英文水平,用英文跟我聊了很长时间。第三个人主要是考察我的Linux的技术,很抱歉好久没有用Linux了,问我的很多简单的命令,本来我以前是会的,可是忘记了。不过,这个时候那个manager讲话了,说我的背景学Linux应该是很快的事情。然后我主要跟他们聊了自动化测试的东西,他们竟然还没有什么自动化的测试,基本还是靠手工测试。他们也希望我能够在自动化测试方面能够给公司带来些新鲜的东西。 第二天,manager给我打电话,说美国的老板想跟我聊聊。与此同时,我也接受到美国的一封email,要跟我电话面试,搞得我有点迷惑。最后才知道,是两个不同的老板要跟我面试。定了周末两天的上午,因为对方是在加州,我们合适的时间只有每天的上午。第一天面试是一个中国人,不过我们全是用英文交谈的。看得出他对我很满意,多次给我说这个职位不是在他的team,如果对方的不要我,我可以来他的team。他是做日本方面的项目,另一个team是做 open source的项目。一直谈的都很愉快,直到谈到待遇的问题。说实话,我当时的目标是每月2万,不过由于微软,Google的情况还不明朗,不想再错过这次机会,因此就要了每月1.5万。没想到他却明确回答不能满足,并跟我说他们有很多福利等等。最后问我要多少钱,我就回答算上福利全年20万。实际上当时有点傻,因为月薪1.5万和加上福利年薪20万应该是差不多的。对方就没有再说什么,我们结束了谈话。第二天是个老外,主要谈一些技术的问题吧,我也没感觉是好是坏,因为昨天的人已经说过不行就去他的team了。 不过,后来他们就再也没跟我联系过。我估计是我的要价太高了,而且我最近知道我一个朋友有多年的Oracle经验,刚刚进入他们那里,也不过是20万年薪。这样解释了我的一个疑惑。我当时就奇怪,堂堂一个Oracle怎么把研发中心放到上地。看来他们本身就不想投入太多。后来又听人说,这个中心的老板不地道,总之有一些rumor,不知道是真是假。 我想当时如果我真想进的话,开口小点应该是没什么问题的。这里给大家介绍一个面试的经验,对方的技术你不熟悉可能不是一个大问题。面试的时候,一定要有自信,让对方知道你有能力,有激情,有头脑。并且,一定要大胆跟他们讨论一些你擅长的技术问题。让他们更细致的了解你的能力,留下与其他人不一样的印象,就更容易打动他们。还有一个经验就是,谈待遇的时候,如果你真的想进这个公司,你就不要说具体数目了,就说我很珍惜这个工作进会,我一直都期望能进入你们的公司,你们可以按照标准给我工资就可以了,我没什么特殊的要求。我后来的面试在待遇上都是如此回答的,并且都得到了offer。 下次有时间,讲讲我去微软,北电面试的经验教训。

来源: [http://www.linuxdiyf.com/viewarticle.php?id=97760](http://www.linuxdiyf.com/viewarticle.php?id=97760)

IT外企那点儿事(7):做一个优秀的基层

Posted on

IT外企那点儿事(7):做一个优秀的基层

觉先

博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 :: 130 随笔 :: 0 文章 :: 544 评论 :: 0 引用 <2010年5月>日一二三四五六2526272829301234567891011121314151617181920212223242526272829303112345

公告

昵称:觉先 园龄:3年7个月 荣誉:推荐博客 粉丝:560 关注:3

+加关注

搜索

常用链接

随笔分类

随笔档案

相册

最新评论

阅读排行榜

评论排行榜

推荐排行榜

IT外企那点儿事(7):做一个优秀的基层

千里之行,始于足下,无论你有多么的豪情万丈,总要从最基础的东西做起。

然而要做一个好的基层工作人员,并不是低头认认真真写好代码就可以的,其中可大有学问。

按照余世维所论,一个好的下属应该:

  • 主动向上司汇报你的工作进度——让上司知道!
  • 对上司的询问,有问必答,而且清楚——让上司放心!
  • 充实自己,努力学习,才能了解上司的言语——让上司轻松!
  • 接受批评,不犯两次过错——让上司省事!
  • 不忙的时候,主动帮助他人——让上司有效!
  • 毫无怨言的接受任务——让上司圆满!
  • 对自己的业务,主动提出改善计划——让上司进步!

我也总结了如下几点,欢迎大家补充。

(1) 做得快还是做得好?

当前的项目管理中,多是强调结果的,号称结果导向或者结果驱动。

作为一个基层,做人重要,做事更重要,除了良好的沟通能力,能拿得出真金白银的成果,更是每个项目经理愿意看到的事情。

然而怎么叫好的结果呢?

一九五八年党的八大二次会议上,提出多快好省的建设社会主义。多快好省四个字即体现了前辈革命家的理想壮志,也成为后来中国管理者心中的梦。所以我们时常听到如下的话:"这些功能下个月一定要出来","代码质量要高,要有详细的注释,测试用例,code review","最好提前一周至少三天,可以准备demo","项目现在经费相对比较紧张,希望大家克服一下"。

然而现代的项目管理给我们画出了如下的三角形:

范围,预算,时间三者相互制约,牵一发而动全身。欲范围大(多),就应该增加项目预算(不省),如增加人手,增加资源,买第三方成品,或者应该延长时间(不快),如推迟release的时间等。欲按期完成(快),则可以增加预算(不省),或者减少功能(不多)。

然而现实中,老板可不这样想,预算是早就做好了的,时间也是确定了的,功能缺一不可,作为基层的程序员我们唯一可以影响的就是用加班换来更多的时间,当然还有中间的一个圆圈——项目的质量。

到底是尽快的做出一个实现基本功能但设计稍有缺陷,测试不太完备,有少量的Bug的版本出来然后慢慢改进呢,还是经过慢慢的精心设计,做出有完备的测试用例,经过严格测试少有Bug的版本呢?

这个问题如果你问程序员,大部分人会选择后者。尤其对于初涉职场,充满激情的程序员们,往往满脑设计模式,满口软件工程,几乎见不得注释中的错别字和没有覆盖到的测试边界,似乎一个不完美的方案就有辱于软件工程师的名号了,我们称之"技术洁癖"。

如果你问项目经理,也会告诉你后者,而且最好以后者的形式用前者的时间(多少有些多快好省的味道)。然而很少有项目经理会直接看你的代码,更不关心你用的何种设计模式,也不会一个个看你的测试用例来思考是否覆盖所有的边界,更不会看你写的注释了。

所以很不幸,除了少数精通技术,熟悉细节,了解程序员苦衷的项目经理外(这可是大多数程序员都翘首以待的领导啊),大部分喜欢前者。

因为精心的设计,良好的文档是需要大量的时间,完备的测试用例的代码量几倍于实现本身,功能测试,性能测试以及Bug的修改更是难以估计时间的,所以总的时间将几倍于前者的时间,在此过程中,你献给项目经理的,除了等待,还是等待。

人是不喜欢等待的,尤其是很少反馈的等待,当我们用windows的时候,往往会出现估计时间相当不准确的进度条,然而我们还是喜欢看着进度条一直走到底,同样项目经理也是。

总是能够很快的做出项目经理能够看到的版本,便容易给人一种能力很强的感觉,至少大部分人会这样认为。

也许你会说:我做的版本Bug很少,后期维护成本低,QA一测不就能够看出孰优孰劣来了吗?

仍然很不幸,在大多数人看来,你一个月做了一个稳定的版本被认为是做了一件事情,而别人两个星期做了一个不稳定的版本,后两个星期改了三个Bug是做了四件事情,而且其每次的会议总有进度可以说,成绩斐然。

而且一个人身上所挂着的Bug的个数,实在不是一件值得羞愧的事情,反而是一件令人感到荣耀的事情,这说明了你重担在身,举足轻重。

如果你做了一个模块,用了一个月,后来半年都不曾出过Bug,而另一个人做一个模块两个星期,出过多个Bug,并且后来兼任其他模块的时候还在改Bug,还是很不幸,你会被认为所做的模块相对简单,不容易出Bug,并随着项目的进行而被淡忘,会被这样提及:"他在半年前做过一个项目",而另一个人却会被认为所做的很复杂,有很多疑难杂症,而且后来会被认为身兼数职,会这样被提及:"随着能力的提升,同时维护并负责多个模块,有并行工作的能力,有很强的解决问题的能力"。

也许你觉得我说的太极端,那就举一个历史上的例子吧,有兴趣大家可以看李亚平的《前清秘史——入主中原之路》,其中是这样描写当时并称“南戚北李”的两位将军的:

李成梁屡立大功,受封为伯爵,跻身于帝国贵族行列。在当时,他的地位、名望等,很有可能已在戚继光之上。有一种看法,包括《明史》的作者们认为,恰恰因为戚继光威名太盛,坐镇蓟门十六年,使敌人从来不敢来犯(没有Bug啊),于是转道入侵辽东,才给了李成梁屡立战功的机会。张居正死后,新政被废,受到张居正支持重用的戚继光被迅速边缘化,在郁郁寡欢中死去(可能明朝认为蓟门这个模块不需要再维护了)。而李成梁,他同样受到过张居正的支持和倚重,然而,可能由于下面的三个原因:其一,远离京师,与张居正没有过多的私人交往;其二,赫赫战功给万历皇帝留下了深刻印象(每次总有进度可说);其三,动荡不安的辽东局势离不开这位骁将(辽东模块还需要维护啊)。从而,李成梁避免了池鱼之灾。

当前社会中,不是如此吗?是修了坚固的河堤的市长感动中国,还是和民众一起抗洪抢险的市长感动中国呢?是治理的地方路不拾遗的公安局长应该升职,还是让黑社会猖狂十年然后一举击溃的公安局长会升职呢?

如果你觉得你的项目经理英明过于历史甚至当朝首辅,那么恭喜你。

(2) 有问题要尽早喊

当一个模块或者一个任务交给你的时候,可能存在各种各样的困难,会出现各种各样的问题,需要各种各样的资源,这一切都应该慎重考虑后尽早提出。

问题的尽早提出,其实是风险控制的一种手段。

调配资源,排除干扰,风险控制是一个项目经理的重要责任之一,然而不要认为项目经理会英明神武到知道一切细节,也不要认为这是项目经理的事情,与你无关。其实一个模块,真正了解细节的是你。

所以对团队来讲,事先问题没有提出,到时候出现是你的甚至你的团队的责任,问题及早提出了,项目经理向相关人员请求资源,到时候没有解决就不是你的责任,甚至也不是你们团队的责任了。这个样子既帮助你的项目经理控制风险,又能够在外国人面前撇清责任,是每一个项目经理都欢迎的事情。

对你个人来讲,问题及早提出了,以后或有Bug,或有delay,都不会给人一种突然的感觉,也给项目经理一种对你,也对整个项目可控的感觉。

从心理学上来讲,人们多惯于先听坏消息,再听好消息,而不愿意先听好消息,再听坏消息,这就是我们常说的冷热水效应:一杯温水,保持温度不变,另有一杯冷水,一杯热水。当先将手放在冷水中,再放到温水中,会感到温水热;当先将手放在热水中,再放到温水中,会感到温水凉。

一个经常举得例子是:某汽车销售公司的老李,每月都能卖出30辆以上汽车,深得公司经理的赏识。由于种种原因,老李预计到这个月只能卖出10辆车。深懂人性奥妙的老李对经理说:“由于银根紧缩,市场萧条,我估计这个月顶多卖出5辆车。”经理点了点头,对他的看法表示赞成。没想到一个月过后,老李竟然卖了12辆汽车,公司经理对他大大夸奖一番。假若老李说本月可以卖15辆或者事先对此不说,结果只卖了12辆,公司经理会怎么认为呢?他会强烈地感受到老李失败了,不但不会夸奖,反而可能指责。在这个事例中,老李把最糟糕情况――顶多卖5辆车,报告给经理,使得经理心中的“秤砣”变小,因此当月绩出来以后,对老李的评价不但不会降低,反而提高了。

(3) 用Bug来说不

不知从何时开始《致加西亚的信》以及《没有任何借口》此类的书开始畅销,从而以执行力的名义把责任全部推到被领导的一方,用军队的方式来要求自己的员工,不讲条件,没有借口,从不说不,来完成领导所给的任务。真不知道资本家有什么资格这样要求自己的员工,作为军人为祖国献身后至少能够成为烈士,家人受到抚慰,而资本家在员工连跳九人的情况下却在论证这个数字其实低于全国平均自杀率的。

然而大多数的领导的的确确喜欢没有借口的下属,也不喜欢听到说不。所以当一个任务下达的时候,或者一种方案被指定的时候,不要直接说不。

领导毕竟是领导,能做到现在的位置,毕竟有强于你的地方;领导毕竟也是人,提出的方案也可能是拍脑袋拍出来的,也许会有不合理性。

然而需要记住的一点是:上情下达可以拍脑袋,下情上达则要用证据。

当你认为领导给的任务或者方案有问题的时候,除了上面提到的喊难在前之外,一定要加一句,"我试试看"。

当你经过实验测试,有数据或者日志足以证明你的结论的时候,可以尝试说,"我觉得可能有些问题"。

然而有时候简单的测试并不能够证明的时候,或者领导再次坚持的时候,那就上手做吧,只是别忘了做的有扩展性一些,能在多种方案之间较容易的切换,并将领导坚持的方案暴露出来。当测试人员发现问题的时候,将比你说不有效果的多。这时候领导关心的便是如何Bug进行修复,不在纠结到底应该采用你的方案还是他的方案了,当然此时你千万不要得意洋洋的指出领导原来方案的不合理性,你不指出,领导其实是从心里认可了你的方案的,并且为你记了一功,如果你指出来,就适得其反了,大部分领导绝不会表面承认自己的错误的,可能会再次坚持自己的方案的合理性,并把因此带来的项目失败或者delay记在你的头上。也许大家清晰的记得曹操不承认"鸡肋"的退兵禁令而杀杨修的故事吧。如果你觉得你的领导气度大于曹操,那么再次恭喜你。

也许你会说:这不是浪费了一个过程吗?其实不然,你先做了领导的方案,然后改Bug的时候应用了自己的方案,在领导眼中,你是一个好的下属,好的执行者,你是做了两件事情的。

如果你坚持做了自己的方案而没有优先用领导的方案,则会有以下风险:

  • 你永远失去了证明你的方案优于领导的方案的机会
  • 你会被认为固执,难于沟通,执行力差
  • 一旦你的方案出现问题,你将单独的承担责任,甚至整个项目delay的责任。如果你优先采用了领导的方案出现问题的时候,一般合格的领导会勇于承担起责任,替你说好话:"我们采取的方案是相对较优的,也是经过测试的,Bug是难免的",相反,如果你固执己见,则没有人会替你说话,反而会说:"要是用原来的方案就不会出现这个问题" 。
  • 领导的方案一般是由一定原理上合理性的,你的方案可能是比较符合你的实际需要,然而当时过境迁,context不在的时候,你百口难辨。

所以,毫无怨言的接受任务——让上司圆满,如果有问题,让Bug来说。

(4) 该干什么的时候干什么

在外企,一个常说的词叫"professional",何为职业化,一个通俗的说法就是,该干什么的时候就干什么,当然无论干什么,永远不要忘记,你是一个程序员,一个基层的程序员。

前面说过,除了写程序,外企的生活是丰富多彩的,健身,按摩,小食品,饮料,旅游,年会,各种协会等等不一而足,而且外企的氛围是相对宽松的,你可以在任何时间尽情享用,没有人会有意见,当然是在你完成了工作的基础之上的。

然而永远需要记住的是,写程序才是你的天职,而多彩的生活是公司对员工的福利,是一种施舍,说的不好听一点,公司花钱请你来是写软件的,不是让你来娱乐的,公司让你娱乐是给你脸,你总不能给脸不要脸吧。话说的难听一点,但细想想,话糙理不糙,试想如果项目经理每次来巡查的时候都看到你或大声的说笑,或尽情的饮食,或玩桌上足球的时候,其内心不会有上面的想法?只不过是一种优雅的方式表达出来罢了。比如走到你的面前,微笑着问:"你的feature做的如何了?","Bug XXX有没有结果?",顺便强调一下你所做的模块的难度和重要性:"你做的这部分比较有难度,是对你能力的挑战",并在最后来一句:"慢慢做,不着急"。你可知晓此彬彬有礼下面的深意?经理两次到你这里来说"不着急"的间隔越短,其实是说明这件事情越着急的。

所以说在办公室的大部分时间,你都应该低头写程序,谈话也要讨论技术问题,娱乐要适度,除非你想被人觉得工作量太少,不努力,或者你有足够的信心自己负责的模块不会出问题。

另外在开会的时候,你由于任务太多,总是盯着自己的笔记本默默写自己的代码吗?不要这样,这样会让组织会议的人感到不被尊重,会让领导觉得你对项目组不够关心,不够投入,甚至不够忠诚。开会的时候,就要像开会的样子。你可以提前阅读材料来准备几个问题;你可以支持,补充或建议组织者的方案;你可以在外国人面前举出证据来维护中国团队的利益;实在没招,你至少可以记会议记录,会后发meeting minutes。这样你给人的印象永远是你是有想法的,你是有贡献的,你是关心项目的,你是热爱团队的。

一个Team出去吃饭,或者出去旅游的时候,你是得意忘形的放开手脚去玩吗?甚至脱离团队和要好的朋友去逛吗?不要这个样子。余世维在《经理人常犯的11个错误》的演讲中曾经说过,出去Team building,对于员工来说是休息,而对于经理来说是工作。的确,你要清楚资本家为什么会出钱让员工去做这些和工作看起来无关的事情?为什么要大家一起出去而不是每人发钱自己去玩?当然是要增加团队的凝聚力和归属感,为共同合作奠定基础。既然对于经理来讲是工作,难道你不应该有责任辅助你的经理做好工作吗?在大家一起吃饭的时候,如果冷场,积极的起一个话题吧;在经理提出玩一个团队游戏的时候,率先支持,主动去做吧;在外出旅游的时候,帮助你的经理订餐馆,清点人数,摄影照相吧;当爬到山峰,或者年会表演节目的时候,喊出增加团队凝聚力和影响力的口号吧;在活动结束后,整理资料,相片,发出email来进一步增加活动的效果吧。这样你就是有组织能力的,辅助经理成功的,有良好影响力的,也是热爱团队的。

这里提到了团队聚餐中的话题问题,这里顺便提一下,当然根据不同的Team的氛围以及当时的情况而定,话题的优先级依次如下:

  • 项目话题:如进度,难点,后面还会提到,学会喊累,喊忙,这是一个比较好的机会。当然此话题比较适合加班或者中午时的团队聚餐,不太适合旅游时候的团队聚餐。此话题可表明你对项目的关心。
  • 技术话题:比如语言排名,那家公司被收购了,平台之间的差异等等。此话题可说明你对技术无限热爱。
  • 员工生活话题:比如周末干什么了,介绍女朋友,结婚,孩子教育等,当然以当事人意愿为准,不要太当真。此话题可说明你关心同事。
  • 娱乐话题:比如看什么电影,娱乐圈出来什么事情等,这是万能话题,也是最保险的话题。
  • 员工敏感话题:比如非议其他Team,或者美国团队等,此类话题最好不要涉及,背后议人不太好。
  • 公司敏感话题:如有的Team裁员,减薪,福利下降等,此话题千万不要提及,这是领导层想尽力遮盖的问题,甚至不在项目经理的权利范围之内。涉及此类话题将给人以你是一个不可托付大任的人。

最后,如果你在学校中是演艺明星或者体育明星,那么年会的表演以及团队之间的比赛也不是你表现英雄主义的地方,而是体现团队意识的地方,也是交流沟通的好机会。所以不妨在节目中介绍一下自己团队的产品;不妨在角色设定的时候劝说core team的人加入扮演一个牛人角色(欢乐可以一定程度上冲淡马屁味道);不妨申请印有团队logo的运动衣;不妨在运功过后和高层一同边走边聊(比平时冲到高层办公室里面好的多的机会);不妨去敬HR一杯酒,被她们多灌几杯(HR的办公室是个敏感区,平时很难交流感情啊);不妨去维护机房的团队那里敬酒以感谢他们的工作,去前台那里敬酒以夸赞她们的服装,发型等(他们对你来说真的很重要,想想几百人的团队,前台和运维都只有两三个人,还是那就话,当供需相差很大的时候,价格都会越来越高)。这将使你成为一个受欢迎的人。

(5) 适当的增加影响力

做一个好的基层程序员,除了完成自己的本职工作以外,也需不断增加自己的影响力,这既是你的品牌,也是日后加薪升职不可缺少的因素。

增加影响力主要有以下几种方式:

  • 在工作中,如果完成了一定的功能,或者测试有了详细的报告,可发邮件给领导并cc整个Team,让领导知道你的付出,和同事分享你的喜悦,让众人知道你的亮点。邮件或者报告要在开头做精炼的总结,使得大部分人能够尽快的了解结果,具体细节可放在后面,供同模块的员工详细查阅。千万不要默认你的上司和其他人都显而易见的知道你完成了什么,这也可能是很多人觉得怀才不遇,难遇明主的原因吧。台湾作家黄明坚有一个形象的比喻:“做完蛋糕要记得裱花。有很多做好的蛋糕,因为看起来不够漂亮,所以卖不出去。但是在上面涂满奶油,裱上美丽的花朵,人们自然就会喜欢来买。”
  • 在各类的会议中,如上面所说,事先准备问题,合理提出建议,适时提供证据,都是在同事,领导,以及外国人面前展现自己的机会。
  • 有时候美国有或管理或技术的老大来中国,都会召开all hands,这是一个不可多得的在整个公司面前展现自己的机会。而在外企,程序员的竞争力大约包括对产品的把握,对技术的把握和对英语的把握等能力。all handls也是展现这三种能力的好地方。也许你会发现这样的事实,在all hands上英语流利的提问者们,提出问题的目的也许并不是为了想弄明白什么,而是为了展现什么。他们大多是这样问的:"As what you side A, but actually what we did in our project is B, so how/what/when C",你会发现,A和B会说的很具体,而C很抽象,显然A是为了展现产品把握能力(你讲的我都听懂了),B是为了展现技术把握的能力(我们采取了什么样的技术),整篇都用英语表达自然展现了英语的能力,最后问一个很Open的问题C,总不能问老大个很难的问题吧。
  • tech talk:当有了一定的技术积累,tech talk是一个很好的展现技术实力的平台,毕竟程序员是吃技术这碗饭的,所以良好的技术口碑对最初的升职至关重要。tech talk所讲的对象一般不是同项目的员工,因而难度要适当的把握,太简单则不足以体现你的技术实力,太难则大家会听的云里雾里,不能真正了解你的价值。在做tech talk的时候,最好一开始有一个整体的流程或者框架的介绍,以使得听众不会在途中迷路。一般有一个规律,就是在最前面几个slides的问题是最多的,大家总能够提出各种各样的问题,所以开始的几页,一定要是你最最熟悉的,最最有价值的,然而随着信息量的增大,后面就几乎提不出什么问题来了,到演讲最后,一般也就只能提出一些open question了,一般可以通过三个阶段轻松回答,其一,that is a good question,其二,it really depends,其三,I'd like to give an example。
  • demo:在很多施行迭代开发的项目管理的公司里,一个阶段是会有一个demo的。很多程序员重代码,而轻demo,明明实现的非常优雅的功能,却懒得花时间生动的demo出来,中国有句古话:六十四拜都拜了,就差最后一哆嗦,多对不起你前面没黑没夜的工作啊。demo是应该好好准备的,应该有一个详细的demo流程,先录入什么数据,然后如何操作,最后应该看到什么等等。然而demo是容易失败的,似乎成为一个难以规避的定律,即无论原来demo如何准备,临阵总会有意想不到的结果,大概因为看demo的人可能会提出奇怪的尝试需求,而可能正是程序员没有考虑过的边界。所以demo中,应该事先将良好的过程录制下来,以防止真实demo过程中有差错,造成功亏一篑,至少可以证明原来是好的。在demo中一定要用近似真实的数据,如输入人名,就用真实身边的员工姓名,输入日期就用当天的真实日期,千万不要用aaa, bbb, 123456此类的数据,既不美观,也容易出问题。而且在demo的过程中,应该严格按照已经准备好的流程走,当完全走完流程后,方才可以处理现场提出的各种尝试,可保证能够完成demo任务。
  • 帮助他人:在不耽误自己工作的情况下帮助他人解决技术难题,是比tech talk和demo更能够体现技术实力的地方,并会积累下人脉,当众望所归的时候,你的升职也就仅仅是时间和名额问题了。举个相似的例子,tech talk好比是保健医生,只不过是给你宣扬养生之道,而解决技术难题就如同主治医师,可以使你药到病除。很显然,如果一个人如果能够很好的按照保健医生的养生之道去做,就很少会去找主治医师去看病了。然而主治医师却比保健医生更受欢迎,一方面因为相对重要的事情,人们多会更重视紧急的事情,一方面可能因为只有在逆境,出现问题的时候,人们才会虚心接受他人的意见。试想听tech talk的人们,就如同6000点的股市中的股民,多抱有"你懂,我可能比你还懂"的想法,而出现了问题的人们,便如跌至2000点股市的股民,才会虚心向专家请教,并对给出的方案五体投地了。而且此点满足,不忙的时候,主动帮助他人——让上司有效!
  • 培训新人:有时候公司会招来一些学校来的实习生,一年一度也会招很多应届毕业生。当然一般公司都会有各种的培训,然而一旦进入团队的时候,如何更快的上手项目,仍然需要一个过程,如果能有老员工指导一二,将会轻松很多。在项目比较紧的情况下,很多老员工不愿意培训新人,万事开头难,起步总是相对缓慢的,害怕因此而耽误进度。当然,以耽误自己的工作换来对新人的培训我也是不赞成的,这也是后面所说的要给自己留buffer的原因所在。但我需要指出的是,给一个饥饿的人一个烧饼要比其成为千万富翁后给一百万更加让人感恩。人的眼光应该长远一些,无论如何都不要轻视一个年轻人,因为你不知道其将来会是什么样子。有的人,年纪大,level高,但是基本可以看出其一辈子的轨迹了,有的人年纪轻,level低,却可能前途无量,你永远不能把握将来谁会是你的贵人。

在增加的影响力的前面,我加了一个形容词——适当。要有和你的level相匹配的影响力,小心功高盖主啊。外国人有时候会强调leadership without authority,然而如果你果真这样做了,多半会招来同事的敌意(你凭什么指手画脚的啊),也可能会招来你的lead心中的隔阂(没有authority你都能够lead啦,给你authoriy还不反了天了,你lead,那我干嘛),所以还是不在其位,不谋其政的好。

(6) 给别人光环

当同事完成一项功能或修改完一个Bug的时候,你是否给过真诚的赞誉,帮其增加上述的影响力?

当同事帮助你解决了问题或者提出了优秀的方案,你是否公开表示感谢,让群众和领导都知晓?

当领导问及你做的模块的时候,你是否有意隐瞒了他人的功劳而突出自己的贡献?

当会议的时候,你是否会处心积虑的故意反对竞争对手的方案,虽然你觉得其实这真的是个好方案?

当发现其他人的Bug,Code reivew的时候发现他人的设计缺陷,你是否幸灾乐祸的大声疾呼,唯恐他人和领导不知?

你是否在同事,领导,HR的面前非议他人,嘲笑他人的设计,褒贬他人的缺陷,鄙视他人的技术,虽然的确你是此方面的大拿?

当你有幸获得一份荣誉的时候,你是否先谢国家(公司),再谢政府(团队),再谢领导,再谢同事?

给别人光环吧,别人也会给你光环。

一个只顾自己头上光环的人,以及一个别人给了光环而不知回报的人,最终都会孤立无援,难以开展工作,是涸泽而渔的做法。

我们必须承认的一点是,每个人都有自己的长处,也有自己的短处,每个模块都有优美的地方,也有不尽人意的地方,你有你擅长的技术,别人也有别人擅长的方向。如果大家互相向别人的头上套光环,则外人和领导看到的会多数是光环,从而大家精诚合作,团队蒸蒸日上。如果大家全部互相揭疮疤,则外人和领导则看到的会多数是负面的,从而大家互相猜忌,整个团队都没有希望。

历朝历代都有权臣,权臣之间必有党争,派别之间多知道对方的优势,也掌握了对方的把柄,如果派系之间相互合作,则大家都会壮大,皇帝则不会知道下面的暗流涌动,然而英明的皇帝多挑拨派系之间的关系,使他们互相揭露对方的把柄,从而下情上达,从中制衡。

我们也会经常看到,当一家公司的高管离开他的老东家而投奔新东家的时候,公开场合下,此高管多会十分赞誉在老东家中工作过的时光,赞誉工作过的团队,赞誉老东家的产品和项目,赞誉自己在老东家取得的进步,而老东家也多会给与此高管十分积极的评价,肯定其作出的贡献,其为公司带来的价值,其培养出的团队。其实如果两者之间如此的默契,如此的互相满意,就不会发生跳槽的事件了,既然选择分道扬镳,则其中必有隔阂,只不过互相心知肚明,各不言明罢了。这样无论对公司的发展,还是对此高管的职业生涯都有好处。试想,此高管必然是清清楚楚公司的优势劣势,公司也明明白白高管的功过是非,就像一对生活了很久的夫妻,既知道你能言善辩,也知道你鼾声震天,既知道你玉树临风,也知道你不爱洗澡,如果在公开场合互相指责,甚至谩骂,岂不家丑外扬?

(7) Daily report和weekly report很重要

很多程序员宁愿多写程序,也不愿意写report,觉得十分麻烦,而又无聊。

但是Daily report,weekly report真的非常的重要。

首先report可以帮助你管理自己的时间。在时间管理中,我们知道,人总是有重要而紧急的事情,重要而不紧急的事情,不重要而紧急的事情,不重要而不紧急的事情之分。你是否总结和思考过自己真的总是做了重要而紧急的事情么?人们总是忙啊忙,从早忙到晚,天天加班,其实每天都在处理各种各样的突发紧急的事件,使得计划一拖再拖,而忽略了对自己很重要的事情。试想想吧,你原来计划过要读的书有多少是真正去读了的?你在朋友面前畅谈的宏图大志有多少是真正实践过的?你还记得儿时的梦想吗?你是一直向着自己想要的方向在不断的进步吗?时间管理的原则告诉我们,每个人应该有一张思考的床,不要穷忙、瞎忙、无心的忙。写daily report和weekly report不完全是应付上司的,也是自己思考总结的过程啊。我还记得最初每周定计划的情况,当一周过去进行回顾的时候,我当时吓了自己一跳,我原以为自己一直过的非常的充实,却发现计划做得事情真的只做了大概三分之一,照此下去,如何进步啊。有兴趣大家可是试着制定一下计划,越详细越好,工作方面的可以写给上司看,学习,社交等方面的可以自己写给自己,有时候多少有些身在江湖,身不由己的感觉。

其二report可以帮助你总结自己的进步。当天做的事情一般人还是记得的,一个星期做的事情,大概就模糊了,半年前做的事情,则很多细节都忘记了。很多的时候,当我们每年对自己进行年终总结以期待明年加薪的时候,当我们想要跳槽来总结自己忙碌了几年的成果的时候,往往会发现,report到用时方恨少啊。面试的时候,对于有经验的人,往往会将项目经验问的很细很细,当时你为什么选择这种方案呢?系统的速度如何一步步改进提高的?你发现你可能说不清楚了。平时尽量多详细的记录一下自己每天的进步吧,这可是影响到你薪水的闪光点啊,对方的公司正等着一个牛人来提高他们的性能呢,你明明取得很不错的结果,只是忘记了自己做了哪些改进,岂不可惜啊。

其三report可以帮助你增加自己的影响力。如上面所述,report不但可以让自己知道自己做了什么,也可以让上司知道你完成了什么,如果写到wiki上,还能让更多的人知道你的成绩。

其四report可以作为维护权利的证据。这一点前面也说过,作为初入职场的基层,作为相对美国来说弱势的中方,证据是非常重要的。当项目delay的时候,你如何证明你是提前schedule完成的?当性能遇到瓶颈,你如何证明你曾经高效且没有做过改动?在写程序的时候,我们知道,当context不在的时候,唯一能够定位问题的,就是log了,report就是你工作的log。

其五report可以使你的上司对你放心。很多初入职场的基层,埋怨上司过多的干预自己的工作,总是有事没事的过来问,做的如何了?有什么困难?这段时间在做什么?有时候这种询问会打断你的思路,着实让人困扰。其实情有可原,你刚来,不放心是可以理解的。如何做到你办事,他放心是你的责任。当有阶段性成果的时候实时报告自己的状态,每天写daily report报告自己的进度都是让上司放心的办法。一个有意思的现象是,当你一天一封daily report向他汇报的时候,他却不怎么过来干预你的工作了,甚至到最后daily report他也不怎么看了。

做到此一点,方能主动向上司汇报你的工作进度——让上司知道,对上司的询问,有问必答,而且清楚——让上司放心!

(8) 给自己留buffer,学会喊累,学会喊忙

初入职场,激情高涨,多喜欢将自己满负荷运作,无论是需求来自领导还是来自同事,都不好意思拒绝,最后弄得自己疲于奔命,焦头烂额。

其实工作中,是应该给自己留有一定的buffer的,一方面,可以在项目有了突发事件的时候,不至于临阵慌乱,尚有调整和处理的时间,不至于第二天demo,当天晚上代码才完成。另一方面,要做好以上所述的事情,还都是需要buffer的,绝不能够低头干个不停。

另外,公司是要对项目负责的,而自己的职业前途,却只有自己负责。除了每天忙于项目之外,总要有一定的时间进行自我进步,从而提升自己的价值。前面也说过,有的人面试的时候,仅仅知道项目中用到的知识点,而相关的却很少知道,从而使自己的职业生涯既不广,也不深。所以日常工作中,留有一定的buffer来将知识点变成知识面是很重要的。

所以如果你真的很忙,真的很累,要勇于喊出来,而不要默默的承受着,当然这不是让你装忙装累,而是向周围散发出一种信息,就是你已经负荷较满了。这样你的领导在安排任务的时候,会综合考虑,你的同事在向你提出需求的时候,也拒绝的合情合理。当然你不能总是喊忙,总是不出成果,如第一点中所说,result永远是最重要的。而总是喊忙,总是能出成果,确是一种工作努力的表现。有的人认为,只有相互说话才叫沟通,其实不然,殊不知自言自语,凝重的表情,同样是沟通的手段。

也只有在有buffer的情况下,你才能做到充实自己,努力学习,才能了解上司的言语——让上司轻松,你才能够做到对自己的业务,主动提出改善计划——让上司进步。

分类: IT外企那点儿事

绿色通道: 好文要顶 关注我 收藏该文与我联系

觉先 关注 - 3 粉丝 - 560

荣誉:推荐博客 +加关注

25

0 (请您对文章做出评价)

« 上一篇:Lucene学习总结之九:Lucene的查询对象 » 下一篇:乌合之众(大众心理研究)之一:民主直通独裁的心理机制 posted on 2010-05-22 14:28 觉先 阅读(6964) 评论(28) 编辑 收藏

评论

/#1楼 2010-05-22 14:54 Bluetooth

非常非常正确。 report非常重要,进度比质量更受领导欢迎,他希望最快的出成绩然后到处汇报和晋升,之后的bug是由其他人来负责的。 code 六年后我也总结出了这两点,虽然还没赢得收益。

支持(0)反对(0)

/#2楼 2010-05-22 15:15 不若相忘于江湖

写的非常好。 

支持(0)反对(0) http://pic.cnitblog.com/face/u35315.jpg

/#3楼 2010-05-22 16:03 阿牛

深有感触呀, 我现在还在做技术洁僻, 晕.

支持(0)反对(0)

/#4楼 2010-05-22 16:30 Dbger

深有同感,极其赞同 楼主看来在外企有多年经验

支持(0)反对(0) http://pic.cnitblog.com/face/u64551.jpg

/#5楼 2010-05-22 16:45 nbjkj

谢谢LZ,对于初入该职场的的我受益匪浅!

支持(0)反对(0) http://pic.cnitblog.com/face/u102166.jpg

/#6楼 2010-05-22 16:53 冰河魔法师

不错,很喜欢,顶一个。

支持(0)反对(0)

/#7楼 2010-05-22 16:56 麦舒

写得不错,受益了。

支持(0)反对(0) http://pic.cnitblog.com/face/u24769.jpg

/#8楼 2010-05-22 20:47 博客园团队

图片不能显示,麻烦上传一下图片。

支持(0)反对(0) http://pic.cnitblog.com/face/35695/20130121190936.png

/#9楼[楼主] 2010-05-22 20:59 觉先

@博客园团队 你好,在我的浏览器里面,好像图片是可以显示的。 如何上传图片呢? 谢谢

支持(0)反对(0) http://pic.cnitblog.com/face/u103165.jpg

/#10楼 2010-05-22 21:01 爱在戏院前

写的很好

支持(0)反对(0)

/#11楼 2010-05-22 21:31 MaoBisheng

拜读了 不过图片没显示出来...

支持(0)反对(0) http://pic.cnitblog.com/face/u37118.jpg?id=10195626

/#12楼 2010-05-22 21:43 MaoBisheng

引用觉先: @博客园团队 你好,在我的浏览器里面,好像图片是可以显示的。 如何上传图片呢? 谢谢 后台写随笔的那个编辑器里有传图片的功能的,位置大概在设置字体颜色的下方。

支持(0)反对(0) http://pic.cnitblog.com/face/u37118.jpg?id=10195626

/#13楼 2010-05-22 22:03 chinese_submarine

很不错的一遍非技术文章,胜过很多技术文章。

支持(0)反对(0) http://pic.cnitblog.com/face/u28698.png

/#14楼[楼主] 2010-05-22 22:12 觉先

引用MaoBisheng: 引用觉先: @博客园团队 你好,在我的浏览器里面,好像图片是可以显示的。 如何上传图片呢? 谢谢 后台写随笔的那个编辑器里有传图片的功能的,位置大概在设置字体颜色的下方。 谢谢,已经上传了图片了

支持(0)反对(0) http://pic.cnitblog.com/face/u103165.jpg

/#15楼 2010-05-22 23:32 xjb

非常喜欢这个系列,甚至都适用于非外企的公司。

支持(0)反对(0) http://pic.cnitblog.com/face/u12916.png?id=04113617

/#16楼 2010-05-22 23:36 steven hu

@觉先 用windows live writer,图片会自动上传

支持(0)反对(0) http://pic.cnitblog.com/face/u34974.jpg

/#17楼[楼主] 2010-05-22 23:48 觉先

引用steven hu: @觉先 用windows live writer,图片会自动上传 谢谢,我用的是windows live writer,只不过这次的图片是从网上搜的,没想到windows live writer并不是上传此图片,而是直接将网上的地址放在文章中,而且原图片好像地址又被移走了。

支持(0)反对(0) http://pic.cnitblog.com/face/u103165.jpg

/#18楼 2010-05-22 23:55 zdd

千古好文!

支持(0)反对(0) http://pic.cnitblog.com/face/u64257.jpg?id=21102348

/#19楼 2010-05-23 08:02 JerryKai

楼主,很长的一篇文章啊! 不过,真的很好!

支持(0)反对(0) http://pic.cnitblog.com/face/u59349.jpg?id=07201540

/#20楼 2010-05-23 10:06 兔兔子

楼主写得太好了!!! 学习了!

支持(0)反对(0) http://pic.cnitblog.com/face/u121822.jpg?id=08205343

/#21楼 2010-05-23 10:31 elwin.wang

LZ是杭州华数的吗?

支持(0)反对(0)

/#22楼 2010-05-23 10:49 JiabaoET

非常在理!

支持(0)反对(0) http://pic.cnitblog.com/face/u102695.jpg

/#23楼 2010-05-23 21:55 Pandaimp

mark!好东西,要多读

支持(0)反对(0) http://pic.cnitblog.com/face/u97216.jpg

/#24楼 2010-05-25 09:48 Coki

太经典了!这种有深度的文章真是少有啊! LZ的每篇文章我都会拜读,确实是实践中总结出来的财富啊!

支持(0)反对(0)

/#25楼 2010-05-27 12:42 木可

very good

支持(0)反对(0)

/#26楼 2010-05-30 15:32 gracestoney

多谢分享,很实用,有些东西可能我们都知道,有些在做了或者尚未开始做,楼主的文章很好地总结和整理出来,效果不同凡响!支持。

支持(0)反对(0)

/#27楼 2010-08-18 22:41 Zero Huang

LZ很强很NB

支持(0)反对(0)

/#28楼19213732010/9/20 13:36:36 2010-09-20 13:36 hans.hu

写得很有见地,可以出书了.

支持(0)反对(0)

刷新评论刷新页面返回顶部

注册用户登录后才能发表评论,请 登录注册访问网站首页。 博客园首页博问新闻闪存程序员招聘知识库

最新IT新闻: · 新硬硬整合时代 · 狗血的百度91并购案啊 阿里和周鸿祎都曾掺和 · 如何让搜索引擎抓取AJAX内容? · 避免代码注释的五大理由 · OpenWrt——适用于路由器的Linux系统 » 更多新闻...

最新知识库文章: · 阿里巴巴集团去IOE运动的思考与总结 · 硅谷归来7点分享:创业者,做你自己 · 我为什么不能坚持? · 成为高效程序员的7个重要习惯 · 谈谈对BPM的理解 » 更多知识库文章... Powered by: 博客园 Copyright © 觉先