【日志归档】 06月, 2008

星期一, 06月 30th, 2008

良好的编程习惯是成长的助推剂



近来看到、听到一些很小的问题,却导致了系统故障(甚至更严重的问题)。

  • 案例1:等号(==)导致的损失
  • 案例2:少传递一个参数导致的损失
  • 案例3:默认返回结果的乐观,导致的损失
  • 案例4:偶然停止的一个系统,导致系统停机
  • 案例5:2个参数没有设置,导致外部系统故障的内部传递
  • 案例6:大小写,导致某类业务失败
  • 等等

事后看这些问题,发现都很简单,都是由于程序员的粗心导致的。或有有人会说,我们应当允许犯错误,我也是非常认可的,但对于一个企业来说却是非常可怕的,上百个程序员,每人都犯一次这类错误,恐怕企业会有些受不了。
如何规避这些问题哪?

  • 制度保证
  • 测试保证
  • 程序员良好的编程习惯

通过下面几个例子,简单说明良好编程习惯对成长的助推作用。
首先,通过观察,发现上面所列的问题,都是一些编程习惯导致不是很好的人身上发生的。
其次,通过和一些同事交流,虽然他们自己没有遇到过这类问题,但良好的编程习惯帮助他们避免了这类问题以及克服了其它困难。
再次,同样一起进入公司的新毕业的学生,工作时间、加班时间也一样多,1年后,发展却非常不同。通过观察,我发现:排处天然因素,后天因素中很重要的一点就是良好的编程习惯帮助他们获得了成长。
良好的编成习惯包含很多方面,综合我身边这类人的特质,总结了下面几点:

  • 坚决按照业界认可(或公司认可)的编程风格编写代码
  • 开发、调试、测试过程中遇到的问题,不是简单的解决问题,而是进行深入的思考,挖掘现象背后的基础层面的东西
  • 对于别人、外界出现的一些BUG,不是简单的听听即可,而是进行试验,思考
  • 对于别人无法解决的BUG,总是尝试各类方法,不解决问题,决不罢休
  • 不断总结-〉实践-〉再总结

【参考文章】
程序员如何成长?
程序员的成长从开窍开始系列 一、如何摆脱低级错误的困扰



星期日, 06月 29th, 2008

SOA是可持续的战略,不是一次项目



常常听到如下关于SOA的说法:

  • 我们完成了SOA化改造。
  • 我们的SOA化,已近实现了80%。
  • 这次项目是为了实现SOA化,因此要请有这方面经验的公司来实施。
  • 从技术角度层面来说,我们达到了SOA化的目标。
  • 这是我们最后一个SOA个项目
  • 等等

如果这些话出自程序员,项目经理等人员,也是无所谓的;如果出自IT管理层的人员,哪就是一种可怕的想法了。因为他把SOA仅仅看作是一次项目了,而没有把它作为战略。这样的后果也是可以预见的,最终本次投资将会失败。
因此,建议那些准备实施SOA的公司,首先回答这个问题:SOA是贵公司的一个战略吗?
为什么要回答这个问题?

  1. 从SOA概念来看
  2. 关于什么是SOA,我有几篇文章,可以参考(《这些都不是SOA》,《ESB产品升级准备:SOA、ESB、JBI、SCA、OSGI概念再学习、再理解》,《SOA,想说爱你不容易》)。丛概念上可以看出,SOA不少技术问题,它是一种思想,一种架构,因而不可能通过一个项目就把这种思想或架构完全实现;思想也是会发展得,今天的思想在明天或许就会不适应。

  3. 从SOA目标来看
  4. SOA的目标是解决业务敏捷性问题。如今,大环境复杂多变,任何一个公司都不敢说自己的业务就是这几个、自己的业务会一直不会变,很多企业,在很短的周期内,就会推出各类产品(特别是服务类企业,例如:银行、互联网企业等)。只有那些能够快速适应变化,主动寻求变化的企业才能够生存下来,发展起来,例如:会跳舞的大象IBM,IT行业最大的特色就是变化快、发展快,如果IBM的业务不能敏捷的适应这种变化,它还能跳舞吗?正因为IBM深刻理解了SOA的目标,因而它把SOA看作一种战略–可持续的战略。

  5. 从IT管理角度来看
  6. 对于IT主管,一定要确保本公司的IT战略是可持续的,不能今天一种想法,明天又看到什么好思想,就换了一种想法,或者换个主管,就彻底换了战略(这种做法,就像我们国内的城市建设,路总是修不好)。既然从一种思路切合到了SOA领域,那么再次切换的成本将会更高,也不可能多种思路同时进行(吃得多,嚼不烂)。此外,谁能保证一次项目就确保几年内业务变化的需要?从我们实施的经验来看,必须持续的进行SOA化,才能确保SOA持续的发挥效果。

  7. 从系统分析角度来看
  8. 每次项目都要进行系统分析,都是基于当前的业务进行,那么不可避免的就会有一些盲点(从认知的角度看,人不可能一次就抓住事物的本质,何况大多数系统分析员不具有这种能力)和不合理支出。这些问题,只有在实施后一段时间才能发现(我们自己的实践经验);此外随着补丁的实施,原有的系统已经恶化,和最初的SOA化目标越来越远。此时,如果不能再次用SOA的思想重新审视系统,就将彻底失去了SOA带来的好处。

  9. 从技术特征来看
  10. SOA非但不能让系统架构变得简单,反而变得复杂了(系统设计要求变高了、系统部署复杂了、发布复杂了、各类SOA相关技术的引入增加了对人员的要求),这也是为什么要引入SOA治理。从这一点来看,只有持续的SOA化,才能最终发挥SOA技术架构的好处。

再次提醒将要进行SOA化的朋友和已经进行了SOA化的朋友,把SOA当作贵公司的可持续的战略来看,而不要认为它紧紧是一次项目。



星期日, 06月 29th, 2008

Java Enum小心使用,它可能增加系统耦合性



关于在SOA环境中使用Java Enum的一些经验已经在《服务化的行军中:Enum使用,快乐的痛苦》一文中进行了讲述。
随着项目的深入,在某些环节使用Enum的不爽之处,上升为一些设计方面的选择问题。

  • Enum不适合作为通用类的属性来使用
  • 在我们的代码中,我看到如下一个情况,有关类:UserPrincipal,它被整个分布式系统中的所有系统共同使用,从包的放置位置:net.esbzone.comm.security就可以看出它的通用性。突然某天,看到有同学在这个类加入了一个Enum属性,这个Enum属性还是另外一个业务系统B内部定义的一个通用常量【这个常量的确很是通用,表示用户类型】。这个例子,首先导致UserPrincipal与业务系统B产生了紧耦合,间接导致所有系统与业务系统B产生了耦合;其次即使它定义在net.esbzone.comm.security包中,也间接导致UserPrincipal与具体业务产生了关联,会增强外部系统对Enum的耦合度,从而削弱了UserPrincipal的独立性;此外一旦Enum发生变化,所有依赖与它的业务系统都要发生变化,代码依赖级别的变化。
    往往,Enum的业务语义太强,与场景的关联性太密切,一旦环境发生了变化,Enum的值就可能发生变化,从而导致使用它的业务域对象也可能要发生变化。
    使用Enum作为通用类的属性,制约了该类的通用性。
    【注意:】在封闭系统内部是非常适合使用Enum,它会增强代码的可读性,减少维护成本,降低风险。

  • Enum不适合作为服务接口的参数来用
  • 首先是序列化的风险。
    其次Enum增强了系统的耦合性,如果只是接口耦合,那么可以通过WS,HTTP POST等方式来降耦。如果使用了Enum之后,我们进一步增加了对Enum这种特殊类型的处理【大部分标准化协议和现代变成语言,都支持原子类型,对象类型,集合类型,但对Enum的支持却各有所不同】,这就增加了耦合性。此外,此时对于一个使用者要面对多个服务提供者的时候,如果遇到这种情况就会更加痛苦不堪。
    再次,Enum在接口层使用,制约了扩展性。当增加一个新的业务常量时,需要修改Enum,此时它的WSDL文件也会发生变化【这点很头痛】,想到于修改了接口描述文件。
    最后,我们从业务协议设计的角度来看,我们需要的只是原子数据类型,而不是Enum这么强的一个对象类型。



星期六, 06月 28th, 2008

故事集合



六十八个超级经典MBA管理小故事
管理小故事精髓百例
让你受益匪浅的管理小故事20则
管理中的心理学
管理小故事100例
豪猪的距离–哲学小故事
翠絲特的小空間



星期五, 06月 27th, 2008

SOA实践之:在程序层,面向服务的设计准则探讨



在面向OO领域有10几条设计准则,那么这些是否都能够延续到SOA领域的服务接口设计层哪?下面列出本人实践过程中,认为能够继续适用的一些原则:

  1. SRP 单一职责原则
    就一个服务接口而言,应该仅有一个引起它变化的原因。
    职责即为”变化的原因”.
  2. ISP 接口隔离原则
    不应该强迫客户依赖于他们不用的方法。接口属于客户,不属于他所在的类层次结构。
    多个面向特定用户的接口胜于一个通用接口。
  3. REP 重用发布等价原则
    重用的粒度就是发布的粒度.
  4. ADP 无依赖原则
    在包的依赖关系中不允许存在环.
    细节不应该被依赖.
  5. IDP(Interface Design Principle)接口设计原则
    规划一个接口而不是实现一个接口。
    其它一些可以参考的点:

  • 放弃程序级别的OO概念。
  • 业务的粒度就是接口方法的粒度。
  • 接口方法尽可能简单、清晰、业务含义明确。

在实际应用中,按照这些准则,我总结了一些具体需要需要的点:《SOA实践之:在程序层,服务接口设计的一些准则》【对于这篇文档,会随着实践而不断补充】

【参考资料:】
面向对象设计准则
override, overload, covariance
OO基本概念



星期五, 06月 27th, 2008

SOA实践之:Java服务接口设计的一些实践准则



在SOA领域,一些OO领域的接口设计原则具有很好的借鉴意义,但随着SOA化带来的分布式特性,有些东西就需要进行特殊处理。下面就我们进行SOA化过程中接口设计过程中,曾经比较容易出现过问题的地方进行部分总结。
【术语说明】

    服务与业务组件的定义:

  1. 业务组件:最小的业务逻辑单元,例如:密码验证组件、登录组件。
  2. 服务:业务模块提供给外部的核心业务逻辑,服务组合业务组件。例如:修改密码服务,会使用密码组件的验证服务,也会使用登录组件的修改密码服务。
  3. 【说明:】可否密码验证组件的功能合并到登录组件哪?可以的,此处之所以单独分离,与我们提供多种密码验证机制有关,登录组件对应的业务并未完全涵盖密码验证组件的功能。

  • 服务接口的方法,禁止重名(overload特性)。大多数序列化工具【例如:XFire】对重名方法进行处理时,都不可能避免的存在或多或少的问题。为了减少麻烦,还是放弃OO的这一特性,或者在面向服务领域,重载本身就不是一个特性。
  • 服务接口的方法,避免返回异常【我们是禁止异常,包括业务异常、系统异常】。这个要求看起来违反了一些对象设计的原则,从实际使用角度来看,具有如下好处:很多工具对异常序列化很容易出现错误;一不小心,外部使用者还会产生异常依赖;需要外部使用者自己把异常翻译为业务语义【从业务角度来说不是件好事情】。
  • 服务接口必须有清晰的文档说明,对于常量性质的参数,要列出支持的常量值。
  • 服务接口尽可能把查询和业务方法分离【非必须】。好处是使用AOP时简单方便,对于查询方法进行特殊处理时也比较方便,例如:与cache整合、与搜索引擎整合、与特殊权限要求进行整合(例如,对返回信息按照权限进行过滤)等。
  • 服务接口参数排列按照如下原则:操作主体对象或ID,业务参数{…},环境参数。
    例如:verifyPassword(String operatorId, String password, ServiceContext serviceContext)
    operatorId是操作主体的ID。
    Password是密码。
    serviceContext是环境参数。
  • 业务处理类接口,返回值可以采用统一对象模式。例如:ServiceResult:

    public class ServiceResult<T> implements Serializable {

    private static final long serialVersionUID = 760567785564620157L;

    private boolean isSuccess;

    private String resultCode;

    private T resultObject;

    public boolean isSuccess() {
    return isSuccess;
    }

    public void setSuccess(boolean isSuccess) {
    this.isSuccess = isSuccess;
    }

    public String getResultCode() {
    return resultCode;
    }

    public void setResultCode(String resultCode) {
    this.resultCode = resultCode;
    }

    public T getResultObject() {
    return resultObject;
    }

    public void setResultObject(T resultObject) {
    this.resultObject = resultObject;
    }
    }
    采用这种模式,实际是按照协议的角度进行设计,所有服务按照统一的包装模式返回。

  • 服务接口的参数避免使用Object类型,集合类型要指定具体对象类型。原因:当使用Object时,使用者获取到WSDL文件时,不知道该传递什么业务数据,如果是其它语言的调用者,更无法理解了;这类接口设计违反了业务SOA的原则,暗含着如下潜台词:业务上不明确的,不清晰的。
  • 服务接口避免使用集合类型,尽可能使用数组类型。
  • 服务接口中使用枚举的原则:如果是对外界发布,避免使用枚举;如果使用者众多,避免使用枚举;如果是内部几个专用系统使用,可以考虑使用枚举,可以参考《枚举产生的系统耦合性》。【文档的清晰化,可以化解常量参数不明确的问题】
  • 服务接口避免设计成面向数据的操作,例如:updateStatus。这类接口,通常包含太多的业务含义,甚至没有业务含义,需要外部使用者去理解业务内部的细节,否则无法进行操作。这也是我们设计服务接口时,需要特别注意的地方,不要让外部使用理解业务内部是如何存储的,结构是什么样的,这样会导致业务耦合度过高,服务内部发生重构,变化时,外部使用也需要进行变化。
  • 服务接口层建议设计一个统一的模板框架,来处理性能分析、特殊参数处理(例如:ServiceContext)、事务处理、异常处理、日志处理、事件处理、审计处理等具有共性的行为。
  • 服务接口的方法名避免以:is,get开头,用find,check等来代替之,避免Java序列化工具把该类当作Java Bean进行处理。
  • 业务组件中异常的要求:所有的业务组件,如果发现违法业务原则的地方,需要中断程序的执行,那么throw统一业务异常,该业务异常可以借鉴如下方式设计:
    public class ComponentException extends Exception {

    private static final long serialVersionUID = -6900280471536579015L;

    private ErrorCodeEnum code = null;

    public ComponentException ErrorCodeEnum code) {
    super();
    this.code = code;
    }

    public ComponentException ErrorCodeEnum code, Throwable e) {
    super(e);
    this.code = code;
    }

    public ErrorCodeEnum getCode() {
    return code;
    }

    public void setCode(ErrorCodeEnum code) {
    this.code = code;
    }
    }

    坏处:从异常名看不出明确的业务语义。
    好处:避免服务层需要捕获多种异常;业务语义通过ErrorCodeEnum返回到业务层。

  • 业务组件内部尽可能少的进行事务处理【除非有特殊的需求】、异常处理【除外业务组件自身组合了外部的业务服务,此时需要处理异常】。
    好处:统一由服务层进行处理,可以避免事务处理的错误。不进行异常处理,可以避免异常转义时,出现信息丢失;此外,如果使用了统一异常,那么就更不能在业务组件内部进行异常处理了,否则会发生原始业务限制规则被丢失的可能。

对于一些基本原则,可以参考《SOA实践之:在程序层,面向服务的设计准则探讨》一文。

使用方,推荐使用代理模式来使用外部服务。
1、可以进行一些特殊处理,例如:网络异常处理,远程性能评估等
2、对内部提供重业务层面的方法,屏蔽环境参数
3、外部服务接口发生变化时,或许修改一处就能够满足变化
4、如果要对传输层、安全进行定制时,会非常方便

【参考资料】
模块分解原理的探索
Interface Design — Best Practices in Object-Oriented API Design in Java
Part 1: Exploring the development, interfaces, and operation semantics of services
Part 2: Exploring the development, interfaces, and operation semantics of services



星期五, 06月 20th, 2008

双赢思维才能笑到最后



从前有个人一直在寻找机会,想要做大事情。有个客商对他说,在不远的海滨有块陆
地,一直延伸到海里很远的地方,他乘船来的时候,看到有大群的水獭在上面晒太阳嬉
戏,等到船稍近,水獭就纷纷潜入水中,不再出来。据客商估计,水獭的巢穴就在附近
的水下,如今水獭的皮毛珍贵,如果能捕捉到这群水獭,所获得的价值肯定会非常高。
客商最后表示,愿意和此人合作,一起做这个事。
  此人一听,怦然心动。可他转念一想,这事并不难做,我自己就能独立完成,又何
必与人合作?
  他找到一个驯养猎犬的商贩,想买猎犬去捕猎水獭。商贩向他推荐了一只训练有素
的猎犬,要价200两银子。可他嫌价格太贵了。再者,他觉得应该把面放得更宽一些,
不能将宝只押在一只狗的身上。于是,他以200两银子买下了5只普通的猎犬。
  他带着5只猎犬来到水獭出没的海滨,果然见有大群的水獭,见有人来,水獭就躲
到了水里。由于没有捕猎的经验,他让一只猎犬潜到水里追索水獭,隔了许久,都不见
猎犬浮上来,他又让另一只猎犬潜到水里。到最后,5只猎犬都没有再浮上来,200两银
子被白白丢到了水里。
  带着满腹的怨气,他丧气地回来,上门找驯养猎犬的商贩理论,认为他的猎犬不顶
用。商贩问清楚原委,觉得有大利可图,就说:“你带我去,如果我的猎犬无法捕捉水
獭而丧生水中,我自认倒霉不说,原来的200两银子也退还给你。但是,如果捕捉到了
水獭,得二人均分。”俩人就此达成了协议。
  俩人来到原处,商贩将价值200两银子的猎犬驱入水中。不一会儿,猎犬就浮了上
来,衔了商贩的一只鞋子,又再次潜到水里。又过了不久,猎犬叼着一只大水獭浮出水
面。已被咬死的水獭嘴里紧紧地咬着鞋子。猎犬接着又衔着鞋子潜入水里,如此往返无
数次,捕得了数十只水獭。
  此人大喜过望,心中暗自盘算,这些捕获的水獭即使与商贩均分,也足可弥补损失
的200两银子,且还有富余。这时,猎犬衔了一块石头上来。商贩说:“这样吧,前面
捕获的这些水獭全都归你,接下来得到的东西全都归我,如何?”
  此人见猎犬只是衔了一块石头上来,估计水下不会再有什么东西,即使有,也绝对
抵不了前面捕获的水獭的价值,就爽快地答应了。达成协议之后,商贩随着猎犬一同潜
入水中,居然捕获了比原先多出数倍的水獭。
  两人一同捕獭,可所获却是天壤之殊,商贩赚得了数千两银子,而一心想要独赚这
份钱的捕獭人,却只得到了数百两银子。
  事情传开之后,有好事之人依据细节研究良久,方才悟出其中的道理:水獭穴居,
若遇有敌来犯,强壮的水獭就会守在洞口担当护卫,掩护穴中的弱小水獭。捕獭人第一
次带着5只猎犬前来捕獭,由于不谙其中诀窍,一只一只地将猎犬放入水里,而猎犬又
太过平庸,遂全丧生在护卫的水獭口中。
  等到商贩带着训练有素的猎犬前来捕獭,猎犬聪明,在先下水打探了一番虚实之
后,每次都是衔着鞋子下水,护卫的水獭上来噬咬猎犬,猎犬就将衔着的鞋子凑上去,
趁水獭咬住鞋子不放的间隙,猎犬反伤其命。等到把所有的护卫水獭解决,猎犬就衔着
石头上来报告主人。商贩知其习性,于是临时修改了协议,把原来捕获的水獭都给了捕
獭人。捕獭人由于着眼于近利,未能通晓其中的关键,反而认为自己占了大便宜。等到
商贩下到水里,到洞穴中捕捉藏着的弱小水獭,犹如探囊取物一般,获利也因而多出数
倍。
  志大才疏的捕獭人,在自己并不熟悉的领域里,既没有足够的运作实力,又不肯接
受他人提出的利人利己的双赢选择,也不具备一分投入换一分收获的意识,而是抱着一
种侥幸心理进行投机。等到出于无奈与人合作时,又短视近利,以致丧失了获取更大利
益的机会。



星期四, 06月 19th, 2008

SOA架构之性能解决策略之一【引入Cache过程的思考点】



    采用SOA架构实现了业务的分离、重用、对BPM的支持。经过初步的测试,这种架构不能满足性能的要求【前提:SQL已经优化,数据库cache已经不能满足需求】,就当前的应用环境来看,引入cache是解决性能的一个办法,这也是比较通用的一个方案。
    目前网上已经有大量的cache实现,介绍cache原理,cache使用案例的资料。下面就我在使用过程中的一些思考点分享一下。
1. 在SOA系统架构的那一层进行cache
soa-arc
系统架构如图所示:可以在1、2、3、4、5每个点考虑增加cache。
在1这个位置采用cache,通常采用Apache相关的cache扩展。
在2、3、4这些位置采用cache,可以使用本地cache,或者远程cache。例如:ehcache、Memcached等。
在5这个位置,可以通过增加服务器内存,调整数据库cache;或者通过数据库伸缩性实现性能提升。可参考该文《大型网站的架构设计问题—-大型高并发高负载网站的系统架构 》【主要讲了MySpace的用户量不断增长过程中,如何逐步提高性能】或相关数据库的性能提升方案。
在2这个位置,可以缓存web页面,业务数据对象等。
在3这个位置,可以缓存业务数据对象、服务相关配置信息、路由规则、消息数据等。
在4这个位置,可以实现通用数据访问层,实现统一数据源查询,业务数据对象可以缓存起来,例如《ebay的架构中的DAL层》。【这一层同时能够为分库,多数据源系统,提供统一数据访问能力。】
具体在那一层实施cache以提高性能,需要依据自身系统的特点来实施。以内容为主的系统,考虑在1,2处采用cache;也业务为主的系统,考虑位置2、3、4、5处采用cache;采用SOA架构的业务,考虑位置3、4、5处采用cache【如果数据库存在切分,多源的情况,可适当倾向位置3,4】。我依据自己的需要,选择了如下一个方案。
soa-arc

2. 资源重复利用的频率【命中率】
之所以要采用cache,目的就是要提供资源重复利用率,减少数据库访问。因此先要评估使用cache能否达到目的【例如:提供性能】,如果命中率太低,需要考虑别的方案;如果批量查询很多,命中率又很低,可考虑放弃部分即时性,用搜索引擎等方案。

3. Cache产品选型
在Java平台,对于内存cache,可以选择Map系列,Ehcache,OsCache等;远程cache,分为中央模式,例如Memcached等;Cluster模式,例如:JBoss Cache等。具体使用那个cache,要依据:缓存什么,性能要求,数据量,可伸缩性(例如1个月之后,就需要加服务器了),事务要求,过期特性,一致性要求等来选择。
我的这个案例:性能要求高;能缓存60%的情况下命中率已经很高;数据量很大,但增长慢;随时需要增加服务器,以增加缓存的数据;不需要考虑事务,业务处理时,直接使用数据库锁,也即允许部分查询脏数据;按照数据特点,分别采用不同的过期时间;一致性要求高。因此选择了Memcached。
【资料:】
了解cache基本知识,java cache产品的一些特性,可以参考《Cache Insight
一篇关于cache选择的文章《Cache的选择以及特性建议
一篇关于远程cache的文章《Remote Cache, Transaction
一篇关于分页情况下,cache使用策略《分页 & QueryKey & 预取
我选择了Memcached作为远程cahce,推荐大家去官方网站看看。

4. 资源如何在cache中存储、资源粒度的选择
在cache存储的资源粒度,首先依据cache资源的特点,例如登录者基本信息,就完全可以一次性缓存起来,对于聚合关系结构的业务对象,在缓存的时候需要考虑业务特点,如果业务上对聚合对象内部的对象访问就很频繁,那么就考虑选择小对象力度缓存,否则考虑大粒度对象。第二点是cache自身的特点,本地JVM cache,可以考虑存储大对象,因为此时没有网络访问、数据流量的考虑,那么即使业务上小对象访问比较多,也可以考虑完全缓存整个对象关系;如果是远程cache,那么就要依据大粒度和小粒度对象访问的频率,然后决定。
【注】:查询返回的集合对象,不适合在cache中存放。
      对象关系过于庞大时,也不适合完全存放在cache中。

    资源序列化:在使用远程cache的时候,需要考虑对象序列化的问题。

  1. 如果是Java序列化,那么资源对象内部,不要包含非数据类对象,例如服务类,Logger等。
  2. 资源对象内部的数据属性如果使用了Long,Integer,Enum(包括自定义枚举)等非原子类型的对象,需要考虑序列化定制【如果资源量比较小,cache服务器资源足够多,可以延后考虑,但不能不考虑】。原因是对象序列化,会导致序列化后的二进制数据偏大,特别是Enum类型要引起关注【可参考《服务化的行军中:Enum使用,快乐的痛苦》一文】。
  3. Hessian,XML序列化同样存在上面存在的问题。

key的规划。坚持如下几个原则:尽可能用外部可以提供的属性作为key;作为Key的属性,尽量避免重复的业务上的重复,例如:多个业务用同一个业务语义作为Key;Key之间存在关系,但多个Key指向同一个业务对象,此时只选择其中一个与对象直接cache,其它key与这个Keycache;Key如果能够按照某种规则推算出来,切勿cache。
【注:】远程cache情况下,同一个对象中存在静态数据和动态数据时,当cache的时候,可以分别建立cache【特别是对于一个关系复杂的大对象,意义更大】。

5. 资源过期策略
缓存在cache中的对要要可以采用一定的过期策略,例如:某个对象缓存10分钟,因为它在10分钟之内还是能够被重复利用的;有些对象无限期缓存,因为它会被长期使用,此时对象是否被从cache中清除,由cache算法负责;最简单的方法是,不设置过期时间,由算法清楚,最终剩下的数据最有可能是重复率最高的。如果担心数据一致性的问题,那么可以依据业务对象特点,分配不同的过期时间。

6. 资源一致性解决方案
使用cache,最麻烦的是解决一致性问题,特别是对于业务系统,这种要求更高。
最简单的方式是:资源发生变化,就从cache中删除。
第二个问题是资源锁的问题,在存在并发的情况下,服务端必须锁定资源,如果不是带锁的cache,此时就要避免从cache中获取数据,以免脏数据。
注意:在多层cache的情况下,还需要考虑cache之间数据的一致性,而不仅仅是cache与数据库的一致性。

7. 每台服务器Cache的数据量评估
JVM内存cache要缓存多少数据,依据服务器内存【如果同时采用了本地文件缓存策略,就需要考虑准备在硬盘上钝化多少缓存数据】,cache对象的大小进行评估。远程cache能够缓存多少数据,依据内存【如果同时采用了本地文件缓存策略,就需要考虑准备在硬盘上钝化多少缓存数据】,cache对象的大小进行评估。

要进行评估,首先要计算出资源的尺寸【按照选择的序列化方式测量】。

计算每台服务器能够cache多少数据或需要cache多少数据才能够发挥cache的效果。在多机器环境下,对于JVM本地cache基本按照内存能容纳多少数据即可,如果同时开启了文件存储特性,可以按照资源活跃度来来粗略估计,在后期再依赖cache监控获得的数据进行精确调整。在远程环境下,如果采用单服务器模式,可以按照完全内存缓存的情况进行计算;对于cluster cache,目前还没有使用过,建议初期采用全内存方式进行计算。

8. 网络流量评估
在远程环境下必须评估网络流量/秒,以供SA参考。

9. Cache效能监控日志
在使用过中,会随时调整一些cache相关的参数,此时性能日志就非常重要。可以从2个层面获取日志:cache服务器自身的性能监控日志;业务系统定制的一些日志参数。
业务定制监控参数的一个简单例子:资源类型,会话数(Session ID),cache请求次数,cache命中次数,当前cache中数据量,数据库访问次数,平均访问时间。

10. Cache可用性监控
对于远程cache模式,需要提供相应的监控方案和通知方案。

11. 远程Cache可用性测试

    考虑如下故障模式,是否对应用系统产生致命影响【主要是性能】:

  1. 本地cache不能正常使用
  2. 远程cache全部不能访问
  3. 其中1个cache服务器不能访问
  4. cache都不能工作时的性能指标等

12. 故障模式解决方案
Cache服务器故障时的解决方案,在确保系统可用的情况下,可以实施那些策略来度过难关。例如: 通过apache限制访问量。

13. Java环境,Cache如何与程序结合

    在Java环境,可以通过如下方式实现结合:

  1. AOP方法拦截方式
  2. 面向属性方式
  3. Cache模板方式
  4. AOP扩展点方式
  5. 事件模式
  6. 代理模式
  7. 直接访问cache API

我选择代理模式实现查询和监控,事件模式实现数据更新。

14. 适度调整程序,以最优化cache效果
大部分情况,我们加入cache对应用层【相对于soa服务层】的影响很小。但某些时候,应用层的某些程序设计方式,数据获取方式,与cache结合的时候,可能会很不爽,甚至会导致成本过高。此时,不要死守某些所谓的原则,可以针对使用cache这种需要,适度调整程序,甚至某些业务的表现方式【只要业务本质不发生变化,程序上甚至可以违背某些API的原则—这些原则有时候,并未考虑特殊的cache使用需求】,以最优化cache效果。

【其它资料:】
Java开源缓存框架
使用Cache Farms和Read Pools提高Web应用的伸缩性
服务器的大用户量的承载方案 Nginx Squid Apache PHP MySQL
Declarative Caching Services for Spring
Spring Aop cache
youtube architecture
Golden rule of web caching
术语:性能、可伸缩性定义
Oracle’s Cameron Purdy Looks at 10 Patterns for Scaling Out — 该文虽然讲的是可伸缩性,但其中很多点也适用于性能思考过程,例如:“10 - Understanding the Problem,9 - Define the Requirements,4a - Plan for Overload,3a - Plan for Failure,2 - Tier Where It Makes Sense,1 - Simplify ”
可伸缩性最佳实践──来自eBay的经验—文中一条规则“适当地使用缓存”很重要,并不是每个业务点或架构层都适合使用缓存。
Trading Consistency for Scalability in Distributed Architectures —- 一致性与可伸缩性
利用 ThreadLocal 提高可伸缩性
Memcached使用点滴



星期一, 06月 16th, 2008

一个程序员眼中的google和百度



    我经常回去百度的贴吧看看,也会用百度搜索些MP3;日常工作中大部分使用google进行资料检索,email使用,链接收藏等。因为工作的关系,常常会寻找一些技术资料,对这方面也比较敏感,随着发现了如下一些差别。
    1、google的更多页面:更多谷歌产品,百度的更多页面:百度产品大全。这2个页面很有意思的,百度的页面,基本都是信息搜索相关业务,其中音乐相关的就有3个;google的这个页面,处包括了一些信息搜索相关的业务外,还有Google 实验室SketchUp(3D绘图软件),文件(在线建立、撰写、储存和分享您的文档与电子表格)等应用软件【因在搜索方面我是外行,因此不进行比较】。从这2个页面,我们就可以看出两者的一个差别,google全球把自己放在与yahoo,微软等公司竞争的层面【在中国,在搜索这个市场,它还是需要追赶百度的】,百度把自己放在国内门户类网站、C2C、B2C(或许还有B2B)竞争的层面。战略上还是有些差别的。
    2、近日看到,google开辟了一个生活搜索频道,很是强大,见文章技术与产品-有感于google和口碑的搜房产品,百度没有类似的频道(有贴吧这样的社区频道),但传闻在搞B2C、C2C相关的内容,要与Alibaba系竞争了。从贴吧生活搜索频道的差别来看,两者对于社区的发展方向是不同的。google在它的生活搜索频道中,极好的诠释了技术+整合+本地化=创新的产品。百度是自己聚焦人气,google是和别人分享人气。此外,从google与天涯等网站合作,也可以看出其社区建设的思路。
    3、在技术领域,我们经常会听到云计算、MapReduce、BigTable、Google guice、google toolkit、Android等技术相关的论文、文章、介绍。却很少听到百度有关的内容【当然了,国内的互联网公司都很少听到这方面的东西,sina搞过MemcachedbNCache,已经很不错了】。在技术领域的影响力和贡献力存在巨大差距,这种潜在的量能积累,在几年后会否转换为商业的优势?视目以待之。
    4、在协作/共享领域,google提供了Google Maps APIOpenSocial APIGoogle Apps等等更多的API;在百度和国内其它互联网公司,在这方面却很少【有些根本没有开放的API】。作为一名程序员,我感谢google提供的这些技术分享,从中学到了很多;作为一名博客作者,我可以用google的这些API写点有意思的东西,也很是快乐。
    总之:在国内,目前百度的商业是非常成功的;google还有很长的路要走。在国际上、在全球战略上、在开发者领域、在开放领域、在云计算领域等方面,Google已经走得很远了,Google也是值得敬佩的【很希望百度、国内其它互联网公司也在这方面能有突破,让我等程序员分享一下百度的技术果实】。在某些业务领域,虽然技术领先未必会赢得商业胜利,随着时间的前进,这种技术的优势会逐步体现出来。

    近日又看到这篇文章浪潮之巅 第九章 硅谷的另一面(一)近日又看到这篇文章,讲了成功公司的几个原则:创始人、能盈利的商业模型、判断力和执行力、运气。
    百度在这几个方面都占据了,所以它成功了;腾讯在这几个方面也都占据了,因而也成功了;淘宝到目前为止没有找到一个好的能盈利的商业模型,因此距离成功还有一步。
    在这几个因素中,没有提到技术的因素,我认为国内有很多人也有好的想法,因为技术达不到,因此最终失败了,所以对于高科技公司,是否还要加上‘合适的技术体系’哪?
    当跨出了第一步之后,商业模型能够被模仿,此时要获得领先优势,就必须依靠技术了。否则必死无疑,yahoo就是一个典型案例。

相关文章:
百度CEO李彦宏的成功之路
百度网络营收增速放缓 流量价值需深度开发 — Yahoo开发的新的广告系统在美国追赶不上google,百度的广告系统因为流量的原因,短期还是业务领先的,技术上还是有差距的,需要不断提升,才能使自己的盈利能力与流量地位相匹配。
韩国互联网公司击败国外巨头的启示:产品本土化的创新 — 淘宝是另外一个例子。

讨论Google搜索的一些文章:
谁比Google 懂中文?
Google的排名算法最权威解密
阻碍Google发展的11大搜索趋势



星期一, 06月 16th, 2008

【收集-004】生命如此短暂



 一天,一名旅行者来到一个地方。不远处,一条小路蜿蜒而上,隐没在绿色的树林
中。他循路走去,来到一道栅栏前。木门敞着。他顺着石铺的小径继续前行。
  在荫翳蔽日的树林间散落着白色的石头。旅行者弯下腰来仔细端详,石头上刻有字
迹:阿布杜尔塔艾格,活了8年6个月零3天。当他意识到这是一块墓碑时,心里不免一
颤,一个孩子这么小就死了。他又转向另一块石头,上面刻着:亚米尔卡利贝,活了5
年8个月零3个星期。看看周围,好像都是墓碑,原来这是一块墓地。他又继续读了几块
墓碑,都是一样的形式:一个名字,一个生活的时间。时间最长的也只有11年。他们的
生命真是太短暂了,旅行者悲伤地哭了起来。
  听到哭声,一个老人走了过来。他是负责看守这块墓地的。旅行者问:“这里是不
是发生过什么灾难?为什么这些死者全都是孩子?还是这里面有什么可怕的咒语?”
  老人笑了笑说:“别害怕。这里没发生过什么灾难,也没有什么可怕的咒语。我们
这里有一个古老的习俗:当一个人长到15岁时,父母会给他一个本子。从此,每当遇到
快乐的事情时,他就打开本子,把它记下来。在左边写上是什么快乐,右边写上这快乐
持续了多长时间。比方说,他遇到了未婚妻,陷入热恋,他们相识的快乐持续了多长时
间,是一个星期还是三个星期;他第一次亲吻她;他的妻子怀孕了,第一个孩子出生
了;他出门旅游;他在异乡遇到了旧识。这些都带给他多长时间的快乐,是几小时还是
几天?就这样一点一点地,他在本子上记下了他经历过的每一次快乐。当他离开人世的
时候,按照我们的风俗,人们打开他的本子,把他快乐的时间加在一起,算出总和,然
后把这个时间刻在他的墓碑上。在我们看来,这个时间才是真正属于一个人生命的时
间。”