首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >认识高性能Web缓存体系,你需要知道这些

认识高性能Web缓存体系,你需要知道这些

作者头像
DevOps时代
发布2018-02-02 14:45:06
1.4K0
发布2018-02-02 14:45:06
举报

前言

我们再看知识体系的时候,我们学一个东西的时候,每次我们都回过头去看一看,这就是所谓的不忘初心。这个说着容易做起来难,当一个人慢慢在成长,在进步的时候,是很难做到不忘初心的。

我们之前说了DNS缓存、浏览器缓存(维护了这么久的服务器,你真的认识 Web 缓存体系?),所以浏览器就是我们安排在千家万户缓存代理服务器,你把浏览器缓存用好,性能就不用说。

为什么这么说?如果遇到关于session或cookie的过期时间这样的问题,浏览器都不会向服务器发送连接请求。它直接用浏览器本地缓存就打开了,你说它快还是不快。

CDN与反向代理缓存

CDN缓存体系

我看了一下所谓浏览器之间的关于网络数据的缓存,可能也就是ARP解析缓存,其他Cache数据应该没有,数据只有Buffer。

为什么有Buffer?我有一个网卡发数据包的时候,我不可能一两个数据包发,我会有Buffer缓存数据包再一起发。我们DNS也有这样的配置,就是配置这样的TCP的Buffer配置。所以我后来研究了一下,网络层面几乎没有。所以用户层出来之后,就直接到了代理层。

我们的请求终于出了浏览器,不容易,一个请求在浏览器有这么多缓存。这个时候我们现在都用CDN,没有CDN的话一定是你的失职,因为现在CDN便宜得不得了,如果传统Web服务你能用的时候不用就是你工作失职。

借助腾讯云的一张图,我们看一下CDN的请求流程。我们可以看是DNS解析,到了腾讯DNS上,它会根据你的local DNS IP发挥最佳接入节点,返回一个IP地址访问CDN接入节点。

问题一:我们经常发现很多CDN调度不准确,为什么?

因为传统的智能DNS是无法获取用户IP的,它只能获取localIP,这时候他就获取不到对的IP地址了。他通过IP地址发起请求,首先到CDN接入节点,边缘节点,边缘节点都是集群。

问题二:如果边缘节点没有怎么办?

到CDN中间源相关存储,如果还没有回到用户的原站,取回数据,缓存,返回给用户,这是整个CDN请求的流程。

问题三:我们之前也有很多下载业务,下载业务基本上是不回源的,怎么办?

我每五分钟把数据同步到CDN用户上,不让它回源,因为我们发现CDN老回源,由于下载量很大的,我们带宽就不够,一回源就把带宽堵死了,这时候怎么办? 方式一:我定期给你同步,那你就要保证在请求之前数据要同步过去,这是一种方式。 方式二:下载站点切CDN的方式,我不知道大家怎么切,很多人可能是改CDN解析。 方式三:,URL动态生成,我们的URL是动态生成的,其实也不算动态生成。当然还有比如说缓存,应用程序本地缓存。

CDN关键技术

CDN关键技术,比如请求的调度,比如刚才的那种情况,IP地址不对怎么办,我还可以做第二次跳转,真正发起请求的时候,这个时候能获取到用户的真实IP。

反向代理缓存

我发现你的IP地址和我IP地址不对称,我给你返回一个CDN,重新下载等等。还有内容文件怎么分发,怎么回源,还有内容存储,这也是CDN重点的地方。再加上配置,比如通过配置管理的方式,自动化批量做边缘节点配置等等有很多。

CDN我们讲了半天,最重要的是反向代理缓存,目前反向代理缓存最主流的东西是ATS。像淘宝、阿里越来越多公司用ATS之后,现在很多也是采用ATS。但是现在主流做法不是单独用这个,都是在前面加上Nginx。

用Nginx+(Lua)在前端做相关七层的相关功能,满足到了下一个层面只做满层的功能。比如你要做安全、防攻击全在做这儿,你要做URL解析,压缩相关功能全在这儿做,最后到这儿整个缓存就可以了,这是目前主流的做法,就是让专业的工具干专业的事情。

所以这里面还有另一个关键,讲自动化运维的时候,有一句话叫做最好的一种架构,尽量的单一技术:负载均衡Nginx,Web服务器Nginx,反向代理缓存Nginx,你的公司只要招一个Nginx大牛,就解决了所有问题,这个真的挺好的。

小公司你觉得没那么明显,但是对于像BAT这样的量级,对于他们来说很明显,为什么?量级太大,如果技术组件泛滥,那就没法玩了。

昨天腾讯大梁分享咱们有听到,几十万台服务器,一个用这个,一个用那个就没法玩,这时候就标准化,接入层用什么,你想用什么我做二次开发满足你的需求,这就是单一标准化技术架构的好处。

我单独截取了几个Nginx反向代理缓存的,这个目录就可以通过挂载tmpfs来做,就不用写硬盘了。当然还有缓存刷新,一般CDN会提供缓存刷新芯片,你可以批量的把你过期的资源全部刷新一遍,这是一种方式。

Web服务器与分布式缓存

Web服务器缓存

我们把用户层和代理层所有缓存都已经讲完了,再往下我们要讲Web服务器。我现在这个请求到达了Web服务器上。

Web服务器有什么缓存?我们先说第一种缓存,缓存动态内容输出,这个做开发的比较熟悉,很多开发框架都有内置缓存引擎,你可以去把一些动态内容输出直接缓存下来,这样的话再次获取的时候就非常方便,当然还可以支持SSI,但是这个慎用,因为对性能影响非常大。

页面静态化

是不是就有一个HTML5页面,这些HTML5页面保存在本地,可能要做一些修改,页面上的登录通过JS加载就可以了。

举个例子,像京东的产品详细页就是静态页面。频道页一般也是静态页面,频道页有单独的域名,还有它的产品详细页,这些页面都是静态页面,为什么?因为它的访问量很高,但是价格是另外再去加载的,所以这个页面就是通过CMS去生成它。

其实还有一个小细节,你会发现我们再打开京东页面,这些静态资源和主站,是在不同顶级域名下,大家知道为什么在不同的顶级域名下面吗?这不是偶然,就是要这样设计,这就涉及到cookie,静态资源需要cookie吗?当然不需要,但是你知道浏览器默认情况下会干什么。比如jd.com写了一个cookie,你只要访问所有京东的页面,都会带上cookie,这个时候影响带宽,影响性能。

这个时候我们需要把它放在单独的顶级域名下面,所以你要记住你的主站和静态资源在做组件分离的时候,一定要使用单独的顶级域名,不要二级域名,没有防止cookie提交,性能会产生影响。

还有做页面组件CDN方式也有很多好处,你可以做到针对不同的资源,配置不同的Web服务器。举个例子,大图片和小图片的存储,性能调优,机器能一样吗?不一样,这时候大图片,小图片就会使用不同的域名来处理这样的关系。然后在大图片集群下用什么技术,在小图片集群下用什么技术,都可以把它分开,这是页面静态化的案例。

页面静态化怎么生成呢?其实一般会有两种主流生成方式:

  • 第一种生成方式,循环生成 比如所有的商品页面,我每隔几个小时把所有商品页面塞到一个队列里面,生成一个少一个,取一个生成一个。
  • 第二种生成方式,队列生成 这个队列要发挥优先级,有高优先级队列和低优先级队列,为什么要划优先级?因为第二种页面生成方式,我作为运维人员在后台修改一个页面,比如页面描述有一些错了,这时候你就不能等定制生成,这时候应该往高优先级队列插一条数据,先把这个页面重新静态化,但页面静态化是最解决问题的方法。
  • 第三种生成方式,搜索生成 能不能静态化?也可以的,因为我们之前在做电商的时候,遭遇过搜索攻击,什么意思呢?别人知道你们这个搜索一定是动态的,怎么办呢?我不停搜你就搜乱了,我们至少要保证把常用的搜索关键字全部做成静态页面,所以你点这些常用搜索就是静态页面,我会定期静态,定期生成,当然还有别的做法。比如搜索要和主站分开,最早搜索又不支持高可用,后来更换以后才变好的。
应用代码执行缓存

下面我们讲应用代码执行缓存,我们都知道我们语言一般分为两种:编译型语言和解释型语言。

  • 编译型语言可以直接编译成二进制代码,直接在Web服务器上运行。
  • 解释型语言比如PHP脚本,要先解析成中间操作码,然后在解释型引擎上再来做运行,那这个中间码也是可以做缓存的。

同样一串PHP脚本,每次解析出来都是一样的,我们就没有必要每次频繁做解析了,这个是可以做缓存的。

说到缓存还涉及到一个问题:安全。比如怎么检测Web木马,很多人回答说做一个扫描器,把所有文件扫一遍,看看有没有木马关键字。不行?这是最简单的方式,因为人家可以变。黑客一直在变,通过扫描器不行。这时候还有一种办法,通过中间码的方式来做Web木马扫描。

PHP OpCache

这里举一个例子,PHP操作码缓存,PHP脚本执行的时候。

首先会检测OpCache,操作码缓存有没有,如果有直接执行。如果没有解析,编译成中间码,然后保存到共享内存里,然后再执行。这样的话,下一次再执行PHP脚本的时候,就会有缓存了。

有人问我说这个缓存能带来多少性能提升呢。我有一个生产案例,我们一个广告API,每天PV至少过亿,当时CPU用户使用率大概高峰一般在70%左右,已经很高了。

使用了OPCache之后,CPU使用率降到百分之三四十,CPU使用率直接降低一半,性能不用说了。我们每个API响应时间要控制在100毫秒以内,当然其他的场景可能会更低。

因为对我们来说100毫秒就OK了,因为涉及业务还比较复杂。那OpCache怎么用呢?在PHP5.5版本之前,你需要通过APC的方式扩展来开启OpCache,在PHP5.5版本之后,只需要: 编译时增加—enable-opcache 修改php.ini增加zend_extension=/full/path/to/opcache.so 修改php.ini配置相关参数。

PHP OpCache缓存

剩下的是应用程序本地缓存,其实还有一个没有讲到,现在用得少。比如缓存动态内容输出,除了框架有这个功能,Web服务器也有。他们会缓存一些URL预设等等,我没有讲到是因为默认是开启的,你也不需要调整,但是你要知道Web服务器都有了。

还有是PEPFastCGI缓存,这个缓存我们也是可以做的。还有一个缓存是应用程序本地缓存,本如做Java的EhCache,可以让你把数据放在本地内存里,这个对性能提升也很大。因为我们之前业务过度依赖Redis,所以Redis经常压力会很大。

这时候我们把缓存体系路径拉出来,我们来考虑一下到底要不要把数据写在Redis里。我们把本地使用缓存可以直接存到缓存中,就不用Redis了,这个对性能提升也很大。

Memcached 数据库读缓存

我们再回过头来看一下缓存知识体系,应用服务可以做缓存动态内容输出,页面静态化,localCache。请求通过浏览器、CDN、Web服务器解释器缓存,应用服务缓存,都没有命中,没关系,我们后面还有一大堆缓存等着它。

我们为什么要将缓存一级级往后呢,我们让请求尽量离用户最近,最快,最少资源能够让用户获取到。因为越往下,成本越高。

访问数据库当然是最慢的了,这时候说不行,这些缓存全部没有命中,我要查数据库,这时候怎么办呢?

等等先不要查数据库,因为查数据库太慢,先查分布式缓存。比如MemCached我们做数据库读缓存,能不能做到写缓存呢?

可以做到,但是很少用MemCached写缓存的。比如我们对用户注册进行修改,以前用户注册肯定走数据库,当大促推广的时候用户注册扛不住,这时候写在消息队列里面直接返回,我会从消息队列读出来,最终把消息写在数据库里,其实大的公司都这么干。

举个例子,下订单不管在哪儿下订单,下完订单点查看订单,告诉你订单还在处理中,不能查看,实际上这个订单还没有写在数据库里,你现在看不了。但是现在我们用MemCached最主要还是做数据库读缓存。

再说一个但是,现在已经不用MemCached了,因为有了Redis之后,MemCached有点鸡肋了,除非是纯缓存,这时候MemCached性能是要超越Redis的。

但是有了Redis以后,我们后来就不用MemCached,用MemCached还要维护它,很麻烦,我直接改成Redis就可以了,对于开发来说就是改几行代码,批量查找切换,就可以切换到Redis上。而且Redis支持不同数据类型,Redis不仅可以做缓存,还可以做存储。

像我们Redis有两个功能,一个是做数据库读缓存,还有一个最重要功能就是存储,很多数据直接写在Redis里,所以Redis不能挂。不能挂就涉及到集群问题,挂了怎么办,Redis集群有哪些种?

Redis做数据库读缓存

首先客户端分片,这是最简单的集群模式,比如说四个Redis你爱写哪儿写哪儿,它会比较灵活,自己可掌控。但是有一个很大的缺点,你要加和删这就费劲了,要是缓存还好,加删有很少的数据Cache丢失。

但是如果你不是在缓存,是做数据存储,这时候涉及到数据迁移,还只能手动迁移,这就比较费劲了。第二种解决方案是通过Proxy做分片,比如Twemproxy。但是还是有一个问题,数据迁移没有,还有Redis Cluster,但是Redis Cluster对用户来说不是透明的。之前用Redis,现在切换到Redis Cluster,各种东西都要改的,这是一个大的问题。

还有目前比较新,应用案例相对来说不是很多。最后讲Codis,Codis之前豌豆荚开源了一个,但是那帮人大部分已经离职了。现在在gataApp上专门有一个项目做Codis,Codis方案怎么做呢?有点类似于客户端分片,首先分0—1663,总共分1664个槽位,把相应的K放在不同槽位上,再把槽位放在的后端不同的Redis服务器上。

但是它有一个好的功能是,它对Redis服务器做了二次开发,叫做Codis服务器。做了二次开发支持做数据迁移,比如我想把0—500槽位迁到另外一台Redis主从的集群上,没问题,鼠标点一下就可以迁移,而且是不中断迁移,这就是它的好处。

而且Codis提供一个Redis-Port,这个工具可以无缝的把Redis迁移到Codis上。它的工作原理是:通过Redis-Port这个工具连到RedisMaster上,把自己模拟成一个Redis Slave,我是你的从,你给我做数据同步。

然后master很自觉的做一个BGS,然后把RBG文件发解Slave,Redis-Port把它解析出来,其实是解析出来成命令了,再做Codis上执行,通过这样的方式,把Redis迁到Codis上。

我之前经历过把几个Redis迁到Codis上,就是用Redis-Port工具非常方便。现在我们很多业务主流都是Codis,不再单纯的用Redis了,而且Codis每个group都有一主多从,从挂了主可以自动替上。而且Codis有一个Proce,这个Proce对于用户来说是拓扑的,连多Proce和连到Redis上是一样的,什么都不用改。

之前用的什么模块现在还用什么模块,什么都不用改。它是无感知的,但是它也有一个缺点,有一些命令是不支持的,不支持的命令都是非常不常用的命令。

数据库与操作系统缓存

因为我们只讲缓存,没有讲架构,架构层面这里面还有很多其他的内容,下面的请求经历各种缓存,终于到达数据库,实在没有办法,都没有命中,这时候数据库也有缓存。

Oracle体系结构

我们先看Oracle,Oracle写在SGA里有Data Buffer Cache,所有内存读写都是在内存做的,但是还有redo log是写在Buffer里面的。

MySQL缓存

MySQL也是一样的,对于运维来说改改配置文件就好了。但是你改配置文件之前要理解一下缓存是怎么用的,这是我们需要理解的。不是说改完配置文件缓存做完了,这是不行的。这个时候请求继续往下走就走到操作系统层面了,那就涉及到操作系统缓存,CPU、内存、磁盘。

操作系统缓存之CPU

首先CPU缓存,我们知道CPU有一二三级缓存。一级缓存又被分为一级指令缓存和数据缓存,所以大家买CPU的时候,要看一看CPU缓存大小,缓存对CPU执行性能是有很大关系的。

L2、L3,L3很多时候是共享的,一个CPU多个核,各个核之间是共享的,所以存取的时候,这个缓存既有Buffer功能,也有Cache功能,最后读写从内存中来。

咱们做运维做性能调优有没有用过CPU绑定?你们配置NJS如果用过,那个其实就是做进程绑定的。把NJS进程绑定到CPU某个核上,绑定的作用是提高CPUCache命中率,因为我们的进程在操作系统运行是受进程调度器控制。

你在CPU一个核上运行以后,如果中断,下一次再运行的时候,可能就在2上,这个时候缓存如果不是共享的,缓存就命中不了,所以我们通过这种把进程绑定到某一个CPU核上,来减少CPU的Cache Miss,来提高性能。

举个例子,我们做虚拟化KVM,我们把KVM进程绑定到CPU核上,和你不绑定到CPU核上,大概性能影响是,没绑之前可能占70%的CPU,绑之后性能大概提升10%左右,因为减少了CPUCache Miss。当然做绑定就丧失了灵活性,但是NJS这样是可以的,它默认也支持。

下面是内存,内存有一个Page Cache,一个是Buffer Cache,Page Cache主要是针对文件层,Buffer Cache是针对块设备的。我们I/O使用,读写是这么做的,我特意把路径写出来了。磁盘块到Buffer Cache到Page Cache到应用程序进程空间。

Linux IO 架构

再看一下I/O,我们现在I/0调度算法是三种,最早是四种,还有一种系AS一种算法,现在是三种。

而且现在都支持多队列写入,这时候我们作为运维工程师调优涉及到I/O调度算法的调优,默认情况下用截止时间没问题。

但是如果你的硬盘是SSD,这时候最好把I/O调度算法调优,就是不做任何调度,按正常的。你先来就先存取,为什么?因为SSD足够得快,你没必要再做调度。I/O里面也有一些缓存,其实也不多。

现在数据经过CPU、磁盘,这时候就涉及到读取了,读取别着急,还有缓存。

  • RAID缓存

首先是RAID卡缓存,这是一个730P的RAID卡,它的缓存容量是2G。RAID卡缓存一般也是有Buffer、Cache两种功能,像它的Buffer很容易理解,写数据的时候先写到Buffer RAID卡,Cache有预读功能,来提高访问速度。 而且RAID卡还有一个好处,这个有电池,所以你即使机器断电没有关系,有电池,数据不会丢。RAID卡写完之后到硬盘上,你会发现现在很多的服务器必须配RAID卡,所有数据必须经过RAID卡才能往下写,就是因为RAID卡有电池。

  • 磁盘缓存

这是一个很普通的戴尔SAS,600G容量,2.5英寸,64兆缓存。写的时候写到64兆,读的时候从64兆里面读。 这时候就有问题的,我有RAID卡缓存,有硬盘缓存,硬盘缓存开还是不开?这个缓存开还是不开是RAID卡控制的,默认是关闭的。

我之前用戴尔系列服务器,默认是关闭的,在服务器上默认磁盘缓存是关闭的,只用RAID卡缓存,这才多大,还是RAID卡大。那个人笔记本可以选择打开或者关闭,这是磁盘缓存。然后获取到数据,一步一步再回去。

总结

我们整体看一下缓存体系结构,一个请求从用户层进来,一直到最后,到物理层,经历所有的缓存全在这里。我们只讲读缓存,写缓冲我们并没有列举。

我们做一个整体回顾,DNS浏览器缓存协商,CDN反向代理缓存,解释器OpCache,Web服务器缓存,动态内容缓存,页面静态化,local Cache,分布式缓存,MySQL、CPU Cache、内存Cache、RAID卡Cache、Disk Cache。

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-09-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DevOps时代 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • CDN与反向代理缓存
    • CDN缓存体系
      • CDN关键技术
        • 反向代理缓存
        • Web服务器与分布式缓存
          • Web服务器缓存
            • 页面静态化
              • 应用代码执行缓存
                • PHP OpCache
                  • PHP OpCache缓存
                    • Memcached 数据库读缓存
                      • Redis做数据库读缓存
                      • 数据库与操作系统缓存
                        • Oracle体系结构
                          • MySQL缓存
                            • 操作系统缓存之CPU
                              • Linux IO 架构
                              • 总结
                              相关产品与服务
                              云数据库 Redis
                              腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
                              领券
                              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档