接上文http://xuliangyong.javaeye.com/blog/171240

对于第二种方法现用观察着模式来解决

思路是这样:当点击a文章(id=1234)够10次后 ,通知文章管理器更新点击次数

update article set hit_count = hit_count+10 where id = 1234

这样就减少了访问数据库的次数

 

代码如下:

public class HitCached extends Observable{
	private static final int DEFAULT_MAX_HITS = 10;
	private Map<Long, Integer> hits = Collections.synchronizedMap(new HashMap<Long, Integer>());
	
	/**
	 * 最大点击量。超过该值就更新数据库
	 */
	private int maxHits = DEFAULT_MAX_HITS;
	
	public HitCached(){}
	
	public HitCached(int maxHits){
		this.maxHits = maxHits;
	}
	
	public void put(Long key, Integer value){
		hits.put(key, value);
	}
	
	/**
	 * 为指定key 增加指定的点击量
	 * @param hitIncreased 增加的点数 
	 */
	public void addHit(Long key, Integer hitIncreased){
		if( !hits.containsKey(key) )
				hits.put(key, 0);
		Integer value = hits.get(key);
		if(value + hitIncreased >= maxHits){
			setChanged();
			notifyObservers(KeyValuePair.create(key, value + hitIncreased));
			hits.remove(key);
		}else{
			hits.put(key, value + hitIncreased);
		}
		
	}
	
	public Integer get(Long key){
		return hits.get(key);
	}
	
	public void clear(){
		hits.clear();
	}
	
}
 
public class ArticleManagerImpl extends HibernateGenericDao<Article, Long> implements ArticleManager ,Oberver{
	
	public void update(Observable o, Object arg){
		KeyValuePair keyValue = (KeyValuePair)arg;
		Article article = this.get(keyValue.getKey());
		article.setHitCount(article.getHitCount() + keyValue.getValue());
		save(article);
	}
 

 

action中调用

private static HitCached hitCached = new HitCached(5);

public String view() {
		if (id != null){
			entity = articleManager.get(id);
			hitCached.addObserver(articleManager);
			hitCached.addHit(id, 1);
		}
}

 这样没十次查看才update一次数据库 更新一次缓存 性能得到了大的提升

存在的问题:

停止服务会丢失一些数据 可加一个监听器 来处理

评论
baibai326 2008-03-26
这个有意思。
感觉自己造一个Map,存入含有id、最后一次更新时间、计数的bean,
按照更新时间,更新次数,同步数据库。
一个定时的flush或size>? 一定量时主动同步数据库是必须的。
neptune 2008-03-25
galaxystar 写道
其实,这里面,数量更新的可靠性是最重要的一点。
如果中央式缓存可以在大访问量下,很稳定的接受数量count,那么每天凌晨做一次数据库的同步不是更好?


同意其观点,用memcached做中央缓存,memcached有专门的方法来加1和减1,每隔一段时间把数据取出再更新数据库,并清零memcached相关项。
FaJa 2008-03-21
xly_971223 写道
抛出异常的爱 写道
myreligion 写道
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?

加上定时flush?

这确实是个问题 定时flush的话 貌似可行 但一次flush全部数据的话 短时间内可能把数据库压垮
分批处理的话需要有类似队列结构的Map,按照顺序flush

设置一个缓存的最大数,每当等于最大数量时,就进行批量更新,并清空缓存

galaxystar 2008-03-21
其实,这里面,数量更新的可靠性是最重要的一点。
如果中央式缓存可以在大访问量下,很稳定的接受数量count,那么每天凌晨做一次数据库的同步不是更好?
chbest 2008-03-21
sorphi 写道
把下面这段代码放到/articles/1234的页面中不是更好么?

<script type="text/javascript" src="/counter/articles/1234"></script>

一般都是这么做的 比较精辟
icewubin 2008-03-18
这种需求不需要同步cache的,就每个cache各管各写库。
超时功能没有的话,自己写一个好了,cache就是一个map,只做10次的这种个数cache,用专业的cache感觉还有点浪费呢。
kabbesy 2008-03-18
点击量是个典型的高频率读写系统,对缓存使用的常规策略一概无效,加上这个数据的价值不是很高(可靠性和事务性要求没有了),所以可以采用这样的方式:

延迟写;
每次写的时候直接从数据库同步到最新数据,使用增量方式;
拒绝分布式缓存(高失效性),拒绝单点缓存(访问频率太高,连接过多),只能够使用单机自己的缓存;
myreligion 2008-03-17
回楼上几位提议,这个问题偶们经历过,实践证明分布式cache是不靠谱的。

如果访问量上来了,用jboss cache这种传说中通讯量很小的cache,在千兆网络中也会造成网络堵塞,影响巨大,性能也差。

对于定时flush,间隔多大?如果间隔很短,其实就没有意义了,而且还可能增大系统负担。如果间隔很大,数据延迟以及内存占用都是问题。

对于这种场景,我觉得有这几个方式值得一试,不过我也没有验证过,呵呵。

1. 普通cache + 超时通知。 cache就是普通的cache,好比ehcache,设定记录最大存活时间(保证延迟可以接受)和最大允许的记录数(限制内存使用),当记录到达最大存活时间或者被挤出缓存时,截获此事件,将移出的记录数据同步到数据库中。这种方式应用比较简单,不过很多cache不支持事件功能比较麻烦。


2. 只cache热门帖子。可以按照业务性质或者点击规则,例如增加一个字段,用于计算帖子最近2分钟的点击次数,如果点击次数操作N次,就认定为热门帖子,对计数进行cache,其他的直接放过。计数增加时,先查看是否在cache中,如果在就更新cache数据,不在就更新数据库,并计算是否需要载入cache。cache中的数据可以定时flush,定时删除,也可以配合方式1进行。

3. 创建一个临时表,把更新信息写入到临时表中,在弄个后台线程慢慢算,慢慢更新。或者弄个单独的统计数据库存着,或是写文件日志。都一个道理。


4. 如果访问量不是非常庞大,好比网站日均pv过千万,直接数据update xxx a = a+ 1 ; 算了,性能还是可以接受的。至少mysql这方面就挺快的。也省事。
xly_971223 2008-03-17
抛出异常的爱 写道
myreligion 写道
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?

加上定时flush?

这确实是个问题 定时flush的话 貌似可行 但一次flush全部数据的话 短时间内可能把数据库压垮
分批处理的话需要有类似队列结构的Map,按照顺序flush
raojl 2008-03-16
利用JSON微量数据通信
EXvision 2008-03-16
我倒是认为用AOP的方式来解决比较好。

在Struts2下面的话用拦截器的方式解决。

只有当点击量达到一定值,才用拦截器更新数据库。貌似这样能彻底解耦。
不过楼上的兄弟说同步怎么办。似乎是个问题。
southben 2008-03-15
同步怎么办
抛出异常的爱 2008-03-14
myreligion 写道
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?

加上定时flush?
myreligion 2008-03-14
cache还是需要维护的吧,好比你一个系统有几十万活动帖子。某些冷门帖子被点了一次(好比检索结果),在很长一段时间都不会点过10次,cache岂不是越来越大?
xly_971223 2008-03-14
sorphi 写道
我的意思是,记录并更新点击数的行为,放在单独的counter应用中来实现,在业务层解耦。

思路不错
不过貌似跟缓存没直接关系
sorphi 2008-03-14
我的意思是,记录并更新点击数的行为,放在单独的counter应用中来实现,在业务层解耦。
xly_971223 2008-03-14
sorphi 写道
把下面这段代码放到/articles/1234的页面中不是更好么?

<script type="text/javascript" src="/counter/articles/1234"></script>

怎样的思路? 没看明白
sorphi 2008-03-14
Readonly 写道
只在cache中放点击次数,当点击次数被10整除时候,再flush到数据库不是更好么?



cache中存放点击数有两种思路:
1.只存放自上次flush后的新增的点击次数,flush之后置为0。集群环境下这样可以采取local cache。

2.初始化时获取原点击次数,flush之后保留原值。集群环境下只能用central cache。

感觉1更好一些。
Readonly 2008-03-14
只在cache中放点击次数,当点击次数被10整除时候,再flush到数据库不是更好么?
sorphi 2008-03-14
把下面这段代码放到/articles/1234的页面中不是更好么?

<script type="text/javascript" src="/counter/articles/1234"></script>
发表评论

提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则

您还没有登录,请登录后发表评论

xly_971223
搜索本博客
博客分类
我的相册
C5b0e206-307c-3f61-aa60-9cfd71c61bb3-thumb
u=3528569133,1587051000&gp=38.jpg
共 2 张
最近加入圈子
存档
最新评论