Уже очень давно я бьюсь над проблемой: а как настроить Redis "чтобы оно работало". Казалось бы - хранить сессии в Redis - что может быть проще ? Это ведь как раз то что доктор прописал. Хер там был. Чем больше я еб#### с этим редисон, тем больше я начинаю ненавидеть все что начинается на NoSQL. Для меня скоро NoSQL будет синонимом - "не работает". Взять к примеру Couchbase/CouchDB. На бумаге все прекрасно. Казалось-бы, вот оно счатье - настало. Все само реплицируется, партиционируется и масштабируется. Хер там был. Оно просто не работает. Если при более-менее высокой нагрузке начнется решардинг - наступает пиз###. Производительность всего кластера настолько деградирует что это равносильно даунтайму. И это не говоря о случайных спадов в производительности - когда у нг внутри какой-то буффер переполняется и время ответа ни с того ни с сего увеличивается в 10 раз. А через минуту все снова охеренно. Но за минуту ты легко можешь отхватить и 10 и 100 тысяч запросов. Какая-то часть из них умрет по таймауту и покажет 50x ошибку пользователю. В погоне за успехом в кратковременных бенчмарках, которые любят размещать в блогах - NoSQL писатели такую херню делают, что диву даешься. Неужели они не понимают что гарантированная производительность(пусть немного медленне) - это гораздо лучше чем 100000 запросов в секунду в пике, с временными спадами до 10 запросов в минуту.
Итак вернемся к нашему редису. На первый взгляд идеальное решение для хранения сессий. Но есть маленькое но.... Он однопоточный.... То есть если вы запустили какую-нибуть тормозную команду - например KEYS, то до тех пор пока команда не выполнится - ни один коннект не будет обработан. Просто такой маленький stop the world. Представьте что у вас 10GB база и кто-то запустил KEYS по ошибке... сколько у вас коннектов отвалится по таймауту ?? Они еще зачем-то прикручивают туда Lua интерпретатор... Если у вас однопоточный сервер с c event-loop, то все что сложнее чем GET/SET вам просто противопоказано! Иначе забыть можно про сколько нибуть предсказуемое время ответа.
Вторая проблема - RDB checkpointing. Документация нам говорит что раз в какое-то время Redis форкает процесс, который его сохраняет на диск. Вроде все охеренно... сохранение происходит в отдельном процессе... никто никому не мешает... Но как то честно говорит документация - на время создания снапшота все блокируется... То есть раз в какое-то время ваш Redis будет подвисать... Причем чем больше ваша база - тем больше подвисание. Вот подвисли мы на 30 секунд - а кто запросы то обрабатывать будет ?? Хуй в пальто ? Что тут еще скажешь ... Прелестно блять, просто прелестно. Писали писали приложение, только оно начало работать... база выросла - и на тебе жопу. И что хочешь тут то и делай. Broken by design.
В общем вы поняли что Redis идеален если у вас маленькая база и нет нагрузки. Во всех остальных конфигурациях - ебитесь как хотите. Но спрашивается - если у вас 10 сессий в час, и 3 хромых пользователя онлайн - нахера вам Redis ??? Храните сессии в файлах и не выпендривайтесь.
Итак, слюни в сторону - что дальше то делать? Если Redis то работает, то не работает - нужно поставить рядом два редиса и переключатся между ними... Выглядит все просто... но чтобы поддерживать оба редиса синхронизированными - нужно настроить репликацию между ними... Если вдруг один Redis задумался - нужно переключится... И при этом не забыть развернуть репликацию... мы же не можем в slave писать... Причем переключить нужно оба сервера... а если первый сервер в серьез "задумался" ?? Он и на пинги -то не отвечает, а ты хочешь чтобы он на более сложные команды ответил... В общем мы рискуем получить рассинхронизацию - когда оба сервера будет считать себя master, а ты потом разбирайся - что и куда у тебя записалось... В общем классический split brain. Легкая на первый взгляд задача оказалась тем еще гемороем. Для того чтобы решить эту проблему Redis предлагает Sentinel. Охеренно, подумал читатель. Но не тут-то было:
Sentinel is currently developed in the unstable branch of the Redis source code at Github.
Документация честно говорит - что Redis Sentinel - он ... ну как сказать... не так уж прям чтобы очень стабильный был. Но то и понятно, задача которую он решает - не из простых. Поставили мы два редиса, два Sentinel... но тут мы понимаем что для того чтобы избежать split brain нам нужно минимум 3 инстанса .... окей, это тоже решаемо... подогнали еще сервак, воткнули туда редис с сентинелем и ждем. Чего ждем непонятно. Ну переключит Sentinel мастера на другую ноду, но нашему приложению-то кто об этом скажет ? Либо нужно писать "умных клиент", который сам будет из 3-х предложенных инстансев выбирать мастера.... либо ставить load balancer.... с недавних пор (версии 1.5.x dev) HA proxy умеет выбирать мастера из N-бэкендов. Вообще пользуюсь случаем хочу сказать - HA proxy охеренен. Просто ты работаешь и чувствуешь как там все продумано, все до мелочей. Начиная от конфигурации и заканчивая логгированием. Сразу видно что HA proxy писался для решения реальных задач в production системах, а не как очередная гиковская игрушка. Dev версии HA proxy более стабильны чем большинство релизных версий современного софта. Сразу видно чо писал его человек старой закалки с огромным опытом. Кстати для тех кто не знает - на сайте HA proxy есть коллекция довольно занимательных статей. В общем при правильной настройке HA proxy - то единственный компонент получившейся системы, за который я могу быть спокоен.
Итак, вернемся к нашим котятам. Теперь получившееся нечто надо протестировать. По возможности реальной нагрузкой... Для этих целей и был написан session_storage_bench. Этот скрипт пытается в точности эмитировать поведение php-fpm процесса: заблокировал сессию, прочитал, подождал 200ms (время обработки запроса), записал обратно, снял блокировку. Он умеет разговаривать с memcache(и другими memcache-like системами, такими как Couchbase) и с Redis. Думаю не составит большого труда написать адаптер для любого другого хранилища сессий. Также он умеет имитировать persistent коннекшены. В общем - пользуйтесь :-)
Комментариев нет:
Отправить комментарий