由CSDN论坛的文件缓存想到的(http://www.csharpwin.com/dotnetspace/2329.shtml)

来源:互联网 发布:linux 查看磁盘阵列 编辑:程序博客网 时间:2024/04/30 03:58

CSDN因为访问量巨大,所以采用了文件缓存机制,即将帖子内容生成XML文件,再在客户端有XSLT解析,确实可以很大的减轻数据库压力。于是我也想了想,如果采用这种文件缓存的方式来增强论坛、Blog的性能,减轻数据库压力,要注意哪些问题呢?于是仔细想了想一些可能的问题和如何来解决:

在这之前我先对本文的术语作一个简单解释:第一篇帖子和它的所有回复都称之为一个主题(Thread),第一篇帖子和它后面的每篇回复都叫做帖子(Post)。另外一个前提是本文中,类似于CSDN的情况:即XML文件缓存是辅助的,在数据库中同时存有一份数据,访问时先访问数据库获取关键信息,然后在显示帖子内容时读取XML文件。

缓存的单位:CSDN的缓存是以一个Thread为单位,将Thread下所有的Posts都生成一个XML,这样一个好处就是生成的文件比较少,缺点就是文件更新较频繁(每有回帖就必须更新一下文件),不方便支持帖子修改/删除功能,客户端下载时需要整个XML下载完才能显示出HTML。我个人倾向于以Post为单位,每个Post生成一个XML,这样做的缺点是生成的文件较多,优点是调用更加灵活,不用频繁更新XML,在客户端解析时可以支持单个Post加载完就显示。

缓存的时机:生成缓存文件主要有两种时机——帖子创建时即生成XML、第一次访问帖子时生成XML。我个人倾向于第二种方案:有利于多台服务器负载均衡,如果缓存文件丢失,可以方便再次生成。CSDN好像是采用的在有新帖子创建时生成/修改XML,不确认。

支持帖子修改:CSDN是不支持帖子修改和删除的(版主应该可以吧),具体原因我不清楚,如果他们的缓存文件时在帖子创建时生成和更新,那么可能是不想频繁更新文件,如果是第一次访问时,那么需要有一个时间戳来记录帖子是不是修改了,如果修改了那么需要更新XML。基于前面两个问题我选择的方案,在第一次访问时生成缓存的XML文件,并且以Post为单位生成XML文件,那么当帖子修改后,我在下次访问时需要更新这个XML文件,而不是访问旧的XML文件。
那么怎么样才能在每次访问时知道帖子更新了呢?如果是帖子修改时就直接更新XML文件当然简单,但是现在不是这样,那么是不是每次先服务器端读取一遍XML,然后对比一下XML中的帖子最后更新时间和数据库中的帖子最后更新时间是不是一致的,如果不是就表示需要更新XML了,这样当然可行,但是效率太低了,不过这倒是给了我一点启发:为什么不直接以帖子最后更新时间(精确到秒)命名,这样在找缓存文件时,如果帖子更新了,而缓存文件没有更新,那么就会找不到缓存文件,再次生成就好了。这样有个问题是会导致过期的文件还存在,倒不见得是坏事情——相当于对每个帖子都有个历史存档了。

权限问题:如果XML路径是很有规律的,并且可以被直接访问到,那么就没有什么权限和隐私可言了,一种比较直接有效的方法,就是通过HttpHandler来隐藏缓存的XML文件的真实路径,并且判断用户是否有权限看到。如果你担心XML文件路径可能被猜出来,那么可以将缓存文件禁止直接外部访问,或者对上面提到的XML文件命名方案进行改进:对于Post增加一个属性——缓存文件名,第一次创建时生成一个随机数作为文件名,如果后来帖子有修改,同时更新这个属性。

文件保存路径:因为每个Post一个文件这种方案会让文件很多,如果一个目录下文件太多,检索效率会非常低的,那么应该对文件进行分区,分成四级目录:第一级将帖子文件按照所属板块(Forum)分类,例如按照板块的ID生成目录;第二级按照Thread的日期来分类,这个可以根据帖子量来决定日期划分,如果帖子量巨大甚至可以每天一个目录;第三级按照Thread来分类,例如按照Thread.ThreadId来生成目录,第四级按照Post来分类,因为每个Post每更新一次就会生成一个新的XML,参考命名方式:
string cacheFilePath = string.Format("Forum{0}\\{1}\\{2}\\Thread{3}\\Post{4}\\{5}.xml",?post.ForumId, post.ThreadDate.ToString("yyyy"), post.ThreadDate.ToString("MM"), post.ThreadId, post.PostId, post.CacheFileName);

换皮肤问题:XSLT本身就可以很方便的实现换肤功能——每种皮肤一个XSLT文件即可,不过这样的一个问题就是需要对XSLT比较熟悉。如果要在传统的论坛换皮肤基础上实现这个功能,可以考虑一个折中的方案:将每个缓存后的Post的XML作为XML数据岛嵌入在帖子显示的位置,本身IE对XML数据岛就支持非常好,即使是FireFox之类不支持XML数据岛的浏览器(貌似是不支持的),也可以结合XSLT来做,这个XSLT只要解析显示帖子内容这部分就好了,相对难度小很多。

实际上这也是我对文件缓存的一些不成熟想法。同时推荐一篇相关文章:Disk-based Output Caching Module