详情页缓存架构

本文详细探讨了Redis集群的持久化、读写分离和高可用性,以及大数据场景下的Storm处理和缓存预热策略。同时,介绍了限流降级的Histrix机制,以及如何应对缓存雪崩。实战部分讲解了商品详情页的缓存架构和动态渲染服务的四级缓存策略。
摘要由CSDN通过智能技术生成

目录

一.redis集群架构

1.redis持久化

2. 读写分离

3.redis高可用性

3.redis-cluster通过gossip协议通信(ping,pong,meet,fail)

4.redis常见问题与调优

5.多级缓存架构

二.初级大数据

1.简介

2.storm(nimbus机器+n个supervisor机器)

1.核心概念

2.并行度与task

3.打包部署

4.缓存预热

5. 热点缓存问题nginx+lua+storm自动降级

三. 限流降级Histrix

1.请求合并

2.stubble fallback

3.多级降级

四.缓存雪崩

1.事前解决方案

2.事中解决方案

3.事后方案

五.实战

1.商品详情页维度划分

2.动态渲染服务

(1. 四级缓存

(2. 消息队列

(3. 全链路多级降级

(4. twemproxy+redis

  (5.

(6. 消息队列去重

(7.jenkins可以从github拉取代码,使用maven构建打包,创建镜像并部署

(8.商品详情整体架构



一.redis集群架构

  • redis持久化的意义在于故障恢复,持久化到磁盘+备份到云服务器可以应对灾难性故障

1.redis持久化

  1. RDB和AOF(写指令的日志)AOF更完整

2.RDB优点:

性能更好,每隔一段时间redis主进程fork子进程执行磁盘IO进行持久化。做冷备RDB相比AOF可以由redis控制固定时长生成快照文件,AOF还需要写脚本。而且RDB是数据快照恢复起来相比指令重放更快。

缺点是容易丢失数据,不适合做第一优先恢复方案,定时写RDB时间间隔一般会比较长。RDB间隔太长生成文件太大对redisfork子进程写RDB可能会有影响。

3. AOF优点

以append-only方式写入,所以没有任何磁盘殉职的开销,写入性能高,文件不易破损。

AOF文件过大,出现后台重写,rewritelog会对其中的指导进行压缩,创建一份需要回复数据的最小日志出来,在创建新日志文件的时候,老的日志文件还是照常写入,新日志ready之后在交换。

在rewrite发生之前可以删除AOF中误操作的指令,重新恢复数据。

缺点是AOF文件相对来说比较大,写qps相比RDB更低。

综合使用RDB和AOF,用AOF来保证数据不丢失,作为数据恢复的第一选择,用RDB来做不同程度的冷备,AOF文件都损坏的时候可以用RDB做快速恢复。

恢复数据之后开启aof要用热修改redis config set,带备份完毕的数据生成了aof之后,开关闭redis改配置文件打开aof

2. 读写分离

一主多从,读写分离主写从读,主同步从。水平扩展slave增加读qps。master主机需开启持久化RDB,AOF.

1.主从复制原理

  • (第一次启动或重连)master启动子进程(同时继续在内存中缓存最新的数据)生成RDB发送到slave节点,slave将RDB保存到磁盘,然后加载到内存,master再将最新的缓存数据发给slave保证数据一致。slave重连master只会生成断掉这部分时间数据的rdb。
  • 断点续传:master node 会在内存中创建一个backlog,master和slave都会保存一个replica offset还有一个masterId,如果master和slave断掉链接,slave会让master从上次的replica offset开始继续复制,如果没有找到对应的offset,就会执行全量复制。
  • 无磁盘化复制:master在内存中直接创建rdb然后发送给slave,不会在自己本地落地磁盘。repl-diskless-sync
  • 过期key处理:slave不会过期key,只会等待master过期key,master过期了key,会模拟一条命令发送slave

2.复制的完整流程

  • slave node启动仅保存master node的信息复制未开始(master host和ip在conf里slaveof配置)
  • slave node有定时任务每秒检查是否有新的master node要连接和复制,有则跟master node建立socket链接
  • slave node发送ping命令给master node
  • 口令认证,若master设置了requirepass,slave则必须发送masterauth的口令过去认证。
  • master启动全量复制将所有数据发送给slave
  • master后续异步将新数据发送给slave node

3.同步相关的核心机制(全量复制)

  • master和slave都会维护一个offset,slave每秒上报自己的offset给master,master也会保存所有slave的offset
  • master node复制数据时会将数据在backlog中同步写一份(处理中断后的增量复制)
  • master run id:master node重启或数据变更,slave node要根据不同的run id区分,run id不同则全量复制不更改run ID重启(debug reload)

  • 从节点使用psync从master node进行复制,psync runid offset,master node根据自身的情况返回响应信息,可能触发全量或增量复制。

3.全量复制

  • master执行bgsave,本地生成一份rdb文件
  • master node 将rdb文件发送给slave node,如果rdb文件的复制时间超过60s(repl-timeout),那么slavenode就会认为复制失败
  • master node生成rdb文件时,会将所有的新的写命令缓存在内存里,在slave node保存了rdb之后再将写命令赋值给slave node
  • client-output-buffer-limit slave 256mb 64mb 60,如果复制期间内存缓冲区持续消耗超过64mb,或者一次性超过256mb那么停止复制,复制失败
  • slave node收到rdb,清空旧数据,重新加载rdb到自己的内存,同时基于旧数据版本对外提供服务
  • slave node开启aof则会执行bgrewrite重写aof

4.增量复制

  • 全量复制过程中,master-slave链接断掉,slave node重连master触发增量复制
  • master直接从自己的backlog中获取部分丢失的数据发送给slave node,默认backlog1mb
  • master就是根据slave发送的psync中的offset来送backlog中获取数据

3.redis高可用性

通过哨兵实现高可用监控master节点,并进行主备切换。

1.哨兵(集群通过选举的方式判断master是否宕了,至少三个实例)

  • 集群监控,监控master和slave进程是否正常工作
  • 消息通知,某个redis实例发生故障,哨兵负责发送消息作为报警给管理员
  • 故障转移,如果master node挂掉了会自动转移到slave node上
  • 配置中心,故障转移发生了,通知client客户端新的master地址。
  • 三哨兵集群,quorum=2,majority=2,如果M1机器宕了,三个哨兵剩下两个,s2,s3一致认为master宕机,然后选举一个来执行故障转移

2.数据丢失的情况

  • 异步复制导致,异步复制未发生主备切换发生
  • 集群脑裂:网络问题导致redis master和哨兵集群切断联系,哨兵判断master故障进行主备切换选举新的master,此时原本的master网络恢复。可能client一直与原本的master可以连接写数据,原本的master恢复后变成slave节点,这一部分数据就会丢失。
  • 解决:min-slave-to-write 1  min-slave-max-lag 10 要求至少有一个slave,数据复制和同步延迟不超过10s,一旦所有的slave都超过10s,master就不会再接受请求。
  • 脑裂问题也可以通过两个参数处理,脑裂之后,旧master判断没有slave向master同步数据超过10s则由客户端降级处理。

  • 从节点向主节点发送 REPLCONF ACK {offset} ,频率每秒1次.作用:

  • 试试检测主从网络状态,该命令被主节点用于复制超时的判断.
  • 检测命令丢失,主节点会比较从节点发送的 offset 与自身的是否一致,不一致则从 buffer 中查找对应数据进行补发,如果 buffer 中没有对应数据,则会进行全量复制.
  • 辅助保证从节点的数量和延迟,master 通过 min-salves-to-write 和 min-slaves-max-lag 参数,来保证主节点在不安全情况下不会执行写命令.是指从节点数量太少,或延迟过高。例如 min-slaves-to-write 和min-slaves-max-lag 分别是3和10,含义是如果从节点数量小于3个,或所有从节点的延迟值都大于10s,则主节点拒绝执行写命令。

3.redis-cluster通过gossip协议通信(ping,pong,meet,fail)

4.redis常见问题与调优

5.多级缓存架构

时效性高:双写缓存加数据库  时效性不高:异步消息+多级缓存   大缓存进行维度拆分提高效率

  1. 三级缓存:nginx本地缓存+redis分布式缓存+tomcat jvm堆缓存
  2. 读写请求串行化,更新数据库请求和刷新缓存请求放置队列保证顺序性,读请求读不到就hang一会等缓存刷新处理高并发情况;读请求更新缓存,写请求删缓存。
  3. 提高缓存命中率nginx分为分发层和应用层,分发层采取根据idhash取模等方式达到一台机器。
  4. openResty打包了lua+nginx,配置nginx导入lua文件执行。
  5. 分发层nginxlua脚本分发请求到nginx应用层服务器,应用层lua逻辑调用数据生产服务(http)层层获取数据渲染模版。

二.初级大数据

1.简介

  1. storm :实时缓存热点数据统计->缓存预热->缓存热点数据自动降级(不存储数据实时数据计算,消息可靠性机制,元数据存储在zk,并行计算)
  2. Hive:高并发访问下,海量日志数据的批量统计分析,日报周报月报,接口调用情况,业务使用情况。
  3. spark:离线批量数据处理,比如从db中一次性倒入亿级数据,清洗处理之后导入redis中供后续使用,大型互联网公司的用户相关数据。
  4. zookeeper:分布式协调,分布式锁,分布式选举-》高可用HA架构,轻量级原数据存储。
  5. HBase:海量数据的在线存储和简单查询,替代mysql分库分表提供更好的伸缩性。
  6. Es:搜索引擎。。。
  7. hadoop:分布式存储,离线数据批处理

2.storm(nimbus机器+n个supervisor机器)

1.核心概念

  • Topology(拓扑)拓扑涵盖了数据源数据获取/生产+业务处理的代码逻辑(spout+balt)
  • Spout:数据源的代码组件,我们可以实现spout的一个接口,尝试从数据源中获取数据(kafka中消费数据)
  • balt:一个业务处理的代码组件,spout将数据传给balt,各种balt可以串联成一个计算链条,实现一个balt接口。
  • tuple:一条数据,每条数据都会被封装在tuple中,在spout和balt中传递。

2.并行度与task

  1. 对于一个拓扑来说并行度就是task,默认情况下一个executor就一个task,最小计算单元是task。每个spout/balt都会运行在一个task中。
  2. 流分组:流分组是task与task之间的数据流向关系。(shuffle grouping随机分组发射数据,Fields grouping根据某一个或多个字段)

3.打包部署

  1. 将本地storm项目maven打包,用storm  jar ***.jar(jar名)  topology包路径  topology名 
  2. storm有ui启动supervisor机器的ui,启动其他两台supervisor机器的logviewer可以看日志。
  3. 部署到nimbus机器上,三台supervisor会启动进程运行。

4.缓存预热

(1. 预热redis

  1. 避免高并发请求下redis第一次启动无数据所有请求直接打到mysql
  2. 对一系列访问频率高的数据灌入redis在进行启动。
  3. 需要根据当天的访问请求状况实时计算出访问频次最高的热数据。并行读取写入redis

(2. 步骤(分段存储按照taskId,技术时采取了FieldsGrouping,因此不同的task持有不同商品的计数,因此预热服务要)

  1. nginx+lua将详情页访问流量日志上报到kafka
  2. storm从kafka中实时消费数据,统计出每个商品的访问次数,访问次数保存基于LRU内存数据结构方案(LRUMap),维护出一个前N个访问最多商品list。
  3. 每个storm task启动基于zk分布式锁,将自己的id写入zk同一个节点中。
  4. 每个storm task完成自己热数据的统计,每隔一段时间遍历map,维护前n个商品的list,更新list
  5. 写一个后台线程每隔一段时间,将统计过后的前n个商品list更新到zk中。存储到task对应的znode中。
  6. 缓存预热的服务有多个实例,每次启动就会去获取一个storm task的列表,根据taskId获取taskId对应的znode分布式锁,取出list从mysql中查询数据写入redis完成预热,多个实例分布式去做基于分布式锁。

(3. 操作

  • nginx+lua,lua脚本创建kafka producer生产数据到kafka。(可以下载resty包(包装了kafka+lua)继续放到lualib/目录下)
  • lua既可以进行nginx流量分发,也可以读取缓存数据渲染模板,流量分发机器不动,修改业务数据生产的机器lua,通过require方法获取导入lualib包下指定工具
  • 写一个拓扑,spout从kafka(kafka启动会连zk,消费者通过链接zk消费)中消费数据发射出去--》LogParamBolt负责解析message获取productId--》CountBolt负责统计计数(LRUMap)。并且CountBolt可以起一个线程每隔一分钟遍历LRUMap,获取前n个list,上报到
  • 上报zk流程
  1. CountBolt将自己的taskId初始化时写入zk的node中形成一个task列表
  2. 每次都将自己的热门商品列表写入自己的taskId对应的zk节点中
  3. 这样并行预热程序会从第一步中获取到task列表
  4. 然后根据每个task获取一个锁,从znode中拿到列表,并行处理

(4. 缓存预热服务的操作

  1. 预热服务启动进行缓存预热
  2. 从zk中读取taskId列表
  3. 依次遍历每个taskId,尝试获取对应的分布式锁,获取失败快速报错,说明有其他实例在预热
  4. 尝试获取下一个taskId的分布式锁
  5. 获取到了分布式锁,检查一下预热状态,预热过则不再预热
  6. 进行预热操作,遍历productId列表,读取数据set到redis和echache里
  7. 预热完成,设置taskId的预热状态
  8. 通过创建zk节点来获取锁,一个节点只会被创建一次。get或setData往节点里获取数据,锁与数据节点均不相同,锁节点最后会删除。
  9. 双重zk锁,锁taskId读相应的数据,锁task-status读修改是否预热的状态

5. 热点缓存问题nginx+lua+storm自动降级

  1. 通过storm遍历LruMap排序统计计算后95%商品的平均访问次数并设置一个阈值n,如果商品访问次数>=n*平均数则认为该商品为瞬间热点数据
  2. storm会发送http请求到nginx,nginx会通过lua脚本处理请求,将热点对应的productId请求发送到流量分发的nginx,将商品完整缓存数据发送到所有的应用nginx放在本地缓存中
  3. 流量分发nginx对热点数据进行降级,遇到热点数据进行随机负载均衡分发到随机的nginx应用服务器上
  4. storm需要保存上次的热点list,每次新的list需要跟上次保存的list做diff,对于非热点商品发送http请求到流量分发的nginx上进行本地缓存热点取消

三. 限流降级Histrix

  1. 一个groupkey一般对应一个服务,内部接口性能不一会对应不一样的commandkey,不同的接口应用不同的线程池不同的threadpoolkey

1.请求合并

  1. 多个command合并一次请求发送,减少网络线程资源开销,可能会拖慢大部分请求的时间
  2. 基于requestContext合并,提供一个批量查询接口,合并多次请求参数调用批量接口
  3. 创建多个histryxCollapser,并行执行,execute和queue方法皆可用

2.stubble fallback

  1. 残缺降级:降级逻辑将失败请求中的部分数据填充默认值返回

3.多级降级

  1. 第一级降级备用数据备用服务机房处理
  2. 第二级降级可以采取stubble fallback,备用降级的线程池记得修改

四.缓存雪崩

1.事前解决方案

  1. 依赖redis集群本身的高可用性,主从架构,数据同步至从节点

2.事中解决方案

  1. ecache多级缓存架构
  2. histrix降级熔断,redis cluster资源隔离,数据服务资源隔离降级
  3. 基于线程池对数据服务进行限流,多级降级采取读取冷数据的方式(stubble fallback)

3.事后方案

  1. redis数据备份与恢复
  2. redis数据彻底丢失或过旧,进行redis缓存数据预热,在启动redis,histrix熔断器发现redis恢复了就关闭熔断
  3. 可以做冷热分离,将一周一月以前的数据版本备份到hbase中

五.实战

1.商品详情页维度划分

  1. 实效性较低的部分每次访问数据填充到html模板,实时性较高的数据采取ajax异步加载。

2.动态渲染服务

(1. 四级缓存

  1.  
  2. nginx本地缓存,抗热点数据,小内存缓存访问最频繁的数据
  3. redis从集群个机房,抗大亮离散数据,采用一致性hash策略构建分布式redis缓存
  4. 本地jvm堆缓存,支持在一个请求中多次读取一个数据,redis崩溃的备用防线,固定缓存一些较少访问的数据,如分类,品牌,过期时间一般为redis的一半
  5. 主redis集群,命中率低小于5%,防止主从同步延迟导致的数据miss,主集群是后备防线
  6. 主redis集群一般采取一主三从多机房的高可用部署

(2. 消息队列

(3. 全链路多级降级

nginx应用层控制,发现redis从集群多次失败设置标记位和周期时间,周期时间内直接访问数据直连服务,直连失败应用层会记录直接访问依赖服务访问数据源,依赖服务需要基于hytrix做好降级措施

(4. twemproxy+redis

  1. 整合nginx+lua,可以连接twemproxy
  2. 可以搭建树状结构,一主多从,两从节点跟两主节点,另一机房的两从节点跟该机器的从节点,形成一主多从的及联。
  3. 支持redis cli支持读写分离
  4. 为主集群部署twemproxy写,从集群部署读

  (5.

不同维度数据存在不同的库,根据dataType接受数据变更消息,存redis,把不同维度的数据写入数据聚合队列

(6. 消息队列去重

不同维度数据现在内存里进行去重过几分钟再发到聚合队列里,起一个后台线程遍历set

(7.jenkins可以从github拉取代码,使用maven构建打包,创建镜像并部署

(8.商品详情整体架构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值