Генеруємо 21k запитів в секунду
Це стаття про те , як ми в Cogniance робили тестування навантаження . Вона є почасти продовженням статті Діми « Тримаємо 11k req/s » , тому я Не буду повторювати інформацію про архітектуру додатки , вдаватися в деталі наших модулів - все це Ви можете знайти там .
Єдина частина , на якій я хотів би зупинитися детальніше, перш ніж перейти до суті , - вимоги . Найцікавіше тут те , що через 6 місяців після старту проекту очікувана навантаження збільшилося приблизно в 100 + раз . Вимоги до тестування навантаження з розряду « дайте нам хоч щось » перейшли в розряд «ми хочемо бачити всі види тестування , про які читали » . Вимоги при старті проекту:- Request rate : 50 req/sec normal rate
- Request rate high : 150 req/sec peaks
- Protocol : http
- Authentication : no - Response time : average 99 % & lt ; 200ms . Вимоги після 6 місяців розробки :
- Request rate : 7000 req/sec normal rate
- Request rate high : 21000 req/sec peaks
- Protocol : https
- Authentication : 2WAY ( mutual ssl )
- Response time : 99 % total & lt ; 100ms . Я не буду зупинятися на тому етапі , коли вимоги дозволяли нам хостити додаток на Діміна телефоні , а відразу перейду до тієї частини , де нам необхідно було напружитися і придумати , як докорінно поміняти тестування навантаження . Для модуля , який показує рекламу ( Ad Server ) , клієнт попросив зробити тестування пріблітельно так , тобто використовуючи « Performance Testing Guidance for Web Applications » від Microsoft. На самому початку нам треба було визначити і описати, які тести ми можемо провести у відносно стислі терміни. Зупинилися на наступних тестах : - Performance Testing . Benchmarking ( Simple scenario , Average scenario , Complex scenario )
- Stress testing ( Complex scenario )
- Scalability testing ( Complex scenario )
- Soak testing ( Complex scenario )
- Layer testing
- Production environment . Instance identification . Розкажу трохи деталей про кожен тип . Performance Testing . Benchmarking . Роблячи так званий « Benchmarking » , ми пробуємо визначити : - як поводиться додаток в умовах навантаження , близькій до максимальної , використовуючи сценарії навантаження від простого до складного ;
-Зробити висновок , вкладаємося ми в SLA чи ні ;
- зібрати « еталонні » метрики ; Переходячи до Stress testing , ми старалися зрозуміти :
- як «відчуває » себе додаток при навантаженні більше встановлених лімітів ;
- визначити точку неповернення. Максимальна кількість запитів , яке може витримати наш додаток ;
- зрозуміти , при якій навантаженні додаток почувається OK; Scalability testing . Говорячи коротко - зрозуміти , наскільки ми можемо « Скейл » , лінійно або нелінійно . За допомогою Soak testing нам потрібно було визначити , як буде себе вести додаток при піковому навантаженні протягом N часу. Під час Layer testing ми хотіли виявити « вузькі» місця і перевірити кожен модуль окремо. І як підсумок нашого тестування навантаження від нас очікували рекомендації до виробничої середовищі . Тепер давайте спробуємо зрозуміти , яким чином і використовуючи які кошти можна досягти всього вищесказаного . Jmeter Почнемо з самого популярного , напевно , рішення - Jmeter . Офіційний сайт говорить нам следюущее : « Ability to load and performance test many different server/protocol types . » На жаль , навіть для нашого найпростішого сценарію він не зовсім підходив . Наприклад , POST запит ( mutual ssl ) , максимально унікальний , з безліччю різних параметрів ~ 3kb , відповідь ~ 3kb і ще кілька GET запитів , які ми створили на основі відповіді . При такому сценарії , генеруючи порядку 300 requests/sec з кожною ноди * (всього нод 5 ) , майстер помирав у розподіленому режимі через якийсь час , більш того , Jmeter вимагав величезної кількості ресурсів, зокрема , пам'яті , періодично падаючи по OOM і не виробляючи очікуваної навантаження. Ще Jmeter використовує щодо застарілий протокол для спілкування між майстром та слейв - RMI , через який вони обмінюються великою кількістю даних , що , в свою чергу , погано позначається на продуктивності в розподіленому режимі.
* CPU Intel® Core ™ i7 CPU , 920 @ 2.67GHz , # of CPU's - 1 , # of cores - 8 , memory - 12 gb . Load UI Наступним кандидатом , який ми успішно використовували раніше для генерації не настільки істотного навантаження , був Load UI . У такого рішення було багато «булочок » : - відмінно працює в розподіленому режимі;
- легко писати/поранити свої скрипти ;
- легко запускається в non - gui режимі;
- можна додавати агенти « на льоту»;
- красиві графіки ;
- і ще багато іншого . Але знову - занадто велике споживання ресурсів і занадто маленька вироблена навантаження ( а саме - велике споживання пам'яті і всього ~ 300 requests/sec з кожною ноди *). Потрібно так само відзначити , що loadui не підтримує більше 5 нод в распределнном режимі роботи . Навіть якщо скористатися платною версією.
* CPU Intel Xeon E5-2680 , 2.80GHz , # of cores - 8 , memory - 15 gb . Load UI підходив нам практично всім: відносно зручний інтерфейс дозволяв робити досить складні конфігурації для тестів і змінювати їх « на льоту» . Він дозволяв нам додавати/прибирати агенти в Рантайм , і якщо ми робили Смоук тести або тільки починали тестування навантаження нового проекту , дозволяв робити це у відносно стислі терміни. Ще одна « плюшка » Load UI - графіки , вони дуже близькі до тих , які хоче в результаті отримати більшість клієнтів (або продакт оунеров ) . Скрипти для власних сценаріїв можна було відносно швидко написати на Groovy . Якщо ж виникали складності , Dev команда завжди могла швидко допомогти в тонкощах написання. Що ж змусило нас відмовитися від використання Load UI на проекті? Відповідь вже була дана вище - навантаження занадто мала, та й кількість агентів , які можна підключити до однієї майстер - Ноде , також невелика - всього 5 . І найбільша проблема Load UI , яку ми , на жаль , так і не змогли побороти - « вмираючі агенти » . Ми довго не могли зрозуміти , чи то це проблеми з нашим апплікейшном , або ж це проблеми агентів , але приблизно через 20 - 60 хвилин агенти в хаотичному порядку « відвалювалися » або « зависали » . Після повторної перевірки іншими інструментами проблема була локалізована , і це послужило додатковим поштовхом до того , щоб відмовитися від Load UI назавжди. Велосипед У нашого клієнта був власний велосипед по тестування навантаження , але рішення це було дуже сирим і працювало не кращим чином . Під час тестів неможливо було зрозуміти , де проблема - на боці додатки або ж на стороні генератора навантаження. Tsung Нашим рятівником став . У цього рішення теж є свої мінуси :
- Не можна додавати агенти « на льоту»;
- Немає можливості написати тест на java/groovy ;
- Ні UI ;
- Поріг входу "трохи вище , в порівнянні з описаними вище рішеннями ;
- Ні готових сценаріїв. Але при цьому він просто робить свою роботу , і справляється з цим на відмінно:
- Не вимагає великої кількості ресурсів для генерації навантаження при складних сценаріях ;
- Може згенерувати просто величезне навантаження ( ~ 11k requests/sec з одного ноди * ) ;
* CPU Intel Xeon E5-2680 , 2.80GHz , # of cores - 8 , memory - 15 gb . Творці описують мета Tsung'a наступним чином : « The purpose of Tsung is to simulate users in order to test the scalability and performance of IP based client/server applications . You can use it to do load and stress testing of your servers . Many protocols have been implemented and tested , and it can be easily extended . » Тут я спробую трохи детальніше зупинитися на деяких аспектах . UI Tsung'a виглядає приблизно так : Всі тести в Tsung - xml , і виглядають приблизно так : & lt ; http url="/adserver/ad?uid=200_request_%%_rnduid%%&type=TTTT&cellid=%%_rndcell%%&lat=%%_lat%%&lon=%%_lon%%" version = " 1.1" method = " POST " contents = " {" app":nmn","appver":"2345","channels":[],"blocked":["%%_channel%%"],"device":{"device":"9910","time":%%_time%%,"platform":"nokia","sd":2,"sw":360,"sh":240,=«" « Os » : "%% _ os %% " , " mf ": " bla "} , = «" « demo » : [ %% _ male %% , " carrier =" "%% _ carrier %% "] , = « " « tastes » : [ %% _ taste %% ]} " = "" & gt ; & lt ; http_header name = " Accept" value = " text/json "/& gt ;
& lt ; http_header name = " Content- type " value = " text/json ; charset = UTF - 8 "/& gt ;
& lt ; http_header name = "Accept - Charset " value = " UTF - 8 "/& gt ;
& lt ; http_header name = " X - Forwarded - For " value = " 1.1.1.1 "/& gt ; & lt ; http_header name = "Accept - Language" value = "%% _ language %% "/& gt ;
& lt ; http_header name = " User - Agent " value = " Mozilla/5.0 ( Nokia; U ; Nokia 3310 ; en -US ) AppleWebKit/534.11 + ( KHTML , like Gecko ) Version/7.0.0 Mobile Safari/534.11 + "/& gt ;
& lt ; http_header name =" Connection " value =" keep - alive "/& gt ; & lt ; http_header name = " Cache - Control " value = " no - cache "/& gt ;
& lt ; http_header name = "Accept - Encoding " value = " gzip , deflate «/& gt ; Проте, розібравшись , ми зрозуміли , що не все так страшно , як здавалося на початку . Припустимо , що ми вже написали якийсь тест і хочемо його запустити за допомогою Tsung . Зробити це просто:
$ cd /home/ubuntu/.tsung $ tsung -f script.xml -l/var/www/start -l path to logs and results Дізнатися поточну генерируемую навантаження :
$ tsung status Очікуємо побачити щось схоже на :
Tsung is running [ OK ] Current request rate : 7727.28 req/sec Current users : 44 Current connected users * : 45 Current phase : 1 * Current connected users : amount of users generating load Детальні результати навантаження ( працює тільки якщо включити детальне логирование ) :
$ cd/var/www/20140506-1628 $ sudo perl /usr/lib/tsung/bin/tsung_percentile.pl --percentiles 99 І як результат ми маємо отримати :
Read : tsung - fullstats.log Read : 21245 values ??for sample , connect Percentile 99 : 51.39892578125 Read : 3342222 values ??for sample , request Percentile 99 : 13284.6879882812 Read : 1764201 values ??for sample , page Percentile 99 : 20497.458984375 Tsung також дозволить нам згенерувати графіки : Вони не настільки красиві і інформативні, як у Load UI , і , швидше за все , їх треба буде ще « обробити напилком » , перш ніж віддати клієнтові або продакт оунеру :
$ sudo perl /usr/lib/tsung/bin/tsung_stats.pl --dygraph Нюанси тестування з Tsung : - Якщо ви хочете , щоб master node брав участь в навантаженні , йому потрібен буде безпарольний ssh доступ на себе, крім беспарольного ssh на всі агенти .
- Закінчилися локальні порти (докладніше ) :
echo 5 & gt ;/proc/sys/net/ipv4/tcp_fin_timeout echo 15000 65000 & gt ;/proc/sys/net/ipv4/ip_local_port_range Підсумок При приблизно * однакових умовах ми отримали наступну навантаження за допомогою вищеописаних засобів :
* Незначні відмінності в інстанси і дрібні зміни в тілі тестів JMETER ~ 300 requests/second per node . Total nodes 5. Total load ~ 1,5k req/sec .
LOAD UI ~ 300 requests/second.Total nodes 5. Total load ~ 1,5k req/sec .
TSUNG - 11k requests/second . Total nodes 2. Total load ~ 21k req/sec .
CUSTOM - 1k headaches/second . Total headache . На закінчення я хочу привести приклад того , які результати віддавати клієнтові або продакт оунеру . Самому невимогливому , думаю , буде достатньо графіків , які вам згенерує Tsung . Але так чи інакше , щоб зрозуміти , наскільки добре (або погано ) Перформа ваш аплікейшн , наступні метрики можуть бути корисні:
Test resume . I.e .:
Time for 99 % of connections , ms Time for 99 % of ad requests , ms Time for 99 % of ad event , ms Test Specification . I.e . : Amount of entities in the system % of served requests % of non - matched Requests stats . I.e .:
tomcat localhost_access.log Instance specification . Ie : Amazon c3.2xlarge , Redis : Amazon ElastiCache m2.xlarge . Result metrics . I.e .:
Stats from agent : Name highest 10sec mean lowest 10sec mean Highest Rate Mean Count Common number of requests/concurrent users from Agent Graphs Conclusion Які висновки ми встигли зробити під час тестування: Нове з'єднання - це дуже $$$ . Приклад :
Open/close connection ~ 70 ms ; Serve request within open connection ~ 12 ms ; RTFM . Без коментарів; Розбивайте систему на частини. Іноді складно « вгадати » , де проблеми , і можна витратити на це багато часу ; Тестируйте будь-який, навіть , здавалося б , самий « добре описаний в інтернеті » солюшн . Це дозволить вам не переписувати систему потом; 21k req/sec - це далеко не межа. Я і хлопці спробуємо відповісти на Ваші запитання , якщо такі будуть .
Опубліковано: 06/10/14 @ 10:03
Розділ Пошуковики
Рекомендуємо:
Успішні кейси просування в Яндексі. Частина 11. Найбільша товарна сітка
6 жовтня , Київ - Одноденний семінар « Сегментація клієнтів по товарних перевагам » від експерта в області Machine Learning
.NET Digest # 0
6 жовтня, Київ - Курс " Java for beginners "
25 жовтня, Київ - Майстер - клас Андрія Лісточкіна " Побудова API - сервісів c Node.JS "