专栏首页EAWorld请求分级与限流——手动打造服务网关

请求分级与限流——手动打造服务网关

转载本文需注明出处:微信公众号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,  -- # 连续3次失败才认定为down    rise = 2,  -- # 对down状态的节点,连续2次成功认定为UP    valid_statuses = {200, 302},  -- 状态正常的code    concurrency = 10,  -- 检查线程数}

(左右滑动查看全部代码)

本文分享自微信公众号 - EAWorld(eaworld),作者:李云涛

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-11-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 建设微服务API网关的一些实践

    随着这些年微服务的流行,API网关已经成为微服务架构中不可或缺的一环。一方面它承担着服务对外的唯一门户,一方面它提取了许多应用的共性功能。

    烂猪皮
  • 一文带你 API 网关从入门到放弃

    来源:http://github.com/aCoder2013/blog/issues/35

    芋道源码
  • 大厂必备的网关服务,为什么那么重要?

    假设你正在开发一个电商网站,那么这里会涉及到很多后端的微服务,比如会员、商品、推荐服务等等。

    Bug开发工程师
  • API网关

    假设你正在开发一个电商网站,那么这里会涉及到很多后端的微服务,比如会员、商品、推荐服务等等。

    chenchenchen
  • 拆解交易系统--服务稳定性

    交易系统承担了整个交易链路上的所有交易相关的流量,同时交易系统上时常会组织一些营销,大促相关的活动,所以需要面对着因大促造成的瞬时流量激增的情况。

    春哥大魔王
  • 腾讯、三一集团合作再次升级,打造重工业领域首个智慧服务中台

    近日,三一集团与腾讯的战略合作再次升级,双方将借助腾讯云企点客服的能力,联手打造工程机械行业首个智慧服务中台,助推三一集团数字化升级。

    腾讯企点
  • 企业案例丨腾讯天幕 X 云开发CloudBase

    重剑轻出,大巧不工。本案例中的“天幕安全巡检”小工具依托云开发CloudBase+小程序可视化而打造,旨在改善 toB 售前打单过程中常见的繁琐流程问题,包括面...

    腾讯云开发TCB
  • DDOS终极防御

    何为DDOS:DDOS被称为分布式拒绝服务攻击,目的主要是让指定目标无法正常提供服务,是目前最强大,最难防御的攻击之一,是一个世界性的难题,并没有一个好的解决办...

    用户2202688
  • 架构原理|服务雪崩效应现象以及处理方法之Hystrix实现

    分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况, 这种现象被称为服务雪崩效应. 为了应对服务雪崩, 一种常见的做法是手动服务降级. 而Hyst...

    猿哥

扫码关注云+社区

领取腾讯云代金券