sulong 于 2010-07-14
9 篇评论 »
看过Servlet 3.0的规范和API后,可以看出来,所谓异步的HTTP,其实异步的不是HTTP,而是服务器端异步地处理HTTP请求,而HTTP客户端,仍旧是同步的等待服务端的处理结果。一般servlet容器会分配一个线程用来处理一个来自客户端的HTTP请求,在这个线程发送回HTTP响应之前,这个线程只属于这个HTTP请求不能离开处理其它请求。采用Servlet3.0之后,当前的线程可以开启异步处理,开启异步处理的时候会得到一个异步处理上下文对象,之后当前的线程就可以不生成HTTP响应而直接退出去处理其它的HTTP请求,其它线程可以在之后通过异步处理上下文来生成和发送那个HTTP响应。可见所谓的异步HTTP其实只是一种可以让当前的处理线程在不生成响应前就离开,而在之后再处理这个HTTP请求的机制。
从客户端看来,不论是哪种方式,浏览器都在发送完HTTP请求之后,都必须同步的等待服务器端的响应。假如浏览器发送完HTTP请求之后,可以在得到服务器处理结果之前转而处理其它事情,而在未来的某个时刻,当服务器处理完请求后,不需要客户端再发送请求,就可以发响应发回给浏览器,也许那才是真的异步HTTP了。但是这是违反HTTP的有请求才响应,无请求不响应的基本原则的。 HTTP长连接可以让客户端和服务器在同一个TCP连接中做多次请求响应,但是并不能改变客户端和服务器之间的同步请求响应模式。
尽管Servlet3.0的异步功能不能改变HTTP的协议,在本质上让浏览器和服务器之间异步的交互,但是这一功能还是有非常大的意义的。假设接受请求和发送响应的时间分别为Req和Resp,每个请求都要执行一个耗时P的操作O,并且O操作会让调用者阻塞,当在P时间内有n个请求发送过来时,用传统的处理方式,由于P时间内每个线程都不能处理完,servlet容器要分配F(n) = n个线程处理请求,如下图所示:

而用Servlet3.0的异步处理时,处理线程可以开启单一线程去做那个耗时P的操作,而把当前请求的异步处理上下文放入一个等待队列中,自己则接着处理其它的请求,假设这个开启异步,加入异步处理上下文的操作需要时间A,那么需要开启F(n) = n*(A+Req+Resp)/(P + Req + Resp) + 1个线程就可以在P时间内处理完所有请求。如下图所示:

假如执行操作O可以不阻塞,耗时C就返回, 那么n客户端每获得一次资源,需要发送f(n) = n*P / (Req + C + Resp) 次请求,而用异步处理的时候,只需要n次请求。可见当A足够小于P时,O阻塞访问时,异步可以用更少的线程处理更多的请求;O非阻塞访问时,异步可以减少请求次数。
以web QQ为例来看看。用户发送消息时,假设服务器分发消息耗时P远远大于开启异步和把消息放到待分发队列的耗时A,那么采用异步处理发送消息,可以用更少的线程处理更多的发送消息请求。用户接受消息,假设平均P时间内用户才有新消息到达,而检查一次新消息的耗时远小于P,那么采用异步则可以减少很多客户端请求。
sulong 于 2010-06-29
2 篇评论 »
1 什么是异步
异步显然是和同步相对应的。同步调用,被调用者要执行完所有的代码才将执行流程交给调用者,在被调用者执行的过程中,调用者只能被动的等待;而异步,则是被调用先将执行流程转给调用者,然后自己再继续执行。如果调用者必须在得到被调用者的所有执行结果才能确定下一步该做什么的话,那么这种情况就该使用同步调用;相反,如果调用者不需要被调用者的执行结果,那么就可以使用异步。
2 怎样异步
在单线程或单进程等单一执行流程的情况下,实现不了能让被调用者个调用者并发执行的异步调用,这种情况下被调用者只能先将要执行的任务环境记录下来,带调用者执行完成后,再回头来执行之前要执行的任务,这样的方式其实算不上是异步,称之为推迟执行更贴切。
在多线程或多进程环境里,才能真正的实现异步,实现调用者和被调用者并发执行的异步调用。被调用者只要开启一个新的线程在新线程里执行任务,而立刻返回让调用者在当前线程继续执行,这样就可以实现异步调用了。
借助于ejb 3.1 , spring 3, seam这样的容器和框架,实现异步调用的方法非常简单,只需要再方法上加上指定的Annotation就可以了。使用spring 2的时候,可以注入taskExecutor,用taskExecutor.execute(Runnable r) 方法来实现异步。另外,通过JMS也可以实现异步。
3 异步有什么好处
说异步比同步调用性能好并不准确。假设 被调用方法里面要完成两个任务,分别耗时 t1和t2,从开始调用到调用返回的耗时,即响应时间,同步调用的时候,Rs = t1 + t2,异步调用的时候Ra = t1 + a1,其中a1代表为了异步调用开启新线程或新进程的耗时,如果要Ra < Rs,显然要求a1 < t2,可见如果异步执行的任务并不比启用异步执行耗时太多的话,异步执行也不会缩短响应时间。如果计算完成同等任务的总耗时的话,同步的时候 Ts = t1 + t2,异步的时候 Ta = t1 + a1 + t2,可见Ts < Ta,此时异步没有任何好处。在要求响应时间非常短的互联网应用中,合理的采用异步可以提高响应速度,提升程序的负载能力。快速的响应用户的请求,将耗时多而用户不急于知道结果的任务交给有限的线程来执行。
然而,对于Java EE这样的环境,一个事务的边界往往是在一个线程里的,所以使用异步之后,就失去了事务的保护,异常后的数据补偿工作增加了程序的复杂性,也让程序更容易出错。一个不好的异步实现机制,往往给程序带来更多的隐患。比如,为每一个异步执行的任务都新建一个线程,很可能在并发数到一定程度的时候,由于创建过多的线程,达到性能瓶颈,甚至于导致程序崩溃。
4 什么时候用异步
首先只有调用者不需要立刻知道结果的任务才能被异步执行;其次被异步执行的任务耗时多于使用异步执行本身的时候,采用异步才值得;再次,要求响应时间短的时候采用异步才有意义。
典型的例子:用户支付订单后要立刻告知用户支付是否成功,并给用户发送邮件,通知仓库发货,告知物流送货。这种情况下,用户只要知道支付成功就行了,发送邮件等任务用户可以过会再感知到,而且发送邮件等任务很耗时,用户肯定不愿意等待完成所有一切之后才知道支付结果。这种情况下,将发送邮件等任务异步执行就很合适。
另外一个例子,A,B两个系统每隔一个小时对一次账,如果B发现账户和A系统不一样,则自动调整。尽管A不需要知道B的调整结果,但是A完全可以等待B执行,反正也没人等也没人急,而且对账频率低负载低,这种情况下就没有必要异步执行调整动作。
sulong 于 2010-04-27
9 篇评论 »
Qcon北京3天的会议终于结束了,对我来说,失望大于期望。我本希望在这次大会中感受到技术的趋势,学习到别人的成功经验,但是结果发现,大会的主题受限于时间,很多内容不能展开,说成功经验的不够深入,泛泛而谈,说技术趋势的变成了广告。
这三天里面,我觉得只有三人的四个演讲很有用。
首先是Michael Nygard的《失败来临的征兆》,讨论了软件故障方面的问题。软件故障总是不可避免的,QA也不能排除所有的软件故障。作为架构师,应当考虑到万一故障发生,如何记录故障,如何防止故障产生的影响扩散开来,如何故障恢复。在如何避免故障方面,Michael也给出了很多经验,比如,集成点给系统带来潜在的故障点,每个集成点都不可信任,测试环境和生产环境的服务器配比不同,导致特殊情况下产生故障,等等。我觉得这个演讲好,是因为他就软件故障这一方面给出了有用的指导意见和很多经验之谈。而且他的某些观点让我觉得也共鸣。我已经在实践中感受到了这方面的问题,但远没有Michael总结得那么完整。
其次是Marc Kwiatkowski带来的有关facebook使用memcache的演讲。这一演讲非常的生动,演示稿里有动画效果,可以直观的展示在使用memcache时遇到的问题和解决方法。精彩之余,又觉得facebook这帮人,好像就是在用php+memcache做一个分布式的缓存,在java领域这一问题可能相对被解决的比较彻底,如果当初facebook用java,而不是php,可能就不会那么费力了。正巧,后来萧百龄《性能和可扩展性再度归来:内存数据网格》的演讲就给我们演示了如何用oracle的Coherence实现一个支持每天数百万交易的赌博网站的例子。
最后,也是这三天里最精彩的两场演讲,是由thought works的首席架构师Jim Webber带来的有关REST的演讲。他的演讲不仅主题突出,而且生动有趣。他给我们带来的结论是,REST在处理非实时的系统集成任务时非常有用。迷信复杂中间件和把REST看成简单的beautiful url + CRUD的人,应当看看他的这两个演讲。
可惜PPT要到两周后才能拿到,到时要再仔细看看了。
另外,本次大会里还有一些有趣的小插曲。大会组委会会在演讲结束后,在会场外一面墙上贴上演讲者头像和其演讲内容的纸,然后听众可以通过在纸上贴笑脸和哭脸的方式来评论该演讲。在微软的演讲后,一帮听众用哭脸在墙上贴出了个Microsoft囧的字样,还纷纷留影。不过后来这个microsoft还是被大会组委会给撕掉了。没有人愿意化那么多钱,大老远跑到北京,听微软一个销售经理做广告。希望infoq以后不要再搞这种东西了。
sulong 于 2010-04-13
1篇评论 »
这已经不是第一次招聘程序员了,每一次都很痛苦。以前只知道找工作不容易,现在发现招工也不容易。招聘就像找对象一样,明明满世界的男人女人,就是找不到你合适的人。
合适的人不是牛人,对于我们这样一个不算太有钱的普通电子商务私营企业,不需要那么多的牛人,也养不起那么多的牛人。除非有非常牛的领导,否则一堆牛人在一起可能只会做出烂事。而且牛人们要做牛的项目,否则没有满足感,会离职的。我就遇到过一个毕业生,觉得自己牛,要做“高并发,高访问量”的程序,才来几天就走了。所以如果你被招聘方拒绝了,也许是因为你太优秀了。
招聘的效率太低了。每次发出招聘启事,都可以收到大量的,不对,是巨量的简历。尽管人力资源部的同事们已经依据其它条件过滤掉了大量不合格简历,仍有数十倍于目标招聘人数的简历到我这里来。经过精心过滤后,去掉近四分之三的简历后,剩下四分之一的要面试的人还是很多。假如要招聘2个人,人力资源部的人过滤后剩100人,再过滤后剩20人面试,只有4人能通过,2人薪资谈不拢,只有2人留下,一年后可能有一人离职。招聘就是这样低效率。
因此,我很希望能招聘到能安心工作的程序员。如果一个程序员的简历里,工作时间不长,却去过很多公司,每家都工作时间不长,那我一定不要他;相反,如果有人能在一家公司里安心做过很多年,那我一定要给他个面试机会
面对众多的简历,我到底要面试那些人呢?我一般是按以下步骤筛选的:
- 先去掉不满足硬性条件的,比如薪资要求过高,学历过低,工作经验太少。
- 去掉一看就觉得不想要的,比如跳槽频繁的,经历过于复杂的,一看就狗屁不通的。
- 挑出一看就喜欢的,比如项目经历很符合我的要求,简历中有闪光点的。
- 去掉平庸的简历。
- 最后从剩下的简历中选出几个较好的凑数。
所以,为了以后简历好点,要慎重对待现在的工作,不要给以后的简历留下污点。然后努力在自己平日的工作中寻找闪光点,计入将来的简历。如果没有污点,也没有闪光点,那就要让自己的简历不平庸。什么样的简历是平庸的?冗长而空洞,短小而无物。简单说,简历的目的是要让招聘者看了后想应聘你,而不能说明为什么人家要录用你的简历,不论多长多短多夸张多好看,都是空洞无物的。如何让招聘者想录用你?首先,要体现你渴望得到这份工作;其次,要说明你如何能胜任这份工作。要做到这两点,就要重视每一次应聘,最好对你要应聘的公司做事前的了解,为要应聘的职位定制简历。一份简历,巨量投放,随叫随到,即时发挥,成功率肯定很低,失败多次后就没有底气,越来越不行。我看了大量的简历,把以前做的项目的模块功能罗列了一番,对自己在项目做过什么,得到什么,有什么想法,寥寥数语,甚至只字不提,这样的简历如何能让我了解你做过什么,能做什么,想做什么?我又如何敢录用你?
我真希望每位应聘者都能认真对待自己的工作和简历,那样无论是应聘者还是招聘者都会方便很多。