2008-03-14
用观察者模式解决点击一次文章 update一次数据库的问题
接上文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>? 一定量时主动同步数据库是必须的。
感觉自己造一个Map,存入含有id、最后一次更新时间、计数的bean,
按照更新时间,更新次数,同步数据库。
一个定时的flush或size>? 一定量时主动同步数据库是必须的。
neptune
2008-03-25
galaxystar 写道
其实,这里面,数量更新的可靠性是最重要的一点。
如果中央式缓存可以在大访问量下,很稳定的接受数量count,那么每天凌晨做一次数据库的同步不是更好?
如果中央式缓存可以在大访问量下,很稳定的接受数量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,那么每天凌晨做一次数据库的同步不是更好?
如果中央式缓存可以在大访问量下,很稳定的接受数量count,那么每天凌晨做一次数据库的同步不是更好?
chbest
2008-03-21
sorphi 写道
把下面这段代码放到/articles/1234的页面中不是更好么?
<script type="text/javascript" src="/counter/articles/1234"></script>
<script type="text/javascript" src="/counter/articles/1234"></script>
一般都是这么做的 比较精辟
icewubin
2008-03-18
这种需求不需要同步cache的,就每个cache各管各写库。
超时功能没有的话,自己写一个好了,cache就是一个map,只做10次的这种个数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这方面就挺快的。也省事。
如果访问量上来了,用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下面的话用拦截器的方式解决。
只有当点击量达到一定值,才用拦截器更新数据库。貌似这样能彻底解耦。
不过楼上的兄弟说同步怎么办。似乎是个问题。
在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>
<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>
<script type="text/javascript" src="/counter/articles/1234"></script>
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 81249 次
- 性别:

- 来自: 北京

- 详细资料
搜索本博客
我的相册
u=3528569133,1587051000&gp=38.jpg
共 2 张
共 2 张
最新评论
-
struts2 配置文件 struts. ...
gdsagdsa
-- by biti910 -
struts2 配置文件 struts. ...
<h1>嘿嘿</h1>
-- by biti910 -
spring中OpenSessionInVie ...
<bean name="openSessionInViewInte ...
-- by davidcen -
关于文章点击量的缓存
bloodrate 写道那得多大得cache啊?每个帖子对应map里得一条记录, ...
-- by robbin -
关于文章点击量的缓存
那得多大得cache啊?每个帖子对应map里得一条记录,以id为key查,估计有 ...
-- by bloodrate






评论排行榜