一般来说,网站随着访问量以及数据库的增大,访问速度将会越来越慢,如何优化这个响应速度,增大用户支持容量是网站从小到中,到大的必经之路。

你也可能听说过对于大型web站点一般严重依赖于cache来弹性放大其基础设施的能力。虽然已知大型网站都使用了cache,但是很少有比较严谨的探讨性文章来说说他们是如何来做这个cache的。其中的原因可能有几个,一方面很多cache的策略都是特定于特定网站的,很难泛化成理论。另一方面可能过于复杂,并无放之四海而皆准的策略存在,特别是cache的过时更新问题到现在为止应该还没有一个非常好的解决方案。

本文介绍几种应用广泛的缓存策略,如果使用得当,应该可以保证永远不会有过期数据访问的问题存在。其中第一个策略叫做:write-through策略,第二种叫做:generational caching.

writethrough是最简单有效的策略。当你向db写的时候,你就顺便向cache更新相应key的数据。这样的好处是,任何随后的请求总是会击中cache,而不用再打到db上返回数据。只有一种情况会打到db: cache内存已经占满,而你访问的key的value已经被清场。该策略也有一些需要注意的地方:

一般人们都会使用object id作为cache的key,但是不同的表,其id可能相同,因此在构造cache key时需要注意这一点,严格定义并且遵循一个统一的key定义规范就很重要了,比如User/17

另外,任何put/delete操作时,首先得确认该操作是否成功执行了,只有确认成功执行了,你才能去更新cache,

否额,可能就会出现db并未更新,但是cache却被更改的情况,从而db和cache就不再一致!

虽然这个策略对单个的object做cache非常有效,但是大部分应用会从db中拉取多个对象,比如(返回所有属于张三的书籍).对于操作包含多个对象的数据,我们来谈谈另一种策略"generational caching"

设想你在设计一个blog app,可能需要一个简单的posts表格包含每一个Post的信息,比如title, createdat等。一般博客类型网站需要有两种页面,一个是单博客页面,一个是博客聚类页面。比如posts/3和posts/两个页面。问题就来了,我们如何有效地对posts/这个页面的数据做好cache呢?

对单博客页面的caching前面介绍的策略非常适合:write through即可,每一个post都将映射为一个cache key(一般都是基于object type和object id,比如Post/3),而每次对一个post的更新都将write-through回cache中,保持数据的一致性。

更困难的问题是:我们如何处理博客聚类列表页面,比如home page或者category page的数据缓存?为了保证db和cache的一致性,非常重要的一点是:任何时候一个Post被update,那么所有包含该Post引用的keys都必须expired掉。而这是并不容易的事情,因为一个post可能在多个cache key中被引用,比如: latest ten posts, posts in php category, posts favorited by user 15等。虽然理论上你可以通过写代码来找到包含已更新post的所有cache key,并且手工去expire掉他,但是必须指出这个过程是非常费事费力也非常容易错误的!我们推荐另外一种思路,这个思路就是genrational caching.

这种generational caching对每种类型的object去维护一个"generation" value。每次一个object被更新,则该generation value就会被增加。依然使用post作为例子,任何时候有人更新了一个post object,我们就增加the post generation object as well. 然后,任何时候我们从cache中读或者写一组boject时,我们就包含这个generation key.

通过包含这个generation value在cache key中,任何时候一个Post被更新,那么接下来的访问就不会击中cache,因此强制回源db获取数据。这种策略的一个结果是:任何时候一个post object被更新或者删除,所有包含多个posts的keys都会隐含expired掉。之所以说是隐含,因为我们永远不会主动去删除这些objects,仅仅通过增加这个generation value,我们就能保证所有old keys永远不会被访问,下面的事情就留给cache系统本身的垃圾回收机制去处理。

在多个实际application中应用该策略后,对于cache的性能提高有以下几点认识:总的来说该策略可以大大提高应用的性能减少数据库的负载。可以节约大量的表格扫描等高密度计算能力要求。同时由于减少了对数据库的请求,其他必须访问数据库的请求也能大大加快性能。

为了保持cache的一致,这个策略相对有些保守,也就是说有可能部分不该过期的cache entry也被强制过期了。比如,如果你更新了一个特定类目下的一个Post,本策略会将所有类目的key都过期。而这看起来会有些低效率和过优化嫌疑。而我也发现大多数应用是read-heavy(重读请写)的因此这种过优化的缓存策略本身不会带来大的问题。相反,如果不适用这种略显“过优化”的简易策略,那么我们的代码实现完全是和应用,model绑定在一起的,是非常难以维护的。

我前面提过在这个策略中任何model都不会被显式地从cache中删除。这也隐含着和caching tool以及库满驱赶策略有关。一般这个cache策略会使用LRU(least recent used) eviction policy来配合使用。一个LRU策略会对那些老的keys优先从内存中移除。

web应用服务端cache策略初探的更多相关文章

  1. 关于如何提高Web服务端并发效率的异步编程技术

    最近我研究技术的一个重点是java的多线程开发,在我早期学习java的时候,很多书上把java的多线程开发标榜为简单易用,这个简单易用是以C语言作为参照的,不过我也没有使用过C语言开发过多线程,我只知 ...

  2. 如何提高Web服务端并发效率的异步编程技术

    作为一名web工程师都希望自己做的web应用能被越来越多的人使用,如果我们所做的web应用随着用户的增多而宕机了,那么越来越多的人就会变得越来越少了,为了让我们的web应用能有更多人使用,我们就得提升 ...

  3. 【转载】Web移动端Fixed布局的解决方案

    特别声明:本文转载于EFE的<Web移动端Fixed布局的解决方案>.如需转载,烦请注明原文出处:http://efe.baidu.com/blog/mobile-fixed-layout ...

  4. winform客户端利用webClient实现与Web服务端的数据传输

    由于项目需要,最近研究了下WebClient的数据传输.关于WebClient介绍网上有很多详细介绍,大概就是利用WebClient可以实现对Internet资源的访问.无外乎客户端发送请求,服务端处 ...

  5. Openstack的web管理端相关

    openstack的web管理端技术方面要关注的问题. 同步?异步 先说浏览器的同步和异步,我们知道的浏览器可以使用ajax实现异步请求,就是浏览器在请求数据的时候,我们管理员还能对浏览器就行其他操作 ...

  6. android中图片的三级缓存cache策略(内存/文件/网络)

    实现图片缓存也不难,需要有相应的cache策略.这里我采用 内存-文件-网络 三层cache机制,其中内存缓存包括强引用缓存和软引用缓存(SoftReference),其实网络不算cache,这里姑且 ...

  7. 从web移动端布局到react native布局

    在web移动端通常会有这样的需求,实现上中下三栏布局(上下导航栏位置固定,中间部分内容超出可滚动),如下图所示: 实现方法如下: HTML结构: <div class='container'&g ...

  8. 教你如何实现微信小程序与.net core应用服务端的无状态身份验证

    随着.net core2的发布,越来越多人使用.net core2开发各种应用服务端,下面我就结合自己最近开发的一款小程序,给大家分享下,怎么使用小程序登录后,小程序与服务端交互的权限控制. .net ...

  9. web移动端常见问题解决方案 (转)

    总结:本文总结了web移动端的常见问题并附上解决方案,包括:Meta标签.获取滚动条的值.禁止选择文本.屏蔽阴影.css之border-box.css3多文本换行.Retina屏幕高清图片.html5 ...

随机推荐

  1. php如何使用rabbitmq实现发布消息和消费消息(一对多)(tp框架)(第二篇)

    一个publisher发布消息  多个个customer接受消息 1:准备工作参照: http://www.cnblogs.com/spicy/p/7886820.html 2,:路由: 3: 方法: ...

  2. postman—post方式几种请求参数区别

    postman中 form-data.x-www-form-urlencoded.raw.binary的区别 版权声明参考: https://blog.csdn.net/wangjun5159/art ...

  3. list转换为树结构--递归

    public static JSONArray treeMenuList(List<Map<String, Object>> menuList, Object parentId ...

  4. warning: already initialized constant FileUtils::VERSION

    Ran into this, and the solution here works: https://stackoverflow.com/questions/51334732/rails-5-2-0 ...

  5. 01 JDBC的问题

    jdbc编程步骤: 1. 加载.注册数据库驱动   DriverManager 2. 创建并获取数据库链接   Connection 3. 创建jdbc statement/preparedState ...

  6. Mongodb添加副本及修改优先级

    Mongodb添加副本及修改优先级 1.添加副本集 #在primary节点上执行 >rs.add( { host: "192.168.1.11:27017", priorit ...

  7. 【LeetCode题解】237_删除链表中的节点

    目录 237_删除链表中的节点 描述 解法 思路 Java 实现 Python 实现 237_删除链表中的节点 描述 请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除 ...

  8. JAVA-6NIO之FileChannel

    Java NIO中的FileChannel是一个连接到文件的通道.可以通过文件通道读写文件. FileChannel无法设置为非阻塞模式,它总是运行在阻塞模式下. 打开FileChannel 在使用F ...

  9. Keepalived 无法自动转换主备角色,请关注 iptables 防火墙配置

    最近在研究服务器高可用集群 (HA)…… 搭建了主备两台Keepalived,配置什么的全是网上照抄的,被验证过无数遍的示例…… 然而Master和Backup无法自动切换.两边会同时绑定浮动IP(V ...

  10. Storm框架:Storm整合springboot

    我们知道Storm本身是一个独立运行的分布式流式数据处理框架,Springboot也是一个独立运行的web框架.那么如何在Strom框架中集成Springboot使得我们能够在Storm开发中运用Sp ...