Настройка 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 в зависимости от неё.
Решение, конечно, не самое быстрое. Но для тестирования на небольшом проекте подходит как нельзя лучше.