Browse > Home / Archive by category '软件架构'

| 订阅RSS

Web中通用列表缓存的策略和实现。

十二月 23rd, 2009 | No Comments | Posted in cache, 软件架构

在当前的web网站中,缓存扮演越来越重要的角色,是应付网站高并发的重要技术手段,在缓存中,对于单一记录的缓存是最简单的,只要卡住所有的保存、删除、更新操作,然后向缓存控制中心提交对应的事件即可,而对于list的缓存通常是很难解决的,这里说说最近在弄的缓存,自我感觉良好。

第零种:系统中最新博客文章,策略是采用ttl,每隔5‘过期一次。

第一种:最简单的list缓存,策略是只要有数据更新要删除此类的所有list缓存。(目前hibernate的二级缓存的实现策略)

第二种: 条件缓存,譬如:某人的博客;博客系统中的用户和文章的关系,当某一用户更新了自己的文章,不应该删除其他人的博客缓存,策略用用户的id参入到缓存的key中

第N种: 非固定值多条件缓存,譬如:某人9:00~10:00 的博客文章列表;策略自定义缓存策略

谈谈我的思路,一样卡住所有的增、删、改操作,当发生增删该的时候,向缓存服务器发送事件。

public class CacheEvent<T> {

private Class<T> targetClass;

private T targetObject;

private Operation operation;

public CacheEvent(Class<T> targetClass, T targetObject, Operation operation) {

this.targetClass = targetClass;

this.targetObject = targetObject;

this.operation = operation;

}

对于第一种:那么我的缓存定义:

@Cacheable(clazz=TestMember.class)
public List<TestMember> getList();

通过方法和实体类产生一个缓存key, 只要发现此这样的实体发生增、删操作,即刻删除此缓存(关于如何删除,见下文)

对于第二种:我的缓存定义为:
@Cacheable(clazz=TestArticle.class,
namespaces={@CacheNsParameter(name=”member”,keyIndex=1)})
public List<TestArticle> getList(@CacheKeyParameter TestMember member,
@CacheKeParameter start,@CacheKeyParameter offset);
通过方法和namespace的定义产生一个缓存key,接受事件,当发生实体的增、删操作,并且TestArticle的member属性和@CacheKeyparameter 标记的属性相等时候,即刻删除此缓存。
如果缓存的key中参数为固定对象主键(譬如:ns中用户id,且文章表中的member_id 不会被update,要么insert ,要么delete,一旦设置就不会更改)或者参数和实体本身无关(譬如:分页参数start、offset)的时候,那么上述两种方法,基本上能满足所有缓存的需求。
对于第三种缓存用的相对少点,需要自定义,我的定义为:
@Cacheable(clazz=TestArticle.class,strategy=”XX”)
public List<TestArticle> getList(@CacheKeyParameter TestMember member,@CacheKeyParameter int month);
由自定义的xx服务类(我使用的是Tapestry5-IOC)来进行处理。
上面说到中很关键的一个东西就是怎么批量的高效删除缓存,譬如:在第二种中多次运行产生的cacheKey为
TestArticle_member_1_0_10   (后三位分别为member_id,start,offset)
TestArticle_member_1_1_30
TestArticle_member_1_40_30
TestArticle_member_2_0_10
TestArticle_member_2_1_10
TestArticle_member_2_30_10
。。。。。。。。。。
很多这样的key,如果要是每次把key记录一下,那这个代价也是挺高的,也要弄一个缓存的东西给记录下来,现在大家注意一下这个缓存的key,用户1增加文章的时候,实际就是删除所有key以TestArticle_member_1 开头的缓存即可,这样就省事多了,问题转换为怎么批量删除,在缓存中没有批量删除这个概念:( ,因为要遍历所有的key进行操作,效率自然高不了,挠头ing,我搜呀搜,无意中发现了官方的FAQ:http://code.google.com/p/memcached/wiki/FAQ#Namespaces 如果我们把TestArticle_member_1 加个版本号的话,不久好了吗,那么第一次时候产生的key为:

TestArticle_member_1_v0_0_10   (后四位分别为member_id,version,start,offset)
TestArticle_member_1_v0_1_30
TestArticle_member_1_v0_40_30
TestArticle_member_2_v0_0_10
TestArticle_member_2_v0_1_10
TestArticle_member_2_v0_30_10
当memeber 1增加文章的时候,我版本号加一,那么下次请求缓存时候key就变成了:

TestArticle_member_1_v1_0_10   (后四位分别为member_id,version,start,offset)
TestArticle_member_1_v1_1_30
TestArticle_member_1_v1_40_30
TestArticle_member_2_v0_0_10
TestArticle_member_2_v0_1_10
TestArticle_member_2_v0_30_10
cache没找到对应的缓存记录,那么执行方法,然后缓存起来,这样就变相实现了缓存的批量删除,有人会说,那岂不参生垃圾数据了,不用担心缓存系统一般都有LRU算法自动删除没用的数据。 :)
问题就豁然开朗了。其他情况也就迎刃而解了。
可以看看偶的测试用例:
约束、限制、建议:
1) 所有实体的缓存都是以实体本身向下延展。
2) 放入到缓存中的列表都是ID集合
3) 尽量以外建、主键、索引作为缓存的key
4) 使用hibernate的时候,不使用ManyToMany关系,用 one-to-many 和中间实体替代,譬如用户的角色列表。
有待完善:
1) 没次读取缓存的时候,需要分析方法中的Annotation,需要使用LocalCache的方式进行缓存起来。
2) 在更高量的访问时候,应该从memcache中读取的数据一部分放入本地缓存中。
3) 加入压力测试。
不过总算一个还算通用的列表缓存实现,通过前三种方式,系统的list缓存自定义方便了许多。借此拍砖,欢迎抛玉。

Linux秘笈25.Linux的Cut命令

三月 18th, 2009 | 2 Comments | Posted in Hacks, 软件架构

Cut command can be used to display only specific columns from a text file or
other command outputs.
Following are some of the examples.
Display the 1st field (employee name) from a colon delimited file

  $ cut -d: -f 1 names.txt
  Emma Thomas
  Alex Jason
  Madison Randy
  Sanjay Gupta
  Nisha Singh

Display 1st and 3rd field from a colon delimited file

  $ cut -d: -f 1,3 names.txt
  Emma Thomas:Marketing
  Alex Jason:Sales
  Madison Randy:Product Development
  Sanjay Gupta:Support
  Nisha Singh:Sales

Display only the first 8 characters of every line in a file

  $ cut -c 1-8 names.txt
  Emma Tho
  Alex Jas
  Madison
  Sanjay G
  Nisha Si
Tags: , , ,

[架构师]05.架构师就是平衡

三月 2nd, 2009 | No Comments | Posted in 软件架构

当我们想到软件架构时,我们最先想到的是经典的技术活动,如模块化体系、定义接口、分配责任、运用模式,并优化性能,架构师还需要考虑安全性、可用性、保障性、发布管理、部署选项,还包括了其他一些事情,但是这些技术上和程序上的问题必须由干系人和他们的利益进行平衡,采取“干系人和利益”的做法,在需求分析上的一个很好的方式,能够确保一些正在开发软件的需求规范的完整性。

在开发软件的组织和组织内部去分析干系人和他们的利益的过程,能揭露最终和软件架构相关的优先级事项,软件架构师将平衡这些优先级事项,在短期和长期上来说,真是一个适合当前的工作环境的好方法。

思考一下,举个例子,工程部门的软件即服务(SAAS)业务,这个业务可能有一些优先事项,如:合同法务会议、创收、客户保障、成本控制和创造有价值的技术资产,这些业务的优先级可能转化为部门的优先级,像确认功能和正确性,正在开发软件的“品质”,以及确保产品开发团队,确保可持续性和可审性的开发操作,以及适应性和长寿的软件产品。

这是架构师的工作,不仅仅是为用户创造有功能的、具有品质的软件,而且还要去兼顾其他部门优先级的事情,像和商业CEO的成本控制,和运营同事的易于管理的利益,和今后方案编制工作人员的易于学习和易于维护的利益,以及软件师专业的最佳实践。

架构师可以在短期内有意识去选择某一个举足轻重的优先事物,但是长远来看,为了真正做好工作,最好坚持一个适当的平衡,这个有影响力的平衡要适合手头上的工作环境,还要顾虑其他因素,譬如:预期软件寿命,关键软件的业务,技术和组织的财务文化。

总之,软件架构不仅仅是经典的技术活动;在项目中他还要平衡技术需求与商业需求相关者的利益。

选自:Architecting is about balancing

Tags: , ,

[架构师]04.沟通是金;伴随透明度和领导能力

二月 25th, 2009 | 1 Comment | Posted in 软件架构

往往软件架构师坐在自己的象牙塔上,对下面的开发者进行发号施令,制定规范、技术决策,技术的开发方向。这些往往导致了一些问题的出现,和一些不满的群体,最终导致软件产品一点都不接近原始的需求。每个软件架构师应该知道如何去沟通软件项目的宗旨和目标。关键是明确有效的沟通应该是透明的和有领导的。

要明确说明怎样沟通。在你的团队中没人愿意去读一份100页的架构决策文档,使用明确和简洁的方式传达你的想法,是任何软件项目成功的关键。 在项目启动阶段,尽可能的保持简单,并用一切手段不要去写长篇累牍的Word文档。使用一些类似Visio的工具去画一些简单的图标,用来表达你的想法。对那些经常发生变化的人,要保持简单,另一种有效的沟通手段,是非正式的白板会议。没有任何东西比得上,带领一群开发者(或其他架构师)在一个会议室使用白板表达你的想法,此外,请务必在任何时候,你随身携带一台数码相机。没有比你被赶出会议室而所有的想法依然停留在白板上更郁闷的事了,拍照,下载,通过wiki分享给团队的其他成员。所以扔掉冗长的Word文档,更专注于让你的想法更全面,然后关注你的架构决策是否有详细记录。

一个软件架构师也是一个领导者,有些软件架构师没有意识到这点,作为一个领导者,你必须赢得你同事的尊重才能在一个健康和高效的环境里面进行高效的工作,让开发者对于一些架构决策一无所知,显然将导致灾难发生。有开发者和你一起创建一个协作环境,能验证你做出的架构决策是否正确。反过来,你也让开发者也参与到架构的进程中来,和他们一起工作,而不是排斥他们,请记住,所有团队成员(如质量控制小组,系统分析师,和项目管理人员以及开发者)需要清晰的沟通和领导。采用透明和高效的领导将改善沟通和建立一个强大且健康的工作环境。

如果“沟通是金” ,那么透明度和领导能力是其谦卑的仆人。

选自Communication is King; Clarity and Leadership its humble servants

Tags: , ,

七个处理日志(Logging)的好技巧

二月 24th, 2009 | No Comments | Posted in 软件架构

在web应用程序中,日志是很重要的,能够知道正在发生什么,以及进行性能(performance)分析和意外事情的分析,那么怎样做,才能让你的日志有用途呢?

1. 产品状态下不应该有debug消息。

我看到了一次又一次的在产品中启动调试日志,这可能是一些开发者无意中检查调试日志记录时候的配置,启用调试能够显著降低你应用程序的运行速度,并且使得在去分析日志变得很困难, 请确保在部署的时候,最好是一些脚本,能够在产品阶段禁止debug信息。

2. 关注您的日志

有些公司在其产品系统中有着良好的日志记录,但不关注他们的日志。关注您的日志,能够发现应用程序中的问题(错误,性能,内存), 并解决这些问题 ,那么基本上你应该没有记录什么已知的错误。

3.使用正确的日志级别

写日志代码的开发者经常不知道那种日志级别在产品阶段使用,有一个文件应该能够解释开发者应该使用那一个日志级别。例如SEVERE应该只用于技术问题,需要立即采取行动。 ERROR应当用于错误,需要有人研究和解决 ,如:没有得到数据库连接、低资源或不集成的点。 这些对你的公司和应用是个规范。

4. 不要仅仅在本机记录日志

如果您的服务器有重大问题,如资源问题,它往往无法登录,你就不能找到您的日志,也不能找到问题,日志应该记录在一个网路驱动上,并复制到另外一台主机或者网络驱动,比如SysLog。一个好的解决方法是使用传播工具写入到一个网络多播组中,这也方便监测(见“可扩展的互联网体系结构” ) 。

5. 监控您的日志

类似“关注你的日志”,你应该安装一个监测解决方案,能够在你的日志中查看SERVRE条目、ERROR条目,异常和其他东西,通过传播,能够很容易监控,一个好的方法是能够分类和计数异常,然后去做一些关于严重的和最常见的处理。

6. 使用易读的格式

开发者往往不太考虑在产品阶段的日志输出,:这将导致难以阅读的日志文件。 看看下面有一个易读的输出:

[8/14/06 8:22:14:653 CDT] 0000a SSLComponent I CWPKI00001I: SSL service not available [ 8/14/06 8:22:14:653的CDT ] 0000a SSLComponentCWPKI00001I :
[8/14/06 8:22:14:813 CDT] 0000a WSKeyStore W CWPKI0041W: One or more key [ 8/14/06 8:22:14:813的CDT ] 0000a WSKeyStore W CWPKI0041W :

这样的格式更容易快速扫描日志,对比一下你的日志输出。

7. 在你的日志中使用错误代码

每个导致日志输出的原因应该有一个独特的错误代码。如果没有一个独特的错误代码是很难在您的源代码中找到原因。错误代码也更容易计数和分类, 使日志报表更容易展示。

想了解更多信息吗? 在web站点上也有一些很好的关于日志的书,象: Michael T. Nygard 写的《Release It!》(真的是非常好的一本书)和Theo Schlossnagle著作的《Scalable Internet Architectures》。

Tags: ,

[架构师]03意外才是最大的问题,并非技术

二月 23rd, 2009 | No Comments | Posted in 软件架构

现在有人正在运行一个失败的薪资项目,可能还不止他一个人。

为什么呢?这是因为他们选择了Ruby而未选择Java,或者选择Python而未选择Smalltalk吗?又或是因为他们决定使用Postgresql而未选择Oracle吗?又或选择Linux而未选择Windows,我们都看到了技术上引起了失败项目,但是那些意外的问题,Java都难以解决呢?

大多数项目是人来构建的,这些人是项目成败的基础,因此,要关注如何才能帮助这些人能够取得成功。

同样,也有一些你认为“没有正确做事”并且破坏这一项目的人,在这种情况下,解决问题的技术已经是过时的和不是必须的,事实上在人类历史上,它可能是最重要的技术创新,你需要的是沟通。

仅仅把熟练地谈话做成一种技术是不够的,学会尊重人,并且给予他们学习核心技能的好处,让他们从一个聪明的架构师转变成一个有效的架构师。

有很多关于这方面的东西,但是有些小窍门能够大大提高你的沟通能力:

1 )处理这些事件是对话- 而不是对抗 。
假如你认为文问题是一个对待这些人的一种方式,那么你一定要了解,你不可能把人放在对立面。

2 )在你确信自己能够明辨是非后,再去进行会话。

如果你正处在在生气,沮丧,郁闷,或其他扰乱心情的事情的时候,和其他人进行沟通,容易引起其他人认为你是在攻击。

3 )利用这些机会,以确定共同商定的目标。

不要告诉开发者在会议上保持安静,因为他们从不让别人讲话,而是去问他们是否愿意帮助你多增加其他人手的参与,并解释说一些人更内向,需要更长的思考才能进行交谈,问他们是否愿意帮助他在谈话之前等5秒钟。

如果你从一个共同的目标出发,对待”有问题”的人,你应该把它作为一个学习的契机,学会控制自己的情绪,这样你不仅仅变得更加有效,而且你还发现,你每次可以学到一些东西。

选自:Chances are your biggest problem isn’t technical

Tags: ,

[架构师]02.简化必不可少的复杂性,减少意外的复杂性

二月 19th, 2009 | 2 Comments | Posted in 软件架构

在任何问题上,必需的复杂事物代表了问题的难度。例如,协调一个国家的空中交通是一个复杂的事情。每架飞机的确切位置(包括高度),速度,方向和目标,必须进行实时跟踪,以防止半空中和跑道上发生碰撞。该航班的飞机,必须能够在一个不断变化的环境中,设法避免意外事情的发生。

相反,额外复杂事物的发展让我们意识到必须减少必需的复杂性。今天我们使用过时的空中交通管制系统就是一个意外复杂的例子。他被设计解决控制数以千计的飞机的复杂问题,但是这个方案本身介绍起来就十分复杂,事实上今天我们使用的空中交通管制系统使用起来是非常复杂的,更新它已经被证明是不可能的,在世界许多地区,空中交通的技术上的指导都超过30年了。

许多框架和解决方案供应商都患有增加意外复杂性的毛病,框架解决具体的问题是有益的,但是框架本身往往添加的复杂性往往超过了他们减少的复杂性。

开发商经常为了达到相同的结果要去解决一些棘手复杂问题,解惑是有趣的,开发商就是解决问题的,谁不喜欢匆忙解决一些难以置信的复杂问题?但是在大型软件,排除意外的复杂性,同时保持了解决必须的复杂性是至关重要的挑战。

你是怎么做的? 喜欢框架是来源于工作编码的需要,而不是仅仅从象牙塔拿下来。看看在一个解决方案中能够直接处理的业务问题的代码和只是应用和用户之间服务的代码的百分比,仔细用心去观察每个提供解决方案的供应商,他们本质上不是坏的,但是厂商往往增加了意外的复杂性,要确保解决方案适合这个问题。

架构师有责任去解决固有的复杂性而不去增加额外的复杂性。

选自:Simplify essential complexity; diminish accidental complexity

Tags: ,

[架构师]01.不要把技术性的东西放在需求之上

二月 18th, 2009 | No Comments | Posted in 软件架构

作为工程师,我们有时建议解决问题的技术,方法和途径,不是因为他是最好的方法,而是因为这些东西对我们的技术发展有好处,而往往这样的做法很少能产生最好的结果。

最好的事情是,因为你为你的客户以及他们的项目做了一些正确的解决方案,所以你的职业生涯将拥有一串乐于和你合作的客户资源。对于你的订单来说,这种信誉要运优于一些牛鼻的语言和一些很棒的设计模式所带来的东西,虽然它是重要的,甚至关键的,但是掌握最新趋势和技术本不应该发生在付费的客户身上。你要牢记,你有讲究信誉的责任。作为一个架构师,你将维护你组织的健康性和目标性,避免所有的利益冲突,让你的组织成为一个不可分割的、忠诚的整体,如果该项目没有尖端性或挑战性不足,那么你去找到一个这样就是。

如果你不能做到这点,那么你将被迫和一些使用自认为很帮技术的家伙为客户做项目,即使一些东西不适合当前的项目,但是抵制一些新的,酷的技术本身就是件很困难的事情。

有了正确的解决方案,该项目将拥有一个快乐的团队、一个更快乐的客户以及没有压力的团队。 这常常能够给你时间去深入现有的旧技术或学习新的东西,或去做自己一直想画类图的事。 你的家人也非常喜欢这些,因为他们能够体会到在你回家时候的不同。

总体来说始终把客户的长期需求优于自己的短期需求,那么您将不会出错。

选自: Don’t put your resume ahead of the requirements

Tags: ,