大型商城活动防刷限流方案

2024-02-14 09:38

本文主要是介绍大型商城活动防刷限流方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近负责的一个某品牌手机的官方商城,他们要发售一款新手机,以往都是各个渠道一起发售,但是本次决定官网首发10000台,这样一来其他渠道的消费者都会被引流到官网来(天猫/京东/苏宁/线下),其庞大的流量并发可想而知,原有的功能实现肯定无法承载这种体量,因此我们全面优化了预售功能,分别按照以下几个点来操作:

1. 页面静态化(动态数据全部通过js异步获取,并且需要控制异步请求的数量,页面缓存到CDN)

2.防bot(包括防刷、限流等)

今天主讲一下发刷和限流方案,需要用到的技术包括Nginx+Lua+Redis

OK我们先来看一下防刷代码,看完代码再来讲解这段代码:

-- access_by_lua_file '/opt/ops/lua/access_limit.lua'  
local function close_redis(red)  if not red then  return  end  --释放连接(连接池实现)  local pool_max_idle_time = 10000 --毫秒  local pool_size = 100 --连接池大小  local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  if not ok then  ngx_log(ngx_ERR, "set redis keepalive error : ", err)  end  
end  local redis = require "resty.redis"  
local red = redis:new()  
red:set_timeout(1000)  
local ip = "redis-ip"  
local port = redis-port  
local ok, err = red:connect(ip,port)  
if not ok then  return close_redis(red)  
end  local clientIP = ngx.req.get_headers()["X-Real-IP"]  
if clientIP == nil then  clientIP = ngx.req.get_headers()["x_forwarded_for"]  
end  
if clientIP == nil then  clientIP = ngx.var.remote_addr  
end  local incrKey = "user:"..clientIP..":freq"  
local blockKey = "user:"..clientIP..":block"  local is_block,err = red:get(blockKey) -- check if ip is blocked  
if tonumber(is_block) == 1 then  ngx.exit(ngx.HTTP_FORBIDDEN)  return close_redis(red)  
end  res, err = red:incr(incrKey)  if res == 1 then  res, err = red:expire(incrKey,1)  
end  if res > 200 then  res, err = red:set(blockKey,1)  res, err = red:expire(blockKey,600)  
end  close_redis(red)

这段的逻辑是这样,请求过来的时候获取当前访问者的ip,拼接出两个key,一个是用于统计该ip的请求次数的,另一个是用来标识是否被限制了,然后redis里去先去get一下这个ip是否被限制了,如果返回1标识被限制了,直接nginx返回403,否则的话对当前ip进行计数,第一次计数时,计数完毕后设置该计数器的失效时间1秒,后面判断计数器的大小是否查过了200,也就是说,如果在1秒的失效时间内请求了超过200次,那么设置当前ip为受限,并设置受限时间为10分钟。


再来看看限流代码,看完代码再来讲解这段代码:

-- access_by_lua_file '/opt/ops/lua/access_flow_control.lua'  
local function close_redis(red)  if not red then  return  end  --释放连接(连接池实现)  local pool_max_idle_time = 10000 --毫秒  local pool_size = 100 --连接池大小  local ok, err = red:set_keepalive(pool_max_idle_time, pool_size)  if not ok then  ngx_log(ngx_ERR, "set redis keepalive error : ", err)  end  
end  local function wait()  ngx.sleep(1)  
end  local redis = require "resty.redis"  
local red = redis:new()  
red:set_timeout(1000)  
local ip = "redis-ip"  
local port = redis-port  
local ok, err = red:connect(ip,port)  
if not ok then  return close_redis(red)  
end  local uri = ngx.var.uri -- 获取当前请求的uri  
local uriKey = "req:uri:"..uri  
res, err = red:eval("local res, err = redis.call('incr',KEYS[1]) if res == 1 then local resexpire, err = redis.call('expire',KEYS[1],KEYS[2]) end return (res)",2,uriKey,1)  
while (res > 10)  
do   local twait, err = ngx.thread.spawn(wait)  ok, threadres = ngx.thread.wait(twait)  if not ok then  ngx_log(ngx_ERR, "wait sleep error: ", err)  break;  end  res, err = red:eval("local res, err = redis.call('incr',KEYS[1]) if res == 1 then local resexpire, err = redis.call('expire',KEYS[1],KEYS[2]) end return (res)",2,uriKey,1)  
end  
close_redis(red)  

限流的逻辑是这样的请求过来获取你的url然后以这个url作为key去redis里计数,然后判断当前url被请求过多少次,如果是一次那么设置该key的失效时间是1秒,然后有一个while循环,循环的条件是当前url被请求的次数大于10,里面做的事情是让当前这个请求等待1秒,此时前面设置的失效时间应该到了,然后再去对当前url计一次数此时返回的数量理论上市1,如果数量等于1那么设置失效时间为1,然后继续while的循环,如果大于10就让他一直去循环做等待1秒然后设置请求次数加1,如果不大于1秒那么就放行允许请求去访问我们的tomcat,所以这里的逻辑其实限制了并发的请求数量是10,也就是同一时刻只允许10个请求通过校验走到tomcat,后面的请求都在排队等待。

说白了就是10个请求进来后,然后让后面的请求等待1秒然后再放进来10个一直这样循环处理。


ok以上就是我分享的防刷和限流解决方案,lua脚本是网上找来的,仅供参考。


这篇关于大型商城活动防刷限流方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/708129

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动

使用Python实现Word文档的自动化对比方案

《使用Python实现Word文档的自动化对比方案》我们经常需要比较两个Word文档的版本差异,无论是合同修订、论文修改还是代码文档更新,人工比对不仅效率低下,还容易遗漏关键改动,下面通过一个实际案例... 目录引言一、使用python-docx库解析文档结构二、使用difflib进行差异比对三、高级对比方

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.

MySQL容灾备份的实现方案

《MySQL容灾备份的实现方案》进行MySQL的容灾备份是确保数据安全和业务连续性的关键步骤,容灾备份可以分为本地备份和远程备份,主要包括逻辑备份和物理备份两种方式,下面就来具体介绍一下... 目录一、逻辑备份1. 使用mysqldump进行逻辑备份1.1 全库备份1.2 单库备份1.3 单表备份2. 恢复

redis中session会话共享的三种方案

《redis中session会话共享的三种方案》本文探讨了分布式系统中Session共享的三种解决方案,包括粘性会话、Session复制以及基于Redis的集中存储,具有一定的参考价值,感兴趣的可以了... 目录三种解决方案粘性会话(Sticky Sessions)Session复制Redis统一存储Spr

基于Redisson实现分布式系统下的接口限流

《基于Redisson实现分布式系统下的接口限流》在高并发场景下,接口限流是保障系统稳定性的重要手段,本文将介绍利用Redisson结合Redis实现分布式环境下的接口限流,具有一定的参考价值,感兴趣... 目录分布式限流的核心挑战基于 Redisson 的分布式限流设计思路实现步骤引入依赖定义限流注解实现

SpringBoot实现虚拟线程的方案

《SpringBoot实现虚拟线程的方案》Java19引入虚拟线程,本文就来介绍一下SpringBoot实现虚拟线程的方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录什么是虚拟线程虚拟线程和普通线程的区别SpringBoot使用虚拟线程配置@Async性能对比H