44. 热点缓存问题:秒杀时的超热商品可能导致系统全盘崩溃的场景

前言

项目地址:eshop-study
切换到相应分支:
在这里插入图片描述

瞬间缓存热点问题

  1. 上一章我们解决的缓存冷启动问题: 热数据 -> 热数据的统计 -> redis中缓存的预热 -> 避免新系统刚上线,或者是redis崩溃数据丢失后重启,redis中没有数据,redis冷启动 -> 大量流量直接到数据库; redis启动前,必须确保其中是有部分热数据的缓存的

  2. 本章我们要解决瞬间的缓存热点
    在这里插入图片描述

基于nginx+lua+storm的热点缓存的流量分发策略自动降级解决方案

方案思路

在这里插入图片描述

storm实时计算热点

  1. 在storm中,实时的计算出瞬间出现的热点
  2. 有很多种算法,简单的算法,某个storm task,上面算出了1万个商品的访问次数,商品id和访问次数存到``LRUMap
  3. 频率高一些,每隔5秒,去遍历一次LRUMap,将其中的访问次数进行排序,统计出往后排的95%的商品访问次数的平均值
  4. 比如商品id列表: [1000,999,888,777,666,50,60,80,100,120],95%的商品即1000后面的9个商品id,访问次数的平均值是100,然后,从最前面开始,往后遍历,去找有没有瞬间出现的热点数据,这里就只是判断第一个;
  5. 设定一个热点商品访问次数阈值,比如95%的平均值(100)的10倍,如果LRUMap中第一个商品id的访问次数超过这个值,我们就认为是瞬间出现的热点数据
  6. 当遍历,发现说第一个商品的访问次数,小于平均值的10倍,让该商品id热点消失,break循环

storm发送热点到nginx

  1. storm通过算法计算出热点商品id列表后,会直接发送http请求到nginx上,nginx上用lua脚本去处理这个请求
  2. storm会将热点本身对应的productId,发送到流量分发nginx上面去,放在本地缓存中;
  3. storm会将热点对应的完整的商品详情缓存数据,发送到所有的应用nginx服务器上去,直接放在本地缓存中

nginx的分发策略降级

  1. 流量分发nginx,添加逻辑:每次访问一个商品详情页的时候,如果发现它是个热点,那么立即做流量分发策略的降级
  2. 之前的普通商品请求 hash策略:同一个productId的访问都同一台应用nginx服务器上,降级成对这个热点商品,流量分发采取负载均衡发送到所有的后端应用nginx服务器上去
  3. 瞬间将热点缓存数据的访问,从hash分发全部到一台nginx,变成了,负载均衡发送到多台nginx上去
  4. 避免说大量的流量全部集中到一台机器,50万的访问量到一台nginx,5台应用nginx,每台就可以承载10万的访问量

storm热点取消逻辑

  1. storm还需要保存下来上次识别出来的热点list

  2. 下次去识别的时候,这次的热点list跟上次的热点list做一下diff,看看可能有的商品已经不是热点了

  3. 热点的取消的逻辑,发送http请求到流量分发的nginx上去,取消掉对应的热点数据,从nginx本地缓存中,删除

实战

热点商品计算

  1. 在storm拓扑中加入热点缓存实时自动识别和感知的代码逻辑
  2. 在storm拓扑中加入nginx反向推送缓存热点与缓存数据的代码逻辑
  3. 在流量分发+后端应用双层nginx中加入接收热点缓存数据的接口

流量分发nginx

服务机器: [eshop-cache03: 192.168.0.108]

  1. vi /usr/hello/hello.conf
    在这里插入图片描述
location /hot {
   
        default_type 'text/html';
        # lua_code_cache off;
        content_by_lua_file /usr/hello/lua/hot.lua;
    }
  1. vi /usr/hello/lua/hot.lua
    在这里插入图片描述
local uri_args = ngx.req.get_uri_args()
local product_id = uri_args["productId"]

local cache_ngx = ngx.shared.my_cache

local hot_product_cache_key = "hot_product_"..product_id
-- 缓存1小时
cache_ngx:set(hot_product_cache_key, "true", 60 * 60)
  1. 重启nginx: /usr/servers/nginx/sbin/nginx -s reload

服务应用nginx

服务机器: [eshop-cache01: 192.168.0.106][eshop-cache02: 192.168.0.107]

  1. 同上面小节分发nginx [eshop-cache03: 192.168.0.108]的第一步;
  2. 同上面小节分
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
一、基于nginx+lua完成商品详情页访问流量实上报kafka的开发 ==================================== 在nginx这一层,接收到访问请求的候,就把请求的流量上报发送给kafka 这样的话,storm才能去消费kafka中的实的访问日志,然后去进行缓存热数据的统计 用得技术方案非常简单,从lua脚本直接创建一个kafka producer,发送数据到kafka ``` wget https://github.com/doujiang24/lua-resty-kafka/archive/master.zip yum install -y unzip unzip lua-resty-kafka-master.zip cp -rf /usr/local/lua-resty-kafka-master/lib/resty /usr/hello/lualib nginx -s reload local cjson = require("cjson") local producer = require("resty.kafka.producer") local broker_list = { { host = "192.168.31.187", port = 9092 }, { host = "192.168.31.19", port = 9092 }, { host = "192.168.31.227", port = 9092 } } local log_json = {} log_json["headers"] = ngx.req.get_headers() log_json["uri_args"] = ngx.req.get_uri_args() log_json["body"] = ngx.req.read_body() log_json["http_version"] = ngx.req.http_version() log_json["method"] =ngx.req.get_method() log_json["raw_reader"] = ngx.req.raw_header() log_json["body_data"] = ngx.req.get_body_data() local message = cjson.encode(log_json); local productId = ngx.req.get_uri_args()["productId"] local async_producer = producer:new(broker_list, { producer_type = "async" }) local ok, err = async_producer:send("access-log", productId, message) if not ok then ngx.log(ngx.ERR, "kafka send err:", err) return end ``` 两台机器上都这样做,才能统一上报流量到kafka ``` bin/kafka-topics.sh --zookeeper 192.168.31.187:2181,192.168.31.19:2181,192.168.31.227:2181 --topic access-log --replication-factor 1 --partitions 1 --create bin/kafka-console-consumer.sh --zookeeper 192.168.31.187:2181,192.168.31.19:2181,192.168.31.227:2181 --topic access-log --from-beginning ``` (1)kafka在187上的节点死掉了,可能是虚拟机的问题,杀掉进程,重新启动一下 nohup bin/kafka-server-start.sh config/server.properties & (2)需要在nginx.conf中,http部分,加入resolver 8.8.8.8; (3)需要在kafka中加入advertised.host.name = 192.168.31.187,重启三个kafka进程 (4)需要启动eshop-cache缓存服务,因为nginx中的本地缓存可能不在了 二、基于storm+kafka完成商品访问次数实统计拓扑的开发 ==============

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值