赵劼
jeffz@live.com
   赵劼,网名老赵,洋名Jeffrey Zhao
   博客:http://www.cnblogs.com/JeffreyZhao/
   推特:@jeffz_cn
   InfoQ中文站编辑
   某创业小公司架构师 + 程序员
   希望可以给给初学者以合适引导。坚定的北大青鸟
    反对者,强烈愤慨恶劣的培训机构对于处于懵懂期
    的初学者以误导,强烈抵制各种虚假广告给业界带
    来的不良影响,强烈建议有理想有抱负的从业青年
    放弃北大青鸟,不要做冤大头。
性能        能耗        冰川
降低        增加        融化



     资源        温室        地球
     浪费        效应        毁灭
   CPU
   磁盘
   浏览器
   DNS
   网页快照
   ……
   客户端缓存
   表现层缓存
   业务逻辑层缓存
   数据访问层缓存
   数据库缓存
   ……
   HTTP/1.1
    ◦ Expires, Max-Age, ETag...
   Request Header
    ◦ If-Modified-Since
    ◦ If-None-Match
   Response Header
    ◦   Expires
    ◦   Cache-Control
    ◦   Last-Modified
    ◦   ETag
   利用HTTP/1.1的标准(同上)
   使用JavaScript编程时缓存数据:
         window.workWithCache = function(id) {
             var data = window._cache["id_" + id];
             if (data != undefined) work(data);

             makeAjaxRequest(id, window.ajaxCallback);
         }

         window.ajaxCallback = function(id, data) {
             window._cache["id_" + id] = data;
             work(data);
         }
   检查缓存No.1~30
                    请求前   请求后
    ◦ 缓存为空
   发出请求
    ◦ 请求图片No.1~30
   收到回复
    ◦ 缓存图片No.1~30
   显示图片
    ◦ 显示图片No.1~30
   检查缓存No.41~70
                     请求前   请求后
    ◦ 缓存为空
   发出请求
    ◦ 请求图片No.41~70
   收到回复
    ◦ 缓存图片No.41~70
   显示图片
    ◦ 显示图片No.41~70
   检查缓存No.21~50
                     请求前   请求后
    ◦ 发现缓存No.21~30
    ◦ 发现缓存No.41~50
   发出请求
    ◦ 请求图片No.31~40
   收到回复
    ◦ 缓存图片No.31~40
   显示图片
    ◦ 显示图片No.21~50
   便利:
    ◦ 单线程环境,避免许多麻烦
    ◦ 对于生命周期短的页面,无须资源释放
   限制
    ◦ 无法跨页面缓存
    ◦ 刷新后缓存即清空
    ◦ 对于生命周期长的页面,需要制定资源释放策略
     何时释放数据?
     释放哪些数据?
   静态页
    ◦ 粒度过大
    ◦ 几乎无法用于一般Web 2.0系统
   整页动态缓存
    ◦ 灵活性较静态页略高
    ◦ 粒度仍然过大
   页面片断缓存(fragment caching)
class BlogController < ApplicationController
  def list
    unless read_fragment(:action => 'list' )
      @articles = Article.find_recent
    end
  end
end


<% cache do %>   <!- Here's the content we cache ->
  <ul>
    <% for article in @articles -%>
      <li><p><%= h(article.body) %></p></li>
    <% end -%>
  </ul>
<% end %>
   某些时候因为@articles没有初始化而出错
   详见Robin Lu于RubyConf China 2009中的演讲
    “Ruby on Rails Pitfalls”,Page 10
public class BlogController : Controller {
    public ActionResult List() {
        var model = LazyBuilder.Create<Model>()
            .Setup(m => m.Articles, () => Article.FindRecent())
            .Instance;
        return View(model);
    }
}
<% Html.Cache("recent-articles", () => { %>
    <ul>
        <% foreach (var article in Model.Articles) { %>
            <li><p><%= article.Body %></p></li>
        <% } %>
    </ul>
<% } %>
   使用相对方便,性能优势明显
   粒度较大,适用面相对较窄
    ◦ “即时性”往往不够
   与业务密切相关的缓存
    ◦ 推荐好友
    ◦ 最新文章
    ◦ ……
   一般用于缓存实体对象
   控制灵活
    ◦ 相对容易设计“即时”的缓存
   复用概率大
    ◦ 命中率
Cache




Page
Cache




Page
   站内短消息列表
    ◦ 帖子列表
    ◦ 回复列表
    ◦ 好友列表
   分页显示
   即时更新
   缓存每页数据时,附带获取数据时的时间戳
    ◦ data + read_timestamp
   在发生更新时,刷新时间戳
    ◦ last_updated_timestamp
   读取缓存时,比较数据获取时间与最后更新时间
    ◦ 如read_timestamp > last_updated_timestamp,则
      cache hit
    ◦ 如read_timestamp < last_updated_timestamp,则
      cache miss
Comment[] GetComments(int articleId, int page) {
    DateTime lastUpdated;
    var cached = GetFromCache(articleId, page, out lastUpdated);

    if (cached == null || cached.TimeStamp < lastUpdated) {
        var data = GetFromDatabase(articleId, page);
        cached = new CacheEntry(data, DateTime.Now);
        SetToCache(articleId, page, cached);
    }

    return cached;
}

void AddComment(Comment comment) {
    ... // write to database
    SetLastUpdatedToCache(comment.ArticleID, DateTime.Now);
}
   共享引用问题
   并发环境下的缓存操作
    ◦ 博客园评论列表
   缓存数据大小
   是否每个数据都要缓存?
    ◦ 爬虫访问?
    ◦ N年前的数据?
   是否每种数据的缓存策略都相同?
    ◦ 存储方式?
    ◦ 过期策略?
Data Access Layer



R
                   W




       RDBMS
   手机之家数据访问组件(引用自许超前的博文)
   是否透明?
    ◦ 多种数据库
    ◦ 多存储方式(RDBMS,K/V存储)
   即时性如何?
    ◦ 数据复制
    ◦ CAP
   是否能够应对所有形式的查询?
    ◦ 功能 vs. 复杂度
   是否一定需要缓存?
    ◦ 复杂查询
    ◦ 并发操作
   手机之家新系统介绍及架构分享
   数据库缓存优化:拆表
   避免缓存滥用
    ◦ 缓存不是万能的
    ◦ 缓存带来复杂度
   业务为技术让步
    ◦ e.g. 难道“即时”就那么重要吗?
   Consistent Hash
Web开发中的缓存
Web开发中的缓存
Web开发中的缓存
Web开发中的缓存

Web开发中的缓存

  • 1.
  • 2.
    赵劼,网名老赵,洋名Jeffrey Zhao  博客:http://www.cnblogs.com/JeffreyZhao/  推特:@jeffz_cn  InfoQ中文站编辑  某创业小公司架构师 + 程序员  希望可以给给初学者以合适引导。坚定的北大青鸟 反对者,强烈愤慨恶劣的培训机构对于处于懵懂期 的初学者以误导,强烈抵制各种虚假广告给业界带 来的不良影响,强烈建议有理想有抱负的从业青年 放弃北大青鸟,不要做冤大头。
  • 3.
    性能 能耗 冰川 降低 增加 融化 资源 温室 地球 浪费 效应 毁灭
  • 5.
    CPU  磁盘  浏览器  DNS  网页快照  ……
  • 6.
    客户端缓存  表现层缓存  业务逻辑层缓存  数据访问层缓存  数据库缓存  ……
  • 7.
    HTTP/1.1 ◦ Expires, Max-Age, ETag...  Request Header ◦ If-Modified-Since ◦ If-None-Match  Response Header ◦ Expires ◦ Cache-Control ◦ Last-Modified ◦ ETag
  • 8.
    利用HTTP/1.1的标准(同上)  使用JavaScript编程时缓存数据: window.workWithCache = function(id) { var data = window._cache["id_" + id]; if (data != undefined) work(data); makeAjaxRequest(id, window.ajaxCallback); } window.ajaxCallback = function(id, data) { window._cache["id_" + id] = data; work(data); }
  • 10.
    检查缓存No.1~30 请求前 请求后 ◦ 缓存为空  发出请求 ◦ 请求图片No.1~30  收到回复 ◦ 缓存图片No.1~30  显示图片 ◦ 显示图片No.1~30
  • 11.
    检查缓存No.41~70 请求前 请求后 ◦ 缓存为空  发出请求 ◦ 请求图片No.41~70  收到回复 ◦ 缓存图片No.41~70  显示图片 ◦ 显示图片No.41~70
  • 12.
    检查缓存No.21~50 请求前 请求后 ◦ 发现缓存No.21~30 ◦ 发现缓存No.41~50  发出请求 ◦ 请求图片No.31~40  收到回复 ◦ 缓存图片No.31~40  显示图片 ◦ 显示图片No.21~50
  • 13.
    便利: ◦ 单线程环境,避免许多麻烦 ◦ 对于生命周期短的页面,无须资源释放  限制 ◦ 无法跨页面缓存 ◦ 刷新后缓存即清空 ◦ 对于生命周期长的页面,需要制定资源释放策略  何时释放数据?  释放哪些数据?
  • 14.
    静态页 ◦ 粒度过大 ◦ 几乎无法用于一般Web 2.0系统  整页动态缓存 ◦ 灵活性较静态页略高 ◦ 粒度仍然过大  页面片断缓存(fragment caching)
  • 15.
    class BlogController <ApplicationController def list unless read_fragment(:action => 'list' ) @articles = Article.find_recent end end end <% cache do %> <!- Here's the content we cache -> <ul> <% for article in @articles -%> <li><p><%= h(article.body) %></p></li> <% end -%> </ul> <% end %>
  • 16.
    某些时候因为@articles没有初始化而出错  详见Robin Lu于RubyConf China 2009中的演讲 “Ruby on Rails Pitfalls”,Page 10
  • 17.
    public class BlogController: Controller { public ActionResult List() { var model = LazyBuilder.Create<Model>() .Setup(m => m.Articles, () => Article.FindRecent()) .Instance; return View(model); } } <% Html.Cache("recent-articles", () => { %> <ul> <% foreach (var article in Model.Articles) { %> <li><p><%= article.Body %></p></li> <% } %> </ul> <% } %>
  • 18.
    使用相对方便,性能优势明显  粒度较大,适用面相对较窄 ◦ “即时性”往往不够
  • 19.
    与业务密切相关的缓存 ◦ 推荐好友 ◦ 最新文章 ◦ ……  一般用于缓存实体对象  控制灵活 ◦ 相对容易设计“即时”的缓存  复用概率大 ◦ 命中率
  • 20.
  • 21.
  • 22.
    站内短消息列表 ◦ 帖子列表 ◦ 回复列表 ◦ 好友列表  分页显示  即时更新
  • 23.
    缓存每页数据时,附带获取数据时的时间戳 ◦ data + read_timestamp  在发生更新时,刷新时间戳 ◦ last_updated_timestamp  读取缓存时,比较数据获取时间与最后更新时间 ◦ 如read_timestamp > last_updated_timestamp,则 cache hit ◦ 如read_timestamp < last_updated_timestamp,则 cache miss
  • 24.
    Comment[] GetComments(int articleId,int page) { DateTime lastUpdated; var cached = GetFromCache(articleId, page, out lastUpdated); if (cached == null || cached.TimeStamp < lastUpdated) { var data = GetFromDatabase(articleId, page); cached = new CacheEntry(data, DateTime.Now); SetToCache(articleId, page, cached); } return cached; } void AddComment(Comment comment) { ... // write to database SetLastUpdatedToCache(comment.ArticleID, DateTime.Now); }
  • 25.
    共享引用问题  并发环境下的缓存操作 ◦ 博客园评论列表  缓存数据大小  是否每个数据都要缓存? ◦ 爬虫访问? ◦ N年前的数据?  是否每种数据的缓存策略都相同? ◦ 存储方式? ◦ 过期策略?
  • 26.
  • 27.
    手机之家数据访问组件(引用自许超前的博文)
  • 28.
    是否透明? ◦ 多种数据库 ◦ 多存储方式(RDBMS,K/V存储)  即时性如何? ◦ 数据复制 ◦ CAP  是否能够应对所有形式的查询? ◦ 功能 vs. 复杂度  是否一定需要缓存? ◦ 复杂查询 ◦ 并发操作
  • 29.
    手机之家新系统介绍及架构分享
  • 30.
    数据库缓存优化:拆表  避免缓存滥用 ◦ 缓存不是万能的 ◦ 缓存带来复杂度  业务为技术让步 ◦ e.g. 难道“即时”就那么重要吗?  Consistent Hash