利用 OpenResty 实现负载均衡、限流功能

业余杂谈 herman 437浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog,发送下载链接帮助你免费下载!
本博客日IP超过1800,PV 2600 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog,之前的微信号好友位已满,备注:返现
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领

OpenResty 很多人可能都没有听说过,但是最近几年它发展很快,很多大厂都有使用,包括 360、BAT、京东、锤子等。所以,不得不说的是,一波学习 OpenResty 的高潮即将来临。

OpenResty 可以通过 lua 脚本扩展 nginx 功能,包括让你感觉 nginx 实现的不能满足你要求的功能,你都可以通过 OpenResty 来实现。

Nginx 本身是用 C 来编写的,但是为了实现一些自定义的特有的功能,你去重新学习一下 C 又不太现实,因此当你会 OpenResty 的时候,就可以派上用场了。lua 的学习成本相比 C 来说能低很多,而且 lua 在 Redis 中都有使用。因此我认为学习 OpenResty 是一个非常不错的选择,性价比非常的高。

今天给大家简单的介绍两个使用 OpenResty 的场景:实现负载均衡、限流。当然 OpenResty 的使用场景实在是太多,包括攻防方面的,比如 cc 攻击等。但这些内容建议大家私下里,感兴趣的自己去学习。

OpenResty 安装我就不讲了,我们先来看一个 hello World 的 demo,让我们熟悉它是怎么使用的。

worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 9000;
        location / {
            default_type text/html;
            content_by_lua '
                ngx.say("<p>Hello, World!</p>")
            ';
        }
    }
}

在 nginx.conf 配置文件中,加入 content_by_lua 这段代码即可。

下面我们来看通过使用 OpenResty 配置,配合 lua 脚本来实现自己的负载均衡策略。

upstream xttblog {
    server 192.168.10.1:8080;
    server 192.168.10.2:8080;
    balancer_by_lua_file lua/balancer.lua;
}

balancer.lua 里的代码你可以自己实现。下面给你一个我的 demo 代码。

local balancer = require "ngx.balancer"
local upstream = require "ngx.upstream"
local upstream_name = 'mysvr3'
local srvs = upstream.get_servers(upstream_name)
function is_down(server)
local down = false
local perrs = upstream.get_primary_peers(upstream_name)
for i = 1, #perrs do
local peer = perrs[i]
if server == peer.name and peer.down == true then
    down = true
end
end
return down
end
local remote_ip = ngx.var.remote_addr
local hash = ngx.crc32_long(remote_ip);
hash = (hash % 2) + 1
local backend = srvs[hash].addr
local index = string.find(backend, ':')
local host = string.sub(backend, 1, index - 1)
local port = string.sub(backend, index + 1)
ngx.log(ngx.DEBUG, "current peer ", host, ":", port)
balancer.set_current_peer(host, tonumber(port))
if not ok then
    ngx.log(ngx.ERR, "failed to set the current peer: ", err)
return ngx.exit(500)
end

负载均衡算法有很多,可以参考我的这篇文章《手把手教你写出 6 种负载均衡算法》。

最后再来看一个限流 demo,nginx.conf 中配置信息如下:

location /xttblog/limit {
    access_by_lua_file lua/limit_conn.lua;
    default_type text/plain;
    content_by_lua_block {
    ngx.print('www.xttblog.com')
        ngx.sleep(0.01)
    }
    log_by_lua_file src/log.lua;
}

limit_conn.lua 中的代码也非常的简单,粘贴如下:

local limit_conn = require "resty.limit.conn"
-- 对于内部重定向或子请求,不进行限制。因为这些并不是真正对外的请求。
if ngx.req.is_internal() then
    return
end
-- 限制一个 ip 客户端最大 5 个并发请求
-- burst 设置为 0,如果超过最大的并发请求数,则直接返回503,
-- 如果此处要允许突增的并发数,可以修改 burst 的值(漏桶的桶容量)
-- 最后一个参数其实是你要预估这些并发(或者说单个请求)要处理多久,以便于对桶里面的请求应用漏桶算法
local lim, err = limit_conn.new("my_limit_conn_store", 5, 5, 0.1)              
if not lim then
    ngx.log(ngx.ERR, "failed to instantiate a resty.limit.conn object: ", err)
    return ngx.exit(500)
end
local key = ngx.var.binary_remote_addr
-- commit 为true 代表要更新shared dict中key的值,
-- false 代表只是查看当前请求要处理的延时情况和前面还未被处理的请求数
local delay, err = lim:incoming(key, true)
if not delay then
    if err == "rejected" then
        return ngx.exit(503)
    end
    ngx.log(ngx.ERR, "failed to limit req: ", err)
    return ngx.exit(500)
end
-- 如果请求连接计数等信息被加到shared dict中,则在ctx中记录下,
-- 因为后面要告知连接断开,以处理其他连接
if lim:is_committed() then
    local ctx = ngx.ctx
    ctx.limit_conn = lim
    ctx.limit_conn_key = key
    ctx.limit_conn_delay = delay
end
local conn = err
-- 其实这里的 delay 肯定是上面说的并发处理时间的整数倍,
-- 举个例子,每秒处理100并发,桶容量200个,当时同时来500个并发,则200个拒掉
-- 100个在被处理,然后200个进入桶中暂存,被暂存的这200个连接中,0-100个连接其实应该延后0.5秒处理,
-- 101-200个则应该延后0.5*2=1秒处理(0.5是上面预估的并发处理时间)
if delay >= 0.001 then
    ngx.sleep(delay)
end

可以看到借助 Lua 这种脚本语言,结合 OpenRestry,想实现自定义的功能就显得很简单。

OpenResty 非常的强大,它还能操作 MySQL、PostgreSQL、Memcached 以及 Redis 等后端应用。如果你对它感兴趣,不妨加我微信好友 xttblog,我们一起精进!

想要上面代码的网友也可以加我好友,我免费送。另外如果想更深入的学习,可以通过购买 OpenResty 的入门实战课程,这门课程是极客时间的《OpenResty从入门到实战》,通过我下方的海报上的二维码,扫码购买,加我好友,我返现给你 24 哦!

OpenResty从入门到实战

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号1:xmtxtt(5000人已满),微信号2:codedq(5000人已满),微信号3:xttblog(超2800)。备注:“xttblog”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » 利用 OpenResty 实现负载均衡、限流功能