2011年9月18日星期日

参加IT168架构师大会总结

  9月9号和10号在北京参加了IT168主办的架构师大会,也很荣幸做了淘宝Java中间件之路的分享,分享的PPT已经在大会的官网放出了。这次两天的会议,跟新老朋友有了不少线下的交流和沟通,感觉不错。也听了好几个Session,有些没有听的,也是当时跟几个朋友在场外交流所致。
      下面总结一下自己听的几个Session
 
      余沛-自动化运维关系管理
           这里面提到了几个阶段,跟陈硕的blog里面讲的不同阶段的运维策略,理念上比较的类似。
           第一个阶段 几台---几十台  手工并且是模块儿的视角。也就是看到的只是单个的部署的产品等
           第二个阶段 几百台--几千台 这个阶段叫做纵向自动化,用机器的粒度看运维,不过运维还是后置服务,有一些脚本、工具等,不过可能比较多的还是在做安装、维护、救火等工作
           第三个阶段 几千台--上万台 运维和开发平行,看问题是按照服务的粒度,运维变成前置服务
           接着又着重介绍依赖管理的部分。包括了任务对任务的依赖,任务时间上的依赖,以及数据型的依赖等。
           应该说,总体来说比较系统的讲述了运维成长的过程。我们自己的机器数也不少了,运维方面的平台、工具还不是那么的完善,希望能够在明年年中之前,能够有比较大的改观。
 
       李瀚-百度贴吧的技术介绍
            这里面记录了一些关键点
            百度贴吧有上百亿的帖子,热门的帖子有上千万的回复,高峰是每秒的PV超过10万。那么在存储方面,做了不少事情。同时,对于快速开发、可用性、安全方面考虑的也很多。

            在WebSever上,用了异步和集群技术,静态文件的获取,可以跑满网卡,大于单机支撑5k-1w的qps,这个取决于单个文件的大小。

            采用Php开发框架,统一开发模式,在性能方面也做了优化。内部实行组件式开发,有公共库以及一些通用组件。

            在存储方面,分为了两块儿,一块儿是轻量级的存储,主要采用的是Mysql以及使用了cache技术。数据量小于1T,支撑几百qps-几k qps,加入cache解决浏览的性能问题。
            引入了分区,使用MQ来进行处理
          
            另外,使用KV存储视频文件,大概在P的量级。

            这个session,主要了解学习了baidu贴吧的一些相关技术架构,也了解了一下数据。

        洪涛-虎扑网的架构升级之路
            这哥们儿看上去非常爷们儿,讲话也比较逗。谈到了虎扑网从成立到现在的发展之路,这个是可以给到一些中小网站一些参考。在这个过程中,用到了一些开源软件,包括但不限于memcached、TT、Redis、RabbitMQ等。后面也会自建机房。这里面,他提到会用硬件负载均衡代替LVS,这个地方我不是很明白,当时也没有能抓住洪涛问下,后面有机会再请教下。

        陈炜-无状态运维管理
              这个家伙跟我住一个屋的,他要讲的东东在讲之前我就看了一下,应该说,他们真的构建了一个相对完善的监管控的系统,也许没有哪个部分的技术本身特别高深,但是能够运用技术,真正把那么多的机器和应用管理起来,能最终落地,我觉得还是非常不容易的。不过这厮还欠我一个东西没给我,明天上班找他要。

        段炼-Defeat Plubic DNS
              这里面首先讲到了使用Google DNS以及OpenDNS的问题,然后提到了如何去解决这些个问题。其中对于如何知道用户所在ISP以及使用的Local DNS,采用了不同的方式来处理。也提到了通过跳转、修改返回的HTML等方式来解决跨运营商访问的问题。在这个方面,自己之前确实没有太多经验,也没有考虑很多。不过说到底,这都是被天朝特色的ISP给搞的。sigh。

        白金-从流量统计、识别出发,看网络出口带宽优化
              这个演讲嘉宾的名字挺酷,他讲的东西很全面,也提到一些探测网络流量等信息的工具,不过这个部分,跟我现在关注的点不太贴合,就当扩充知识面了。

        陈尔冬-新浪的私有云平台
              这哥们儿真的很帅,讲的也很好,新浪的SAE和内部的私有云还是不错的,10月份他们会来杭州参加QConHangzhou,到时候再好好聊聊。
              我记录了一些数据
              私有云有4000+机器

                       每日100亿动态请求
                       每日200亿的数据库请求
                       总共运行了500个项目 
        马如悦-Hadoop@Baidu 
              一个非常实在憨厚的哥们儿,我也是记录了一些数据     
             目前Hadoop集群有1.5w node, 年底大概3-4w台, 明年会到达10w台
             整个集群input data/per day >10PB  google  1,20万机器,30PB
             Hadoop一共分了10个clusters
             最大的cluster 3000 nodes
             1.5亿文件+1.5亿块+2000个节点:重启花费40分钟
             baidu-hdfs2-arch 把namespace跟文件管理分开,上面的相当于 一个规则服务器
             针对不同的需求分来处理,比如throughtput 、realtime 等;追求不同,侧重点就要不同
        总体来说,IT168架构师大会,和QConBeijing以及将要举办的QConHangzhou还有Velocity China相比,我感觉整体质量稍微弱些。当然,这仅仅是从我个人的角度来说,从内心来说,希望IT168架构师大会越办越好,提供一个好的平台给技术人员交流、提高。

2011年8月30日星期二

写给明年毕业的应届生同学-参加实习生转化面试后的感受


从8月中旬到最近,全是在做跟校园招聘的事情:有跟试题相关的事情,更多的是我们已经在实习的同学的转化面试。
之前写过几个跟招聘相关的文章,本来不想再写跟招聘相关的文章了,不过最近还是忍不住想写一下跟应届生同学相关的事情。
在我之前的文章里面《给将要实习和毕业的同学-第一份工作的选择》,提到了我对于实习生和应届生同学要选择第一份工作的建议,不过那个时候,同学们都是在找实习工作,现在面对的是如何选择自己的第一份正式工作(这是对于大部分同学,工作后考研的不算),感觉肯定会不太一样,考虑的也会更加的谨慎。
从最近跟很多明年要正式毕业的同学的沟通看,也听到了一些声音。基本上大家对于在淘宝的实习以及淘宝的环境、氛围和发展空间都还比较满意。有一些同学通过在淘宝的实习真正了解了淘宝(实习前对于公司的氛围,技术都不太了解,这说明我们在同学中的影响力还不够大洼)。我也问到同学们最终会怎么考虑来确定自己去哪家公司,北京的同学比较关心户口(杭州的没有这个问题,因为能解决),待遇也是大家很关心的一个事情。问到个人对未来的规划的时候,同学们很关心今后的发展空间,也有部分同学表达了希望先做技术然后再做管理的想法。我下面分别说下我对这几个问题的看法,如果对于自己今后工作很关心并且自己愿意在事业上去努力的同学,可以继续看,如果你对上面的两者有一个不关心,我觉得就不用再往下看了。
关于户口,就我了解,这个可能是这个星球上为数不多的国家还在实行的一个政策,它的好坏我就不发表看法了。想留在北京的同学,肯定都想得到北京户口,而现实是这非常的困难,ZF企业应该是非常容易解决这个事情,而其他的企业肯定是不能承诺这个事情。我非常能够理解同学们的想法,我也曾经应届过。在北京,有户口肯定比没有户口在有些方面要方便,不过就我的了解,现在在北京有叫做工作居住证的东西,这个东东也能解决你在北京的很多问题。如果真的没有北京户口,能够把户口放到离北京很近的地方就行了(主要为了后面办一些手续的时候方便,在天朝,你的身份证在有些时候是不顶用的)。我也听到同学提到了曲线救国的想法,先去能够拿户口的地方工作一年,有了户口后在跳槽。其实这里面有个选择,就是在户口和个人的发展上的选择。如果 二者可以得兼该多好,可是人生就是在不停面对很多选择,就是看你放弃什么了。如果我建议你放弃户口,我知道大家很难听进去,但是我想说,如果你真的遇到了一个很合适的公司,提供给你的是有很大空间的岗位,我真的非常建议你认真考虑考虑这个问题。一年时间可能不算长,但是,如果你为了户口,去到一个对你的职业发展没啥帮助的地方的话,对你后面的发展不会有好处。不要觉得可以在这一年内可以通过自己的学习去提升然后一年后跳槽,你要知道,在实战中成长的更快,能更好的跟上发展节奏,前面不是有很多读了硕士的同学很难进入五大(现在是四大了)事务所,而他们本科的同学已经是比较主力的员工了。你真的那么有把握一年后自己可以去你现在想去地方么?当然,我非常理解,北京户口,对于很多同学,毕业的时候可能是唯一的机会,而工作,后面会有很多机会。只是我想说的是,有很多机会,是否能够把握住很好的,也是一个问题。这个事情,我只是希望同学们慎重考虑,但我尊重每个同学的选择。
关于待遇,这个也是很现实的问题,我一直认为公司给你的待遇除了月薪还有很多,这里面包括看得见的福利以及“看不见”的机会。记得08年在合肥校招的时候,一个应聘产品经理的比较优秀的硕士同学因为1K的差距,去了深圳的一家比较小的公司,貌似这家公司现在也没有很突破的发展。我想,他如果当时来到淘宝,到现在也两年了,如果他自己努力拿出出色的表现,我想可能会有奖励的期权了,今年也能够申请无息置业的贷款了,晋升加薪也不是问题,去年也有马总额外的红包了,也可以参加蒲公英计划。从这两年或者三年来看, 我想他在待遇上并不吃亏,说这些,不是说淘宝或者阿里就有多好,而是我想告诉大家,不要仅仅只是看中非常短期的待遇上的问题,如果在加上在一个好的环境给你的帮助,那么你收获的更多。你还是要看到行业前景、以及这个行业里面公司的前景以及公司给你的空间,而不是当下的1K或者多少的差距。毕竟,我相信2012还是可以过去的,大家还是要考虑自己长期的发展的。我经常说,在淘宝,老大让我犯错,给我这么好的环境,还给我钱,多好的地方啊。呵呵。另外,我也推荐大家去看下江苏卫视和中国教育台合办的一个节目《职来职往》,优酷、土豆上都能看到,周五晚上是中国教育台9点36分会放。当成娱乐节目看看也挺好的,这个是类似非常勿扰形式的一个求职节目。里面的杨石头老师提到的两盲一定啊什么的,包括郑艳郑妈妈提到的建议还有很多达人给的建议都很不错的。我觉得对于应届生同学还是有帮助的,也看看别人求职面试的表现,这个一般你们不太能看到。
接着在说说个人发展规划的事情。有同学问我怎么找自己的方向。我的看法是这样的,一毕业就有自己很明确的方向并且能持续做下去的并不多。反正我不是,我当时毕业的时候只是知道自己不喜欢做什么,主要两个不喜欢,一是做业务系统不喜欢,二是做网站不喜欢。但实际上我是来了淘宝后,才慢慢有自己喜欢的方向。我能够给同学的建议是,首先不要虚度光阴,其次提高你的效率,因为从长的时间段来看,在某个阶段你深入了,还是那个阶段你朝广度发展了,都对你有帮助。回首我进入淘宝之前的五年,从做地市大集中的邮政系统,到做Windows的桌面IDE的开发,到自己创业的时候啥都做,包括去跟客户的技术人员沟通,跟客户的领导沟通等,看起来都没有什么延续性,但是我在淘宝的这几年,发现这些其实对我都有很大帮助。所以,如果你现在没有特别喜欢的方向,不要苦恼,把当下做好,不要虚度光阴,并且提高自己的效率,你要记住,时间是有限的,你要提升自己的效率,这样你就能收获更多,当然学习的方法也要注意,比如学以致用就是很好的方式,而那种为了学而学,看了就看了的方式,时间花了,效果不好的。记得开复老师说过,人在不同的阶段,你的精力的分配的比例是不一样的。在大家刚毕业的时候,我还是觉得一定要抓住这宝贵的时间,提升自己,因为随着年龄的增长,你花在家庭上的比例会越来越大。开复老师提到的花费在慈善方面的,我这里就不说了。所以也不要太纠结自己有没有找到一个确定的方向,随着你的阅历、经验的增多,会找到自己的方向的。另外,不要去因为外界的一些因素去选择自己的方向,考虑下自己的优势,自己的兴趣。前面几年多做些事情,提升自己的综合素质,然后找到一个方向深入下去,挺好的。和我年纪相仿的人应该看过刘青云饰演的大时代吧,他在里面也是经历了很多,找到了自己的方向。哈哈,不过这个只是个电视剧。
提到开发转管理,我估计很多人看到过说开发人员三十岁怎么办?或者另外一个版本是开发人员三十五岁怎么办?我读大学的时候,看到的是三十岁怎么办的版本,可能后来发现三十岁很好办,做技术没问题,就变成了三十五岁怎么办。在国外,其实那些年龄很大的人都还在做开发工作,都还在搞技术。在国内,这样的例子也有一些但是从比例上来说可能很小。从我的角度来说,三十岁或者三十五岁之后能否做技术取决于两点,一个是你所在的环境,另外一个是你自己。环境指的是说,有些公司,比如一些系统集成商,大多的套路是一套系统,到这个地方,改20%,到那个地方,再改20%,每个地方都收100%的钱,重复性的东西很多,门槛不是太高。新人过来半年一年就是主力了。年龄大一些的人,不能加班了,不能长期出差了,等等,会造成一定要走管理岗位了,这个就是我说的环境。但是,国内的很多互联网公司(别的行业我也不了解),在技术上有很大的空间是可以去做的,挑战很多。在淘宝,多隆同学从进入阿里到现在,十一年了吧,一直在做技术,还有正明(章文松博士),还有正祥(阳振坤老师),都是在技术上做了很久很深的人。这哥几个,技术的级别如果换成管理序列,都是副总裁的级别。在淘宝这样的公司,技术上只要你愿意,环境上肯定没问题。再说到人,不要因为你的专业而觉得自己在技术上走不下去。不要觉得科班计算机系或者相关专业的同学就一定会怎样怎样,关键还在自己,再说个身边的例子吧,在B2B有一位高级技术专家,他毕业后(我记得好像是公安高等专科学校毕业的)在派出所工作了将近10年,当了多年所长,但是不愿意在这个行业这样下去,就转行了,从测试做起,然后写ASP做网站,最后在Java以及分布式系统方面的专家。我相信这样的例子不止我身边这一个,所以,不要直接给自己那么多的限制和理由,觉得自己在技术上不能一直做下去。说这么多,是想告诉大家,如果你真的很喜欢技术,那么找一个能够给你提供这个环境的地方,好好干吧。而不要觉得做技术的到了三十岁或者三十五岁就一定要转。当然,也有同学就是对于管理或者说带团队有兴趣,这也很好,我的老大行癫就是一个技术和技术管理都很牛的人。但是,大家一定要先打好技术基础,打的越扎实越好,而且即便做了管理,也要跟进技术的发展和动向。
最后,本科生同学还遇到一个要不要读硕士的问题,反正我是没有去读的。这里我不想发表什么,想交流的直接找我吧。了解我的人知道我的态度以及想说什么的。
真的最后,我负责的团队(淘宝Java中间件团队)和另外一个比较基础的团队(业务平台)已经合并了,新的团队叫做通用产品团队,对外博客还是那里。有感兴趣的同学,不管是实习、应届、社招都可以跟我直接联系交流。我也打个广告,大家都知道淘宝做了拆分,我还是在淘宝网,我们的技术团队除了我这个通用产品团队外,还有关注交易、商品、店铺这三大块儿淘宝最久的业务的开发团队—交易平台团队,以及淘宝网的SNS、聚划算、商户平台以及内部服务平台的综合业务团队,还有在北京的新业务团队,负责机票、彩票、旅行等等很多新的业务,大家有兴趣的也可以跟我联系。微博,旺旺,邮件皆可。

8月18号在Oracle架构师日上分享的PPT

2011年6月7日星期二

写给有工作经验的想来淘宝的同学-我眼中的淘宝

淘宝的招聘,社招和校招都是很重要的部分,我之前谈校招谈的多些。今天这篇文章,主要想说说社招的情况。本文针对的同学,就是已经工作了一定时间、想加入淘宝的工程师们。

本文我主要分两个部分,首先我会介绍下我眼中的淘宝,然后我会给那些想加入淘宝的工程师们一些建议。

先说说我眼中的淘宝。为什么想说这个,是我在网上看到了不少对于阿里系以及淘宝的评价。众说纷纭。来过离开的、现在还在的、没有进来的朋友们,我想都有自己对淘宝的一个评判,我先说说我听到的一些不好的声音:

有说在淘宝学不到技术的;

有说淘宝不是个技术公司,主要是运营的;

有说淘宝加班严重的;

有说淘宝

。。。。。。

总结下来,其实大家关心的是三个方面:

待遇

有没有自己的时间

能不能得到成长。



先说待遇,这个我也说不出什么,不过,我个人的看法是这样的,一个公司提供给你的待遇包括了看得见的钱和看不见的环境和机会。这里的看不见,是你在没进来之前不知道的或者在你选择Offer时不能直接可见并去比较的。这里,我不想去争辩什么,我只想提醒大家,要综合考虑。三到五年后,你的财富不仅仅是收入的那个数字(更不是你第一年的收入*年限(你要看总体收入)),还有你的成长以及你的履历背景。而且,我这么说,只是提醒大家综合考虑,不是说淘宝的薪水没有竞争力。

然后说技术,首先,我个人认为,在国内没有一家纯粹技术的公司。都是商业公司,但是对技术的重视和技术水平,有差别。对于淘宝,她有自己的使命和愿景。但是,非常需要大家注意的是,在使命、愿景的背后,是要靠技术来支撑的。而且,越是像淘宝这样的规模,越是需要在各个方面去精益求精。在技术上,海量存储、大规模搜索、并行计算、系统自动化智能化、大规模分布式系统、性能优化与成本控制,各种算法等等都需要去钻研和深入,在业务上,交易、商品、店铺、团购、商城、运营支撑、广告推荐、新业务等等都需要去梳理和完善。在淘宝,其实有很多的机会和空间。举个简单的例子,有很多人觉得做网站没啥难度。就好像很多人觉得自己盖个两层的小楼没啥难度一样,来自农村、郊区的同学,估计家里很多都自己盖楼了。但是,让你去盖个金茂大厦,你搞得定么?盖3层楼和盖88层,完全不是一个概念了。就拿最近的例子,去年双11的促销活动,当时和淘宝合作的系统,很多出现了问题或者是已经挂了。而淘宝的压力是他们的之和,可是淘宝岿然不动,这是靠运营就能解决的么?靠简单的买设备就能搞定么?

再说说成长,在我们内部,一般是新人做已有系统,老人去做新的系统。一方面让新人可以熟悉原有系统和环境,更多的了解淘宝,另外是让老的人有新的空间,而不是总是重复。其实这个机制下,是能够很好的帮助新老员工去成长。而且,内部的分享和资料也很多,我想,能否成长,更多的是你自己是否投入,是否努力。在淘宝,不会是想把一个人就永远放在一个位置上,重复的重复的去做事情。可以说,主管会比员工更关心员工自身的成长,起码我就是这样。而且,在淘宝,你遇到的系统、业务的挑战和压力,以及周围的这些牛人同事,都会让你成长很快。

再说说加班。就我的了解,一定要加班的事情,不是那么的多的。但是公司毕竟是公司,有些战略项目或者其他的特殊的情况下,一定有Deadline的,这种情况下的加班,肯定是存在的。但是更多的时候,晚上留在公司的同学,是在学习。在这个行业,知识、信息很多,更新很快,如逆水行舟,不进则退。这里不是像有些人说的那样,每天加班到9点10点,一周六天,那都是比较特殊的时候,我也经历过,我就只有08年1月份一个月是这样的。其实,我从来没有想过自己能够早上9点到下午6点工作,之后一点都不想技术相关的事情。我这样问问大家,假设你们可以这样,你们自己踏实么?我觉得重要的是,通过这样的努力,是不是自己提高了,自己是觉得节奏快但是开心,还是觉得痛苦。

在淘宝整四年了,我觉得淘宝是一个让我很开心满意的地方。这里的氛围很简单、快乐。重要的是,我在这里成长很快,学到了很多东西。在这里,提供了很好的平台,让你自身得到发展。拿我的例子来说,从我加入淘宝时不懂Java、觉得互联网没啥技术含量,到直接用Java来做一个消息中间件-也是我用Java写的第一个应用,到后面的其他产品以及现在带领整个中间件团队,到和同事一起写书,到外部去分享,到去跟别的公司的同行技术交流等,我觉得自己真的是在这个环境下进步非常快。在淘宝,各个领域、方向都有很厉害的人,大家可以多去各个团队的博客上去了解下我们各个团队的信息,我们中间件团队的博客地址是http://rdc.taobao.com/team/jm/,其他团队的博客,在我们这里也有链接。跟这么多牛人在一起工作,你会觉得很幸福,成长和进步会很快,能够接触了解很多知识以及各种场景,并且在这样的挑战下快速成长和进步。如果你觉得自己是一个对技术很热爱、很有追求的人、并且也自信自己的水平很好,发简历给我吧。哈哈。huali@taobao.com

前面提到这些,不是说淘宝多么的好,完美无缺,我只是希望能够告诉大家,不要觉得淘宝没有技术、自己得不到成长;不要觉得淘宝就是整天加班、做些很表面的开发;其实,在个人成长方面,淘宝可以提供给你很多机会,给你舞台。当然,我们也有不足的需要改善的地方,这很正常。如果已经是一个非常完美的系统了,那么似乎空间也没有了。

最后,我看到有不少的朋友有意愿加入淘宝,但是又没能如愿。我想说说我的看法。我下面说的不是攻略不是捷径,而是个人的建议。

淘宝是非常注重技术,所以,淘宝在技术方面的要求,还是很高的。面试过的人应该都有感觉的。对于我们来说,我们需要很资深的能够给我们直接提供很大帮助的人,也需要工作时间不长,但是特别有潜力的人。对于一个候选人:

已经具备的知识、经验;

个人特质、潜力;

沟通和团队合作;

对技术的兴趣、自我驱动;

会是我们考察的部分。当然最后的结果是综合的。那么一般来说,对于沟通和团队合作,以及对于技术的兴趣自我驱动部分,不论资深资浅,都非常重要。对于潜力来说,对于资浅的同学更加重要些。而已经具备的知识、经验,对于资深的同学,更重要些。

那么分开来说。对于工作时间不久的同学,你一方面要避免总是在一个事情上重复,增加自己的知识面和广度。如果真的是一直做的事情类似,那么也要做出深度来。另一个方面整理整理自己的知识体系,想想自己今后想做什么,看看自己需要学什么。工作中没有类似的机会的话,自己也可以在自己的时间里多练练手。而你在面对面试官的时候,你需要通过你的经历,去展示你的知识、经验,去展示你对技术的兴趣以及你对某个技术、产品的深入理解等等,而不要是去罗列自己做了多少个项目,更需要的是你的亮点。在某个部分的深入,胜得过你做三次类似的项目,而你技术上的综合的能力,对你也是很有帮助。

对于资深的同学,我很难说给你们什么建议(自己都不够资深)。非要说的话,如果你的背景跟我们很符合,又愿意来帮助我们,那么赶快投简历吧(huali@taobao.com)。如果你想加入我们,但是背景上有比较大的差距,那么,可能还是需要您要有些相关的工作经验或者技能上的经验,仅仅是兴趣热情,坦白说还是比较困难的。还是需要您有相关的技能或者经验。

有什么想法,欢迎跟我多交流。

2011年5月23日星期一

给将要实习和毕业的同学-第一份工作的选择

现在已经快6月份了,寻找暑期实习工作的同学,应该都有了自己的Offer或者多个Offer了。而对于明年就要离开校园的同学,现在选择实习单位,很大程度上是选择毕业后要加入的公司了。我想,有不少同学,尤其比较出色的同学,在选择的时候会有些困惑和纠结。我想说说我的看法。
我下面谈到的部分,主要是针对研发工程师的,也许对于别的岗位也能有所参考。
同学们要选择自己毕业后的第一家公司,会考虑比较多的因素,从我个人来说,想到的几个主要的因素是:
地域
薪资
行业
职位
公司
对于上面的因素,每个同学的排序是不同的,权重也不会相同。对于每个人的选择,我觉得没有对与错,只是每个人会有每个人的看法。

那么,在如何选择之前,首先需要自己对自己做一个评估。并且,也要考虑一下自己的目标。
对自己做评估,做到非常准确,也很困难。但是我们还是要去想几个事情:
你喜欢什么?
你现在能够做到什么,具备怎样的知识和经验?
你有怎样的特质和潜质?
兴趣点很重要,做自己有兴趣的事情,你不会觉得辛苦、更不会觉得痛苦,而是乐在其中,工作不比学校中做些课程实验,想想自己到底喜欢什么。
而你能够做到什么、具备怎样的知识和经验,更多的是对你目前的技能的评估,看看你能够目前胜任怎样的工作。
而自己的特质和潜质,是你成长的推进剂,也是在你所掌握的知识和经验外的非常重要的东东。
想清楚这三块儿,对你的选择会有帮助。而且对于还在找工作的同学,也很有帮助。你要归纳下这三个部分,简历上、面试中让你的面试官知道这些,并且你要给他具体的案例的支撑。

在毕业的时候,想清楚自己比较长期的目标,是非常困难的一件事情。不过,不能因为困难,就不去考虑。还是要想想,自己希望自己3到5年后,成为怎样的一个人?能够做到怎样的一个程度?目标引领我们前进的方向,即便在过程中,我们会调整目标,但这不妨碍我们先确立自己的目标。有了目标,我们的行动就不再盲目。
看到这里,同学们先好好评估下自己,然后想想自己的目标吧。

那么,下面我想说说我个人的建议。请注意,下面仅仅代表我个人观点。
我看到很多同学在选择的时候,会非常看重地域和待遇这两个因素。其实这个真的是不正确的(我知道,这么说很多同学是听不进去的)。我觉得如果你想长期的做这一行,那么更重要的是要考虑如何能够让自己得到发展和提高。而薪资和发展无关,地域关系也不太大。
先说薪资,我觉得对于刚毕业的学生,千万不要因为A比B一个月高了1K、2K的,就不去考虑A和B哪里更合适自己。如果A和B对自己的发展差不多,选个薪资高的肯定没问题。但是如果把薪资凌驾在发展之上,将来你比你没去的那家公司要更加的后悔。也有同学说,薪资体现了公司对你的看重,那我想说,这个比较不是拿A和B提供的薪资比,而是要分别在A和B的内部横向对比。你才知道你是不是被看重。另外,被公司看重和自己发展的快和好,未必是成正比的。我这里举个例子。
A很重视你,给你很大的空间,让你自己发挥,重点培养你;B没那么“重视”你,给你安排很“常规”的发展计划。最后的结果,一定是在A更好么?这个未必的。对于刚毕业的同学,我知道会有非常厉害的人,不过这个比例注定不会很大。对于大部分同学,甚至也包括非常优秀的同学,你需要的是一个好的环境,而不是所谓的被重视。为什么对于B,我的重视和常规加了引号呢?其实,除了政府企业外,我觉得没有哪个企业是不重视人才的。一般来说,同样一个人,在A被很重视,在B感觉一般,那么背后的现实是,B比A的实力要更加强,人员的水平更高。这就是一个简单的鸡头凤尾的问题。而不要说对于刚毕业的同学了,包括有工作经验的人,环境都非常的重要,不是有那么句话么,一滴水到了一杯奶中,水就变成了奶,一滴奶到了一杯水中,奶就变成了水。好的环境,给你提供了更快成长的平台。好的平台会给你系统的培训;会给你一个周围很多牛人的团队;会给你很多机会,可能你觉得在团队里不是最优秀的,但是如果你能认真的工作一段时间,在出去跟其他同龄人比比,那你就知道结果了。
所以,我想说的是,不要对薪资的看重超过了个人发展。去对你发展有利的环境,用3-5年作为周期,你自己的发展不但更好,总的收入也不会差。而对你来说,更重要的财富是你自己的能力。
再说地域,很多人一定要去上海、要去北京、要去哪里哪里。这个地域的选择,和薪资是类似的道理,还是个人发展更加的重要。可能有同学说,北京的IT环境更好。这个没错,问题是,这个环境对于你在不同的时间,帮助是不同的。对于刚毕业的同学,内部环境对你的帮助,是要远远超过外部的环境的。IT环境更好,我能想到的就是交流方便和跳槽方便。对于刚毕业的同学,第二个就别先考虑了,而交流这个部分,对于刚毕业的同学,内部的信息和一些基础的知识,就够你学一壶的了。
说到这里,其实总结来说,告诉大家的就是要考虑你的Offer中,哪个对个人的发展是最有利的。我提到的几个因素中,行业、职位、公司,这个需要综合考虑。在同样行业、同样职位中,选择公司就很重要了。比如,在互联网行业,都是研发的岗位,那么会有很多公司可以选择。个人的发展,跟公司的发展是密切相关的,你肯定要选择目前发展比较快的公司,这里机会更多,这与大小无关。另外,你要看下公司提供怎样的平台给你而不仅仅是让你觉得被重视、给你空间。对于咱们绝大部分同学来说,你们更加需要的还是一个帮助你成长的平台,而不是仅仅给你的是空间,让你折腾。
这个平台,应该会提供给你机会成长,而不是总是原地踏步做重复的事情;
这个平台,应该会有很多学习的机会给你,不仅仅是培训,还有在实战从学习的机会,还有牛人的指导;
这个平台,能够让你接触前沿的技术、已经做到或者有机会做到业内领先、能够有最大的挑战。
总结来说,同学们千万不要把地域和薪资放到最重要的部分,而是先挑选对你发展有利的公司,然后再比较地域和薪资。而说到如何去挑选对你发展有利的公司,那么主要是要有自己的目标以及对于可以选择公司的了解。通过师兄师姐、朋友同学、互联网,多去了解目标公司,最后做选择。同学们,对于你们大部分人来说,毕业后更加需要的是一个能够比较系统的帮助你成长的公司,3-5年后,你羽翼渐丰后,每个人会有不同的路和选择。但是刚毕业的时候,还是需要有个好的环境,让自己能够快速成长。刚毕业甚至没有毕业的时候,能够自己去翻江倒海的,不管去创业还是去独挡一面的,是很少数的人。所以,大部分同学,还是要去一个有好的平台和环境的公司。
同学们,看到这里,希望前面的内容能够对你们有所帮助,也欢迎同学们跟我交流。照例放上我和我团队的联系方式。
Email: huali@taobao.com
Sina微博: @曾宪杰_华黎
Twitter:@vanadies10
团队博客: http://rdc.taobao.com/team/jm/
最后,还是要说下淘宝网。淘宝网拥有全球最大的交易平台(我不是说交易额)。商品数、交易笔数都是第一的。这里有很多的挑战,有很多方向,包括但不限于海量存储、大规模搜索、并行计算、系统自动化智能化、大规模分布式系统、性能优化与成本控制,此外还有很多算法、业务相关的领域。更多技术上、业务上的内容,欢迎加入我们来具体了解。
关心淘宝的在校同学,可以关注下我们的针对校园招聘的网站--http://campus.taobao.com/index.php,这里有很多的信息和内容。对Java中间件团队感兴趣的同学,请直接跟我联系。
最后的最后,我想给同学们说下我自己刚毕业的情况。
我02年毕业于浙江大学计算机科学与工程系,算是科班出身吧。我只是个小本科,到现在工作快9年了。在我当时毕业的时候,其实我最看重的是地域,我的兄弟们,在上海的很多。所以,我义无反顾的去了上海,其实我们那年工作很难找,很幸运的是我还是找到了上海的一个工作,记得当时我们学校BBS上,很多同学都说要去上海,哪怕过去是扫大街也要去。02年底我曾经在朋友的联系下,跟当时是阿里巴巴CTO的吴炯先生,有过一次面对面的沟通,他跟我说了很多我现在说给应届同学的话。同样因为地域的关系,我没有选择阿里巴巴。那个时候我是一个有些自负又没有自己内心目标的人,我觉得我做什么都行的(其实那个时候自己接触的面广,但是其实都不深),我也觉得努力就能成功。我太看重自己以及一些主观上的东西,忽视了环境、公司发展等因素。从02年,辗转5年,经历了上海、成都、重庆,经历了打工和创业,我在07年6月和幸运的并且稀里糊涂的加入淘宝。这四年下来我感觉自己成长了很多,真的是工作以来提升最快的阶段。跟很多牛人在一起工作,很舒服、很轻松,而且进步很快。在这里,你可能不一定能够独领风骚,但是,你一定会进步迅速。在这里,也提供了很多的机会,就看你自己能不能把握。在这里,经历了很多很多,学到了很多很多,不论是我的领导,我的同事,都让我学到了很多,给了我很大帮助。这里,就是这样一个简单、快乐的团队和氛围。不要犹豫,加入我们吧。

2011年4月28日星期四

写给想加入淘宝的在校同学--广州实习生招聘感想

2011淘宝春季校招已经到了尾声了,五一前,面试都会结束。我参加了广州站的实习生面试。这两天跟不少同学做了交流沟通。这里想谈一下我的感受,以及想给加入淘宝的同学们一些建议。这次没有通过的同学也不要气馁,我们秋季校园招聘见。
这两天见了不少同学,我能感受到同学们的热情,以及对于技术的热爱。也很感谢同学们对于淘宝的关注。下面我先来说说我在广州两天面试下来的感受。
程序设计的基础还需要加强:
被我复试的同学,几乎都被我问到了如何自己去实现一个字符串中查找字串的问题。在第二天,每个同学过来,第一件事情就是在我的笔记本上,把这个代码给我写出来。那么结果如何呢?
几乎所有的同学都知道要完成功能,最简单的做法应该怎么做。但是,只有一位硕士同学,写出来的代码,基本上上是实现了这个功能。其他的要么写不出来,要么是错的。但是,就这么个题目,我没有看到一个让我非常满意的答案。我这里说的满意不是说要你写出KMP的实现,只是希望能够看到功能正确、异常情况考虑清楚、常规的优化要有。
这是一个侧面,反应出来的问题是基本功的问题。有些同学会觉得这个可能不重要,我知道思想,写程序么,我写多了,熟练了就好。我这里想说的是,写程序是基础,如果你说你很热爱技术、很喜欢写程序,而很基础的都写不好,如果你是面试官,你会怎么想呢?也许给你些时间,你真的就能够写出很好的程序了,但是这个貌似是也许。如果你在面试的时候,就已经可以展现出这些,你不是会比别人出色么?反过来,如果别人都可以做到,你不行,你不是很危险么?
那么我出的这个题目需要考虑什么呢:
字符串和要查找的字串是不是null要考虑吧?
如果字符串比要查找的字串短,可以直接返回结果吧?
循环遍历的时候,字符串的起点,应该要保证从起点到结束,比字串长把?
继续说这个字符串查找的例子。有些同学,在我问到有没有优化的办法的时候,提到了KMP,但是我具体怎么实现,记不起来了。OK,我也不能马上写出来KMP的实现。但是我继续问,KMP比这个直接循环比较的原始方式有改进,那么KMP是解决了什么问题?或者说是在什么问题上解决的更好。然后有很多同学就不知道了。给我的感觉是,因为同学记不得KMP的具体实现,所以也不知道去解决了什么问题。我觉得这个逻辑是刚好反过来了。我们应该先去理解KMP解决了什么问题,或者说去看看最初的实现,有什么地方可以改善、可以提高。这个是根本的东西,如果你理解了,即便不知道KMP,你也有机会搞一个KMP出来,即便你不记得KMP的具体实现,那又有什么关系呢?
在回杭州的路上,我想到了一句话,你是用文科的方式学习知识还是理科的方式学习知识。我是这么看的,如果更多的是去记忆,就是文科的方式学习,我们需要的是去理解,是去看到背后的、纸面反面的东西。这个是根本。我听过一个笑话,两个学习文科的同学,互相提问,AB,历史书的X页的Y行上说:哪一年,巴黎人民在什么教堂举行了起义,B记得年份,但是死活想不起来是什么教堂。A告诉B,答案是“一个”教堂。我撅翻。
那我们要搞开发,千万不要用这样的方式,我知道没有同学会这么学习,但是如果你不深入去理解、了解所以然,那么结果上也差不多。
前面说了基础,下面我想说说逻辑思维。
逻辑思维,我觉得主要指的是去分析、解决问题的能力,去灵活运用自己知识的能力。这个部分,我觉得扎实的基础是很关键和必要的,而对知识的深入理解更为重要。我举一个例子,说到深度优先搜索、广度优先搜索,可能绝大部分的人都知道。但是如果出题目是一个场景,可能很多同学就不知道该怎么整了。比如,我问了一个农夫带着狼、羊、早过河的问题,这个是一个非常之经典的问题,中学的信息学奥赛会用到的题目。可是有很多同学,就不知所措了。这就是一个分析和运用知识的能力。在我们实际工作中,遇到的问题都是需要我们去分析然后找方案的,不会说直接告诉你,我们需要用广度优先搜索去干个嘛、用深度优先干个嘛等等。同学们都很年轻,学习计算机的时间相对有限,作为面试官,我们不期望你什么问题都能很好的解决,但是一些基本的,大学学过的知识,你需要能够很好的运用,另外,也会看你的思路。此外,对面试官的问题的准确快速理解,也会反映你的能力。
再说说对技术的热爱。
我上篇博客提到,我们喜欢热爱技术的人,这次我遇到的同学,除了两个女孩子外,好像都告诉我很热爱技术。在这里,我不是不相信你们的话,只是我想让同学们明白,热爱技术不是说说的,你需要来证明给面试官。我举个例子,我很热爱尤文图斯(意大利的足球俱乐部)。我只是这么一说,没用。有两个办法可以证明我很热爱,一个是我周围的朋友,尤其是跟我十多年一起的朋友可以证明,但是这个办法不灵光,要用这个办法,除非是你相信并认识我的朋友才行;另外一个办法是,我可以告诉你尤文图斯的很多历史、很多故事,告诉你我从94年开始看尤文图斯的比赛一直到现在的很多点点滴滴,那么第二个办法就相对靠谱。那么回到同学们的面试,如果你很热爱技术,你的朋友、同学知道,他们可以证明,但是我不认识他们,这条路不行。那么就是第二个方法,你热爱技术,热爱某个方面的,那么你一定是会看很多这方面的文章、书等,你的了解就会比别人深入。你可以讲你的收获等等,但是如果你很热爱某个方面的技术,结果还没有大多数人了解的多,那我又撅翻了。
学习能力。这个方面,更多的需要你自己去展示自己之前的一些经历。当然也会把这个部分和对于分析和解决问题放在一起去考察。我觉得学习可以分三个层次:
了解(基本会用)
熟练、经验丰富(用的多,遇到不少问题,知道一些别人不知道的细节的点)
理解(知道背后的原理、实现等)
同学们时间有限,我建议你还是能够在一两个部分很深入,而不是搞了很多,但都是很浅或者就是知道有那么个东西,这样不好。你能够把一两个部分搞的很深入,那么,我也相信你在类似的其他方面,给你时间,你也可以搞的很深入;但是如果你都是知道一点知道一点,我就不确定你到底能够钻多深了。
举个例子,有同学说对并发、JVM感兴趣。问了一些问题,发现概念性的回答的还不错,但是深入一下,问为什么要这样,这样的好处坏处,他就不知道了,告诉我书上这么说的,我说那你自己觉得呢?告诉我说,没有想过。这样的学习方式,我觉得就是可以提高和改善的。
再说说项目经验。
项目经验对于你来说,未必多了就好。主要是精。
对于本科生同学,尤其这次招聘的都是大三才读了一个学期的同学,你不用去苛求自己去做多少项目,也许你还没有这样的机会,你可以专注于学校的课程实践(我们当年叫做大作业),以及根据你自己的兴趣学习到的知识的一些运用。比如当年我对于基于Socket通信很感兴趣,就自己去做了一个类似Mud的东西,然后去改进完善。对于硕士同学,你们想对是有不少时间的,应该有更多的实战的经验,但是我很建议的是,我更在乎你在项目中的贡献,你的深度,你的提升。我很建议大家不要去重复的做很多差不多的事情,对你自己没很大好处。我上次也提到了,这就是叫做工作五年,一年经验。如果真的是老板逼着去一直重复,我也希望你能够在第二次、第三次的过程中,做出新意来。
上面提到的这些方面,都是非常基础的。如果这些大家不能够做好的话,不管去淘宝还是类似的公司,我想面试都是会挂掉。而看到这个部分,对于我写的内容很不屑的觉得太简单并且自己已经做到非常好的同学,我给你一个建议,发邮件给我吧。huali@taobao.com,我们可以去谈些更深入的问题。当然也可以在新浪微博或者Twitter上加我。我的新浪微博是@曾宪杰_华黎,twitter@vanadies10。前面主要是针对比较大众的同学的一些感受、建议。那些在学校期间特别突出优秀的同学,直接联系我就是了。我会给你更有挑战、更有深度的东西。
我们这次春季实习生招聘,已经尾声了,没有通过的同学,如果你对淘宝有兴趣,也不要气馁,后面还有机会,可以等到秋季的应届生招聘。那么剩下还有差不多半年的时间,我建议你看看自己还有哪些地方是自己的短板的,抓紧时间去提升一下。从基础做起,不要好高骛远。记得我个人历史上写过最好的一篇作文是《立鸿鹄之志,从小事做起》,这个是解读《一屋不扫,何以平天下》的。同学们一定都有远大的志向,但是要从小事做起、从基础做起,脚踏实地,努力前行。对于离毕业还有比较长时间的同学,你们很幸运,还有更多的时间去提高、完善自己,但是千万不要挥霍光阴。加油!

2011年4月16日星期六

写给想加入淘宝的工程师朋友们


    本文下面谈到的招聘求职,只针对研发工程师。不涉及其他的岗位。

    看到很多人想进淘宝,而我们也很需要优秀的工程师和技术专家。这几年也忙忙碌碌的面试了很多人,也从自己手上毙了很多人,我很希望能有很多优秀的人才加入我们。这里想说说自己在招聘过程中的感受,也希望给想加入淘宝的同学一些建议。
    首先先来说说对于实习生和应届生招聘的我的看法和建议。
    先说说我们对实习生和应届生的要求。我们需要的实习生和应届生,简单来说,有下面几点:
    1 具备一定程序开发基础
    2 逻辑思维能力比较强
    3 学习能力好
    4 热爱技术
    5 自我驱动
    因此,参加过我们2011春季实习生的招聘笔试的同学,或者在网上看到我们笔试题目的同学,会发现我们考察的都是最基础的东西。我们通过笔试,希望对1,2 两点去做一个考察。而后续的面试,会更多的关注3,4,5。当然,也会有问题跟1,2相关的问题。
    那么,对同学来说,如果要想进入淘宝,需要怎么做呢?我想这个可能也是很多同学关心的。
    其实答案是没有捷径。少走弯路就是了。
    在学校期间,如果不翘课,其实业余时间也不是那么的多的,我是建议大家把时间能够用在刀刃上。
    首先要能够打好基础,数据结构、算法这些一定要掌握好,一些科班的专业课程,尤其数据库、操作系统、体系结构、网络等也要去好好学习。
    然后,多写些程序,熟能生巧。不要面试时让写段代码的时候,就茫然了。
    接着,能够熟练的运用所学的知识编程解决具体问题。千万不要只是记住了很多的概念、名词或者书上的话而已,要能够去运用。并且也要能够深入的去学习,要知其然并且知其所以然。
  最后,关注下业界的一些技术动向,多了解了解没啥坏处(这个部分对实习生和应届生的要求不高)
  另外一块儿是和实习相关的,一般来说,实习总是好事,多些项目经验也好的,但是千万注意的是,你要能从实习、项目中是否持续的学习到新的知识,得到成长了,如果只是一味的去重复,那多个项目经验基本就合并同类项了。也就是我们常说的,工作了五年,只有一年的工作经验。
  那么怎么做呢?
  大学生活要努力,也会很辛苦(我个人是觉得大学是比高中辛苦很多的,高中几乎天天都踢球、玩游戏啥的),不管你是在课堂上好好学习还是像我这样为了学习去翘课,都没关系,关键是要能够学好知识并且动手练习,书本上的习题,其实都是有针对性的,可以去做一下,编程方面,更是需要勤加练习,不管是课程实践、还是习题、或者是你自己想去做个什么东东,多动手。另外,就是在这个过程中要深入。我知道大学的时间有限,但是我相信你总是可以深入的去学习一块儿的知识。深入的理解了一个部分,比肤浅的了解三个部分更有价值。
  此外,有些同学会关心和了解淘宝在用什么框架用什么系统等,其实这个我觉得不那么重要,更重要的还是你自己的基础、你个人的能力和潜力。
  最后,我们关心一个人现在所具备的知识和经验,但是更关心的是一个人的潜力、学习能力和自我驱动方面的东西。所以,我的建议是同学们一定要把基础打好,深入学习,多写程序,能够总结自己的经验,一步一个坚实的脚印往前走。能够过段时间就回顾下自己的成长。
  上面说了应届生和实习生的状况。下面想简单说下有2,3年工作经验的情况。有工作经验的同学,如果想进入淘宝,那么你除了能做到上面提到的之外,更加需要能够把程序写好,这个写好不是说功能对了就行了,而是真的写好,比如你的代码是不是已经最优化了,你对问题的考虑、异常的处理是不是全面了等等。另外,也需要你在项目、产品中能够有突出的表现,比如说你能够在完成功能的时候,深入的了解你使用的技术,能够在之前项目、产品的基础上有所改进和创新,能够有自己比较喜欢的领域并且有所深入等等。总之,在面对淘宝的面试官的时候,你需要用你过去经历让他知道你的学习能力、你对技术的深入、你自己在项目产品中的创新和改进等等。
  对于非常资深的朋友,我没啥要说的,如果真要说,就是一句,加入我们吧,一起把淘宝做的更牛。
  最后,广告一下,我们团队-淘宝Java中间件-也持续在招人,可以看下我们团队的博客 http://rdc.taobao.com/team/jm/,也可以把简历发送给我 huali@taobao.com

2011年4月15日星期五

北京之行,收获很多

     这周一到周三三天,在北京。感谢团队的伏威同学的组织安排,到北京的多家业内的公司进行了交流,也在betacafe和北京的做了沟通。北京的交流的氛围确实很好,从交流中也感觉到淘宝在Java方面,确实做得还是比较多、比较深的。今后如果有机会,是能够跟大家再更多的交流,周二晚上的时间很有限。
     这次拜访了飞信、豆瓣、谷歌、新浪微博、创新工场,也跟百度的朋友有所交流,也认识了新朋友,收获很多。今后还要多出去走走看看。
     另外,也有一个广告,淘宝会在今年的7月份在杭州举办淘宝技术嘉年华,希望到时候有更多的业内朋友来参加。

2011年2月23日星期三

Java字节码框架ASM-读写字节码的用法


    目前,最新的ASM是3.3.1版本的,整个学习笔记,也围绕着3.3.1这个版本来展开。
    在ASM3.3.1中,提供了7个jar包,分别是
         asm-3.3.1.jar
         asm-commons-3.3.1.jar
         asm-tree-3.3.1.jar
         asm-analysis-3.3.1.jar
         asm-util-3.3.1.jar
         asm-xml-3.3.1.jar


         参看ASM的javadoc(http://asm.ow2.org/asm33/javadoc/user/index.html),可以看到一共有7个package,package和jar的对应关系如下
         asm-3.3.1.jar 包含了org.objectweb.asm和org.objectweb.asm.signature两个packages
         asm-commons-3.3.1.jar包含了org.objectweb.asm.commons这个package
         asm-tree-3.3.1.jar 包含了org.objectweb.asm.tree这个package
         asm-analysis-3.3.1.jar包含了org.objectweb.asm.tree.analysis这个package
         asm-util-3.3.1.jar包含了org.objectweb.asm.util这个package
         asm-xml-3.3.1.jar包含了org.objectweb.asm.xml这个package


         其中asm-3.3.1.jar,是包含了核心的功能,而其他的jar,都是基于这个核心的扩展。
         那么我们就从最核心的部分说起。


         如大家所了解的,ASM是一个操作字节码(bytecode)的框架,非常的小巧和快速,这个asm-3.3.1.jar,只有43k的大小。
         asm提供了字节码的读写的功能。而asm的核心,采用的是visitor的模式,提供了ClassReader和ClassWriter这两个非常重要的类以及ClassVisitor这个核心的接口。
         ClassReader的职责是读取字节码。可以用InputStream、byte数组、类名(需要ClassLoader.getSystemResourceAsStream能够加载到的class文件)作为构造函数的参数构造ClassReader对象,来读取字节码。而ClassReader的工作,就是根据字节码的规范,从输入中读取bytecode。而通过ClassReader对象,获取bytecode信息有两种方式,一种就是采用visitor的模式,传入一个ClassVisitor对象给ClassReader的accept方法。另外一种,是使用Low Level的方式,使用ClassReader提供了readXXX以及getXXX的方法来获取信息。
         对于一般使用,用ClassReader的accept方法,使用visitor模式就可以了。


         那么接着我们来看一下ClassVisitor。
         ClassVisitor这个接口,定义了一系列的visit方法,而这些visit方法,我们通过实现ClassVisitor接口中的visit方法(其实就是一堆的回调函数),就能够得到相应的信息。
         在asm中,ClassAdapter这个类,用asm的javadoc上的话说,就是一个代理到其他ClassVisitor的一个空的ClassVisitor(An empty ClassVisitor that delegates to another ClassVisitor.)。具体来说,构造ClassAdapter对象的时候,需要传递一个ClassVisitor的对象给ClassAdapter的构造函数,而ClassAdapter对ClassVisitor的实现,就是直接调用这个传给ClassAdapter的ClassVisitor对象的对应visit方法。
         后面我们会看到一个使用ClassAdapter的例子。
         
         说到这里,我们主要介绍了ClassReader这个类,ClassVisitor这个接口以及ClassAdapter。那么我们先看一个简单的例子,是使用ClassReader和ClassVisitor的一个示例。


package org.vanadies.bytecode.example.asm3;


import java.io.IOException;


import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;


public class ClassReaderExample {
    private static class MyClassVisitor implements ClassVisitor {


        @Override
        public void visit(int version, int access, String name,
                String signature, String superName, String[] interfaces) {
            System.out.println("class name:" + name);
            System.out.println("super class name:" + superName);
            System.out.println("class version:" + version);
            System.out.println("class access:" + access);
            System.out.println("class signature:" + signature);
            if(interfaces != null && interfaces.length > 0){
                for(String str : interfaces){
                    System.out.println("implemented interface name:" + str);
                }
            }
            
        }


        @Override
        public void visitSource(String source, String debug) {
        }


        @Override
        public void visitOuterClass(String owner, String name, String desc) {
        }


        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            return null;
        }


        @Override
        public void visitAttribute(Attribute attr) {
        
        }


        @Override
        public void visitInnerClass(String name, String outerName,
                String innerName, int access) {
        }


        @Override
        public FieldVisitor visitField(int access, String name, String desc,
                String signature, Object value) {
            return null;
        }


        @Override
        public MethodVisitor visitMethod(int access, String name, String desc,
                String signature, String[] exceptions) {
            return null;
        }


        @Override
        public void visitEnd() {
            
        }
    }
    
    public static void main(String args[]) throws IOException{
        ClassReader classReader = new ClassReader("java.lang.String");
        classReader.accept(new MyClassVisitor(), 0);
    }
}
    这个简单的例子,打印了String这个类的基本信息。
    从上面的例子看,ClassVisitor这个接口的方法中,有些返回值是void,有些是返回了XXXXVisitor。
    这里,返回XXXVisitor的,我们举个例子,比如visitMethod这个方法,返回的是MethodVisitor。这里,在visitMethod的方法中,给出了Method的基本信息,如果需要去获取Method内部的详细的信息(包括代码,注解等),那么需要返回一个MethodVisitor对象出去,如果返回null,那么在ClassReader中,就不会去展开对这个Method的详细信息进行遍历了。
    除了MethodVisitor,还有,AnnotationVisitor,FieldVisitor。
    另外,在org.objectweb.asm.signature这个包中,有一个SignatureVisitor以及SignatureReader和SignatureWriter,这个是处理Signature的。
    而除了ClassAdapter外还有MethodAdapter,作用类似与ClassAdapter,只是MethodAdapter是针对MethodVisitor的。




    到这里,我们已经了解了如何读取bytecode的信息了,也了解了如何使用ClassReader和ClassVisitor了。 接下来,我们要看一下,如果使用ClassWriter这个类了。

 ClassWriter,顾名思义,是用来写字节码的。ClassWriter实现了ClassVisitor这个接口。这里可能大家会觉得奇怪,ClassReader什么接口都没有实现,为啥ClassWriter要实现ClassVisitor的接口呢?ClassWriter只要提供了方法,让我写字节码就行了哇。
大家还记得,通过ClassReader获取类的字节码,有两种方式,一种是使用Visitor模式,这种方法很简单,前面也有demo,另外是使用low level的get和read来进行,这个很复杂。而如果ClassWriter提供的是low level的put和write这类的方法,会提高门槛,很不好用。而ClassWriter实现了ClassVisitor接口,那么就能够很好的跟ClassReader的Visitor模式结合起来。并且,我们使用ASM操作字节码,在写方面更多的是修改、添加和删除,而不是用ASM来完全去写新的class。
ClassWriter中,还有一个toByteArray的方法,这个是把ClassWriter对象生成的字节码,写到一个byte数组中。用于我们来获取字节码的最终结果。
那么,我们可以做一个很简单的例子。就是把ClassWriter对象作为ClassReader accept方法的参数,传给ClassReader,然后在accept方法结束后,我们用ClassWriter对象的toByteArray方法,就能够获得类的字节码了。
这个例子,就不贴源码了,有兴趣的同学,可以自己搞一下。
那么,我们把ClassWriter用在哪里呢?上文提到了,删除、修改、增加。那么一般来说,删除我们是不太用的。主要是修改和增加。
比方说我们如果自己要做AOP,用到的就是修改和增加。假如我有一个类,其中有一个execute方法,我如果自己做AOP,我可以把这个execute方法改名,比如叫做execute$1,然后我增加一个execute方法,新的execute方法中,我可以调用原来的execute方法(现在是execute$1)了,并且在调用前后做一个处理。
我们来看一下具体代码


package org.vanadies.bytecode.example.asm3;


import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;


public class ClassWriterAopExample {
    public static class Foo {
        public void execute(){
            System.out.println("Hello World");
        }
    }
    
    public static void main(String[] args) throws Exception{
        Foo foo = new Foo();
        foo.execute();
        ClassReader cr = new ClassReader(Foo.class.getName());
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        cr.accept(new ClassAdapter(cw){
            @Override
            public void visit(
                    final int version,
                    final int access,
                    final String name,
                    final String signature,
                    final String superName,
                    final String[] interfaces)
                {
                    cv.visit(version, access, name + "$1", signature, superName, interfaces);
                }


            @Override
            public MethodVisitor visitMethod(
                    final int access,
                    final String name,
                    final String desc,
                    final String signature,
                    final String[] exceptions)
                {
                    if("execute".equals(name)){
                        //这里只是简单的比较了方法名字,其实还需要比较方法参数,参数信息在desc中
                        return cv.visitMethod(access, name + "$1", desc, signature, exceptions);
                    }
                    return cv.visitMethod(access, name, desc, signature, exceptions);
                }
            
        }, 0);
        //到这里,如果调用cr.toByteArray,生成的字节码中,已经没有execute方法了,而是execute$1
        
        //我们接着需要增加一个execute方法
        MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "execute",
                "()V", null,
                null);
        //开始增加代码
        mv.visitCode();
        //接下来,我们需要把新的execute方法的内容,增加到这个方法中
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        mv.visitLdcInsn("Before execute");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); 
        mv.visitVarInsn(Opcodes.ALOAD, 0);
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/vanadies/bytecode/example/asm3/ClassWriterAopExample$Foo$1", "execute$1", "()V");
        mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
        mv.visitLdcInsn("End execute");
        mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
        mv.visitInsn(Opcodes.RETURN);
        mv.visitMaxs(0, 0); //这个地方,最大的操作数栈和最大的本地变量的空间,是自动计算的,是因为构造ClassWriter的时候使用了ClassWriter.COMPUTE_MAXS
        mv.visitEnd();
        //到这里,就完成了execute方法的添加。
        //可以把字节码写入到文件,用javap -c,来看下具体的内容
    }
}
这个代码,要比之前的ClassReader的例子要复杂一些。主要复杂的地方在重写execute方法那里,其实就是类似在用汇编在写代码。具体怎么来写或者生产这个代码,有很多办法。
我们这里只是先展示一下如果能够去修改字节码。这个例子展示了,修改原有方法名字,以及增加方法的做法,其他的增加字段等,都可以通过ClassWriter来处理。
具体在运行时能够改变类的行为,我们可以通过Instrumentation的方式或者采用自己实现的ClassLoader的方式来处理。上面例子中,只是展示了如何修改字节码,这个和实际在运行时达到AOP的效果,还是有距离的。

2011年2月22日星期二

Java Basic Diagnosis Tool

    之前遇到过几次Java占用CPU过多的问题,去定位问题的办法也很简单,主要是就是通过 top -H -p javapid,看一下哪些Java的线程占用CPU多,然后通过jstack,dump java的线程,然后去看下这些线程具体再做什么。
    不过人肉去做这个事情,很麻烦,写了一个简单的工具,放在了google code上,也希望能偶有更多人把一些类似这样比较基础的、但是能够减少人肉的工具也放上来,方便需要去查问题的人。
   具体 google code中project的地址是 http://code.google.com/p/java-basic-diag-tool/

2011年2月4日星期五

Java HashMap的并发问题

    使用Java的同学应该都是知道HashMap是线程不安全的,不能够并发的去put和get,如果有并发操作,会抛出ConcurrentModificationException这个异常。不过可能很多同学没有注意,这个异常并不是一定会抛出的。而并发的去对HashMap对象进行put和get的结果,是可能造成死循环。
     年前在线上,也遇到了这么一次。当时是有同学找过来,说有台机器的load很高,已经启动了流量控制,也没有请求进到容器中。后来dump了thread,也通过top -H看到占用CPU比较高的线程,发现都是在执行HashMap.get,想到可能就是上面的原因,后来看了源码,发现确实是这么一个问题。
具体对于HashMap在并发操作时陷入死循环的分析,可以参看这篇博客 http://pt.alibaba-inc.com/wp/dev_related_969/hashmap-result-in-improper-use-cpu-100-of-the-problem-investigated.html

充实与效率

    先讲一个发生在自己身上的故事。
    最近跟IP地址搞上了, 需要把形如a.b.c.d的ip地址转为数值型表示,然后根据网段的起始和结束地址,确定所在的ISP。
在调试和运行的过程中,会需要把数值型的地址转为形如a.b.c.d,然后需要用whois去查询这个a.b.c.d所属的ISP。
开始的时候,是手工的处理了几个地址,用计算器,把数值型转为a.b.c.d;通过命令行的whois去查询信息,然后人肉看一下whois的结果。
发现这个过程真的烦,写了一个python程序,代替计算器做的事情,爽了一些。
后面,用程序实现了命令行whois的功能。
再后来,自己分析了whois查询后的结果。
到这三步做完,基本上是从原来纯手工的工作,变为了自动化的过程。
其实这三步工作变为程序来做,本身没什么很大的困难,这里想记录的,也是想提醒自己和大家的是,大家要能够了解,让自己每天都很充实是没错的,但是需要注意自己的效率。
这也就是很多人会说的要聪明的读书、聪明的学习,我想就是这个道理了,让自己充实、忙应该是很容易的,重要的是,自己对自己时间的投入产出比。我们单位时间是不是做了足够的事情。我们也需要多思考思考,自己是不是聪明的在忙。

通过编程获取Whois的信息

       近期帮助同事在处理从纯真网络上拿到的IP信息,确定这些IP所在的城市、区县,以及这些IP属于哪些ISP。后来需要用到whois上查询的信息。
       开始的几次,通过whois命令简单的查询了一下。后来同事看到http://blog.chinaunix.net/space.php?uid=9950859&do=blog&cuid=1300091这篇博客介绍的用法,把教育网、电信、铁通、网通(之前是网通,现在算联通)的信息都拿下来了。从这些ISP中提取各自负责的IP段,处理了很多IP信息所对应的ISP,不过还是有些没有能够得到处理。就像写程序去自动处理。
       网上搜索了一下,发现其实whois的协议是非常简单的文本协议。whois服务器的端口,是43,可以直接telnet连接到whois服务器(比如 whois.apnic.net)的43端口,然后输入help,就可以查看支持的协议。
       Trying 202.12.29.222...
Connected to whois.apnic.net (202.12.29.222).
Escape character is '^]'.
% [whois.apnic.net node-2]
% Whois data copyright terms    http://www.apnic.net/db/dbcopyright.html

help
% -l <ip-lookup>   Returns first level less specific inetnum,
%                  inet6num or route objects, excluding exact matches.
% -L <ip-lookup>   Returns all level less specific inetnum,
%                  inet6num or route objects, including exact matches.
% -m <ip-lookup>   Returns first level more specific inetnum,
%                  inet6num or route objects, excluding exact matches.
% -M <ip-lookup>   Returns all level more specific inetnum,
%                  inet6num or route objects, excluding exact matches.
% -x <ip-lookup>   Requests that only an exact match on a prefix be
%                  performed.  If no exact match is found no objects are
%                  returned.
% -c <ip-lookup>   Requests first level less specific inetnum or inet6num
%                  objects with the "mnt-irt:" attribute.
% -b <ip-lookup>   Requests first level less specific inetnum or inet6num
%                  objects with the "mnt-irt:" attribute. Only object keys
%                  and "abuse-mailbox:" attributes are visible.
% -d <ip-lookup>   Enables use of the -m, -M, -l and -L flags for lookups on
%                  reverse delegation domains.
%
% -i <attribute-name> <inverse-key> Perform an inverse query.
%
% -F               Produce output using short hand notation for attribute
%                  names.
% -K               Requests that only the primary keys of an object to be
%                  returned.  The exceptions are set objects, where the
%                  members attributes will also be returned. This flag does
%                  not apply to person and role objects.
% -k (optional normal query) Requests a persistent connection. After
%                  returning the result the connection will not be closed by
%                  the server and a client may issue multiple queries on the
%                  same connection.
%                  Note, that server implements 'stop-and-wait' protocol,
%                  when no next query can be sent before receiving a reply
%                  for the previous one.  Use RIPE whois3 client to be able
%                  to send queries in batch mode.
%                  Except the first -k query, -k without an argument closes
%                  the persistent connection.
% -g (mirroring request) Request a NRTM stream from the server.
%                  See [REF], section 4. "Mirroring the RIPE Database" for
%                  more information".
% -G               Disables the grouping of objects by relevance.
% -B               Disables the filtering of "notify:", "changed:" and "e-mail:"
%                  attributes.
%
% -R               Switches off use referral mechanism for domain lookups,
%                  so that the database returns an object in the RIPE
%                  database with the exact match with the lookup argument,
%                  rather than doing a referral lookup.
% -r               Switches off recursion for contact information after
%                  retrieving the objects that match the lookup key.
% -T (comma separated list of object types, no white space is allowed)
%                  Restricts the types of objects to lookup in the query.
% -a               Specifies that the server should perform lookups in all
%                  available sources.  See also -q sources" query.
% -s (comma separated list of sources, no white space is allowed) Specifies
%                  which sources and in which order are to be looked up when
%                  performing a query.
%
% -q sources       Returns the current set of sources along with the
%                  information required for mirroring. See [REF], section
%                  2.9 "Other server features" for more information.
% -q version       Displays the current version of the server.
% -t <object-type> Requests a template for the specified object type.
% -V<client-tag>   Sends information about the client to the server.
% -v <object-type> Requests a verbose template for the specified object
%                  type.
%
% [REF] RIPE Database Reference Manual.
%       http://www.ripe.net/ripe/docs/databaseref-manual.html
   whois的每次请求结束后,服务器会自动断开连接。
   有了上述的信息,我们就可以很简单去实现一个自己的whois查询功能了。比如,我这边针对单个ip的查询,就可以使用-l这个参数。
    具体就是,先创建和服务端连接的socket,
    然后通过socket发送"-l ip\r\n"给服务端
    读取响应,直到socket被关闭。
    具体代码就不贴了,非常简单,需要的同学,分分钟就写好了。