如何使用 Nginx 分析和 A/B 测试定位用户

介绍

Nginx 是一个强大的代理和 Web 服务器,由一些最大的网站用于处理客户端连接和服务内容. 虽然大多数用户都熟悉 Nginx 的基本功能,但还有其他功能可能在典型使用中不易见。

在本指南中,我们将探索一系列功能,可以帮助测试新内容并收集有关您的用户的统计数据,这些功能可用于内容开发目的,进行简单的A/B测试,并了解访问您的网站的不同用户群体的行为。

简单的A/B测试与分割客户端模块

我们将首先向您展示如何通过 Nginx 自行配置一些基本的 A/B 测试。我们可以使用一个名为http_split_clients的标准 HTTP 模块来完成此操作。

该模块提供了一个单一的指令,毫不奇怪地称为split_clients,该指令根据配置的要求将连接请求分为两个或多个类别。

指令的基本语法看起来像这样:

 1http {
 2
 3    . . .
 4
 5    split_clients "variable_to_evaluate" $new_variable {
 6        percent_group%        value_to_store;
 7        percent_group%        value_to_store;
 8    }
 9
10}

该指令通过对传入的第一个变量的值进行交互并对结果进行哈希工作. 相同的值将始终产生相同的哈希,允许产生一致的结果. 被检查的变量在评估时必须产生一个字符串。

split_clients区块内的行代表了各种或替代品,它们是由它们应该消耗可用的哈希空间的百分比来定义的。

这在考虑一个例子时更容易理解。看看下面的块:

1split_clients "${remote_addr}" $designtest {
2    10%         ".first";
3    10%         ".second";
4    *           "";
5}

在上面的示例中,我们正在评估连接的值为$remote_addr,该值由 Nginx 设置为客户端的 IP 地址。 客户端的 IP 地址的值是使用 murmurhash2 哈希算法进行哈希。 在此时, Nginx 会检查计算的哈希在哪个范围内。

由于第一个定义的组指定了总哈希的10%,这将匹配从0到429496729,这是可用的范围的第一个十分之一。

IP 地址大约有 429496730 到 858993459 的哈希,该哈希范围由下一个 10% 的可用哈希表示,将匹配第二行。

对于所有其他 IP 地址哈希(大约从 858993460 到 4294967295),将设置$designtest变量为空字符串。

如何在服务器上执行此操作

这基本上允许我们随机地将特定百分比的连接到不同的变量值。

例如,我们可以添加一个服务器和位置块,根据$designtest变量的值提供不同的内容。

 1http {
 2
 3    . . .
 4
 5    split_clients "${remote_addr}" $designtest {
 6        10%     ".first";
 7        10%     ".second";
 8        *       "";
 9    }
10
11    server {
12        listen 80;
13        server_name localhost;
14        root /usr/share/nginx/html;
15
16        index index${designtest}.html;
17
18        location / {
19            try_files $uri $uri/ =404;
20        }
21    }
22}

对于属于第一组的哈希的 IP 地址,Nginx 会尝试服务一个名为 index.first.html 的文件,同样,对于属于第二组的 IP 地址,Nginx 会搜索一个名为 index.second.html 的文件。

现在,如果我们在我们的文档根中创建三个索引文件,这些将根据其 IP 地址的结果哈希服务给不同的用户:

1echo "<h1>First Site</h1>" | sudo tee /usr/share/nginx/html/index.first.html
2echo "<h1>Second Site</h1>" | sudo tee /usr/share/nginx/html/index.second.html
3echo "<h1>Default Site</h1>" | sudo tee /usr/share/nginx/html/index.html

如果您对您的 Nginx 配置做出上述更改并重新启动 Web 服务器,您可以测试此操作,我们可以检查我们的 config 文件是否没有语法错误,然后通过键入重新启动服务:

1sudo nginx -t
2sudo service nginx restart

如果我们在我们的浏览器中访问该网站,我们将看到上述三种文件之一。很可能,它将是最后一个,因为它将为网站的80%的访问者提供服务。

例如, GeoPeeker网站可以用来从世界各地的不同位置查看您的网站. 如果您键入您的域名,您可能会看到至少显示您的替代网站之一:

Alternative site indexes

另一个类似的网站是 LocaBrowser,它允许您从不同的国家中选择。 请记住,所服务的页面的分割不是基于地理位置,而是基于IP地址的哈希,所以这并不意味着来自一个国家的所有访问者将被服务于相同的文件。

虽然上面的例子很简单,但这个概念可以扩展很多. 您可以使用split_clients指令设置的变量来设置cookie和用户ID,将标题传递给后端代理,等等. 如果您想更全面地进行A/B测试,您可能希望使用您设置的变量来确定向不同方提供的文档根。

同样重要的是要记住,${remote_addr}检查只是一个有用的例子。你可以基于在字符串中工作的任何 Nginx 变量的值进行哈希。你可以找到包含在核心模块中的一些列表(http://nginx.org/en/docs/http/ngx_http_core_module.html#variables),尽管其他变量通过其他模块可用。 查看更多信息的文档。

如何使用 empty_gif 指令设置跟踪像素

管理员试图通过跟踪像素来计算访问他们的网站的用户的一种方式,跟踪像素是管理员通过简单的日志收集有关哪些IP地址在何时访问哪些页面的数据的良性方法。

传统的跟踪像素是通过在页面上嵌入一个微小的透明图像的方式。当用户访问网站时,该图像被请求作为页面加载过程的一部分。管理员可以将这些请求放入一个单独的日志,以及请求来源的IP地址,客户端在提出请求时加载的页面等。

「empty_gif」模块在 Nginx 中提供此功能.虽然任何请求都可以用于跟踪,但「empty_gif」指令允许您服务存储在内存中的微小的透明.gif 文件,避免磁盘访问。

通常情况下,该指令与单独的日志指令一起使用,以便分离后续分析的请求,例如,您的配置可能有一个看起来像这样的部分:

 1. . .
 2
 3http {
 4
 5    log_format tracking '[$time_local] : $remote_addr : $remote_user : '
 6                        '$args : $http_referer : $http_user_agent';
 7
 8    server {
 9
10        . . .
11
12        location = /logme.gif {
13            empty_gif;
14            access_log /var/log/nginx/tracking.log tracking;
15            expires epoch;
16        }
17    }
18}

在这里,我们在http背景下设置了一个log_format来记录我们想要跟踪的信息。

之后,我们可以设置一个位置块来匹配特定的 .gif 请求. 我们正在使用 = 修改器,以便任何对 .gif 的请求都能快速有效地匹配,而无需在其他地方寻找更好的匹配。

内部,我们使用empty_gif指令来从内存中服务透明的1x1像素.gif。我们告诉这个位置的请求使用我们之前指定的格式登录到一个单独的文件。

现在,我们可以向我们的页面添加一个图像,请求我们选择的图像,例如,一个非常简单的页面可以看起来像这样:

1<html>
2    <head>
3        <title>Your Site</title>
4    </head>
5    <body>
6        <h1>Normal Content</h1>
7        <img src="/logme.gif">
8    </body>
9</html>

当访问者点击此页面时,将被请求的/logme.gif图像,导致 Nginx 写到我们的tracking.log文件中有关请求的详细信息,这可以通过调整您的log_format并通过使用文本处理工具分析您的日志来构建一个更复杂的系统。

基于地理区分的内容

之前,我们向您展示了如何将 Nginx 配置为自动将用户分为组,以便使用split_clients模块进行 A/B 测试。

IP 地址通过某些提供商编制的一组表来对接到接近的位置,他们主要从负责分配不同地理区域的 IP 空间的众多注册表中获取此信息。

购买位置数据库

Nginx可以使用这些数据来分离客户端,使用包含在ngx_http_geoip_module模块中的各种指令。

在Ubuntu上,您可以通过键入来获取国家级地图:

1sudo apt-get update
2sudo apt-get install geoip-database

获得国家级地图的更通用方法是通过下载文件使用wget。我们可以创建一个目录来存储数据库,然后通过键入下载文件:

1sudo mkdir -p /usr/local/share/GeoIP
2cd /usr/local/share/GeoIP
3sudo wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz

我们需要通过键入删除文件:

1sudo gunzip GeoIP.dat.gz

对于更具体的城市级数据库,您也可以使用wget下载:

1sudo mkdir -p /usr/local/share/GeoIP
2cd /usr/local/share/GeoIP
3sudo wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz

再一次,我们将需要解析文件:

1sudo gunzip GeoLiteCity.dat.gz

配置 Nginx 以使用位置数据

一旦我们有位置数据库,我们可以配置 Nginx 来利用数据。

我们可以通过设置下列指令告诉 Nginx 在磁盘上的每个数据库的位置,这些指令必须在 Nginx 配置文件中的http背景中设置:

 1. . .
 2
 3http {
 4    # If you downloaded the country-level data using `apt-get` uncomment and use:
 5    #geoip_country /usr/share/GeoIP/GeoIP.dat;
 6    # If you downloaded the country-level data using `wget`, use:
 7    geoip_country /usr/local/share/GeoIP/GeoIP.dat;
 8    geoip_city /usr/local/share/GeoIP/GeoLiteCity.dat;
 9
10    . . .
11}

一旦位置已设置,您可以利用 Nginx 用于每个数据库的变量。

*$geoip_country_code:用来表示一个国家的两个字母的国家代码. 例如,US是指美国,或RU是指俄罗斯. 这些可以找到(这里)(http://dev.maxmind.com/geoip/legacy/codes/iso3166/)。

  • **$geoip_country_code3:几乎与上面的相同,但使用三个字母的变体。 例如,USARUS
  • $geoip_country_name: 名称与链接列表中的国家代码相同。 例如新西兰NZ

城市级数据库为我们提供了更大的变量数量. 使用该数据库,我们可以访问:

  • $geoip_area_code_: 美国电话号码的遗留区域代码域。 准确的数据不应以此为依据。
  • $geoip_city_Continent_code_: 双字母大陆代码.
  • $geoip_city_country_code: 国家一级数据库提供的同样的双字母国家代码。
  • $geoip_city_country_code3_: 由国家一级数据库提供的同一三字母国家代码。
  • $geoip_city_country_name: 与国家一级数据库提供的国家名称相同。
  • $geoip_dma_code_: 美国地点的DMA区域或地铁代码. 这可以在Google的AdWords API中找到,发现这里.
    • $geoip_纬度 : 原生IP的纬度估计.
  • ================================================================================================================================ 原生IP经度的估计.
  • $geoip_ region: 一种双特征区域代码,用于代表一政治区域,如一地,一州,一省等.
  • $geoip_ region_name_: 与上述区域代码相关的全名. *$geoip_city:与原生IP相接的城市名称.
  • $geoip_postal_code_: IP所在地区的邮政编码. (英语)

再次,重要的是要强调,通过这些变量可用的数据是最好的猜测基础上。

通常我们会使用上述变量之一与地图指令,以条件设置另一个变量的值,这使我们能够创建一个变量,其值由数据库告诉我们关于客户端的位置。

例如,我们可以配置我们的网站以显示不同的内容,如果访问者来自澳大利亚或新加坡。

对于这个例子,我们将使用$geoip_country_code。该变量的值将决定我们在我们创建的$site_version变量中存储的内容。

 1http {
 2    # If you downloaded the country-level data using `apt-get` uncomment and use:
 3    #geoip_country /usr/share/GeoIP/GeoIP.dat;
 4    # If you downloaded the country-level data using `wget`, use:
 5    geoip_country /usr/local/share/GeoIP/GeoIP.dat;
 6    geoip_city    /usr/local/share/GeoIP/GeoLiteCity.dat;
 7
 8    map $geoip_country_code $site_version {
 9        default     "";
10        AU          "/australia";
11        SG          "/singapore";
12    }
13
14    . . .
15}

如果访问者的国家代码表示他们来自澳大利亚(AU),我们将$site_version设置为/australia。如果访问者来自新加坡(SG),我们将$site_version设置为/singapore。如果他们的国家代码表示其他值,我们将$site_version设置为空串。

这使我们能够对来自特定国家的访问者修改文档根,这是一个任意的选择,以证明您可以根据客户端的地理位置数据来区分内容。

要修改文档根,我们只需要在服务器块中设置指令,以便它是这样的:

 1http {
 2    # If you downloaded the country-level data using `apt-get` uncomment and use:
 3    #geoip_country /usr/share/GeoIP/GeoIP.dat;
 4    # If you downloaded the country-level data using `wget`, use:
 5    geoip_country /usr/local/share/GeoIP/GeoIP.dat;
 6    geoip_city    /usr/local/share/GeoIP/GeoLiteCity.dat;
 7
 8    map $geoip_country_code $site_version {
 9        default     "";
10        AU          "/australia";
11        SG          "/singapore";
12    }
13
14    . . .
15
16    server {
17        . . .
18
19        root /usr/share/nginx/html${site_version};
20
21        . . .
22
23    }
24}

如果用户来自澳大利亚,则服务请求的文件根将更改为/usr/share/nginx/html/australia。同样,对于来自新加坡的访客,内容将从/usr/share/nginx/html/singapore提供。

我们可以设置默认的 /usr/share/nginx/html 文档根来轻松地测试这一点。

1cd /usr/share/nginx/html

接下来,我们可以创建我们提到的目录,并将一些非常基本的内容插入到每个新目录中的index.html文件中,这将使我们能够看到我们的位置是否会影响我们提供的内容:

1sudo mkdir australia && echo "<h1>australia</h1>" | sudo tee australia/index.html
2sudo mkdir singapore && echo "<h1>singapore</h1>" | sudo tee singapore/index.html

一旦所有这些都已设置,我们可以测试我们的配置并重新加载 Nginx:

1sudo nginx -t
2sudo service nginx restart

现在,我们可以再次利用 GeoPeeker网站,看看我们是否从不同的地点提供不同的内容。

在这里,您可以看到来自美国或爱尔兰的访客的默认页面,以及我们为来自澳大利亚或新加坡的访客添加的测试文本:

Geolocation differences

这验证了 Nginx 通过检查客户端的 IP 地址对位置数据库进行正确的选择。

结论

通过利用这些策略和功能,您可以开始收集分析数据,以帮助您对网站内容做出更明智的决定. 虽然有许多外部工具可用于捕捉此类数据,但在投资其他解决方案之前,使用 Nginx 原生工具的选项可能是很好的选择。

Published At
Categories with 技术
Tagged with
comments powered by Disqus