赵劼,网名老赵,洋名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 < ApplicationControllerdef listunless read_fragment(:action => 'list' )@articles = Article.find_recent
endend
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 databaseSetLastUpdatedToCache(comment.ArticleID, DateTime.Now);
}
共享引用问题
并发环境下的缓存操作◦ 博客园评论列表
缓存数据大小
是否每个数据都要缓存?◦ 爬虫访问?
◦ N年前的数据?
是否每种数据的缓存策略都相同?◦ 存储方式?
◦ 过期策略?
RDBMS
Data Access Layer
RW
是否透明?◦ 多种数据库
◦ 多存储方式(RDBMS,K/V存储)
即时性如何?◦ 数据复制
◦ CAP
是否能够应对所有形式的查询?◦ 功能 vs. 复杂度
是否一定需要缓存?◦ 复杂查询
◦ 并发操作
手机之家新系统介绍及架构分享
数据库缓存优化:拆表
避免缓存滥用◦ 缓存不是万能的
◦ 缓存带来复杂度
业务为技术让步◦ e.g. 难道“即时”就那么重要吗?
Consistent Hash