尹衍林
(鸡西大学 电气与信息工程系,黑龙江 鸡西 158100)
在网站设计过程中,完全依靠实时数据库查询,虽然可以获得最快的数据同步,但是会增加服务器的压力,从而影响服务器执行的效率,缓存技术可以解决效率方面的问题。通过使用适当的缓存设置,可以向用户提供较好的应用程序体验。如果缺乏整体缓存机制设计,不仅会导致网络的性能低劣,还会引发一些功能缺陷。
无论是页面缓存还是数据缓存,在设计的过程中都应当尽量遵循以下一些基本原则。
缓存的使用是建立在占用内存(甚至磁盘空间)的基础上的,所以缓存的滥用必然导致大量磁盘空间和内存的无谓消耗。因此,虽然缓存的查询速度非常快,我们仍然要尽量保持缓存的清洁和简约,需要用到缓存的地方,毫不犹豫地使用它,但是对于一些不太可能被访问到的数据,尽量不要随意地、长时间地保存在缓存中,那样虽然在表面上也并不会影响整个网站数据的查询,但是这些数据会在无意中失去管理,成为内存中的垃圾,甚至还可能为网站数据安全带来风险。
众所周知,缓存中的内容与数据库中的内容很难在每时每刻都保持绝对一致,这种一致性只能无限地接近,在这个无限接近的过程当中,需要付出性能的代价。由于网站服务器的CPU数量和性能在长时间内是基本稳定的,与扩展性相对较强的内存相比,CPU可以说是整个系统中的稀缺资源,因此在获得更好的数据更新效果的同时,也要注意到缓存更新所带来的效率问题。
这里的同步不是指数据库数据与缓存数据的同步,而是指不同的缓存项中的数据,甚至是分布式系统中不同服务器中的数据同步。这种数据同步优先级别要大大高于数据库与缓存之间的同步。因为数据库与缓存之间的同步很少会带来操作上的歧义,但是不同缓存项中的数据如果产生了差别,就可能在两个不同的地方针对同一笔数据或者流程采取不同的操作,对于网站系统来说,这样的漏洞比程序本身的Bug更难控制。
缓存中一旦建立了相应数据的缓存项,就应当充分利用它。这要求缓存的通用性和兼容性更强,并且建立很好的接口;缓存模块只有建立在良好的设计基础之上,才能更好地实现。
具体问题具体分析,这一理论贯穿于软件开发的整个过程,以上四种原则是缓存机制设置的最基本原则,在实际应用过程中,难免会出现一些特殊问题或受特殊因素的影响而使设计发生改变,因此在创建缓存模块的过程中,要全面考虑,根据不同的情况灵活应用。
以问答模块为例,问答等模块都是建立在用户模块基础上的,也就是说用户登录以后才能使用该模块的功能。系统在多数页面中往往会包含用户的个人信息(如用户名、站内信提示、账户信息等),这样的页面一旦被整个缓存起来,在一段时间内,所有的用户都将看到一模一样的个人信息,这显然是不合理的。所以在模块中使用页面缓存时要非常注意,尽量不要整个页面都使用页面缓存,而是缓存局面的用户控件或者服务器控件。
由于页面缓存的灵活性低于数据缓存,所以在一些可以使用页面缓存但是数据变动较为频繁的页面中,我们将更优先考虑页面缓存,如问题详细信息页面的回答列表。
数据缓存优化设计是整个缓存机制的重点,这不仅因为数据缓存的代码会比较复杂,不像页面缓存那样可以简单地进行配置,更重要的是数据缓存贯穿整个模块乃至整个网站,可能会涉及到网页的任何一个页面,其变动性和灵活性对缓存扩展性的要求很高,并且数据缓存在很多情况下会直接关系到整个网站的数据安全和稳定性。因此,构建一个强大稳定的缓存模块是十分必要的。
正因为数据缓存是所有缓存的重中之重,网站和其中任何子模块的缓存设计都应当把数据缓存放在最重要的位置。对于问题模块来说,几乎所有内容都可以使用缓存,因此我们的目标是,尽可能使所有页面请求的数据都从缓存中读取,而不是直接从数据库读取。对于数据库数据的缓存通常有两种做法——全部缓存和部分缓存。
全部缓存是将所有数据库的信息一个不漏地放入缓存中,以缓存查询完全替代数据库查询。这种做法的优点是:更新条件简单,只需要从数据库中读取所有数据即可;查询逻辑简单,只需要查询缓存中的数据,如果缓存中不存在,就表示数据库中也不存在,没有必要再到数据库中查询。缺点是:占用更多的内存,查询时程序可能面临更多的冗余数据;一旦数据更新过程出错,可能导致不完全的查询。虽然为了保证查询的可靠性,我们可以把在缓存中查询不到的数据再从数据库查询,但是这样会降低全部缓存的效率,甚至有时候还不如直接从数据库查询。
为了弥补全部缓存的不足,我们可以使用部分缓存。部分缓存是指把一部分数据存入缓存中,当程序查询数据的时候,优先从缓存中查询,当缓存中不存在此数据时,再从数据库查询。如果数据量十分庞大,并且命中率比较低的时候,部分缓存是一个不错的方案。部分缓存中数据可以是系统约定的,也可以是从数据库中查询到数据,返回的时候顺便记录到缓存中。在缓存过期之前,再次查询相同数据的时候,程序能够很快地从缓存中找到数据。
与全部缓存相比,部分缓存的优点显而易见,即更加节约内存,数据更有效,查询效率更高。同样,部分缓存也存在不足,如重复查询。数据重复,这个问题和线程有关,假设A和B两个进程同时以相同的目标查询缓存,结果缓存中不存在,然后程序自动分别将这两个查询结果添加到缓存中[1]。
解决这个问题的方法是使用一些设计模式(单例模式)限制对缓存的访问,在同一个时间内只允许一个线程访问缓存。但是这种做法在应对这个缺陷的时候,还是会存在一些问题,如果数据库查询速度比较慢就会出现一些问题。
在设计各缓存模块的过程中,应当运用灵活原则,在充分考虑数据库特征的基础上,采取全部缓存和部分缓存两个策略,可以将两者的一些思路结合起来应用。对于一些数据量不大、相对比较固定、查询频率比较高的数据,可以使用全部缓存,如目录和用户信息;对于数据量大、查询频率不高的数据,可以使用部分缓存,如提问信息。
数据缓存和页面缓存不同,配置的灵活性为我们提供了足够多的架构空间。因此,一个设计合理的数据缓存模块将有助于网站建设的成功。
搜索引擎的索引是一个核心单元,几乎所有的搜索都是围绕着索引进行的,从搜索机器人的抓录网页,到SEO的一些优化原则,搜索引擎到处都离不开索引。
当关键字上升到索引之后,就成了系统程序的组成部分,而不仅仅是用户感兴趣的一些字词,在搜索引擎(包括站内搜索模块)的开发过程中,处理好索引,包括索引的内容、方式和结构,将有助于搜索效率的提高,使日后网站维护更加便捷。从缓存中匹配关键字,根据关键字查询到对应记录,可以在很大程度上提高搜索效率。还可以在服务器后台配置数据库时预先将数据中的关键字存储到数据库中,并为这些关键字和数据建立关联,这样当从数据库中查询数据时,就不必重复查找关键字,也不必在有限的关键字产生的时候遍历所有的缓存中的数据,同时,也可以使用一些更高效的索引方法,将更多的关键字提供给程序,以最直接的方式查询。
当网站发展到一定规模之后,一台服务器已不堪重负,就会用到分布式系统。这不仅仅是数据库和服务器的分离,还包括多台服务器同时处理业务逻辑。各台服务器的内存是相对独立的,如何处理不同服务器内存中数据的同步是一个难题。对于访问网站的用户来说,访问的往往是同一个(或一些)域名下的信息,不同的服务器返回的数据和结果对他来说应该是没有差别的。网站的数据更新非常快,有时一秒钟内可能就有几个、十几个甚至更多的请求,如何保证各个线程之间数据的同步就成了一个突出的问题。在缓存模块的应用中也有一个有关多线程的应用,更新缓存通常会为其设定一个过期的时间或者依赖项,当缓存过期后,内容被清空,此时并没有及时更新缓存,而是等待下一次访问的时候更新。这样保证了缓存过期后第一次访问时是最新的数据,但是通常情况下需要花费很多时间查询和初始化数据。在这种情况下,可以建立一个独立的线程(或者服务),在服务器后台运行,不依靠用户访问来触发缓存更新事件,而是让系统自觉地更新,这些更新可以依据时间、缓存项或者是其他一些更加灵活的条件来实现。
这里的关键字是指查询字符串本身。在搜索引擎中,并不是所有的字符串都能够成为查询的关键字,如不构成实践意义的符号,或者对搜索过程造成影响的符号、字符,如星号、顿号、单引号等,这些比较特殊的字符应当在程序进行实际搜索之前过滤掉。
对于程序来说,它本身是不能理解关键字的真实含义和多个关键字之间的联系的,如“再接再厉”常常会被人们错误的写成“再接再励”,所以当用户搜索“再接再励”时,他的实际意图可能是搜索“再接再厉”关键字,这时需要一个人性化的搜索引擎对此给出提示,为用户提供一个有可能更准确的关键字[2],一般而言可以通过两种方法来实现。一是用固定关键字关联,即将多个常用的关键字进行关联,它们之间和字母、汉字的关系一般是比较固定的;二是拼音关联,在电脑上输入错别字是常有的事情,如果使用拼音输入法,这些错别字除了发音相同、相近之外,可能并没有太多的区别,如将“再接再厉”输入成“再接再利”就无法使用一种固定关键字关联的办法,这个时候将“再接再厉”的拼音记录下来,与用户输入的关键字的拼音进行比较,当拼音相同或者相近的时候,系统就可以给出对应热门关键字的友好提示。
基于数据库访问的特征以及存储器硬件特点,所有这些缓存所围绕的一个主题都是避免执行更多的数据库操作[3]。缓存中的信息最终来源于数据库,所以如果能够尽量加快或者减少缓存和数据库之间的交流,也能提高缓存模块的使用效率。
在网站的开发过程中,要建立一套完善的缓存机制,并根据网站的现状进行更新和升级,灵活地使用这些缓存。因此,很多时候需要专门为缓存组建一些模块,使网站在运行过程中能够更可靠、更稳定地使用缓存。
[1]朱印宏.ASP.NET3.5+SQLServer网站模块化开发[M].北京:清华大学出版社,2009:471-472.
[2]赵玉伟,赵小雨,乔木.缓存技术在B/S架构信息系统中的应用[J].计算机工程,2008,34(1):233-235.
[3]杨立身,曹志义.内存缓存技术在门户网站开发中的应用研究[J].电脑知识与技术,2008,3(7):1415-1416.