#### 缓存架构体系
##### 多级缓存架构
html(Cache) ->> VIP ->> LVS ->> nginx(Cache) ->> Lua(访问缓存,如果没有则访问数据库)
#### redis 集群
工作原理,主从复制
1、Slave服务启动,主动连接Master,并发送SYNC命令,请求初始化同步;
2、Master收到SYNC后,执行BGSAVE命令生成RDB文件,并缓存该时间段内的写命令;
3、Master完成RDB文件后,将其发送给所有Slave服务器;
4、Slave服务器接收到RDB文件后,删除内存中旧的缓存数据,并装载RDB文件;
5、Master在发送完RDB后,即刻向所有Slave服务器发送缓存中的写命令;
##### 集群配置文件
#端口
port ${PORT}
#非保护模式
protected-mode no
#启用集群模式
cluster-enabled yes
cluster-config-file nodes.conf
#超时时间
cluster-node-timeout 5000
#集群各节点IP地址
cluster-announce-ip 192.168.211.141
#集群节点映射端口
cluster-announce-port ${PORT}
#集群总线端口
cluster-announce-bus-port 1${PORT}
#开启aof持久化策略
appendonly yes
#后台运行
#daemonize yes
#进程号存储
pidfile /var/run/redis_${PORT}.pid
#集群加密
#masterauth itheima
#requirepass itheima
##### 创建集群
#进入到任意一个安装好的redis节点的bin目录,里面有个脚本对象redis-cli,然后执行集群创建
--cluster-replicas 表示有一个主有几个slave。
./redis-cli --cluster create 172.18.0.2:7001 172.18.0.3:7002 172.18.0.4:7003 172.18.0.5:7004 172.18.0.6:7005 172.18.0.7:7006 --cluster-replicas 1
##### 增加节点
增加主节点 192.168.211.141:7007 到 192.168.211.141:7001 集群
./redis-cli --cluster add-node 192.168.211.141:7007 192.168.211.141:7001
分配哈希槽 从 39c58827f 分配到 aed4f6a02235822a7 100 哈希槽
./redis-cli --cluster reshard 192.168.211.141:7001 --cluster-from 39c58827f --cluster-to aed4f6a02235822a7 -- cluster-slots 100
增加从节点 增加从节点 192.168.211.141:7008 到 192.168.211.141:7007 集群里的 6a02235822a7 master下
./redis-cli --cluster add-node 192.168.211.141:7008 192.168.211.141:7007 --cluster-slave -- cluster-master-id 6a02235822a7
##### 移除节点
移除主节点
将哈希槽转到到其他master节点
./redis-cli --cluster reshard 192.168.211.141:7007 --cluster-from 443096af2ff8c1e89f1160faed4f6a02235822a7 --cluster-to 80a69bb8af3737bce2913b2952b4456430a89eb3 --cluster-slots 33 --cluster-yes
转移完哈希槽后,删除主节点
./redis-cli --cluster del-node 192.168.211.141:7007 443096af2ff8c1e89f1160faed4f6a02235822a7
移除 fa0441e5a821dce20ae 下的 192.168.211.141:7008 从节点
./redis-cli --cluster del-node 192.168.211.141:7008 fa0441e5a821dce20ae
#### redis sentinel 哨兵
##### 监控
###### 10秒监控
每隔10秒,每个Sentinel节点会向主节点和从节点发送info命令获取最新的主从结构,该命令有3个作用:
1、通过向主节点执行info命令,获取从节点的信息,这也是为什么 Sentinel节点不需要显式配置监控从节点
2、当有新的从节点加入时都可以立刻感知出来
3、节点不可达或者故障转移后,可以通过info命令实时更新节点结构信息
###### 2秒监控
每隔2秒,每个Sentinel节点会向Redis数据节点的 __sentinel__:hello 频道上发送该Sentinel节点对于
主节点的判断以及当前Sentinel节点的信息 ,同时每个Sentinel节点也会订阅该频道,来了解其他 Sentinel
节点以及它们对主节点的判断。该定时任务主要有2个作用:
1、发现新的Sentinel节点:通过订阅主节点的__sentinel__:hello了解其他的Sentinel节点信息,如果是
新加入的 Sentinel节点,将该Sentinel节点信息保存起来,并与该Sentinel节点创建连接。
2、Sentinel节点之间交换主节点的状态,作为后面客观下线以及领导者选举的依据。
###### 1秒监控
每隔1秒,每个Sentinel节点会向主节点、从节点、其余Sentinel节点发送一条ping命令做一次心跳检测,来确认
这些节点当前是否可达,从而实现检查每个节点的健康状态。
#### nginx 缓存
##### OpenResty
OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及
大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、 Web 服务和动态网关。
OpenResty 通过lua脚本扩展 nginx 功能,可提供负载均衡、请求路由、安全认证、服务鉴权、流量控制与日志监
控等服务。
OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地
变成一个强大的通用 Web 应用平台。这样, Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持
的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
##### 浏览器缓存
客户端侧缓存一般指的是浏览器缓存、app缓存等等,目的就是加速各种静态资源的访问,降低服务器压力。 我们
通过配置Nginx设置网页缓存信息,从而降低用户对服务器频繁访问造成的巨大压力。我们先配置一个案例,再基于
案例去讲解Nginx缓存。
nginx 缓存配置
server {
listen 80;
server_name localhost;
location / {
#静态文件路径
root /usr/local/server/html;
#缓存10秒
expires 10s;
}
}
过期时间配置说明
expires 30s; #30秒
expires 30m; #30分钟
expires 2h; #2个小时
expires 30d; #30天
##### 代理缓存
nginx 配置
proxy_cache_path /usr/local/openresty/nginx/cache levels=1:2 keys_zone=openresty_cache:10m max_size=10g inactive=60m use_temp_path=off;
server {
listen 80;
server_name localhost;
location /user {
proxy_pass http://192.168.18.236:8089;
#启用缓存openresty_cache
proxy_cache openresty_cache;
##针对指定请求缓存
##proxy_cache_methods GET;
##设置指定请求会缓存
proxy_cache_valid 200 304 10s;
##最少请求1次才会缓存
proxy_cache_min_uses 3;
##如果并发请求,只有第1个请求会去服务器获取数据
##proxy_cache_lock on;
##唯一的key
proxy_cache_key $host$uri$is_args$args;
proxy_pass http://192.168.18.236:8089;
}
}
proxy_cache_path /usr/local/openresty/nginx/cache levels=1:2
keys_zone=openresty_cache:10m max_size=10g inactive=60m use_temp_path=off;
【作用】指定缓存存储的路径,缓存存储在/usr/local/openresty/nginx/cache目录
【levels=1:2】设置一个两级目录层次结构存储缓存,在单个目录中包含大量文件会降低文件访问速度,因此我们建议对大
多数部署使用两级目录层次结构。如果 levels 未包含该参数,Nginx 会将所有文件放在同一目录中。
【keys_zone=openresty_cache:10m】设置共享内存区域,用于存储缓存键和元数据,例如使用计时器。拥有内存中的密
钥副本,Nginx 可以快速确定请求是否是一个 HIT 或 MISS 不必转到磁盘,从而大大加快了检查速度。1 MB 区域可以存
储大约 8,000 个密钥的数据,因此示例中配置的 10 MB 区域可以存储大约 80,000 个密钥的数据。
【max_size=10g】设置缓存大小的上限。它是可选的; 不指定值允许缓存增长以使用所有可用磁盘空间。当缓存大小达到限
制时,一个称为缓存管理器的进程将删除最近最少使用的缓存,将大小恢复到限制之下的文件。
【inactive=60m】指定项目在未被访问的情况下可以保留在缓存中的时间长度。在此示例中,缓存管理器进程会自动从缓存
中删除 60 分钟未请求的文件,无论其是否已过期。默认值为 10 分钟(10m)。非活动内容与过期内容不同。Nginx 不会
自动删除缓存 header 定义为已过期内容(例如 Cache-Control:max-age=120)。过期(陈旧)内容仅在指定时间内未
被访问时被删除。访问过期内容时,Nginx 会从原始服务器刷新它并重置 inactive 计时器。
【use_temp_path=off】表示NGINX会将临时文件保存在缓存数据的同一目录中。这是为了避免在更新缓存时,磁盘之间互
相复制响应数据,我们一般关闭该功能。
##### 缓存清理
nginx增加 ngx_cache_purge 模块。
设置清理缓存地址:
location ~ /purge(/.*) {
# 清理缓存
proxy_cache_purge openresty_cache $host$1$is_args$args;
}
$1 代表的是 (/.*) 的数据
#### LUA
lua是一门性能著称的脚本语言,被广泛引用在很多方面。lua一般用于嵌入式应用。
优势:
1,可以非常轻松嵌入到其他程序中。
2,提升应用性能,比如:游戏脚本,nginx,wireshark的脚本。
3,兼容性强,可以直接使用c代码写的函数。比如corona 移动应用开发平台,跟phoneRap类似。
4,在给软件提供嵌入式脚本编程能力上,lua是最佳选择。
#### nginx限流
##### 控制速率
采用漏桶算法。
nginx配置(在server之上,创建缓存空间):
contentRateLimit:10m 命名空间的名字,缓存空间大小
limit_req 使用限流配置
rate=2r/s 速率限流标志,每秒中处理两个请求。
limit_req_zone $binary_remote_addr zone=contentRateLimit:10m rate=2r/s;
server {
location /* {
limit_req zone=contentRateLimit;
}
}
缓存请求,缓存请求数量4个
burest=4,若同事有4个请求到达,nginx会处理第一个请求,剩余3个请求将放入队列,然后每隔500ms从队列中获取
一个请求处理,若请求数大于4,将拒绝处理的多余请求,直接返回503.
不过单独使用burst参数并不实用。假设burst=50,rate依然为10r/s,排队中的50个请求虽然没100ms会处理一个
,但是第50个需要等待50*100ms时间,因此burst结合nodelay一起实用。不需要延迟,同时处理。
location /* {
limit_req zone=contentRateLimit burst=4 nodelay;
}
##### 控制并发连接数
###### ip并发限流
nginx 配置
配置限流名,限流缓存大小
没秒钟只循序有两个并发请求
limit_conn_zone $binary_remote_addr zone=addr:1m;
server {
location /* {
limit_conn addr 2;
}
}
###### 总数限流
nginx配置
# 根据ip进行限流
limit_conn_zeon $binary_remote_addr zone=perip:10m;
# 根据servername限流
limit_conn_zone $server_name zone=perserver:10;
server {
location /* {
# 用户限流
limit_conn perip 3; # 单个客户端ip与服务器连接数
# server限流
limit_conn perserver 100; # 限制与服务器的总连接数
}
}
#### 缓存穿透解决方案
在mysql读取数据后,如果无数据,将无数据状态放入redis中,防止缓存穿透。
##### 布隆过滤器:
防止缓存穿透,有多种方案。布隆过滤器主要是解决大规模数据下不需要精确过滤的业务场景,如检查垃圾邮件地址。
爬虫url地址去重,解决缓存穿透问题等。
#### 缓存击穿解决方案
##### 定时器
定时刷新缓存信息
##### 多级缓存
将缓存存放在nginx,redis做多级缓存。
##### 分布式锁
在数据库查询的代码块,加分布式锁,只由一条请求去mysql查询,将数据存放至缓存。
##### 队列术
使用nginx队列
nginx配置
server{
location / {
# 启用openresty缓存
proxy_cache openresty_cache;
# 针对指定请求缓存
# proxy_cache_methosd GET;
# 设置指定请求会缓存
proxy_cache_valid 200 304 10s;
# 最少请求一次才会缓存
proxy_cache_min_uses 1;
# * 如果并发请求,只有第一个请求会去服务器获取数据
proxy_cache_lock on;
# 缓存唯一的key
proxy_cache_key $host$uri$is_args$args;
proxy_pass http:abc.com
}
}
#### 缓存雪崩解决方案
1) 缓存高可用
即使个别节点,个别机器,甚至是机房宕机,依然可以提供服务,比如redis sentinel 和 redis cluster
都实现了高可用。
2)限流
微服务网关或者nginx做好限流操作,防止大量请求直接进入后端,使后端负载过重最后宕机。
3)数据预热
预先更新缓存,再即将发生大并发访问钱手动出发加载缓存不同的key,设置不同的过期时间,让缓存失效的
时间点尽量均衡,不要同时失效。
4)队列术限流
使用nginx队列或者mq队列,缓存用户的请求,让所有的相同的操作只有1次查询数据库,并将查询的数据加入到
缓存。
5)加锁
6)多级缓存(推荐)
nginx-cache -> redis-cache -> mybatis-cache -> mysql
#### 缓存一致性解决方案
Canal主要用途是基于mysql数据库日志解析,监听数据库数据变化。
##### Canal工作原理
1,canal模拟mysql slave的交互协议,伪装自己为mysql slave,想mysql master发送dump协议
2,mysql master收到dump请求,凯斯推送binary log给 slave(canal)
3,canal解析binary log对象(原始为byte流)
###### canal配置
1) 开启mysql的bin-log
在mysql的配置文件 mysqld.cnf 最下面增加如下配置:
# 开启binlog
log-bin=/var/lib/mysql/mysql-bin
# 选择row模式
binlog-format=ROW
# 配置mysql replaction需要定义,不要和canal的slaveId重复
server-id=123456
创建canal用户
create user canal@"%" IDENTIFIED by "canal";
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT,SUPER ON *.* TO 'canal'@'%';
FLUSH PRIVILEGES;
2) canal安装
docker run -p 11111:11111 --name canal -d docker.io/canal/canal-server
配置CanalServer
修改 /home/admin/canal-server/conf/canal.properties,讲他的id改成和mysql数据库中的
server-id不同的值。
修改 /home/admin/canal-server/conf/example/instance.properties ,配置要监听的数据库
服务地址和数据变化的数据库以及表
# 监听的数据库
canal.instance.master.address=192.168.18.204:3306
# 用户名
canal.instance.dbUsername=canal
# 密码
canal.instance.dbPassword=canal
# 监听表规则
canal.instance.filter.regex
mysql关注表,perl正则表达式
多个正则使用逗号分割,转义符需要使用双斜杠
例:
1,表示所有 .*
2, canal schema下所有表: canal\\..*
3, canal下以canal打头的表: canal\\.canal*
4, canal sechema下的一张表:canal.test1
5,多个组合使用: canal\\..*,canal\\.canal.*,canal.test1
注意:此过滤条件只针对row模式的数据有效(ps. mixed/statement因为解析不到sql,所以无法
准确提取到tableName进行过滤)
3) canal springboot yaml配置
canal:
server: canal 服务地址
destination: example
java 代码
@CanalTable(value="") // 监听哪张表变更
public class async implements EntryHandlerM<监听表对应的java实体>{
//指定表插入触发
insert()
//指定表修改触发
update()
//指定表删除触发
delete()
}
缓存架构体系
最新推荐文章于 2022-04-11 16:58:34 发布