转自:https://www.dotblogs.com.tw/wasichris/2015/11/14/153922
前言
一般而言系统资料多来自远端资料库及WebAPI等,若频繁地从资料源捞取资料,有可能造成资料提供者的负担,且系统亦需承担因频繁捞取资料所造成的等待时间成本;这时我们可以考虑使用快取(Cache)来增加资料读取效率,避免上述冲击发生。 简单来说,快取就是以资料时效性及记忆体空间来换取资料获得效能,所以可能会面临资料不同步(资料源与快取)的问题,因此决定何时要收回快取来向资料源重新捞取资料,是程式开发者需要考量的一个重要议题,以下介绍几种不同快取回收时机,可以依照自身需求选择适用之条件。
快取使用方式
从.NET 4.0 开始,我们可以载入System.Runtime.Caching组件来实现快取机制,透过MemoryCache.Default来取得预设记忆体快取实体,使用方式就类似操作Session资料,但可依照需求来自定快取回收时机。
1. 加入快取(Set, Add, AddOrGetExisting)
- Set (快取已存在时,直接覆写)
- Cache[key]=value (快取已存在时,直接覆写,但无法设定CacheItemPolicy)
- Add (快取已存在时,不会覆写原有设定,会回传false结果告知新增失败)
2. 设定快取回收时机(CacheItemPolicy)
让系统可以在适当的时机点再次向资料源请求资料,作为新快取值供系统取用,可用逻辑如下。
- 指定时间是否到期(Expiration)
- AbsoluteExpiration (ex. 设定快取后10s 回收快取)
- SlidingExpiration (ex. 10s 内没人取用就回收快取)
- 监控资料源是否改变(ChangeMonitor)
- HostFileChangeMonitor (实体档案异动时回收快取)
- SqlChangeMonitor (DB档案异动时回收快取)
- CustomizedChangeMonitor ( 可以继承实作ChangeMonitor 类别来建立独有的监控逻辑)
3. 接收快取异动通知(Callback)
- UpdateCallback (回收快取-前)
- RemovedCallback (回收快取-后)
应用层面
举个简单范例来比较各种快取回收机制。 需求是这样,笔者有许多资料会放置在TXT档案中,这些资料都是系统会经常使用到的资讯,但我们不希望频繁地去读取该档案,以避免频繁读取磁碟而造成效能的消耗,因此希望加入快取来达成我们的目标;由于此范例重点在比较各快取收回机制效果,因此就不着墨适用性的问题了。
首先定义DataSourceProvide 做为资料来源类别,其中FileContents 属性会从实体档案中取得资料,接着会将资料存放于快取中,由于笔者想要验证不同快取回收机制所产生的效果,因此提供三种快取机制供切换测试使用;由于资料来自于实体档案,因此除了可在时间上的操作快取回收时机外,还可以使用HostFileChangeMonitor做为资料异动监视器,如有异动随即回收快取。 测试程式代码如下所示。
1 | public class DataSourceProvider |
测试主程式如下,可选择不同快取回收机制(CacheItemPolicy)来比较各自成效。 其中设定快取被回收后Callback方法,让它直接印出cache removed 讯息告知用户,方便后续测试时于画面显示快取被回收的时机点。
1 | static void Main(string[] args) |
程式启动后,首先就是选择所需使用的CacheItemPolicy 机制
当选择AbsoluteExpiration作为CacheItemPolicy 时,表示设定快取2秒后会回收快取; 从以下测试发现当设定快取后,时间超过2秒确实会回收快取,且在下一次取资料时,再次读取实体档案来载入至快取。
若使用SlidingExpiration作为快取Policy时,表示快取超过3秒没被取用的情况下,快取会自动被收回,结果如下图所示;所以换句话说,如果此快取密集地不断被取用(3秒内至少一次),此快取将永不被回收。
最后,若使用ChangeMonitors 作为快取Policy时,则表示当实体档案资料来源只要一有异动,快取就随即被收回;因此在这个CacheItemPolicy 中,快取回收机制将与时间没有任何关系了。
结论
综观上述三种方式,可能会有人觉得当然是使用ChangeMonitors 作为CacheItemPolicy 最好,在资料源被异动时马上收回快取,让资料不会有不同步的情况发生,又兼具快取特性;但是试想一个情况,当资料来源每秒都在不断地变动时(也许是汇率),而我所需的资料其实不需要这么即时,因为每次取得的汇率资料是可以被保留使用10秒钟,因此在这情境中是否可以使用AbsoluteExpiration作为快取回收机制,让快取经过10秒后过期被收回才会比较合适呢? 其实笔者想表达的意思是,快取的使用不一定适用所有情境,需要搭配不同快取回收机制才能达到提升效能的效果,因此请不要一昧地加注快取机制于系统中,否则可能会造成反效果。
参考资讯
http://blog.miniasp.com/post/2010/05/01/ASPNET-4-Cache-API-and-ObjectCache.aspx
http://blog.darkthread.net/blogs/darkthreadtw/archive/2008/06/23/kb-cache-add-vs-cache-insert.aspx