perface

小道一句:本文为原创文章,某SDN博主抄袭我的文章不带出处的。

最近有需求,需要把服务a发给服务b的请求复制给服务c,服务a发给服务b的时候会经过nginx,这个nginx是有lua脚本来辅助工作的。说白了,这个nginx+lua就是abtestingGateway。

架构图如下:

下面看看怎么实现abtestingGateway来复制流量。

分流条件

customercode和user字段的数据都在请求里的json数据里面。

  1. 匹配到customercode等于我们指定的值后把流量分到服务B。
  2. 在条件1的基础上,判断是否有users这个字段,有的话服务b,服务C同时发,否则只发服务B。
  3. 如果没有匹配到customercode,那么就转发到服务C上。

分流策略添加

这个请参考我们的另一篇博文 abtestingGateway 分流策略添加

编写复制请求的代码

我在abtestingGateway下,在customercode.lua(lib/abtesting/diversion目录下)文件里面添加代码

逻辑是这样的:

当abtestingGateway拿到customercode后,从redis里面拿取对应的upstream,如果upstream是服务b的upstream,那么就需要复制流量咯,反之。

所以我们在getUpstream里添加一段代码

_M.getUpstream = function(self, customercode)
if not tostring(customercode) then
return nil
end local database, key = self.database, self.policyLib local backend, err = database:hget(key, customercode)
if not backend then error{ERRORINFO.REDIS_ERROR, err} end if backend == ngx.null then backend = nil end -- 下面就是新添加的代码 begin
if backend == "newacm" then -- newacm就是我们配置的upstream名字
copyRequest()
end
-- end local new_acm_uri = ngx.var.new_acm_uri
if new_acm_uri and backend then
backend = backend..new_acm_uri
end
return backend
end

匹配到指定的upstream后,那么就走copyRequest的方法了,代码如下:

_M.copyRequestToOldAcm = function(self)
if ngx.var.copy_switch == "on" then -- 分流开关,on为打开
copyRequest()
end
end function copyRequest() -- 匹配到我们指定的customerCode以后,那么就复制一份请求发送到老的ACM上,原因是因为发送给老的acm就可新老一块同步数据了
users_exist = false -- 有这个users那么这个标志位为true,没有的话就是false
action = ngx.var.request_method local postData = ngx.req.get_post_args() --如果post请求里面没有这个customercode参数,
if postData then -- post 请求
local errinfo = ERRORINFO.UNKNOWN_ERROR
if postData then
for k, v in pairs(postData) do --这个k为未json反序列化的数据,v为布尔值
local after_json_k = cjson.decode(k) --提交上来的数据为json格式的,需要反序列化一下
if after_json_k then
for k1 ,v1 in pairs(after_json_k) do
if k1 == "customer" then
if v1.users then
users_exist = true
end
end
end
end
end
end
end if users_exist == true then --没有匹配到users在post请求数据里,那么就不需要复制一份请求到老的的acm上了,直接return就行了。否则需要复制
log:info("the request has users arguments ,so needn't copy the request to the old acm!")
return false
else
log:info("the request doesn't have users arguments, so need to copy the request to the old acm!")
end if action == "POST" then
--ngx.req.read_body() -- 解析 body 参数之前一定要先读取 body
local arg = ngx.req.get_post_args() -- post需要参数传递
arry = {method = ngx.HTTP_POST, body = ngx.var.request_body, args=arg}
else
arry = {method = ngx.HTTP_GET}
end oldacm = ngx.location.capture_multi {
{ "/oldacm" .. ngx.var.request_uri, arry},
}
if oldacm.status == ngx.HTTP_OK then -- 只返回online server的结果
-- ngx.say(online.body)
log:info("copy request result is ok!!")
return true
else
-- ngx.status = ngx.HTTP_NOT_FOUND
--for i,r in pairs(oldacm) do end
log:info("copy request result is failed!! the response body is -->"..oldacm.body)
return false
end end

然后我们在diversion/diversion.lua里面添加下这段代码,添加的这段代码起到这个作用的,abtestingGateway在运行的时候,只要匹配到了我们的规则,比如customercode=123456,匹配到了customercode=123456,那么abtestingGateway会从redis获取这个规则对应的upstream,然后把这个upstream放在nginx的内存里面,在接下来的60秒以内,只要匹配到规则就直接从内存里面拿取,不走getUpstream这个函数了,所以也触发不了复制请求的代码块了。这就是为什么我们还要添加下面这些代码:

 95 local copyRequest = function()
96 local cm = require("abtesting.diversion.customercode")
97 local cr = cm:copyRequestToOldAcm()
98 return cr
99 end
264 local info = "get upstream ["..ups.."] according to ["..idx.."] userinfo ["..usertable[idx].."] in cache 1"
266 log:info(info)
267 if string.find(ups,"newacm") == 1 then
268 copyRequest()
269 end

左边的数字是代码所处的行数,可以参考行数来添加代码。

最后我们需要在nginx的配置文件里面添加oldacm这个location,不然会提示404咯

    location /oldacm/ {
proxy_pass http://stable/; # 服务B ip
}

然后重启nginx即可咯。测试,没啥问题。

AbtestingGateway 复制请求到其他服务上的更多相关文章

  1. [转]在 Azure 云服务上设计大规模服务的最佳实践

    本文转自:http://technet.microsoft.com/zh-cn/magazine/jj717232.aspx 英文版:http://msdn.microsoft.com/library ...

  2. ubuntu安装discourse论坛----结合在apache服务上建立虚拟主机

    指导操作:https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md 一.先安装 Docker / Git: wg ...

  3. SpringCloud学习之Hystrix请求熔断与服务降级(六)

    我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...

  4. 揭秘有状态服务上 Kubernetes 的核心技术

    背景 随着 Kubernetes 成为云原生的最热门的解决方案,越来越多的传统服务从虚拟机.物理机迁移到 Kubernetes,各云厂商如腾讯自研上云也主推业务通过Kubernetes来部署服务,享受 ...

  5. WCF服务上应用protobuf

    WCF服务上应用protobuf Web api  主要功能: 支持基于Http verb (GET, POST, PUT, DELETE)的CRUD (create, retrieve, updat ...

  6. Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件(二)

    Android 发送HTTP GET POST 请求以及通过 MultipartEntityBuilder 上传文件第二版 上次粗略的写了相同功能的代码,这次整理修复了之前的一些BUG,结构也大量修改 ...

  7. 利用python httplib模块 发送Post请求测试web服务是否正常起来!

    最近在学习python,恰好老大最近让我搞个基于post请求测试web服务是否正常启用的小监控,上网查了下资料,发现强大的Python恰好能够用上,所以自己现学现卖,顺便锻炼下自己. 由于本人也刚接触 ...

  8. SpringCloud实战-Hystrix请求熔断与服务降级

    我们知道大量请求会阻塞在Tomcat服务器上,影响其它整个服务.在复杂的分布式架构的应用程序有很多的依赖,都会不可避免地在某些时候失败.高并发的依赖失败时如果没有隔离措施,当前应用服务就有被拖垮的风险 ...

  9. 15分钟在阿里云Kubernetes服务上快速建立Jenkins X Platform并运用GitOps管理应用发布

    本文主要介绍如何在阿里云容器服务Kubernetes上快速安装部署Jenkins X Platform并结合demo实践演示GitOps的操作流程. 注意:本文中使用的jx工具.cloud-envir ...

随机推荐

  1. BZOJ2759一个动态树好题 LCT

    题如其名啊 昨天晚上写了一发忘保存 只好今天又码一遍了 将题目中怕$p[i]$看做$i$的$father$ 可以发现每个联通块都是一个基环树 我们对每个基环删掉环上一条边 就可以得到一个森林了 可以用 ...

  2. linux find命令用法

    Linux下find命令在目录结构中搜索文件,并执行指定的操作.Linux下find命令提供了相当多的查找条件,功能很强大.由于find具有强大的功能,所以它的选项也很多,其中大部分选项都值得我们花时 ...

  3. CentOS 7.0关闭默认防火墙启用iptables防火墙

    转自:https://www.cnblogs.com/lixuwu/p/6087023.html 阅读目录 1 配置防火墙,开启80端口.3306端口 2 关闭SELINUX 3 CentOS 配置防 ...

  4. 八幅漫画理解使用 JSON Web Token 设计单点登录系统

    原文出处: John Wu 上次在<JSON Web Token – 在Web应用间安全地传递信息>中我提到了JSON Web Token可以用来设计单点登录系统.我尝试用八幅漫画先让大家 ...

  5. SpringMVC+Thymeleaf +HTML的简单框架

    一.问题 项目中需要公众号开发,移动端使用的是H5,但是如果不用前端框架的话,只能考虑JS前端用ajax解析JSON字符串了.今天我们就简单的说下前端框架Thymeleaf如何解决这个问题的: 二.开 ...

  6. wifipineapple外接SD卡

    通过SSH或者web访问URL, http://172.16.42.1:1471 输入帐号:root  密码:pineapplesareyummy(默认账号密码) ssh连接:ssh root@172 ...

  7. ubuntu crontab 在时间段内随机执行一次

    crontab 在linux下做定时任务的命令, 1. 基本格式 * * * * * cmd 第一个表示:分钟 1-59, 每分钟用 */1 第二个表示:小时 023 第三个表示:日期1-31 第四个 ...

  8. 解决 Docker pull 出现的net/http: TLS handshake timeout 的一个办法

    echo "DOCKER_OPTS=\"\$DOCKER_OPTS --registry-mirror=http://f2d6cb40.m.daocloud.io\"&q ...

  9. EBS测试环境DataGuard配置

    1.环境信息 primary数据库(必须运行在归档模式) ip 127.71.28.71 sid test db_unique_name test log_mode archivelog force_ ...

  10. Microsoft/Git-Credential-Manager-for-Mac-and-Linux

    纠正Mac上的错误: Fatal: java.lang.Error encountered. Details: unexpected errorfatal: credential helper '!/ ...