基于ngx_lua的分流系统设计

1.2k 词
    <h3 id="导言"><a href="https://fankeke.github.io/#%E5%AF%BC%E8%A8%80" class="headerlink" title="导言"></a>导言</h3><p>为了在接入层面做到对请求精细化的控制和导流,需要在nginx上做分流的工作,解决包括但不限于几种需求,如版本上线,灰度发布、特殊用户,特殊版本等。其工作流程如下:</p>

在业务侧,可以根据需求将其业务节点划分为组,可以按照自己定制的策略来反馈给nginx,根据需求来导流相应分组。

NGINX+Lua实现

方案预期

在到达分流目的同时,需要有到达其它几个目的:
1 配置方便,兼容其它功能
如果某个服务需要接入分流系统,SRE可以清晰清楚且便捷的配置即可,不会影响其它的功能,不需要有其它冗余的操作或交流。

2 提供降级开关
响应业务需求,SRE或者业务需求发能够方便地选择开启或者关闭某个分流需求,甚至不需要对nginx做重启操作

3 即配即走,不重启NGINX
我们希望能够到达即配即走的效果,不重启NGINX。(当然接入分流系统时配置文档的变更,SRE需要重启)
(事实上如果业务接入了其它lua的功能,那么连配置都不用更改,直接走新的Lua框架即可生效)

4 系统轻巧,耦合度低
希望将系统做的足够轻巧,能够掌握整改分流过程和生效过程,方便及时排查问题,不影响其它业务。

5 高容错性
系统不应该对请求有伤害,包括系统不可用时、分流集群不合法时等意外情况下,都要保重请求的正常。

6 流量统计
能够从对分流情况有明确的感知和了解,包括每个分流集群的qps、响应时间等。

方案设计

方案架构

为了达到上面几个目的,构件了一套轻巧的系统。核心思想为表驱动的方式:以业务的appkey为索引,通过查表找出该业务需要分流的策略,将具体分流策略下放,加载策略进行分流。

在请求来临时,取出appkey,查找分流数据,执行分流策略。每个不同的分流逻辑在不同的分流文档里面完成。
该表时刻处于变化中,从第三方存储中定时加载到nginx共享内存。其分流流程如下:

分流数据的更新逻辑如下:
方案一:

当管理机把更新的表推送到redis后,每个nginx会从redis里面定时拉取该表,缓存入nginx的共享内存。
该方案优势:
1 每个分流的Nginx都可以自己拉取,只要有定时拉取的逻辑
存在的问题:
1 单个worker拉取,需要patch tengine源码,担心会造成问题
2 每个nginx定时轮询,且定时时间短

方案二:

通过http接口,在每次数据真正变更时候走http来更新每个分流nginx的内存,并将最新的一份数据存储在redis里面容灾。
优势:
1 不用定时器,即不需patch源码
2 在数据真正变动时进行更新,没有无谓轮询。