SOA架构之性能解决策略之一【引入Cache过程的思考点】
采用SOA架构实现了业务的分离、重用、对BPM的支持。经过初步的测试,这种架构不能满足性能的要求【前提:SQL已经优化,数据库cache已经不能满足需求】,就当前的应用环境来看,引入cache是解决性能的一个办法,这也是比较通用的一个方案。
目前网上已经有大量的cache实现,介绍cache原理,cache使用案例的资料。下面就我在使用过程中的一些思考点分享一下。
1. 在SOA系统架构的那一层进行cache

系统架构如图所示:可以在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】。我依据自己的需要,选择了如下一个方案。

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的时候,需要考虑对象序列化的问题。
- 如果是Java序列化,那么资源对象内部,不要包含非数据类对象,例如服务类,Logger等。
- 资源对象内部的数据属性如果使用了Long,Integer,Enum(包括自定义枚举)等非原子类型的对象,需要考虑序列化定制【如果资源量比较小,cache服务器资源足够多,可以延后考虑,但不能不考虑】。原因是对象序列化,会导致序列化后的二进制数据偏大,特别是Enum类型要引起关注【可参考《服务化的行军中:Enum使用,快乐的痛苦》一文】。
- 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可用性测试
-
考虑如下故障模式,是否对应用系统产生致命影响【主要是性能】:
- 本地cache不能正常使用
- 远程cache全部不能访问
- 其中1个cache服务器不能访问
- cache都不能工作时的性能指标等
12. 故障模式解决方案
Cache服务器故障时的解决方案,在确保系统可用的情况下,可以实施那些策略来度过难关。例如: 通过apache限制访问量。
13. Java环境,Cache如何与程序结合
-
在Java环境,可以通过如下方式实现结合:
- AOP方法拦截方式
- 面向属性方式
- Cache模板方式
- AOP扩展点方式
- 事件模式
- 代理模式
- 直接访问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使用点滴