每日一博 | 请求分级与限流——手动打造服务网关
转载本文需注明出处:微信公众号EAWorld,违者必究。
项目背景
雪崩一词指的是山地积雪由于底部溶解等原因而突然大块塌落的现象,具有很强的破坏力。在系统架构中提到的雪崩,就是由于一台服务器或者一台服务器中的某个模块发生故障进而引起连锁反应,最后导致大量的服务器或者软件模块无法正常工作,这种现象也较做“急剧变化”现象。
在某通信集团统一流程平台项目上线初期就发生过几次服务雪崩的事故,由于业务系统接入持续增多,业务系统的查询请求数量大大高于了前期的设计。当集群中的一台节点宕机下线后,请求压力迅速传导给了整个集群,从而引发了集群整体宕机。
解决方案
为了保障平台整体能稳定运行,在重新对服务器负载进行估算、增加集群冗余后,项目组增加了在部署架构、压力负载分流方面考虑,以持续提升平台性能。
我们对现有平台集群的逻辑架构进行了调整,将业务访问请求按系统ID分流到各子集群,由各集群分开处理,通过对业务请求的细分,达到子集群隔离,提升系统的稳定性与可扩展性。
具体到实施层面,项目组预备在负载均衡上增加服务网关的功能,使得nginx集群不再单纯的做反向代理,而是扩展为服务网关。
服务网关
服务网关基于openresty开发,OpenResty是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
我们在其基础上实现了以下功能:
流量限制:设立限流名单制度,对于非VIP且请求量大的用户进行限流。对名单中用户的请求进行计数,限制用户每分钟的请求次数,避免重复调用或短期内大量无效请求。
请求分域:根据请求来源的租户实现请求分域,将不同的租户请求分发到该租户的专用集群。
健康检查:提供一个简单的查询页面,可以查询当前集群节点的健康状况。
部署架构调整
在改造网关之前,我们首先要对集群的物理架构进行调整。通过对统一平台的业务量以及调用量的统计,以及对业务请求的监控我们发现,无论从业务数量以及调用量来看,业务压力主要来自于其中的两个业务系统。
于是我们对现有架构进行了调整,将负载均衡随机分发请求到集群,调整为按系统分发,将一个大集群切割成若干个小集群,按请求所在的系统将请求分发到各自响应的集群中。
请求分域
首先我们已经通过调整集群的部署,将集群进行了物理分割,接下来我们只需要将相关系统的请求转发到对应的集群中即可。
首先通过获取每个请求的请求头,来获得该请求的所属系统、所属用户等关键信息。
map $host $fmt_localtime { default '';}
map $host $bpm_method { default '';}
map $host $bpm_tenantid { default '';}
map $host $bpm_province { default '';}
map $host $bpm_userid { default '';}
map $host $bpm_provinceFlag { default '';}
map $host $RequestId { default '';}
(左右滑动查看全部代码)
然后我们在脚本中定义好每个系统的节点地址
#报账
upstream bpm_cluster_rbs {
server 10.24.20.45:8080;
server 10.24.20.46:8080;
……
server 10.24.20.52:8080;
}
#合同
upstream bpm_cluster_cms {
server 10.24.20.53:8080;
……
server 10.24.20.60:8080;
}
#其他
upstream bpm_cluster_other {
server 10.24.20.10:8080;
……
server 10.24.20.16:8080;
}
(左右滑动查看全部代码)
最后当收到请求时,将对应请求转发到对应的upstream就可以了
function forwardUpstream(tenantid)if tenantid == "CMS" --对于合同 系统 而且是 查询待办相关操作 then ngx.var.upstream="bpm_cluster_cms" elseif tenantid == "RBS" --对于报账 系统 而且是 查询待办相关操作 then ngx.var.upstream="bpm_cluster_rbs"else ngx.var.upstream="bpm_cluster_other" enden
(左右滑动查看全部代码)
限流
lua-resty-limit-traffic是一个openresty中用于限制和控制流量的Lua库,使用这个库可以方便的对用户、IP进行限流
https://github.com/openresty/lua-resty-limit-traffic
(左右滑动查看全部代码)
lua-resty-limit-traffic模块限流分为两种:
第一种限制某用户每分钟只能调用120次(允许在时间段开始的时候一次性放过120个请求)
local limit_count = require "resty.limit.count"
local lim, err = limit_count.new("my_limit_count_store", 120, 60)
(左右滑动查看全部代码)
第二种限制每分钟处理120个请求(平滑处理,每秒钟只放过两个请求)
local limit_req = require "resty.limit.req"
local lim, err = limit_req.new("my_limit_req_store", 2, 0)
(左右滑动查看全部代码)
实战中,我们的策略是将流量大的用户加入到限流名单中,名单内的用户会在redis中维护一份配置表,包括
在请求进来后,我们先从请求头中获取当前请求的用户
map $host $bpm_userid { default '';}
(左右滑动查看全部代码)
然后判断该用户是否在限流名单内,如果确定为限流用户则读取该用户的配置信息
local cache_ngx = ngx.shared.my_ngx_redis_cachelocal user_conf = cache_ngx:get(userid)local redis_josn = cjson.decode(user_conf)local maxReq = redis_josn['maxReq']local nextReqTime = redis_josn['nextReqTime']
(左右滑动查看全部代码)
根据配置调用限流方法,设置某用户每分钟只能调用XX次请求(允许一次性放过)
local limit_count = require "resty.limit.count"
local maxReq = redis_josn['maxReq']
local nextReqTime = redis_josn['nextReqTime']
local lim, err = limit_count.new("my_limit_count_store", maxReq, nextReqTime)
if not lim then
ngx.log(ngx.ERR, "failed to instantiate a resty.limit.count object: ", err)
return ngx.exit(500)
end
local delay, err = lim:incoming(key, true)
-- 如果发生错误则返回500,如果请求数超过了 count 限制则返回403
if not delay then
if err == "rejected" then
return ngx.exit(403)
end
ngx.log(ngx.ERR, "failed to limit count:", err)
return ngx.exit(500)
end
(左右滑动查看全部代码)
健康检查
upstream.healthcheck本质上是个定时器,它会定期发送指定的http请求并解析响应码,去探测upstream中每个peer的存活状态,再结合历史请求记录来判断并标记其状态。
模块的源码见下面的页面:
https://github.com/openresty/lua-resty-upstream-healthcheck
(左右滑动查看全部代码)
实战中我们的代码如下:
local ok, err = hc.spawn_checker{ shm = "healthcheck", -- defined by "lua_shared_dict" upstream = "bpm_cluster_rbs", -- defined by "upstream" type = "http", http_req = "GET /default/engineState.jsp HTTP/1.0\r\nHost: bpm_cluster_rbs\r\n\r\n", -- raw HTTP request for checking interval = 2000, -- 每两秒检查一次 timeout = 1000, -- 1 sec is the timeout for network operations fall = 3, --
(左右滑动查看全部代码)
关于作者:李云涛,普元高级开发工程师,擅长性能调优、微服务、容器、消息队列等技术。先后参与邮储银行Java开发平台、中移总ERP流程平台、中煤信息技术中台等平台的的架构设计与平台研发工作。
关于EAWorld:使能数字转型,共创数智未来,长按二维码关注!
本文分享自微信公众号 - EAWorld(eaworld)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Chrome 正在获得新的渐进式 Web 应用程序功能
Google 正在开发一个新的 API,允许 Chrome 渐进式网络应用程序 PWA(progressive web app)读取操作系统文件系统中的文件。 渐进式网络应用程序 PWA是最新的网络技术,支持任何人将网站作为原生移动或桌面应用来打开。而在浏览器中,文件处理程序代表网络应用程序处理具有给定的 MIME 类型或文件扩展名之一的文件的能力。例如,当你安装一个图像编辑器作为网络应用时,它可以在其清单中注册其处理 jpg、png 等文件类型的能力。 在新 API 的文档中,Google指出,他们的目标是提高网络应用和本地应用之间的透明度,并通过启用对文件处理程序的支持,提供 "更一致的用户体验"。并且在下个版本中,Chrome 将会有一个新的权限提示,要求用户确认 PWA 是否可以将自己注册为某些文件扩展的文件处理程序。 目前,Chromium 已经具有支持在 Chrome 和其他浏览器中处理起源试验(origin trials)的功能,但新的文件处理 API 与其他经历起源试验过程的 API 不同,因为启用和禁用试验会导致操作系统中的一些状态被改变(注册文件处理程序)。据悉,G...
- 下一篇
重磅!!! CentOS 之父创造的 Rocky Linux 8.3 镜像下载来啦!!!
是的,在经历了3月30号的跳水,4月30号的意外后,在全球人民的五一国际劳动节当天,Rocky Linux 8.3 RC1 发布啦! Gregory Kurtzer 述:今年最受期待的开源项目发布就在这里!这是Rocky Linux 8.3的第一个候选发行版的首次安装!Rocky是社区企业操作系统,现在CentOS已成为RHEL的协作开发测试基地。特别感谢所有实现此版本的朋友。言出必行,Rocky Linux已经准备就绪! 中文社区爱好者安装截图: 为方便国内Rocky Linux爱好者下载试用,Rocky Linux中文社区已经进行了多种方式的作种,包括:迅雷VIP、BT下载、百度网盘、天翼云盘等(在此感谢社区爱好者),欢迎大家下载试用,有任何问题,可以在Rocky Linux中文社区QQ群、微信群交流沟通。 下载链接:https://rockylinux.cn/rocky-linux-mirror-download.html 欢迎加入中文社区QQ群:626649599 微信群:rockylinuxcn [群已满,加微信单独拉人]
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS关闭SELinux安全模块
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- CentOS7安装Docker,走上虚拟化容器引擎之路
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Windows10,CentOS7,CentOS8安装Nodejs环境