1 缓存的应用
缓存(cache),原始意义是指访问速度比一般随机存储器(RAM)快的一种高速存储器,设置缓存是为了更好发
挥计算机系统的高性能。
1.1 缓存分类
1)应用级缓存
应用级缓存也就是我们平时写的应用程序中所使用的缓存。在平时程序中一般是按照如下操作流程来实现缓存的操作,首先张三用户读取数据库,并将读取的数据存入到缓存中,其他用户读取的时候,直接从缓存中读取,而不用查数据库,从而提高程序的执行速度和效率。
2)系统级别缓存
系统级别缓存是抛开我们应用程序之外硬件的缓存操作,例如某些CPU的缓存操作和如下图多级缓存流程类似,CPU在操作数据的时候,先读取1级缓存,1级缓存如果没有数据则读取2级缓存,2级缓存没有数据则读取3级缓存,3级缓存如果没有数据就直接从主存储器(存储指令和数据)读取数据。
1.2 缓存淘汰算法
数据缓存之后,为了避免缓存无限变大,我们需要对缓存进行管理,将一些不用的或者很少用的或者很久没更新的缓存淘汰掉,这里就需要用到一系列淘汰算法了,淘汰算法主要有如下几种:
1)FIFO(先进先出)
数据最先存入缓存,那么也将最先备淘汰掉。
2)LRU(最不常用数据)
判断缓存最近被使用的时间,时间最远被使用的缓存优先淘汰。
3)LFU(最少使用)
一段时间内,被使用的次数最少的数据,优先淘汰掉。
1.3 缓存应用场景
1)频繁查询数据缓存
有一些数据经常被访问,而且变更频率较低,实时性要求不高的数据,可以把它存储到缓存中,每次读取数据直接读缓存即可,从而提升数据的加载速度和系统的性能。
2)列表排序分页数据
一些变更频率较低查询频次较高的列表、分页、排序数据,可以存入到Redis缓存,每次查询分页或者排序的时候,直接从Redis缓存中获取。
3)计数器
网站中用于统计访问频次、在线人数、商品抢购次数等,也可以使用缓存来实现。
4)详情内容
站点中,资讯内容、商品详情等较大变更频率又低的内容,可以采用缓存来加速数据的读取,降低IO操作。
5)分布式Session
实现会话共享的时候,可以使用Session来存储需要共享的会话,从而节省内存空间。
6)热点排名
我们可以使用ZSet来存储热数据,并实现热点数据的排名。
7)发布订阅
用Redis也可以实现发布与订阅,但不推荐,推荐用MQ。
8)分布式锁
可以使用Redisson结合Redis实现分布式锁,Redis实现的分布式锁效率极高,得到了市场的广泛使用。
1.4 微服务架构缓存的使用
在微服务架构中,会大量使用到缓存,如上图:
2 高并发站点缓存技术选型
双十一大促销活动有很多技术挑战,而最大的挑战之一就是高并发,而应对高并发的最有效手段之一就是分布式缓存,分布式缓存不仅仅是缓存要显示的数据这么简单,还可以在限流、队列削峰、高速读写、分布式锁等场景发挥重大作用。分布式缓存可以说是解决高并发场景的一头野兽。
2.1 双十一活动大促分析
双十一无论抢红包、商品秒杀、抢优惠券,并发量都是超高,流量可以说是平时几倍乃至几十倍,对服务器造成的压力也几何数字增长,因此双十一必须要考虑各种场景的技术解决方案。
面对双十一巨大流量涌入,需要解决的问题我们做一个分析:
2.2 高性能利器-缓存
传统关系型数据库能处理的并发链接一般都很有限,如果优化的很优秀,并发链接量可高达几千,而一般公司对其优化的并不怎么乐观,很多公司的数据库并发链接量只控制在了几百。单纯用数据库实现数据的高效存取是存在很大挑战和问题的,因此一定要找一种方式或者软件取代传统关系型数据库的存取功能。
针对传统关系型数据库存取性能瓶颈,我们可以采用高性能的非关系型数据库来取代传统关系型数据库,这里以当前主流的分布式缓存技术Redis为例,可以实现单机每秒读10万次以上,写每秒8万次以上的能力,远超关系型数据库,因此解决传统关系型数据库的存取能力,我们可以用非关系型数据库来优化甚至取代关系型数据库。
2.3 缓存性能对比
当前主流的缓存技术有 Memcached 、 Tair 、 Redis ,这几款分布式缓存都各有优缺点,大家可以根据不同的使用场景来选择使用。
Memcached:
Redis:(推荐)
Tair:
3 双十一缓存架构设计
一谈到缓存架构,很多人想到的是Redis,但其实整套体系的缓存架构并非只有Redis,而应该是多个层面多个软件结合形成一套非常良性的缓存体系。比如咱们的缓存架构设计就涉及到了多个层面的缓存软件。
3.1 缓存架构设计
上图缓存架构体系借鉴了一线大厂京东缓存架构设计经验,并在京东设计方案上进行了优化,让它更符合一线厂家的需要。上述架构图综合了多种缓存和多层面的缓存设计,从前端页面缓存到代理服务器lvs和nginx缓存,以及后端服务redis缓存,包括缓存数据同步等。
对上述架构,我们来个宏观解说:
3.2 Redis集群高级应用
这里安装6个redis,配置如下:
小知识点(Redis6.0.5):
注意安装Redis6.x的时候一定要切换到gcc7再安装,否则会报如下错误:
切换语法:
3.2.1 Redis版本特性介绍
Redis我们采用Redis6.0.5最新版本,它有很多新特性,我们这里对Redis每个版本的特性介绍一下:
Redis2.6
Redis2.8
Redis3.0(里程碑)
Redis3.2
Redis4.0
Redis5.0
Redis6.0.5(里程碑)
3.2.2 Redis集群配置
现在安装对应的应用软件一般都推荐使用Docker容器,我们这里也不例外,直接使用Docker容器进行安装,安装大概要分这几个步骤:
配置Redis信息
创建 redis-cluster.tmpl 配置Redis信息(redis.conf)
Redis创建配置
创建 redis.sh 配置需要创建的 Redis 集群
这里涉及到了一个网络的定义 redis-net ,代码如下:
移除脚本创建
创建 stop.sh 脚本,用于停止Redis容器,并且移除对应容器
脚本授权:给 redis.sh 和 stop.sh 添加可执行权限:
执行脚本开始安装Redis节点,并进入到 /usr/local/bin 目录下执行 redis-cli 创建集群关联:
--cluster-replicas 表示有一个主有几个slave。
安装好了后,我们链接Redis效果如下:
3.2.3 主从复制
我们先来理解下主从同步,如下图:
我们可以用 DesktopManager 链接Redis集群,并测试数据,往redis集群添加2条数据,可以明显看到主从效果,效果如下:
上面是我们集群时随机创建的从节点,如果手动给指定节点添加从节点也是可以实现的,我们这里实现给 7001 添加一个从节点。
3.2.4 集群扩容收容
上面虽然创建了主从复制,但如果手动给节点添加一个从节点,有可能添加从节点,也有可能添加从节点,这是我们想要干的。接下来我们给集群节点添加指定的从节点。
我们安装 7007 、 7008 、 7009 几个Redis节点,然后将 7007 和 7008 作为主节点,添加到集群中, 7009 作为从节点添加到集群中。
基于Docker安装Redis这里编写了一个脚本,安装脚本 redis-port.sh 如下:
我们执行 redis-port.sh 脚本,实现 7007,7008,7009 节点安装。
添加课执行权限:
查看集群状态
主节点查看:
主节点状态信息如下:
从节点查看:
从上面信息我们可以看出集群关系:
3.2.4.1 添加集群主节点
我们需要给集群节点添加一个主节点,我们需要将 192.168.211.141:7007 节点添加到 192.168.211.141:7001 节点所在的集群中,并且添加后作为主节点,添加命令行如下:
命令说明:
执行命令后,效果如下:
此时我们可以进入到集群节点之一查看此时的集群状态,我们进入到 7002 节点中输入 cluster node 查询,操作方法如下:
效果如下:
3.2.4.2 哈希槽分配
从上面的集群节点信息我们可以看出一个问题,其他主节点都有一串数字范围,而刚才添加的 7007 节点没有这段数字范围,这和Redis集群原理有关系,我们来讲解一下集群的原理,然后实现新增节点哈希槽(这段数字范围)的分配。
Redis原理:
从原理上分析,因为之前 7001,7002,7003 已经瓜分了16384个哈希槽,所以再增加一个新节点是没有剩余哈希槽分配的,所以新增的 7007 节点没有分配到哈希槽。我们只能重新分配哈希槽,才能让新增节点分配到一定的哈希槽,重新分配哈希槽后,我们还要考虑之前其他Redis节点中的数据迁移。
重新分配Hash槽
我们将 7001,7002,7003 中的 100 个哈希槽挪给 7007 ,命令如下:
命令说明:
参数说明:
将100个哈希槽挪给7007后,我们查询下节点信息:
效果如下
3.2.4.3 添加集群从节点
我们需要往集群中给 7007 节点添加一个从节点 7008 ,添加从节点的主要目的是提高高可用,防止主节点宕机后该节点无法提供服务。添加从节点命令如下:
命令说明:
参数说明:
执行命令后,效果如下:
集群信息查看:
3.2.4.4 缩容
1)数据迁移
2)哈希槽迁移
3)从节点删除
4)主节点删除
在真实生产环境中,我们也会跟着我们的业务和环境执行缩容处理,比如双十一过后,流量没有那么大了,我们往往会缩容处理,服务器开销。
Redis实现缩容,需要哈希槽重新分配,将需要移除的节点所分配的所有哈希槽值分配给其他需要运行工作的节点,还需要移除该节点的从节点,然后再删除该节点。
移除从节点
移除 7007 的从节点 7008 ,命令如下:
参数说明:
删除后,我们再来查看集群节点,此时再无7008节点。
迁移Master的Slot
我们需要将 7007 节点的哈希槽迁移到 7001,7002,7003 节点上,仍然用上面用过的 redis-cli --cluster reshard语法,命令如下:
第1次迁移:
命令说明:
效果如下:
查看集群节点:
我们再次迁移其他哈希槽到其他节点,将剩余的哈希槽迁移到7002和7003去。
第2次迁移:
第3次迁移:
集群状态查询:
删除7007主节点
删除节点命令如下:
效果如下:
集群节点查看:
3.3 Redis Sentinel
哨兵是用来解决redis高可用性的,可以监控集群中主从的变化,然后进行故障转移。
3.3.1 哨兵讲解
一套合理的监控机制是Sentinel节点判定节点不可达的重要保证,Redis Sentinel通过三个定时监控任务完成对各个节点发现和监控。
周期10秒监控
每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的主从结构,该命令有3个作用:
周期2秒监控
每隔2秒,每个Sentinel节点会向Redis数据节点的 __sentinel__:hello 频道上发送该Sentinel节点对于主节点的判断以及当前Sentinel节点的信息 ,同时每个Sentinel节点也会订阅该频道,来了解其他 Sentinel节点以及它们对主节点的判断。
该定时任务主要有2个作用:
周期1秒监控
每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认这些节点当前是否可达,从而实现检查每个节点的健康状态。
Redis-Sentinel是用于管理Redis集群,主要执行如下任务:
执行流程
哨兵来实现Redis高可用有这5个流程:
状态说明
节点状态分为:ok、主观下线、客观下线。
正常(ok):就是节点在线,能够正常响应哨兵的检测和命令。
主观下线(sdown):指单个哨兵,发现主节点在down-after-milliseconds时间内无正确响应,做出的状态判断。
客观下线(odown):指多个哨兵对一个主节点做了sdown判断后,互相使用is-master-down-by-addr命令交流后,做出的节点已经下线的判断。
4 Nginx缓存
为了提升网站的整体性能,我们一般会采用缓存,从宏观层面来说,会采用浏览器缓存和后端缓存,Nginx处于Web网站的服务最外层,而且支持浏览器缓存配置和后端数据缓存,用它来做部分数据缓存,效率更高。
Web缓存是可以自动保存常见文档副本的HTTP 设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地设备而不是服务器中提取这个文 档。
4.1 OpenRestry安装
OpenResty? 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、 Web 服务和动态网关。
OpenResty 通过lua脚本扩展 nginx 功能,可提供负载均衡、请求路由、安全认证、服务鉴权、流量控制与日志监控等服务。
OpenResty? 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样, Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
关于 OpenRestry 的学习,大家可以参考: http://openresty.org/cn/
安装依赖库
下载安装包
解压安装
安装完成后,在
/usr/local/openrestry/nginx 目录下是安装好的nginx。
4.2 浏览器缓存
客户端侧缓存一般指的是浏览器缓存、app缓存等等,目的就是加速各种静态资源的访问,降低服务器压力。
我们通过配置Nginx设置网页缓存信息,从而降低用户对服务器频繁访问造成的巨大压力。我们先配置一个案例,再基于案例去讲解Nginx缓存。
4.2.1 Nginx Web缓存配置
nginx 提供了 expires 、 etag 、 if-modified-since 指令来进行浏览器缓存控制。我们使用 expires 来配置Nginx对网页的缓存。
1)上传html
将1.html上传到服务器的 /usr/local/server/html 目录下。
2)配置nginx
修改
/usr/local/openrestry/nginx/conf/nginx.conf 文件,配置如下:
过期时间配置说明
第一次请求 <
http://192.168.211.141/1.html>
第二次请求 <
http://192.168.211.141/1.html>
4.2.2 Http缓存控制头
参数说明:
4.3 代理缓存
用户如果请求获取的数据不是需要后端服务器处理返回,如果我们需要对数据做缓存来提高服务器的处理能力,我们可以按照如下步骤实现:
4.3.1 proxy_cache
proxy_cache 是用于 proxy 模式(一般也可称为反代)的缓存功能,proxy_cache 在 Nginx 配置的 http 段、server段(location 段)中分别写入不同的配置。http 段中的配置用于定义 proxy_cache 空间,server 段中的配置用于调用 http 段中的定义,启用对 server 的缓存功能。
属性使用说明
proxy_cache_path:
proxy_cache:
proxy_cache_valid:
proxy_cache_min_uses:
proxy_cache_lock:
proxy_cache_key:
'
4.3.2 缓存操作
我们在 nginx.conf 中添加如下配置:'
此时
/usr/local/openresty/nginx/cache 目录下只有1个temp文件夹。
我们执行3次请求 <
http://192.168.211.141/user/wangwu> ,可以发现此时多了一些其他目录,这些目录就是存储每个请求对应的缓存