`
jinnianshilongnian
  • 浏览: 21513606 次
  • 性别: Icon_minigender_1
博客专栏
5c8dac6a-21dc-3466-8abb-057664ab39c7
跟我学spring3
浏览量:2420447
D659df3e-4ad7-3b12-8b9a-1e94abd75ac3
Spring杂谈
浏览量:3010220
43989fe4-8b6b-3109-aaec-379d27dd4090
跟开涛学SpringMVC...
浏览量:5640568
1df97887-a9e1-3328-b6da-091f51f886a1
Servlet3.1规范翻...
浏览量:260217
4f347843-a078-36c1-977f-797c7fc123fc
springmvc杂谈
浏览量:1597925
22722232-95c1-34f2-b8e1-d059493d3d98
hibernate杂谈
浏览量:250368
45b32b6f-7468-3077-be40-00a5853c9a48
跟我学Shiro
浏览量:5860558
Group-logo
跟我学Nginx+Lua开...
浏览量:702867
5041f67a-12b2-30ba-814d-b55f466529d5
亿级流量网站架构核心技术
浏览量:785734
社区版块
存档分类
最新评论

第八章 流量复制/AB测试/协程

阅读更多

流量复制

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

 

构造两个服务

    location /test1 {
        keepalive_timeout 60s; 
        keepalive_requests 1000;
        content_by_lua '
            ngx.print("test1 : ", ngx.req.get_uri_args()["a"])
            ngx.log(ngx.ERR, "request test1")
        ';
    }
    location /test2 {
        keepalive_timeout 60s; 
        keepalive_requests 1000;
        content_by_lua '
            ngx.print("test2 : ", ngx.req.get_uri_args()["a"])
            ngx.log(ngx.ERR, "request test2")
        ';
    }

  

通过ngx.location.capture_multi调用

    location /test {
         lua_socket_connect_timeout 3s;
         lua_socket_send_timeout 3s;
         lua_socket_read_timeout 3s;
         lua_socket_pool_size 100;
         lua_socket_keepalive_timeout 60s;
         lua_socket_buffer_size 8k;

         content_by_lua '
             local res1, res2 = ngx.location.capture_multi{
                   { "/test1", { args = ngx.req.get_uri_args() } },
                   { "/test2", { args = ngx.req.get_uri_args()} },
             }
             if res1.status == ngx.HTTP_OK then
                 ngx.print(res1.body)
             end
             if res2.status ~= ngx.HTTP_OK then
                --记录错误
             end
         ';
    }

此处可以根据需求设置相应的超时时间和长连接连接池等;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选择版本 

map $cookie___jda $ab_key {
    default                                       "0";
    ~^\d+\.\d+(?P<k>(1|3|5))\.                    "1";
}

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

    location /abtest1 {
        if ($ab_key = "1") {
            echo_location /test1 ngx.var.args;
        }
        if ($ab_key = "0") {
            echo_location /test2 ngx.var.args;
        }
    }

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

    location /abtest2 {
        if ($ab_key = "1") {
            rewrite ^ /test1 break;
            proxy_pass http://backend1;
        }
        rewrite ^ /test2 break;
        proxy_pass http://backend2;
    }

 

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

首先下载lua-resty-cookie

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

 

    location /abtest3 {
        content_by_lua '

             local ck = require("resty.cookie")
             local cookie = ck:new()
             local ab_key = "0"
             local jda = cookie:get("__jda")
             if jda then
                 local v = ngx.re.match(jda, [[^\d+\.\d+(1|3|5)\.]])
                 if v then
                    ab_key = "1"
                 end
             end

             if ab_key == "1" then
                 ngx.exec("/test1", ngx.var.args)
             else
                 ngx.print(ngx.location.capture("/test2", {args = ngx.req.get_uri_args()}).body)
             end
        ';

    }

 首先使用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 

    location /api1 {
        echo_sleep 3;
        echo api1 : $arg_a;
    }
    location /api2 {
        echo_sleep 3;
        echo api2 : $arg_a;
    }

 我们使用echo_sleep等待3秒。

 

2、串行实现

    location /serial {
        content_by_lua '
            local t1 = ngx.now()
            local res1 = ngx.location.capture("/api1", {args = ngx.req.get_uri_args()})
            local res2 = ngx.location.capture("/api2", {args = ngx.req.get_uri_args()})
            local t2 = ngx.now()
            ngx.print(res1.body, "<br/>", res2.body, "<br/>", tostring(t2-t1))
        ';
    }

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

api1 : 22 
api2 : 22 
6.0040001869202

 

3、ngx.location.capture_multi实现

    location /concurrency1 {
        content_by_lua '
            local t1 = ngx.now()
            local res1,res2 = ngx.location.capture_multi({
                  {"/api1", {args = ngx.req.get_uri_args()}},
                  {"/api2", {args = ngx.req.get_uri_args()}}

            })
            local t2 = ngx.now()
            ngx.print(res1.body, "<br/>", res2.body, "<br/>", tostring(t2-t1))
        ';
    }

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

api1 : 22 
api2 : 22 
3.0020000934601

    

4、协程API实现 

    location /concurrency2 {
        content_by_lua '
            local t1 = ngx.now()
            local function capture(uri, args)
               return ngx.location.capture(uri, args)
            end
            local thread1 = ngx.thread.spawn(capture, "/api1", {args = ngx.req.get_uri_args()})
            local thread2 = ngx.thread.spawn(capture, "/api2", {args = ngx.req.get_uri_args()})
            local ok1, res1 = ngx.thread.wait(thread1)
            local ok2, res2 = ngx.thread.wait(thread2)
            local t2 = ngx.now()
            ngx.print(res1.body, "<br/>", res2.body, "<br/>", tostring(t2-t1))
        ';
    }

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

api1 : 22 
api2 : 22 
3.0030000209808

   

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

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

 

Lua协程参考资料

《Programming in Lua》

http://timyang.net/lua/lua-coroutine-vs-java-wait-notify/

https://github.com/andycai/luaprimer/blob/master/05.md

http://my.oschina.net/wangxuanyihaha/blog/186401

http://manual.luaer.cn/2.11.html

 

5
0
分享到:
评论
2 楼 Aceslup 2017-10-25  
协程还是不理解哦
1 楼 LinApex 2016-01-03  
这个很赞,根据cookie进行部分上线,灰度上线,原理就是这个。

相关推荐

    在线教育产品AB测试实施案例-云眼.pdf

    在线教育产品AB测试实施案例-云眼.pdf AB测试是在线教育产品营销转化的关键环节之一,本案例介绍了某在线教育机构通过云眼A/B测试工具实施的AB测试优化策略和方法,取得了显著的转化率增长效果。 标题解释:在线...

    云眼AB测试产品介绍.pdf

    在荣誉资质方面,云眼是清华大数据产业联合会会员、信息产业部用户体验协会会员,并在2018年连续获得了多项重要荣誉,包括成为百度商业服务平台的AB测试服务商、阿里云天池众智计划成员,以及获得“中国企业产品服务...

    learn-ab-and-multivariate-testing, 关于 A/B 和多元测试的教程.zip

    learn-ab-and-multivariate-testing, 关于 A/B 和多元测试的教程 A/B &多变量测试教程 这是对和多元测试概念的简短介绍,以及如何启动。 关于如何在 Google内容实验实验中实现这些功能的实际教程,请看我们的概述: ...

    ab, 为 A/B 测试,特性斜坡和更多的Etsy框架.zip

    ab, 为 A/B 测试,特性斜坡和更多的Etsy框架 AB已经存档AB不再受支持,已经被存档。 请看一下特性 API,代替。 你还可以查看 https://github.com/etsy/ab/tree/pre_archive 站点上的原始源代码。

    压力测试工具ab

    **压力测试工具ab详解** 压力测试是评估系统在高负载或大量并发请求下性能的重要手段。在IT行业中,尤其在服务器优化和应用性能管理中,压力测试工具扮演着至关重要的角色。"ab"(ApacheBench)就是这样一个简单而...

    Lind是一个可以在您的网站上创建任何类型AB测试的开源项目

    3. **分配流量**:设置用户流量如何在不同变体间分配,可以随机或者基于特定规则。 4. **运行测试**:发布更改并启动测试,让用户自然地参与到各个变体中。 5. **收集与分析数据**:Lind会自动收集数据,通过内置的...

    SMI 慧荣3265AC/AB 量产工具

    【标题】"SMI 慧荣3265AC/AB 量产工具"是指由SMI(Silicon Motion)公司推出的专门针对慧荣3265AC和3265AB主控芯片的U盘生产与修复软件。这类工具主要用于U盘的批量生产和故障修复,确保U盘的性能和稳定性,同时也可...

    AB测试和灰度发布平台架构设计和实践.pdf

    "AB测试和灰度发布平台架构设计和实践.pdf" 本文档详细介绍了AB测试和灰度发布平台的架构设计和实践。AB测试是一种常用的测试方法,通过比较两种或多种版本的产品或服务,来确定哪一种版本对用户的影响最大。灰度...

    Apache 压力测试工具ab 专注接口测试 并发测试

    Apache的ab(ApacheBench)是一款简单而强大的压力测试工具,专用于接口和并发测试。在Web服务性能优化和系统负载能力评估中,ab扮演着关键角色。它可以帮助开发者和运维人员了解服务器在高并发情况下的表现,以及...

    sixpack一个和语言无关的AB测试框架

    **六Pack:跨越语言的A/B测试框架** 在数字化时代,优化用户体验和提高转化率是企业和网站运营者的重要目标。A/B测试作为一种科学的方法,通过对比不同版本的页面或功能来确定哪个版本更能吸引用户、提升转化。而`...

    Ruby-Split基于Rack的AB测试框架

    Ruby-Split是一个基于Rack的AB测试框架,它允许开发者在Web应用中轻松地实现A/B测试,以优化用户体验和转化率。Rack是Ruby世界中的一个基础中间件层,它使得构建Web应用和服务变得更加简单。Split框架充分利用了Rack...

    tcp/ip测试工具sokit

    发送区的编辑框内的字符会按照ascii值发送(多字节字符按照UTF8编码),如果需要发送十六进制原始数据,请将相应数值的ascii表示放进方括号中,例如, [FF AB CD 12 12], 实际发送时会过滤掉方括号本身,以及其中的空格字符...

    ab测试工具

    **ApacheBench(ab)测试工具详解** ApacheBench,简称ab,是Apache HTTP服务器项目提供的一个命令行工具,用于对Web服务器进行性能测试。它能够模拟多个并发用户请求,以此来评估服务器在高负载下的处理能力和响应...

    18.如何搞定AB测试?.pdf

    8. 判断是否需要进行A/B测试:并非所有功能更新都需要A/B测试,有些功能即使数据不佳也必须上线,这时应关注如何优化用户体验。 9. A/B测试的局限性:虽然A/B测试是验证功能效果的有力工具,但它并不适用于所有情况...

    react-React的简单AB测试组件

    `react-React的简单AB测试组件` 提供了一种方便的方式来实现这一目标,使得在React应用中集成A/B测试变得相对轻松。 首先,我们需要理解A/B测试的基本概念。A/B测试是一种统计方法,通过随机将用户分配到两个或多个...

    pickpick一个用于Web的AB测试引擎

    8. **版本控制**:通过版本控制系统,如Git,可以轻松管理和维护不同版本的测试代码。 9. **安全性**:考虑到隐私问题,Pickpick可能遵循无痕模式,不收集个人可识别信息,仅记录匿名的用户行为数据。 10. **社区...

    A/B测试实施方法指南

    A/B测试(也称为分离测试)是一种意在提高转换率和反响率的测试方法。通常用于市场营销,比较两个样本的结果。在网页设计中,A/B测试通常用来测试设计元素(有时是针对现有的设计),以便获得访客最好的反响。根据A/B...

    ab 压力测试工具

    "ab压力测试工具"是Apache HTTP服务器项目的一部分,它是一个简单但功能强大的命令行工具,用于对Web服务器进行性能测试和负载测试。这个工具能够模拟多个并发用户向服务器发送HTTP请求,帮助管理员评估服务器在高...

Global site tag (gtag.js) - Google Analytics