Posts Tagged ‘思考’

软件的质量属性

June 17th, 2009

1 软件的质量属性

如果要我们描述一个人,我们会说,他的年龄多少,性别是什么,姓名是什么,等等。这些年龄,性别和姓名等,就是一个人的属性。类比的,软件也有属性,本文将讨论一下和软件质量相关的一些重要的属性。

2.1 正确性(Correctness)

正确性是软件最基本,最重要的属性。他代表了这个软件能够正确的执行计算并给出用户正确的结果。如果软件不能保证正确性,那么这个软件将没有价值可言。比如,一个总是计算错误的财务软件,显然是没有任何用处的。对小型的,功能单一的软件来说,正确性是显而易见的,要么正确,要么不正确。但是对于大型的复杂的软件来说,衡量正确性的标准都相当复杂或不确定,所以正确性本身也不是个简单的是和否的问题了。需求不等于正确性,需求不仅要求正确性,还会要求其他属性,如性能等,需求也不一定要求100%的正确性,只要计算结果对于最终用户来说是可用的就可以了。

2.2 有效性

有效性是指软件能在有效的时间内给出计算结果。一个无效的软件,即便其必然能得到正确的结果,也是无价值的。比如,穷举法总是正确的,但是在解决某些问题时,穷举法并不能在有效的时间内给出结果。如果一个用来预报明天天气的软件,却要在后天才能算出明天的天气情况,即使算正确了,也是没有意义的。

2.3 可用性(Availability)

可用性和有效性是对正确性和和有效性的一个综合,一个正确而有效的软件,才是可用的软件。如果在一段里,一个软件总能在有效的时间里给出正确的结果,那么这个软件在这段时间里就是可用的。而高可用,就是说一个软件可以在相当长的时间里保持可用性。

2.4 健壮性(Robustness)

在异常状况下,软件仍能够保持可用性,被称为健壮性。如果一个软件,由于输入数据不正确,或者运行时发生了些不正常状况等,就立刻崩溃,以致于不能再工作,显然是不健壮的。相反的,在这样恶劣的情况下,仍能够工作,则是健壮的。

2.5 可靠性(Reliability)

可靠性是指一个软件能在很长的时间内保持可用。一个健壮的软件,显然能提可靠性。对于某些持续提供服务的软件来说,高可用是很重要的。比如,网络服务器,我们往往需要它7×24不停的可用。通过故障恢复等措施,可以提供软件的可靠性。

2.6 容错性

容错性是指软件能够自动的纠正错误的输入,得出正确的结果。比如大部分的浏览器,都能够解析不是很严格正确的html。容错性可以提高最终用户的用户体验。

2.7 性能

直观的说,性能就是软件快不快。但是仔细考虑的话,可以把性能分成很多更细的属性。

2.7.1 效率

在完成相同的计算任务时,软件占用越少的CPU时间越少的内存空间等计算资源,性能越高。换句话说,在相同的计算资源的条件下,完成的计算任务越多,效率越高。效率就是软件利用计算资源的能力。

2.7.2 响应时间

响应是软件对用户操作作出回应的速度。用户使用软件时,犹如和人交流,快速的响应,犹如和用户对答如流,会让用户更加的开心。比如,点击开始按钮后,出现一个显示计算进度的进度条,要比立刻全屏锁定,不让用户做任何操作要好多了即使后者可以更快的完成所有的任务。

2.7.3 吞吐量

单位时间内,软件能处理的数据量,或任务量。比如,一个网络服务器,单位时间内内够处理的http请求,和生成的html的数据量。吞吐量侧重于从输入输出上衡量软件的性能。

2.7.4 负载

负载是软件能承受的访问压力的能力。同样以网络服务器举例,能同时支持越多的用户访问,负载能力就越强。负载和吞吐量不完全相同。吞吐量很高,比一定能支持很多人访问;相应的,负载很好,单位时间内的输入输出可能并不高。

2.8 可伸缩性

在不修改,或者很少修改代码的情况下,通过添加硬件计算资源就可以提高软件整体性能的能力。对于大型的服务器软件,可伸缩性是很被重视的。理想情况下,系统的计算能力能随着硬件的添加而线性增长,很可惜,没有软件能达到这一程度。大部分软件在设计之初并没有考虑到可伸缩性,根本就不可伸缩,而另一些软件,增添硬件会使性能下降,或降低可靠性。

2.9 安全性

软件保护重要资源免受非法访问或恶意攻击的能力。安全性对于某些软件来说是非常重要的,对于另外一些软件来说则不那么重要。安全是一个复杂的工程,往往和整个软件运行环境相关。

2.10 适应性

软件不需要修改,就可以在别的环境下运行的能力。适应性高的程序,在设计之初就要考虑到软件可能运行的各种计算环境,并做好相对的准备。这样在程序生成后,不需要修改就可以在不同的环境下运行。

2.11 可移植性

将软件从一个环境下迁移到另一个环境下运行的能力。为了实现可移植,要抽象出软件所依赖的计算资源,在这一抽象层之上开发。移植时,只要修改抽象层在别的环境下的实现,而不必修改其上的部分。

2.12 一致性

软件的结构一致,是指软件用相同的方式处理相同的问题,用相同的符号表示相同的概念。一致性给程序带来美感,使程序更简单。一致性差的软件,就像被混淆器混淆过,最终只能使程序失去生命力。

2.13 可读性

软件代码可以被阅读和理解的能力。除了正确和有效,可读性可能就是我们最关心的属性。可读性好的代码,即便有缺陷,还有修正的机会,相反,犹如天书一般的代码,不能进化,没有前途。一致性可以提高可读性。

2.14 可扩展性

在尽量不修改原有代码的基础上通过添加新的代码而修正缺陷,实现新功能的能力。扩展性要求程序在设计之初就考虑到程序的哪些地方将来可能需要扩展,并留下余地。

2.15 可测试性

程序对测试方法和测试工具的友好性。容易测试的程序,在变动之后才容易验证其正确性。

2.16 可维护性

软件投入生产后被维护的难易程度。理想状态下,软件在投入生产后不需要停止服务,只要修改少部分代码,就可以实现新的功能需求或错误修正。一致性好,可读性好,可扩展性好,可测试性好的软件拥有更好的可维护性。一个上线后不久就没人看得懂源程序,修改一个小bug就要牵一发而动全身,修改后不知道其他功能能否正常运行的软件,是维护人员的噩梦。

2.17 易用性

指最终使用者学习和使用软件的难以程度。

3 属性间的相互影响

以上列出的各属性并非相互之间没有关系的,有些属性的提高利于其它属性的提高,而有些属性的提高则会降低其他属性。比如,程序中做了很多便于用户使用的计算工作,必然会降低程序的吞吐量;为了提高代码效率而使用各种小技巧导致代码难以阅读和理解;越容易阅读的代码,越容易扩展,越容易维护,等等。具体它们之间是怎样的关系要具体问题具体分析。

4 小结

软件的众多属性可以分成内在和外在两大类。内在属性是用户感觉不到的,而外在属性是用户感觉得到的属性。比如正确性和响应速度是用户感觉得到的,但是可扩展性和易读性用户就不知道了。我们应当在满足外在属性要求的同时提高内在属性,不能外表光鲜,内里脏乱。不同的软件,不同的场景,对不同的属性的要求是不同的,而且这些属性也有相互冲突的,因此我们不可能兼顾所有,只能抓住主要矛盾。一般情况下,正确性,有效性和易读性是最重要的。

  • Share/Bookmark

如何保证jms消息的顺序性

June 3rd, 2009

JMS提供的queue和topic两种工作方式,其中queue能保证消息在传输中的顺序性,这是队列先入先出(first in first out)的特性。JMS本身不能保证多个队列里的消息的顺序性,比如 先放入queue1的消息m1,并不一定总是比后放入queue2的消息m2,先到达同样的目的地。

并发地发送和接收消息不能保证消息按正确顺序进入队列和被消费。比如,有两个线程分别发送创建订单和支付订单消息,由于线程运行的不确定性,即使我们按顺序先开始发送创建订单的线程,后开始支付订单的线程,如果两个线程开始时间间隔不够长,还是有可能后开始的线程先发送掉消息。同样的情况发生在并发的接收处理消息时。

那么如何保证消息的顺序性呢?

一种方案是,乱序接收,顺序处理。也就是说,消息在发送,传输和接收过程中可能是乱序的,但消费者在接收到消息之后,并不立即处理,而是先将消息排序,然后在处理。JMS消息头部的 JMSCorrelationID可以帮助我们完成这个工作。JMSCorrelationID存放了另一个消息的id。消息的发送者,如果要保证消息的顺序性,要将后发送的消息的JMSCorrelationID设置成前一个消息的id。消费者接收消息后,如果发现其头部有JMSCorrelationID,则查看该消息是否已被处理过,如果没有,则等待该消息,至到该消息被处理后,才处理这个消息。这一工作需要发送者和接收者都记住已经发送和接收过的消息,以便于给后来的消息参考。

另一种方案是,顺序发送,顺序传输,顺序接收,顺序处理。其中传输可以由queue来保证,但是发送接收和处理则需要应用程序来控制。简单的说,直到前一个消息发送成功,才能发送后一个消息,同样的,直到前一个消息被接受和处理结束,才能接收和处理后一个消息。这样的做法无疑会降低并发带来的好处。

以上所说的方案,是用来严格控制消息的顺序性的,然而,如果消息的发送的间隔时间足够长,不需要做过多控制,也可以控制消息的顺序性。假设,一个消息正常情况下,由发送,传输,接收到处理成功,最大时间耗费是2秒,那么只要我们保证消息发送的时间隔达不低于2秒,那么这两个消息就可以被正确的处理。这一条件咋听起来很苛刻,但事实上大部分的消息都满足了。比如,同一个订单的创建,和请求支付,最快也要数秒的时间,而退款的开始和结束,可能要数天。在典型的web应用中,操作人员不可能那么快的点击系统,而系统也不可能那么快的响应。进一步的,如果两个需要顺序处理的业务事件可能在极端的时间里连续发生,我们只要在程序上控制,人为将间隔拉开,就可以保证顺序性。

在系统的各各环节控制消息的顺序,代价高昂,而带来的好处却只是针对那极少数极端情况;通过业务或程序的方式,保证消息的有效时间间隔,代价较小,也能有效保证顺序。

如果系统中有很多的间隔极端,又需要保证顺序的消息,那你就要考虑是否将这两个消息合并成一个,或则不该采用jms了。

  • Share/Bookmark

企业应用集成–引入ESB

May 11th, 2009

随着时间的推移,一个企业的业务会越来越复杂,企业应用越来越多,应用间交互越来越复杂。新的应用的开发,耗在集成的上的时间和精力越来越多,而且集成也成了bug最容易发生的地方。如果不能很好的处理好集成问题,开发将很难再进行下去。

如果每个应用之间直接通过jms或http连接,应用数为N,那么最坏情况下,共有N(N-1)/2个连接,随着N的增长,应用间的连接越来越多,集成越来越累。如下图所示:

struct_without_esb

这个时候使用ESB,可以是系统从网状结构改成总线结构。如下图所示:

esb

每个应用只要做好和ESB的连接,这将大大的降低系统结构的复杂度。ESB将负责路由应用间的消息。路由功能是ESB一个强项,不通过写代码,只要改改配置文件就可以实现简单的简单的路由规则。在网状结构中,每个应用负责决定消息是否发送到什么地方。比如,如果app1需要将消息发送到app2和app3,那么他要主动的和app2,app3连接,发送去消息。而在esb结构中,app1只需要把消息发送到esb上,由esb负责将这个消息路由到app2和app3。这样应用更关心和消息相关的创建和消费的业务功能,而不用关心消息的路由,而esb只关注消息的路由,却不用关注具体的业务逻辑。这样的关注点分离是很有益的。

另一方面,esb支持众多的协议,不仅支持jms, http,还支持比如corba, esb等协议,可以方便的和应用连接上。esb还内置的消息格式的转化内容的增强等功能。这样,app1, app2可以通过不同的协议连接到esb上,而且app1发送的可以是某种二进制报文,而app2接收的却是xml,不同协议的桥接,不同消息的格式和内容的差异,都可以在esb中弥补掉。这一能力对于集成遗留系统非常很有用。

可见esb让应用系统更关注于业务逻辑,而把路由,消息格式内容的转化和不同协议的支持等功能放到统一地方,几乎就是专门为应用集成而生的。

  • Share/Bookmark

企业应用集成–java

April 28th, 2009

java企业应用最终往往运行在某种应用服务器中,比如tomcat,jboss等。部署的单元是war, jar 或者 ear文件,开始的时候,我们可能会将多个应用放到一个单元里来开发管理和部署。随着应用的增多,为了能够让每个应用能够独立的运行不受干扰,也为了开发工作能很好的安排,往往会将各应用分开,于是会有多个war, jar,或ear文件。试想一下,假设你有订单系统,产品系统,客服系统,等,如果这些应用都被放在同一个部署单元里,当需要更新客服系统时,会短暂的导致订单系统不能正常工作,而这种情况往往是不能被接受的。另外,如果客服系统非常繁忙,由于部署在同一台物理服务器上,共享硬件资源,订单系统会受到干扰,而这也不是我们想要的。将单独的应用单独打包,单独部署成为必然。那么就面临着让这些应用通信,将它们集成的问题。


与java和php之间集成相比,java与java之间的集成,不仅可以使用共享数据库,soap,或基于http的简单的文档交换,还可以使用jms,rmi等多种方案。其中jms是j2ee众多的标准中最为成功的协议之一,很少有人针对它发表过不满意见。我们在工作中就采用了jms。和http相比,它有如下优势:

为java量身定做的

jms不仅可以传输普通的字符串,还可以直接传输java对象,并和java的其它服务结合起来,接口api也符合java的使用习惯。如果用http,我们还得要考虑如何把对象序列化等问题,比较麻烦。

使用长连接

http主要用在客户端和服务器交互上,为了能让服务器支持大量的客户端,http往往都以一种无状态和短连接的方式工作。而jms主要用在java应用之间的交互,不需要支持那么多的客户端,用长连接更加适合。典型的http服务器,可能同时要给数千数万人提供服务,如果服务器和每个客户端保持一个连接,那对服务器来说,显然是一个非常大的负担。所以,通常客户端和http的一次交互完成后,连接就断开,而下次访问时,还得要重新建立连接。jms服务器面对的客户端一般只有几个,至多几十个,和每个客户端保持连接的开销是可以接受的。典型的企业可能有如下系统:订单系统,产品系统,结算系统,等等,这些系统,每个都和集中的jms服务器保持一个连接,总连接数也是很少的,所以可以保持长连接。这客户端和jms服务器通信的时候,不必每次都建立连接,减少了网络操作,提升了性能。

异步

http操作的过程是同步的,如果要使用异步的方式工作,需要程序员再做些编码工作。而jms天生就以异步的方式来工作的,不必做过多的编码。消息的生产者一旦把消息发送出去,就可以立刻返回不必等待消息的消费结果,后续的消息消费可以自动的异步执行。将不必要立刻执行的动作异步执行,可以大大降低系统的响应时间。

可靠的消息传递

在使用http通信的过程中,如果发生了网络异常,是否要做重发,以及如何重发,会是一件很痛苦的事情。jms提供了persitent的传递模式,在这种模式时,客户端代理在发送消息之前,会先把消息持久,如果发生网络异常,客户端代理会自动处理重发,而不需要应用程序关心。jms消息的唯一编号,可以有效的阻止一个消息被重复处理的问题。

在java应用集成时,jms比http更适合。成熟的jms服务器软件很多,除了ibm的mq,jboss mq, apache activemq 都是很不错的选择。

  • Share/Bookmark