首页 > 系统相关 >Nginx流量复制/AB测试/协程

Nginx流量复制/AB测试/协程

时间:2023-06-11 18:31:46浏览次数:54  
标签:AB 协程 lua local args Nginx cookie location ngx


在实际开发中经常涉及到项目的升级,而该升级不能简单的上线就完事了,需要验证该升级是否兼容老的上线,因此可能需要并行运行两个项目一段时间进行数据比对和校验,待没问题后再进行上线。这其实就需要进行流量复制,把流量复制到其他服务器上,一种方式是使用如tcpcopy引流;另外我们还可以使用nginx的HttpLuaModule模块中的ngx.location.capture_multi进行并发执行来模拟复制。

 

构造两个服务


1. location /test1 {  
2.     keepalive_timeout 60s;   
3. 1000;  
4.     content_by_lua '  
5. "test1 : ", ngx.req.get_uri_args()["a"])  
6. "request test1")  
7.     ';  
8. }  
9. location /test2 {  
10.     keepalive_timeout 60s;   
11. 1000;  
12.     content_by_lua '  
13. "test2 : ", ngx.req.get_uri_args()["a"])  
14. "request test2")  
15.     ';  
16. }


  

通过ngx.location.capture_multi调用


1. location /test {  
2.      lua_socket_connect_timeout 3s;  
3.      lua_socket_send_timeout 3s;  
4.      lua_socket_read_timeout 3s;  
5. 100;  
6.      lua_socket_keepalive_timeout 60s;  
7.      lua_socket_buffer_size 8k;  
8.   
9.      content_by_lua '  
10.          local res1, res2 = ngx.location.capture_multi{  
11. "/test1", { args = ngx.req.get_uri_args() } },  
12. "/test2", { args = ngx.req.get_uri_args()} },  
13.          }  
14. if
15.              ngx.print(res1.body)  
16.          end  
17. if
18.             --记录错误  
19.          end  
20.      ';  
21. }


此处可以根据需求设置相应的超时时间和长连接连接池等;ngx.location.capture底层通过cosocket实现,而其支持Lua中的协程,通过它可以以同步的方式写非阻塞的代码实现。

 

此处要考虑记录失败的情况,对失败的数据进行重放还是放弃根据自己业务做处理。

 

AB测试

AB测试即多版本测试,有时候我们开发了新版本需要灰度测试,即让一部分人看到新版,一部分人看到老版,然后通过访问数据决定是否切换到新版。比如可以通过根据区域、用户等信息进行切版本。

 

比如京东商城有一个cookie叫做__jda,该cookie是在用户访问网站时种下的,因此我们可以拿到这个cookie,根据这个cookie进行版本选择。

 

比如两次清空cookie访问发现第二个数字串是变化的,即我们可以根据第二个数字串进行判断。

__jda=122270672.1059377902.1425691107.1425691107.1425699059.1

__jda=122270672.556927616.1425699216.1425699216.1425699216.1。

 

判断规则可以比较多的选择,比如通过尾号;要切30%的流量到新版,可以通过选择尾号为1,3,5的切到新版,其余的还停留在老版。

 

1、使用map选择版本 



1. map $cookie___jda $ab_key {  
2. default                                       "0";  
3. 1|3|5))\.                    "1";  
4. }


使用map映射规则,即如果是到新版则等于"1",到老版等于“0”; 然后我们就可以通过ngx.var.ab_key获取到该数据。




    1. location /abtest1 {  
    2. if ($ab_key = "1") {  
    3.         echo_location /test1 ngx.var.args;  
    4.     }  
    5. if ($ab_key = "0") {  
    6.         echo_location /test2 ngx.var.args;  
    7.     }  
    8. }



    此处也可以使用proxy_pass到不同版本的服务器上 



    1. location /abtest2 {  
    2. if ($ab_key = "1") {  
    3. break;  
    4. //backend1;
    5.     }  
    6. break;  
    7. //backend2;
    8. }



     

    2、直接在Lua中使用lua-resty-cookie获取该Cookie进行解析

    首先下载lua-resty-cookie



    1. cd /usr/example/lualib/resty/  
    2. wget https://raw.githubusercontent.com/cloudflare/lua-resty-cookie/master/lib/resty/cookie.lua

     



    1. location /abtest3 {  
    2.     content_by_lua '  
    3.   
    4. "resty.cookie")  
    5. new()  
    6. "0"
    7. "__jda")  
    8. if
    9. 1|3|5)\.]])  
    10. if
    11. "1"
    12.              end  
    13.          end  
    14.   
    15. if ab_key == "1"
    16. "/test1", ngx.var.args)  
    17. else
    18. "/test2", {args = ngx.req.get_uri_args()}).body)  
    19.          end  
    20.     ';  
    21.   
    22. }

     首先使用lua-resty-cookie获 取cookie,然后使用ngx.re.match进行规则的匹配,最后使用ngx.exec或者ngx.location.capture进行处理。此 处同时使用ngx.exec和ngx.location.capture目的是为了演示,此外没有对ngx.location.capture进行异常处 理。

     

    协程

    Lua中没有线程和异步编程编程的概念,对于并发执行提供了协程的概念,个人认为协程是在A运行中发现自己忙则把CPU使用权让出来给B使用,最后A能从中断位置继续执行,本地还是单线程,CPU独占的;因此如果写网络程序需要配合非阻塞I/O来实现。

     

    ngx_lua 模块对协程做了封装,我们可以直接调用ngx.thread API使用,虽然称其为“轻量级线程”,但其本质还是Lua协程。该API必须配合该ngx_lua模块提供的非阻塞I/O API一起使用,比如我们之前使用的ngx.location.capture_multi和lua-resty-redis、lua-resty- mysql等基于cosocket实现的都是支持的。

     

    通过Lua协程我们可以并发的调用多个接口,然后谁先执行成功谁先返回,类似于BigPipe模型。

     

    1、依赖的API 



    1. location /api1 {  
    2. 3;  
    3.     echo api1 : $arg_a;  
    4. }  
    5. location /api2 {  
    6. 3;  
    7.     echo api2 : $arg_a;  
    8. }


     我们使用echo_sleep等待3秒。

     

    2、串行实现



    1. location /serial {  
    2.     content_by_lua '  
    3.         local t1 = ngx.now()  
    4. "/api1", {args = ngx.req.get_uri_args()})  
    5. "/api2", {args = ngx.req.get_uri_args()})  
    6.         local t2 = ngx.now()  
    7. "<br/>", res2.body, "<br/>", tostring(t2-t1))  
    8.     ';  
    9. }


    即一个个的调用,总的执行时间在6秒以上,比如访问http://192.168.1.2/serial?a=22



    1. api1 : 22
    2. api2 : 22
    3. 6.0040001869202


     

    3、ngx.location.capture_multi实现


    1. location /concurrency1 {  
    2.     content_by_lua '  
    3.         local t1 = ngx.now()  
    4.         local res1,res2 = ngx.location.capture_multi({  
    5. "/api1", {args = ngx.req.get_uri_args()}},  
    6. "/api2", {args = ngx.req.get_uri_args()}}  
    7.   
    8.         })  
    9.         local t2 = ngx.now()  
    10. "<br/>", res2.body, "<br/>", tostring(t2-t1))  
    11.     ';  
    12. }



    直接使用ngx.location.capture_multi来实现,比如访问http://192.168.1.2/concurrency1?a=22



    1. api1 : 22
    2. api2 : 22
    3. 3.0020000934601



        

    4、协程API实现 



    1. location /concurrency2 {  
    2.     content_by_lua '  
    3.         local t1 = ngx.now()  
    4.         local function capture(uri, args)  
    5. return
    6.         end  
    7. "/api1", {args = ngx.req.get_uri_args()})  
    8. "/api2", {args = ngx.req.get_uri_args()})  
    9.         local ok1, res1 = ngx.thread.wait(thread1)  
    10.         local ok2, res2 = ngx.thread.wait(thread2)  
    11.         local t2 = ngx.now()  
    12. "<br/>", res2.body, "<br/>", tostring(t2-t1))  
    13.     ';  
    14. }



    使用ngx.thread.spawn创建一个轻量级线程,然后使用ngx.thread.wait等待该线程的执行成功。比如访问http://192.168.1.2/concurrency2?a=22



    1. api1 : 22
    2. api2 : 22
    3. 3.0030000209808



       

    其有点类似于Java中的线程池执行模型,但不同于线程池,其每次只执行一个函数,遇到IO等待则让出CPU让下一个执行。我们可以通过下面的方式实现任意一个成功即返回,之前的是等待所有执行成功才返回。



    1. local  ok, res = ngx.thread.wait(thread1, thread2)

    标签:AB,协程,lua,local,args,Nginx,cookie,location,ngx
    From: https://blog.51cto.com/u_6186189/6458539

    相关文章

    • mac下gitLab、sourceTree的配合使用
           1、认识一下gitLab这个版本管理工具。说到版本管理工具,大家会想到svn,git和svn还是有差别的。svn是集中化的版本控制系统,只有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。git是分布式......
    • zabbix监控mysql的QPS和TPS的python写法
      #!/usr/bin/envpython#coding=utf-8importsysimportosimportcommandsclassQpsTps(object):def__init__(self):self.QPS=''self.TPS=''defgetQps(self):(Queries,QPS_result)=commands.getsta......
    • zabbix监控多JMX端口
      1.开启Tomcat JMX功能CATALINA_OPTS="$CATALINA_OPTS-Dcom.sun.management.jmxremote-Djava.rmi.server.hostname=10.124.129.241-Dcom.sun.management.jmxremote.port=8889-Dcom.sun.management.jmxremote.ssl=false-Dcom.sun.management.jmxremote.authenticate=false&quo......
    • database/sql库
      database/sql是Go语言中一个标准库,用于处理关系型数据库的操作。它是一个轻量级的SQL数据库抽象,提供了一些基本的接口,包括连接、查询、事务等。database/sql使用SQL驱动程序的方式连接不同的数据库,让我们可以使用统一的API,而不用考虑底层数据库驱动的差异性。连接数据库......
    • nginx-gridfs Benchmarking Raw Results
      RawDataSpreadsheetwithtestresults(ODFformat)Thesefollowinglinksshowtherawoutputfromthebenchmarkingutilities.GridFSOverNetworkThistestscenarioshowsperformanceforHTTPrequestsoveragigabitEthernetLANconnection.MongoDBand......
    • lab1
      Part1:PCBootstrapexercise1https://pdos.csail.mit.edu/6.828/2018/reference.htmlhttp://www.delorie.com/djgpp/doc/brennan/brennan_att_inline_djgpp.htmlexercise2步进调试Part2:TheBootLoaderexercise3调试boot.S和main.chttps://zhuanlan.zhihu......
    • Fabric不能启动后台进程问题
      在用Fabric启动远程后台进程时,由于自己的后台程序使用类似下面的方式后台运行,导致后台进程不能启动成功 javaMyServer&看了一下官方文档,说是有几种方式可以解决这个问题,下面是我使用的方法首先修改自己的启动后台进程的脚本 nohupjavaMyServer&>/dev/null&然后......
    • 2023年6月11日,TreeSet,Comparable,HashMap
      1.Set1.TreeSetTreeSet1、存储Integer的元素,升序排列2、存储String的元素,字典排列TreeSet根据元素的不同类型使用不同的排序规则publicclasstest01{/***知识点:TreeSet*1、存储Integer的元素,升序排列*2、存储String的元素,字典排列*......
    • 每日一个 ChatGPT 使用小技巧系列之2 - 用 ChatGPT 研读 SAP ABAP BAPI 的实现源代码
      本系列之前的文章:与其整天担心AI会取代程序员,不如先让AI帮助自己变得更强大每日一个ChatGPT使用小技巧系列之1-给出提纲或者素材,让ChatGPT帮你写作正好昨天有朋友向我发起知乎咨询,询问关于SAPABAPBAPIbapi_vendor_create的使用问题,本文就来说一说:bapi_v......
    • iPhone两秒出图,目前已知的最快移动端Stable Diffusion模型来了
      前言 近日,Snap研究院推出最新高性能StableDiffusion模型,通过对网络结构、训练流程、损失函数全方位进行优化,在iPhone14Pro上实现2秒出图(512x512),且比SD-v1.5取得更好的CLIPscore。这是目前已知最快的端上StableDiffusion模型!本文转载自机器之心仅用于学术分享......