redis在诗篇建站系统缓存中的应用

jianglibo 发布于 2011/10/25 12:05
阅读 1K+
收藏 8

诗篇建站系统是一个在线的建站平台,多用户,多域名给缓存带来一些挑战。

 系统主要有一下几类资源:

 1、站点媒体,在模板中使用的图片,css,js等。处于文件系统中

 2、资产,比如文章附件,相册图片等,资产信息保存在数据中,内容保存在文件系统中。

 3、网页,模板产生的网页,这是使用Redis的地方。

 因为要支持顶级域名,所以服务器只能通过域名来区分不同的站点,比起oschina通过/u/148211/blog,这种路径方式要复杂,面对更多的问题。

 一个站点--》多个域名

 当用户访问:http://sfj.fh.gov.cn的时候,通过apache proxy到tomcat的时候,通过urlrewrite将域名携带到query string中,http://www.myproxy.com:8080/?hostname=sfj.fh.gov.cn.tomcat通过hostname,找到对应的site。

 以上是系统的初步介绍,接下来就分析redis缓存机制。

 为什么使用Redis?快+简单。

 诗篇建站系统的缓存仅针对模板产生的文件,就像oschina的页面。

 /article/47571,显示一篇文章,这里的article携带两层含义,1、对象是article,2、模板是article.ftl。

 /article/47571?tpl=specialarticle,也是显示一篇文章,对象是article,模板是specialarticle.ftl

 /section/223233同理,只不过对象是目录

 如何将内容缓存呢?一种直观的模式就是url作为key,内容作为data。

 这是我从redis复制出来的片段:

 1732) "7a3d57c7-fb84-44ec-9be8-55e6d7e0c648"

 1733) "19764,section,19793"

 1734) "/article/23678hostname=sfj.fh.gov.cn&"

 1735) "cc564424-5c47-44a6-a9bc-0269bf8bc177"

 1736) "8920,article,20182"

 1737) "siteid:8920"

 这里有4种类型的key,

 1、"7a3d57c7-fb84-44ec-9be8-55e6d7e0c648",这种类型是etag,值是一个url,也就是上面1734的类型。

 2、"19764,section,19793"是对象和etag的关系。

 3、"/article/23678hostname=sfj.fh.gov.cn&",是url,值是一个hash,1、content,2、etag两个键。

 4、"siteid:8920",保存的是一个list,站点所有的etag。

 现在来走一遍看看,这个缓存如何工作在filter里面工作:

 1、用户访问:http://sfj.fh.gov.cn/article/123

 a、如果用户是第一次访问,那么没有etag在header里面,以url作为key,获取content和etag,在response中设置etag,让content输出。

 b、如果用户是回头客,那么含有etag,以etag为key查找,如果没有找到,说明这篇内容已经更新或者删除,继续走下去。如果找到,说明内容没变,返回304即可。

 c、如果etag没有,url也没找到,说明是这个人是系统启动以来第一次访问这个内容的人。走正常流程,模板解析,将结果放入1、etag--》url,2、url--》{conent:xxx,etag:yyyy},3、obidentity--》etag,4、siteId--》etaglist

 d、如果需要刷新整站缓存,在后台的网站列表中选择对应站点的“更新缓存”即可,执行的动作是:

 从siteid键,获取整站的etag或者obidentity,依次删除即可。

 e、如果一篇文章修改了,流程如下:

 根据obidentity--》etag,etag-》url,将etag和url都删除即可。那么关联的目录怎么办?没问题!

 article.getSections(),得到文章所属的所有目录,同样删除,这个目录的父目录也必须更新,只要通过

 section.getParent()递归删除即可。这个功能集成在artile和section里面,自动进行。

这是文章的clearCache:

	public void clearCache(ObAction oa){
		//34637,,-1首页模式。
		Jedis jd = jpservice.getInstance();
		try {
			String js = this.getSiteId() + ",article," + this.getId();
			String etag = jd.get(js);
			if(etag != null){
				String jurl = jd.get(etag);
				if(jurl != null){
					jd.del(jurl);
				}
				jd.del(etag);
			}
			for(Section s : this.getSections()){
				s.clearCache();
			}
			//首页:
			WebSite ws = emp.get().find(WebSite.class, getSiteId());
			ws.clearHomePageCache();
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			jpservice.putBack(jd);
		}
	}

2、这是目录的clearCache:
	public void clearCache(){
		Jedis jd = jpservice.getInstance();
		try {
			String obid = this.getSiteId() + ",section," + getId();
			String etag = jd.get(obid);
			if(etag != null){
				String jurls = jd.get(etag);
				if(jurls != null)
					jd.del(jurls);
				jd.del(etag);
			}
			Section ps =getParent();
			while (ps != null) {
				ps.clearCache();
				ps = ps.getParent();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			jpservice.putBack(jd);
		}
	}

3、这是site的clearCache:
	public void clearHomePageCache(){
		Jedis jd = jpservice.getInstance();
		try {
			String fr = getId() + ",,-1";
			String fretag = jd.get(fr);
			if(fretag!=null){
				String frurl = jd.get(fretag);
				if(frurl != null)jd.del(frurl);
				jd.del(fretag);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			jpservice.putBack(jd);
		}
	}
	
	public void clearAllSiteCache(){
		Jedis jd = jpservice.getInstance();
		try {
			String jsid ="site:" + getId();
			long l = jd.llen(jsid);
			List<String> keys = jd.lrange(jsid, 0, l);
			for(String etag : keys){
				String url = jd.get(etag);
				if(url != null){
					jd.del(url);
				}
				jd.del(etag);
			}
			jd.del(jsid);
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			jpservice.putBack(jd);
		}
	}


加载中
0
杨子江
杨子江
很不错的实践经验 
0
ouotu
ouotu

不错呢。

返回顶部
顶部