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. 早期(编译器)优化--javac编译器

    java语言的“编译期”其实是一段“不确定”的操作过程,可能是指一个前端编译器把.java变成.class的过程,也可能是指虚拟机的后端运行期编译器(JLT)把字节码转变成机器码的过程,也有可能是使用 ...

  2. Cocos Creator 的Hello World

    1,创建项目[参考来源:官方文档] 在 Dashboard 中,打开 新建项目 选项卡,选中 Hello World 项目模板. 然后在项目路径栏中指定一个新项目存放路径,路径的最后一部分就是项目文件 ...

  3. axios 取消请求的方法

    开发中遇到需要取消请求的功能,,点击终止查询可以取消开始查询请求,再次点击开始查询又可以进行查询. 解决方法:axios官方文档上的CancelToken,一开始用了这个api后,可以成功取消请求,但 ...

  4. Resources for Learning about .NET Internals

    http://adamsitnik.com/Disassembly-Diagnoser/ http://mattwarren.org/2018/01/22/Resources-for-Learning ...

  5. 字节码 反编译 APKTool 重新打jar包 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  6. crontab不能执行sudo:抱歉,您必须拥有一个终端来执行 sudo

    最近做一个可执行shell调度的需求,要求用户输入shell,然后后台定时调度运行.实现大致为:保存用户的输入,设定时间,crontab定时执行用户的输入.但这里涉及到一个安全问题,如何确定用户的输入 ...

  7. MySQL 各级别事务的实现机制

    MySQL 各级别事务的实现机制在处理cnctp项目已合包裹状态同步的问题时,发现读包裹状态和对包裹状态的更新不在一个事务内,我提出是否会因为消息并发导致状态一致性问题.在和同事讨论的过程中,我们开始 ...

  8. iOS 在tableview的侧滑事件里执行tableView.selectRow无效的解决办法

    很奇怪的问题,在执行默认选中一个cell的时候,突然发现这句话不起作用了 (我的场景是:当前cell侧滑删除后,默认选中上一个cell) 搞了半天,终于发现罪魁祸首竟然是因为:这句话写在了侧滑事件的方 ...

  9. 启用phpstorm代码提示功能

    参考:http://www.dawnfly.cn/article-1-331.html mac下实际上将省电禁用即可

  10. PC端和移动端在前端开发上的一些区别,前端里移动端到底比pc端多哪些知识

    (1)———————— 前端里移动端到底比pc端多哪些知识,为啥面试时好多公司都问h5水平如何?我做过几年的web前端开发,就简单谈谈自己的感受吧.首先来看看PC端和移动端在前端开发上的一些区别: ( ...