nginx限流配置|8月更文挑战

why?

本篇文章旨在帮助网站限制用户访问频率,必定程度上挡住了部分爬虫攻击。
可经过扩展get_client_id 识别客户端 或 HTTP_FORBIDDEN 来回传给验证码。滑块操做等人机验证html

安装OpenResty

OpenResty® 经过汇聚各类设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师能够使用 Lua 脚本语言调动 Nginx 支持的各类 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发链接的高性能 Web 应用系统。
OpenResty是一个基于Nginx的平台,里面提供了许多高质量的第三方模块。咱们本次使用的是redis + lua组合,因此须要OpenResty来提供lua环境
点击此处下载nginx

新建一个站点用于测试

package main
import "github.com/gofiber/fiber/v2"
func main() {
	app := fiber.New()

	app.Get("/", func(c *fiber.Ctx) error {
		return c.SendString("content content content")
	})

	app.Get("/api/member/get", func(c *fiber.Ctx) error {
		user := struct {
			UserName string `json:"userName"`
			Age      int    `json:"age"`
		}{UserName: "juejin", Age: 100}
		return c.JSON(user)
	})

	app.Listen(":8080")
}

复制代码

在上述代码中,咱们提供了一个http get /api/member/get的API,他返回了一堆json
在根节点则返回了一堆没有意义的字符 访问API截图以下:git

image.png

将站点托管到nginx中

在server节点里,指定特定的路径名并使用lua script
此处403只是返回了一个静态页面,后面咱们能够像开头说的那样换成验证码之类的...github

location ~ /api { #这里能够自定义路径
    proxy_http_version 1.1;
    access_by_lua_file lua/access_limit.lua; #指定lua的路径
    allow 127.0.0.1;
    proxy_pass http://127.0.0.1:8080;
    proxy_redirect default;
}

error_page 403 /403.html; #这个是咱们拒绝访问时,返回给客户端的响应
location = /403.html { 
    root   html;
    allow all;
}
复制代码

lua 处理请求

Q:每次请求都要链接redis,会不会致使链接耗尽、资源紧张?
A:OpenResty为咱们提供了链接池,资源是能够重用的,不会致使资源紧张redis

咱们首先来肯定一下基本的参数:
block_client = 1 //用来记录封锁时长
limt_client = 5 //每秒访问个数
local limit_expiry = 1 //记录limit_expiry秒内的访问
local max_count = 5 //limit_expiry秒内的访问秒内的最大访问次数json

主要方法解析:api

  1. get_client_id 方法:这个方法主要是用来识别用户身份的。能够取 ip 、 token 、 cookie 之类的作个签名以当作用户的访问令牌的。这里偷个懒,只是取了原ip
local function get_client_id()    
   local headers = ngx.req.get_headers()
   local clientId = headers["X-Real-IP"] or headers["x_forwarded_for"] or ngx.var["remote_addr"] or "0.0.0.0"
   return clientId
end
复制代码
  1. 释放链接
--从链接池关闭redis
local function close_redis(client)
   if not client then
       return
   end
   --将redis链接放回链接池
   local ok, err = client:set_keepalive(pool_max_idle_time, pool_size)
   if not ok then
       ngx.say("redis connct err:",err)
       return client:close()
   end
end
复制代码

完整代码:

gitee.com/cergou/juej…markdown

写在最后

本次主要学习了lua来实现限流,性能上没有带来明显的负荷
主要思路为:设定一个N秒内过时的key,客户端发起请求时经过get_client_id来识别用户身份。每次请求时给这个key自增1,当此值超过咱们规定的最大值时。拒绝此用户的请求,并将此用户记录到block_client。下次直接拒绝该用户请求。block_client过时后。用户又能正常访问服务cookie

思惟导图:并发

image.png

相关文章
相关标签/搜索