全站缓存时代

原则:动静分离,分级缓存,主动失效。

Web 开发中,接口会被分为以下几类:

  1. 纯静态页面。打死我都不会修改的页面。很长一段时间内,基本上不会修改。比如:关于我们。
  2. 纯动态页面。实时性,个性化要求比较高。页面变化很大,或者每个用户看到的都不一样,比如:朋友圈。
  3. 短时静态页面。在一定时间内基本不会变化,或者是容忍不需要实时更新。比如:文章、新闻。
  4. 动静结合页面。这个页面既有动态,也有静态内容。也是实际应用中最多的。

对于以上类型的页面,可以做不同的缓存方案。各位大神们应该根据自己业务的情况,灵活调整缓存方案。以下内容可以作为参考。

模板渲染

高速发展的模板引擎,给前端渲染带来了活力。Mustache、jade、hbs 灵活的模板语法让页面开发变得更省力和高效。

HtmlDOM == VeiwEngine.render(template ,data);

浏览器只认识 DOM 结构的字符串,也就是常说的 HTML5 格式。对于前端来渲染 DOM,还是后端渲染的问题,在此不用讨论,为了情况前端的性能和体验,后端渲染会更合适。对于同一个页面,每次请求都会产生一次渲染吗?渲染总是要计算的,这样多浪费服务器性能啊!确实是这样,除非你用了缓存。

页面缓存的方案

1. 纯静态页面

直接放 CDN。纯静态页面的访问量一般不会很大,程序直接响应也是可以的。

2. 纯动态页面

都说是动态页面了,那就不要做页面缓存了。可以考虑做数据缓存,或者是 redis、DB 缓存。

3. 短时静态页面

1. 服务器端文件缓存

请求-->处理接口--> 模板渲染 ---> 存储文件---> 响应文件

缓存动态页面,你也可以把生成的文件存到 CDN,然后让 CDN 去响应请求。如果你的请求需要过一些验证,那就把文件存储到服务器,由业务服务器去响应请求。文件还有一个好处是:流。例如:FileReadStream.pipe(ResponseStream)。响应的时候,不需要把文件的内容加载到内存,而是直接用 stream 的方式响应。但是弊端也不少,文件存储,会有并发读写死锁问题。

还有一个问题,分布式系统。可能你有 A、B、C 三个服务器。A 服务器生成了一个文件,还需要实时同步到 B 和 C。当然也可以让 A、B、C 挂载同一个磁盘。问题又来了,这个文件要不要备份呢?

2. Redis Cache

请求--> 接口接口---> 模板渲染 --> 存储数据--> 响应 DOM

把请求的 url 当做 key,把模板渲染好的数据当做值,然后根据缓存规则,把数据存储到 redis。

这种小成本的缓存在我们的系统中有实践,的确大幅提高了系统的响应时间和 QPS,页面的请求大部分是从 redis 读数据,然后返回,单机测试过极限性能,14k QPS。简单描述一下。我们称之为静态化staticize

  1. 开始请求
  2. 请求校验,filter 等等
  3. 查询缓存 redis
  4. 如果有缓存,则直接响应
  5. 没有缓存,查询数据,重新渲染,存储到 redis.
  6. 响应
  7. 如果需更新缓存,只需要删掉对应的redis 值

4. 动静结合的页面

这种页面在实际情况中更常见。原则:静态页面缓存,动态部分异步请求。

Paste_Image.png

静态部分也是模板渲染过来的,浏览器会从 CDN 或者后台缓存中获取到静态页面。页面响应的时间和浏览器的渲染会直接影响用户体验。动态更新的部分一般会在一些细节部分,比如页面的登录状态。对于所有用户来说,我看到的这个页面,只有用户头像部分会不一致。如果系统为每个用户生成一个静态页面成本就太高了,而且完全没必要。

这个页面就变成了:页面 == 短时静态页面 + 局部动态页面。

『用户状态信息』这个特殊的动态内容,还需要用到本地的缓存机制。用户在切换页面的时候,每个页面都需要动态加载用户信息,所以我们的做法是在第一次请求到这个信息的时候,存储到 localStorage,然后设置过期时间。退出的时候,主动清理 localStorage。

比如:个性化,个人推荐这种因人而异的板块都可以做成局部动态页面的形式。

5. 数据缓存

以上的方案同样适用于异步请求。

对于CDN 或者其他缓存来说,缓存不知道你存的内容是 DOM 还是 JSON,还是其他格式。它只是帮你存储数据。你同样可以的把,数据接口、局部 DOM 结构(非完整 html 格式)存储到 CDN 或者是 redis 中。比如:页面的配置信息,或者从相关推荐系统请求的 dom 结构。

缓存更新

一般会有主动失效和自动失效缓存机制。

CDN 和 redis 等缓存都可以根据规则设置缓存时间。缓存过期后,会再次获取新的数据。
主动更新一般会用 API 调用方式实现。比如删除 key,或者调用 CDN 接口进行删除操作

Paste_Image.png

缓存穿透

一般会在第一次请求的时候生成缓存,如果服务器端没有缓存,然后在同一时刻出现高并发请求,请求会直接到达业务逻辑部分,很可能导致系统直接挂掉。

解决办法:

  1. 主动创建缓存。缓存求由系统定时创建。
  2. 请求的时候设置标志位。第一个请求到达,标识这个 url 正在创建缓存,其他请求进入等待队列。

全站 CDN 加速

CDN 动态加速如下图所示:

Paste_Image.png

例如我的网站有以下接口和页面:

  1. http://www.localhost.com/ // 短时缓存,动静结合
  2. http://www.localhost.com/api/user/1 // 纯动态
  3. http://www.localhost.com/post/hello-world // 永久静态

所以,1、3页面会放到 CDN,2 直接去源站请求。怎么做到呢?

  1. 在 CDN 配置自主源站。意味着请求 CDN 地址的时候,CDN 会去源站请求数据,然后缓存到 CDN 节点。
  2. 设置缓存规则
    / 缓存 1 分钟
    /post/* 缓存 1 年
    /api/ 不设置缓存
    
  3. cname www.localhost.com 到 CDN 提供的空间域名
Paste_Image.png

多平台 Mulit Origin

一个 URL 可能会在不同的平台有不同的返回和表现形式。

产品的想法都是很完美,一个按钮在不同的平台会有不同的显示状态。实际情况非常复杂,在我们的系统中,出现过一个页面出现在 七 个平台,每个平台的显示效果会不一致。不管是模板渲染,或者是 js 处理按钮状态等等都是非常复杂的,或者 pc 和移动端页面表现出样式和结构差异。如果还要把这个页面放到缓存,就更加复杂了。

为每个平台生成一份缓存?可以!

平台的识别来自 UserAgent,不同的浏览器或者 app,都有不同的UserAgent。不同的来源我们称之为 Origin。Origin + url 就可以生成唯一的 key,去识别唯一的缓存。缓存不限于 redis 和 文件缓存。

CDN 识别来源去读取不同的文件,就需要 CDN 那边做一些开发工作了。Upyun、七牛这边暂时不支持的。BAT这种大公司他们自己维护的 CDN 就能完美地做到。

另一种思路:

1个项目,两个域名,2个动态 CDN。PC 和移动端页面分离、接口共享。

例如:为同一个项目配置两个域名:www.localhost.comm.www.localhost.com,同时为这两个域名各设置一个动态 CDN。

由一项目提供两个域名服务,比如:IndexController.main 处理请求 /homepage,移动端和 PC 端的请求路径分别为
* http://m.www.localhost.com/homepage
* http://www.localhost.com/homepage

main action 会根据请求来源url,分别渲染不同的页面。不同的域名页面,也就被不同的动态 CDN 缓存起来。

对于 /api/xxxx的接口,自然不需要做 PC 和移动端或者其他平台的区分,一个 action 就可以解决了。这样就避免了维护两套系统的问题。

结语

以上,全站缓存基本完成。

不要凭空去拉高 QPS或者乱用缓存,根据你的业务和实际情况来对待。最重要的事情就是要牢记:保持简洁,按需使用。

参考文献

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 【转】缓存在分布式系统中的应用 缓存在分布式系统中的应用 摘要 缓存是分布式系统中的重要组件,主要解决高并发,大数...
    武汉苏乞儿阅读 848评论 0 10
  • 缓存在分布式系统中的应用 摘要 缓存是分布式系统中的重要组件,主要解决高并发,大数据场景下,热点数据访问的性能问题...
    garyond阅读 1,597评论 0 12
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,727评论 1 92
  • 今天我们一起来看看另外几位的判词。 欲洁何曾洁,云空未必空。 可怜金玉质,终陷淖泥中。 意思是:打算清新洁寂却从未...
    无风TINO阅读 561评论 0 2