Блог веб-программиста

2Окт/120

Настройка nginx для A/B тестирования с помощью lua

Возникла жесткая необходимость настройки сплит-тестирования (A/B тестирование) сайта.
Поскольку в моем случае разные версии сайта были даже на разных движках, то самым логичным было менять document root в зависимости от куки пользователя.
Но вот незадача - эту куку надо ещё как то установить. Делать для этого отдельный бекенд, как советует mixlr мне не хотелось.
Как установить рандомную куку средствами самого nginx, я так и не понял.
Решено было использовать сборку nginx - OpenResty, поскольку в ней уже встроен модуль HttpLuaModule.
Да, я знаю, что это извращение, но писать модуль для nginx на C не было никакого желания.

В результате получился вот такой вот скрипт на lua, который нужно вставить в нужное место в своём конфиге:

set $target '';
 
access_by_lua '
	local abtest = 0
	local abtestMax = 1
	local userAgent = ngx.req.get_headers()["User-Agent"]
 
	local cookie = ngx.var.cookie_abtest
	if ngx.re.match(userAgent, "(yandex|google|MSIE|bot)", "i") then
	    cookie = 0
	end
 
	if cookie == nil then
		math.randomseed( os.time() )
		abtest = math.random(0, abtestMax)
    		ngx.header["Set-Cookie"] = {"abtest=" .. abtest .. "; path=/", "abReason=nil"}
 
	else
 
		if tonumber(cookie) >= 0 and tonumber(cookie) <= abtestMax then
 
			abtest = cookie
 
		else
			abtest = 0
 
			ngx.header["Set-Cookie"] = {"abtest=" .. abtest .. "; path=/", "abReason=badRange"}
		end
 
	end
 
	ngx.var.target = abtest
';
 
root /var/www/meta$target;

Логика проста - скрипт смотрит, есть ли кука.
- если user-agent содержит yandex, google, MSIE или bot -- кука с тестом 0 -- это для того, чтобы поисковики и IE видели старую версию сайта(№0). Поисковики тем самым не обвинят нас в клоакинге.
- если кука nil, т.е. её нет - выбираем случайную куку от 0 до abtestMax и передаём её в браузер. Таким образом вероятность выпадения при abtestMax=1 - 50%/50%
- если кука не в нашем диапозое [0;abtestMax] - кука будет 0(версия сайта №0)
- если в диапозоне, то всё ок

Далее устанавливается переменная $target равная номеру теста и ниже уже ставится documentRoot в зависимости от неё.

Решение, конечно, не самое быстрое. Но для тестирования на небольшом проекте подходит как нельзя лучше.

Связано с категорией: linux, SEO Нет комментариев