пятница, 16 мая 2014 г.

Session storage benchmark

           Уже очень давно я бьюсь над проблемой: а как настроить 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 коннекшены.  В общем - пользуйтесь :-)          

Martini Gorelic

     По просьбам трудящихся написал middleware для интеграции Martini framework и NewRelic:
https://github.com/yvasiyarov/martini_gorelic
Пожелания, улучшения, pull requests - are welcome :-)

вторник, 13 мая 2014 г.

NewRelic middleware for beego

   Потратил вечер чтобы облегчить жизнь пользователям beego framework.  Теперь подключить NewRelic к любому beego приложению можно за 5 минут:
         https://github.com/yvasiyarov/beego_gorelic
Надеюсь кому-нибуть да пригодится :-)

воскресенье, 11 мая 2014 г.

Go web frameworks

      В последнее время появилось много довольно симпатичных веб фраймворков для Go.  Сегодня решил потыкать несколько из них. Ну и сделать небольшой бенчмарк как водится в таких случаях.  
          Все фраймворки тестировались на одном и том же железе - полудохлом макбуке бородатых годов и компилировались с помощью go1.2.1 darwin/amd64. Дабы избежать холиваров сразу скажу:
  • Да, я знаю что бенчмарки Hello word и реального приложения имеют мало общего и я не собираюсь их сравнивать между собой
  • Ежу понятно что приложение на чистом net/http будет быстрее. Цель данного исследования - узнать ту "цену" которую нам приходится платить за удобство использования того или иного фраймворка.    
Для тестирования мы используем siege (конкретно siege -c 100 -b -r 100 ). 
И так, Hello world на чистом net/http (исходники доступны на тут ):

 
Transactions:         10000 hits
Availability:        100.00 %
Elapsed time:          4.62 secs
Data transferred:         0.10 MB
Response time:          0.04 secs
Transaction rate:      2164.50 trans/sec
Throughput:          0.02 MB/sec
Concurrency:         77.89
Successful transactions:       10000
Failed transactions:            0
Longest transaction:         0.14
Shortest transaction:         0.00

      Hello world используюя Martini фраймворк (исходники):
 Transactions:              10000 hits  
 Availability:             100.00 %  
 Elapsed time:              6.87 secs  
 Data transferred:         0.11 MB  
 Response time:              0.06 secs  
 Transaction rate:        1455.60 trans/sec  
 Throughput:              0.02 MB/sec  
 Concurrency:              94.52  
 Successful transactions:    10000  
 Failed transactions:           0  
 Longest transaction:         0.42  
 Shortest transaction:         0.00  
Эти результаты наглядно показывают что за все нужно платить. Даже даже не самый сложный фраймворк отъедает значительное количество ресурсов.
           Следующий подопытный - gocraft. По предоставляемым возможностям он очень похож на martini, скажем так - это фремворки одного уровня. Вот результаты тестов gocraft:
 Transactions:              10000 hits  
 Availability:             100.00 %  
 Elapsed time:              4.71 secs  
 Data transferred:         0.10 MB  
 Response time:              0.04 secs  
 Transaction rate:        2123.14 trans/sec  
 Throughput:              0.02 MB/sec  
 Concurrency:              78.24  
 Successful transactions:    10000  
 Failed transactions:           0  
 Longest transaction:         0.33  
 Shortest transaction:         0.00  
Исходники можно посмтреть тут. Я специально не стал убирать middleware's чтобы тесты между gocraft и martini были максимально честными.  Как вы видите показатели практически идентичны чистому net/http. И значительно быстрее martini. Хотя влияние Martini четко просматривается.
        Следующим подопытным будет revel. По предоставляемым возможностям это фреймворк совсем другого уровня, и сравнивать его с предыдущими кандидатами будет не совсем корректно.  Это видно даже по "hello word". Если у martini и gocraft это просто 10 строк исходного кода, то для revel - это целое приложение с MVC структурой и кучей всяких файлов.  Одно хорошо - все эти файлы генерируются автоматически и мы с помощью одной команды: revel new myapp  получаем готовое приложение. А теперь результаты:
 Transactions:              9872 hits  
 Availability:              98.72 %  
 Elapsed time:              34.14 secs  
 Data transferred:         19.24 MB  
 Response time:              0.22 secs  
 Transaction rate:        289.16 trans/sec  
 Throughput:              0.56 MB/sec  
 Concurrency:              64.71  
 Successful transactions:    9872  
 Failed transactions:          128  
 Longest transaction:         20.17  
 Shortest transaction:         0.00  
Сказать что результаты меня разочаровали - значит ничего не сказать. В принципе на PHP +Yii мы получаем тоже самое без всяких оптимизаций. Плюс к тому Availability не 100%... и это у Hello world...  В общем revel меня разочаровал. В консоли он ругался что-то вроде:
 2014/05/11 16:37:22 reverseproxy.go:141: http: proxy error: dial tcp 127.0.0.1:62188: too many open files  
 2014/05/11 16:37:22 reverseproxy.go:141: http: proxy error: dial tcp 127.0.0.1:62188: too many open files  
 2014/05/11 16:37:22 reverseproxy.go:141: http: proxy error: dial tcp 127.0.0.1:62188: too many open files  
 2014/05/11 16:37:22 reverseproxy.go:141: http: proxy error: dial tcp 127.0.0.1:62188: too many open files  
 2014/05/11 16:37:22 reverseproxy.go:141: http: proxy error: dial tcp 127.0.0.1:62188: too many open files  
 2014/05/11 16:37:22 server.go:1633: http: Accept error: accept tcp [::]:9000: too many open files; retrying in 5ms  
 2014/05/11 16:37:22 reverseproxy.go:141: http: proxy error: dial tcp 127.0.0.1:62188: too many open files  
зачем создателю revel понадобился reverse proxy - ума не приложу.
        Последний кандидат на сегодня - beego. По своему уровню он очень похож на revel - он также гененирует целое приложение с кучей папочек. Но результаты у него куда лучше:
 Transactions:              10000 hits  
 Availability:             100.00 %  
 Elapsed time:              20.27 secs  
 Data transferred:         15.19 MB  
 Response time:              0.18 secs  
 Transaction rate:        493.34 trans/sec  
 Throughput:              0.75 MB/sec  
 Concurrency:              90.49  
 Successful transactions:    10000  
 Failed transactions:           0  
 Longest transaction:         0.71  
 Shortest transaction:         0.00  
Response time в 5 раз выше чем у gocraft, но это объяснимо. В общем мой выбор это beego и gocraft. В зависимости от характера приложния.

суббота, 10 мая 2014 г.

Costa Victoria Singapore - Indonesia Part 3

      Если вы не читали начало истории, то лучше сначала прочитать первую часть рассказа и поглазеть на фотки к ней. В общем часов в 10 утра мы приплыли к последней точке нашего маршрута - острову Ламбок
По сравнению с промышленным островом Ява, и островом городского типа "Бали" Ламбок показался нам зеленой деревней. На острове нет пристани, к которой может причалить корабль таких размеров как Costa Victoria поэтому для того чтобы сойти на землю придется воспользоваться корабельными шлюпками. 

     Но в части такси - ситуация совершенно одинаковая. Все контролируется мафией, цены конские. Мы решили не экспериментировать и за 80$ сняли на весь день машину с водителем который провез нас по всему острову и показал все его достопримечательности. В подарок нам дали гида - который оказался местным студентом, который таким образом практикует английский. Оказалось что в отличии от мусульманской Явы и буддистского Бали, на Ламбоке много христиан. Каталиков естественно :-) 
В отличии от гористой Явы, Ламбок довольно равнинный остров. Как только выезжаешь из порта - везде зелель, поля с рисом, сады... в общем после того гавна которое было на Яве он реально кажется маленьким райским островком



Декабрь - не самый лучший месяц для посещения Индонезии. Именно поэтому круиз обошелся нам так дешево. Но и погода очень часто оставляла желать лучшего. Нет, холодно не было. Но постоянная облачность не особо радовала.




В общем вы сами сидите насколько там все зелено. Люди тоже отличаются, они как-то по проще. 
Местный напиток - обещает что если выпьешь - будешь бегать как трехногий олень. Для мужской силы тоже были. Но я выбрал этот - после целого дня хождения по острову - напиток для ног было куда более актуален.
Закат над островом Ламбок был великолепен. Жаль фотографии не могут передать в полной мере этой красоты. Вечером мы отчалили в обратный путь - Costa Victoria взяла курс на Сингапур. 

Costa Victoria Singapore - Indonesia Part 2


    Первая часть моего повествования Costa Victoria Singapore - Indonesia была написана давно, так сказать по горячим следам - прямо во время поездки. С тех времен прошло уже почти пол года, но до продолжения руки дошли только сейчас. Далее немного фото к первой части рассказа.
Это не Costa Victoria, но очень похоже
Обожаю смотреть на море
Costa Victoria у причала. Остров Ява.
Внутри корабля

Казино внутри корабля
Все воскресенье ы любовались на это
Порт Семаранга, остров Ява. Совсем не туристическое место.
Ява уже давно "не торт"
"морячки" нашли свою гавань :-)
На борту всегда кормят всякой вкусняшкой

Дело было под Рождество

вторник, 6 мая 2014 г.

На почитать


Вообще HHVM на которой работает и Hack и PHP в 3-уй версии работает прямо таки замечательно. У меня получилось перенести на него проект, который писали уже лет 5 как и на основе Zend Framework 1, который сам по себе давно не поддерживается. В общем кроме прям ну очень специфичных и кривых вещей - все остальное полностью работает. Можно HHVM прям паралельно с PHP-FPM запускать и тестировать проект