APP下载

内存缓存机制在.NET平台上的设计与实现

2018-05-14徐晓思

数字技术与应用 2018年2期
关键词:命中率

徐晓思

摘要:对于使用数据库存储数据的系统而言,硬盘较慢的读取速度极大的限制了系统整体性能的提高。内存缓存机制将常用的数据从数据库缓存到内存中并实时调整缓存数据,有效的提高了数据的查询效率,降低了系统的响应时间。

关键词:内存缓存;.NET;命中率

中图分类号:TP333 文献标识码:A 文章编号:1007-9416(2018)02-0139-05

1 引言

对于使用数据库存储数据的系统而言,面临的主要问题是如何高效的查询数据,而硬盘较慢的读取速度极大的限制了系统整体性能的提高。由于数据库存储的数据量通常都比较大,如果一次性将所有数据全部缓存到内存中,会导致内存紧张甚至溢出,影响整个系统的性能和稳定性。因此,需要在.NET平台上设计并实现一个内存缓存机制,将部分使用到的数据从数据库缓存到内存中,并根据缓存项的命中情况自动调整缓存数据,以提高数据读取的效率。

2 设计

当有数据读取请求的时候,首先检查是否命中,即要读取的数据是否在缓存中。如果命中,则直接读取缓存中的数据进行使用,并更新缓存的状态。如果数据不在缓存中,则首先读取数据库中的数据进行使用,然后将数据添加到缓存中。为了防止内存溢出,在程序中对缓存数据的数量设置了上限。当需要将数据添加到缓存中的时候,首先会检查缓存是否已满,如果缓存已满,则根据清理算法对缓存进行清理后,再将新的数据添加到缓存中。数据读取的流程图如图1所示。

为了提高命中率,在有数据库写入操作的时候,同样需要更新缓存中的数据。当有数据库写入请求的时候,首先将数据写入到数据库,然后检查是否命中,即要写入的数据是否在缓存中。如果命中,则更新缓存项的数据和状态。如果没有命中,则需要将数据添加到缓存中。同样,在添加的时候需要首先检查缓存是否已满,如果已满则需要首先清理缓存后,再将新的数据添加到缓存中。数据写入的流程图如图2所示。

内存缓存机制使用特定的缓存清理算法,缓存项中除了记录数据,还记录了该项的首次命中时间FirstTime(添加到缓存中的时间)、最后命中时间LastTime(最后一次被读取或修改的时间)以及命中次数HitCount,并從以下四个角度去设计缓存清理算法:

(1)命中次数:对内存中所有缓存项按照HitCount进行排序,清理所有HitCount低于阈值的缓存项。

(2)最后命中时间:对内存中所有的缓存项按照LastTime进行排序,清理所有LastTime早于阈值的缓存项。

(3)平均命中周期:根据当前时间CurrentTime计算出缓存项的平均命中周期AveragePeriod并排序,清理所有AveragePeriod高于阈值的缓存项,计算公式为AveragePeriod=(CurrentTime-FirstTime)/HitCount。

(4)首次命中时间:如果前三种算法都未生效,则对内存中所有的缓存项按照FirstTime进行排序,清理FirstTime最早的那一项。

所有的阈值都可以在配置文件中进行设置。根据不同的部署环境设置不同的阈值能够有效的保证缓存的命中率和清理算法的效率。

3 实现

内存缓存机制依靠CacheItem、CacheGroup和CacheManager这三个类来实现,类之间的关系如图3所示。

CacheItem是缓存项在代码中的实现,用来存储缓存的内容。同时,该类还包含与命中有关的属性,并提供了获取和更新缓存内容的方法。

CacheItem包含以下私有属性:

(1)id:缓存项的唯一标识符,String类型。CacheManager必须通过id才能在CacheGroup中找到对应的缓存项,这个属性在CacheItem创建的时候被赋值,并且在缓存项的生命周期中始终保持不变。因此,该属性通过只读公有字段Id开放给外部读取,但是不能被修改。

(2)content:用于存储缓存的内容,这个属性是Object类型的,因此可以存储.NET中的任何对象。由于对content的读取和修改会引起该缓存项命中相关属性的变化,因此外部无法直接操作该属性,必须通过CacheItem提供的方法来对内容进行读取和修改。

(3)hitCount:命中次数,Integer类型。该属性记录缓存项的命中次数,在缓存内容被读取或修改的时候会自动增长,因此通过只读公有字段HitCount提供给外部读取,但是不能被修改。

(4)firstTime:首次命中时间,DateTime类型。该属性记录缓存项添加到缓存中的时间,在CacheItem创建的时候被赋值,并且在缓存项的生命周期中始终保持不变。因此,该属性通过只读公有字段FirstTime开放给外部读取,但是不能被修改。

(5)lastTime:最后命中时间,DateTime类型。该属性记录缓存项最后一次被读取或修改的时间,在缓存内容被读取或修改的时候会自动更新,因此通过只读公有字段LastTime提供给外部读取,但是不能被修改。

除此之外,CacheItem还包含一个只读公有字段Average Period,该字段根据公式计算缓存项的平均命中周期,在每次被读取的时候自动进行计算。

CacheItem的构造函数包括两个参数id和content,用于在创建的时候属于缓存项的唯一标识符和内容。

CacheItem包含以下两个公有方法:

(1)RetrieveContent:该方法用于返回缓存项的内容,并自动更新lastTime和hitCount两个私有属性。

(2)UpdateContent:该方法包含一个Object类型的参数,用于更新缓存项的内容,并自动更新lastTime和hitCount两个私有属性。

CacheItem的类图如图4所示。

CacheGroup是缓存项的集合,继承自KeyedCollection类,泛型TKey的类型是String,泛型TItem的类型是CacheItem。该类通过实现继承的GetKeyForItem方法,基于CacheItem的Id生成了索引,使CacheManager可以直接通过查询索引得到指定Id对应的缓存项。

CacheGroup的类图如图5所示。

CacheManager用于管理CacheGroup及其中的所有CacheItem。该类使用单实例模式,将构造函数私有化,仅在首次被调用的时候私有的创建唯一的实例instance,并通过只读公有字段Instance发布给外部使用。

CacheManager包含以下私有属性:

(1)cacheGroup:CacheGroup类的对象,用于存储CacheItem。

(2)max:Integer类型,表示cacheGroup中缓存项的数量上限。当缓存项达到数量上限的时候,如果要再添加缓存项,则首先需要对cacheGroup进行清理。

(3)clearStrategies:List类型,包含配置的所有缓存清理策略。

(4)defaultStrategy:ClearStrategy类型,包含默认的缓存清理策略。

CacheManager包含以下私有方法:

(1)CheckCapacity:检查cacheGroup中的缓存项是否达到数量上限。

(2)ClearCache:调用缓存清理策略清理缓存项。

(3)CreateCache:添加缓存项。在将缓存项添加到cacheGroup之前,会先调用CheckCapacity检查缓存项数量,如果已经达到上限,则调用ClearCache方法清理缓存。

(4)DeleteCache:删除缓存项。

CacheManager包含以下公有方法:

(1)Start:该方法用于启动CacheManager,包含两个参数max和clearStrategies,分别用来设置缓存项的数量上限以及用到的缓存清理策略。

(2)Stop:该方法用于在程序退出的时候关闭CacheManager,释放占用的内存。

(3)RetrieveContent:根据Id提供对应缓存项的内容。该方法有两个参数,一个是查询的Id,另一个是用out关键字修饰的Object对象content,该对象会在方法结束的时候和返回值一起返回给调用者,返回值的类型是Boolean。如果有缓存项命中,则将命中的内容赋值给content并返回True,否则将content赋为空值并返回False。

(4)UpdateContent:该方法包含两个参数id和content,用于更新id对应缓存项的内容。如果根据id无法命中缓存项,则调用CreateCache方法添加缓存项。

CacheManager的类图如图6所示。

CacheManager、CacheGroup和CacheItem只负责缓存读写的逻辑,缓存清理的逻辑由缓存清理策略实现。缓存清理策略的实现类图如图7所示。

抽象类ClearStrategy是所有缓存策略类的基类,该类实现了IClearStrategy接口的SetThreshold和Clear方法,并扩展了RemoveItems和RemoveItem方法,为子类实现了设置阈值和删除缓存项的功能。ClearStrategy定义了一个抽象方法GetOutdatedItems,这个方法返回List类型的对象,此对象包含需要被清理的缓存项清单。子类只需要重写GetOutdatedItems方法,根据自身的清理策略实现逻辑代码,获取并返回要清理的缓存项清单,即可完成缓存清理。

4 测试

内存缓存机制的测试基于应用了该机制的智能会议系统,并包括以下两个部分:

(1)缓存命中率测试:按照一个中等规模会议室(30到50人)设置数据量和缓存参数,对缓存命中率进行测試,测试的结果如图8所示。根据测试结果可以得到,命中率在测试初期较低,随后快速上升,在300次请求后增速减缓,在850次请求后趋于稳定。稳定后的命中率在66%左右,即平均每3次数据读取请求可以命中2次,只有1次需要读取数据库。

(2)系统响应时间测试:在内存缓存机制开启和关闭两种情况下分别对系统响应时间进行测试,并对两组响应时间进行比较。两种情况下系统响应时间测试的结果如表1所示。从表中可以看出,内存缓存机制在开启情况下的响应时间明显低于关闭情况。

5 结语

本文基于.NET平台讨论了内存缓存机制的设计、实现及应用效果的测试。从测试结果可以看到,内存缓存机制在命中率方面有不错的表现,有效的提高了数据的查询效率,降低了系统的响应时间,实现了设计的目标。

参考文献

[1]常广炎.Memcached分布式缓存系统的应用[J].电脑编程技巧与维护,2017,(07):24-25.

[2]邢蕾.内存缓存技术在门户网站开发中的应用研究[J].山东工业技术,2016,(20):152-153.

[3]胡嘉瑜,华蓓.基于APU的内存键值缓存系统[J].电子技术,2016,45(09):54-59.

[4]石磊,黄高攀,乔雄.基于内存数据库的索引算法研究[J].信息技术,2016,(11):139-142.

[5]许春聪,刘钊,文海雄,黄忠主,郑强.基于内存的数据存储技术研究[J].科技与创新,2018,(02):19-21.

猜你喜欢

命中率
基于文献回顾的罚球命中率与躯干稳定性影响因素研究
第9 届世界女子大金属地掷球锦标赛单人连续拋击技术运用分析
夜夜“奋战”会提高“命中率”吗
2015男篮亚锦赛四强队三分球进攻特点的比较研究
投篮的力量休斯敦火箭
试析心理因素对投篮命中率的影响