PyConCZ’16
DOS YOURSELF
a.k.a. Load Testing
Dariusz Aniszewski
! DariuszAniszewski
" @aniszewski_eu
PyConCZ’16
➤ z polštiny
➤ 9 to 5
➤ Senior Software Engineer @ Polidea
➤ Python user since 2010
➤ Load testing aware since 2011/2012
➤ After hours
➤ Home-brewer
➤ IoT enthusiast
2
$ WHOAMI
PyConCZ’16
MOTIVATION
PyConCZ’16
➤ Introduction
➤ Example performance problems
➤ Tools
4
AGENDA
PyConCZ’16
1. You must not perform load testing on server you are not
authorised to test.
2. You should not perform load testing on live, production
server, even yours.
5
DISCLAIMER
PyConCZ’16
DISCLAIMER
6
http://devopsreactions.tumblr.com/post/133458045982/load-testing
PyConCZ’16
INTRO
PyConCZ’16 8
https://commons.wikimedia.org/wiki/File:Umgeni_River_Bridge_Load_Test.jpg
PyConCZ’16
➤ Load testing is the process of putting
demand on a software system or computing
device and measuring its response.
9
WIKI SAYS:
PyConCZ’16
➤ Load testing is performed to determine a
system's behavior under both normal and
anticipated peak load conditions.
10
WIKI SAYS:
PyConCZ’16
➤ Make your users happy
➤ Don’t loose money
➤ Ensure system mets non-functional requirements
➤ usable under expected load
➤ usable under N-times larger than expected load
➤ Ensure your hardware is working efficiently
➤ Ensure your architecture is working efficiently
➤ Determine how much traffic you can handle on single node
11
REAL REASONS
PyConCZ’16
WHOA, WAIT…
PyConCZ’16
➤ Unit Tests are Awesome
➤ Integration Tests are Awesome too!
➤ But still not enough…
➤ Unit tests are very isolated
➤ Both of them use minimal data
13
AREN’T UNIT TESTS JUST ENOUGH?
PyConCZ’16
PERFORMANCE
ISSUES
“
PyConCZ’16
There is absolutely no way that all of
them will hit the same API exactly at
the same time.
- Dariusz Aniszewski, 2011
15
PyConCZ’16
➤ Project for weekly magazine
➤ iPad app & on-premise backend
➤ ~4000 active iPads every week
➤ Everything was running smoothly
16
BACKGROUND
PyConCZ’16
https://www.flickr.com/photos/methodshop/5808144764
17
PyConCZ’16
➤ Virtual bookshelf
➤ Introduced in iOS 5
➤ Workflow:
➤ Silent push that there is new publication available
➤ Application downloads new publication in background
➤ Application displays nice badge on its icon
➤ User opens app and new publication is ready
18
NEWSSTAND
“
PyConCZ’16
There is absolutely no way that all of
them will hit the same API exactly at
the same time.
- Dariusz Aniszewski, 2011
19
!! WRONG !!
PyConCZ’16
➤ Every device connected to the Internet hit our API at once
➤ Hundreds of parallel downloads of ~90MB packages
➤ No crash ;-)
➤ Download speed was terrible, usability was poor
➤ On-premise network infrastructure was bottleneck
➤ Moved to S3 week later
20
NEWSSTAND
PyConCZ’16
BAD MODEL DESIGN
PyConCZ’16
➤ Gather lots and lots of stats from mobile app
➤ Store them locally for short period of time
➤ Export them to BigTable
➤ Make it readable via Django
22
OBJECTIVES
PyConCZ’16
SESSION DATA
23
class SessionData(models.Model):
player = models.ForeignKey(PlayerStats)
# 1 - 5
start = models.IntegerField(blank=True,null=True)
end = models.IntegerField(blank=True,null=True)
length = models.IntegerField(blank=True,null=True)
since_last = models.IntegerField(blank=True,null=True)
referrer = models.CharField(max_length=2000,blank=True,null=True)
# 6-7
NoAPS = models.TextField(blank=True,null=True)
NoGCPAPS = models.IntegerField(blank=True,null=True)
PyConCZ’16
GETTING WORSE
24
# 8 - 23
VoGCPAPS = models.IntegerField(blank=True,null=True)
AVoGCPAPS = models.IntegerField(blank=True,null=True)
NoDPAPS = models.IntegerField(blank=True,null=True)
VoDPAPS = models.IntegerField(blank=True,null=True)
AvoDPAPS = models.IntegerField(blank=True,null=True)
USDSPS = models.FloatField(blank=True,null=True)
VoDPPS_USD = models.FloatField(blank=True,null=True)
VoGCPPS_USD = models.FloatField(blank=True,null=True)
VoGCPPS_DINARS = models.FloatField(blank=True,null=True)
EUPS = models.IntegerField(blank=True,null=True)
EDPS = models.IntegerField(blank=True,null=True)
EPPS = models.FloatField(blank=True,null=True)
NoTAAPS = models.IntegerField(blank=True,null=True)
VoTAAPS = models.FloatField(blank=True,null=True)
DoTAAPS = models.TextField(blank=True,null=True)
GLaSS = models.IntegerField(blank=True,null=True)
PyConCZ’16
AND WORSE
25
# 24-40
GLaSE = models.IntegerField(blank=True,null=True)
PaSS = models.IntegerField(blank=True,null=True)
PaSE = models.IntegerField(blank=True,null=True)
SCBaSS = models.IntegerField(blank=True,null=True)
SCBaSE = models.IntegerField(blank=True,null=True)
GCBaSS = models.IntegerField(blank=True,null=True)
GCBaSE = models.IntegerField(blank=True,null=True)
GCUPS = models.IntegerField(blank=True,null=True)
GCCPS = models.IntegerField(blank=True,null=True)
GCBPS = models.TextField(blank=True,null=True)
DBaSS = models.IntegerField(blank=True,null=True)
DBaSE = models.IntegerField(blank=True,null=True)
DUPS = models.IntegerField(blank=True,null=True)
DCPS = models.IntegerField(blank=True,null=True)
DBPS = models.TextField(blank=True,null=True)
EBaSS = models.IntegerField(blank=True,null=True)
EBaSE = models.IntegerField(blank=True,null=True)
EUPS_all = models.IntegerField(blank=True,null=True)
PyConCZ’16
AND WORS… OH COME ON...
26
# 41 - 56
OECOS = models.IntegerField(blank=True,null=True)
PECPPS = models.FloatField(blank=True,null=True)
EBPS = models.TextField(blank=True,null=True)
APPS = models.TextField(blank=True,null=True)
VoAAPPS = models.FloatField(blank=True,null=True)
APwDPS = models.TextField(blank=True,null=True)
VoAAPwDPS = models.FloatField(blank=True,null=True)
APwCPS = models.TextField(blank=True,null=True)
VoAAPwCPS = models.FloatField(blank=True,null=True)
ExPPS = models.IntegerField(blank=True,null=True)
VoAEPPS = models.FloatField(blank=True,null=True)
EPwCPS = models.IntegerField(blank=True,null=True)
VoEPwCPS = models.FloatField(blank=True,null=True)
EPwDPS = models.IntegerField(blank=True,null=True)
VoEPwDPS = models.FloatField(blank=True,null=True)
poAMOBEP = models.TextField(blank=True,null=True)
PyConCZ’16
UH. END.
27
# 57 - 63
APADtIF = models.TextField(blank=True,null=True)
LABSE = models.CharField(max_length=200,blank=True,null=True)
LPCaSS = models.IntegerField(blank=True,null=True)
LPCaSE = models.IntegerField(blank=True,null=True)
PADaPS = models.IntegerField(blank=True,null=True)
LTaSP = models.IntegerField(blank=True,null=True)
SPDO = models.IntegerField(blank=True,null=True)
PyConCZ’16
Overloaded database with big inserts
Drastic decrease of response time
Service was unusable
Drastic decrease of active users
28
PROBLEM
PyConCZ’16 29
HOTFIX
def receive_session_stats(request):
[...]
session = SessionData()
session.player = stats
# 1 - 5
session.start = data.get("1",0)
session.end = data.get("2",0)
[...]
session.save()
return HttpResponse()
def receive_session_stats(request):
return HttpResponse()
PyConCZ’16
class NewSessionData(models.Model):
player = models.ForeignKey(PlayerStats)
data = models.TextField()
➤ Gather lots and lots of stats from mobile app
➤ Store them locally for short period of time
➤ Export them to BigTable
➤ Make it readable via Django
30
LONG TERM SOLUTION
PyConCZ’16
INEFFICIENT
FRAMEWORK USAGE
PyConCZ’16
➤ Is awesome!
➤ Is easy to use, powerful and generally great
➤ Is dangerous!
➤ It makes it very easy to forget about performance
➤ Is magical
➤ You don’t see queries that are generated
➤ Those queries might be not optimal
32
DJANGO ORM
PyConCZ’16 33
DJANGO ORM
class Author(models.Model):
first_name = models.CharField(max_length=64)
last_name = models.CharField(max_length=128)
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author)
pages = models.IntegerField()
def get_books_by_size(request, pages_min, pages_max):
books = Book.objects
.filter(pages__gte=pages_min, pages__lte=pages_max)
return JsonResponse({
"books": [{
"id": book.id,
"title": book.title,
"pages": book.pages,
"author": {
"id": book.author.pk,
"last_name": book.author.last_name,
}
} for book in books]
})
PyConCZ’16 34
DJANGO ORM
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author)
pages = models.IntegerField()
def get_books_by_size(request, pages_min, pages_max):
books = Book.objects
.filter(pages__gte=pages_min, pages__lte=pages_max)
return JsonResponse({
"books": [{
"id": book.id,
"title": book.title,
"pages": book.pages,
"author": {
"id": book.author.pk,
"last_name": book.author.last_name,
}
} for book in books]
})
PyConCZ’16 35
DJANGO ORM
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author)
pages = models.IntegerField()
def get_books_by_size(request, pages_min, pages_max):
books = Book.objects
.filter(pages__gte=pages_min, pages__lte=pages_max)
return JsonResponse({
"books": [{
"id": book.id,
"title": book.title,
"pages": book.pages,
"author": {
"id": book.author.pk,
"last_name": book.author.last_name,
}
} for book in books]
})
PyConCZ’16 36
DJANGO ORM
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author)
pages = models.IntegerField(db_index=True)
def get_books_by_size(request, pages_min, pages_max):
books = Book.objects
.filter(pages__gte=pages_min, pages__lte=pages_max)
return JsonResponse({
"books": [{
"id": book.id,
"title": book.title,
"pages": book.pages,
"author": {
"id": book.author.pk,
"last_name": book.author.last_name,
}
} for book in books]
})
PyConCZ’16 37
DJANGO ORM
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author)
pages = models.IntegerField(db_index=True)
def get_books_by_size(request, pages_min, pages_max):
books = Book.objects
.filter(pages__gte=pages_min, pages__lte=pages_max)
return JsonResponse({
"books": [{
"id": book.id,
"title": book.title,
"pages": book.pages,
"author": {
"id": book.author.pk,
"last_name": book.author.last_name,
}
} for book in books]
})
PyConCZ’16 38
DJANGO ORM
class Book(models.Model):
title = models.CharField(max_length=128)
author = models.ForeignKey(Author)
pages = models.IntegerField(db_index=True)
def get_books_by_size(request, pages_min, pages_max):
books = Book.objects
.select_related('author')
.filter(pages__gte=pages_min, pages__lte=pages_max)
return JsonResponse({
"books": [{
"id": book.id,
"title": book.title,
"pages": book.pages,
"author": {
"id": book.author.pk,
"last_name": book.author.last_name,
}
} for book in books]
})
PyConCZ’16
AND SO ON
PyConCZ’16
LET’S TEST!
PyConCZ’16
➤ Inside job
➤ You must
➤ Have a deep understanding of system
➤ Set up internal monitoring software on your system
➤ Without it, you just monitor average response time
41
BEFORE YOU BEGIN
PyConCZ’16
➤ Application monitoring
➤ Availability monitoring
➤ Error reporting
➤ SLA calculator
➤ Integrates with your app via agent
➤ Works very well with Python
42
NEW RELIC
PyConCZ’16
AVERAGE RESPONSE TIME
43
PyConCZ’16
SLOWEST ENDPOINTS
44
PyConCZ’16 45
DETAILED BREAKDOWN
PyConCZ’16
➤ Custom breakdown segments available.
46
EVEN MORE DETAILED BREAKDOWN
PyConCZ’16
➤ Good to know
➤ Helps with maintenance planning
47
REQUESTS PER MINUTE
PyConCZ’16 48
SLOWEST SQL QUERIES
PyConCZ’16 49
DATABASE INSIGHTS
PyConCZ’16
TOOLS
PyConCZ’16
APACHE BENCH
PyConCZ’16
➤ part of Apache Server
➤ ab -n 100 -c 10 http://hit--me.herokuapp.com/100ms
➤ -n <= total number of requests to be made
➤ -c <= maximum concurrency level
52
APACHE BENCH
PyConCZ’16 53
APACHE BENCH
PyConCZ’16 54
http://www.myloadtest.com/performance-testing-memes/
PyConCZ’16
JMETER
PyConCZ’16
JMETER
56
➤ Pros:
➤ very powerful load testing tool
➤ tests can be imported to some cloud services
➤ load tests almost everything
➤ Cons:
➤ Complicated
➤ Big entry threshold
PyConCZ’16
JMETER
57
PyConCZ’16
JMETER
58
PyConCZ’16
JMETER
59
PyConCZ’16
JMETER
60
PyConCZ’16
JMETER
61
PyConCZ’16
JMETER
62
PyConCZ’16
CUSTOM SCRIPT
PyConCZ’16
➤ Pros:
➤ Can test exactly what you need
➤ Cons:
➤ Possible re-inventing a wheel
➤ Who said your testing script is optimal… :)
64
CUSTOM SCRIPT
PyConCZ’16
LOCUST
PyConCZ’16
➤ locust.io
➤ Python based, using gevent
➤ Well documented
➤ Load testing as Python code
➤ Distributed tests support



➤ Small problem: Python 2 only
66
LOCUST
PyConCZ’16 67
LOCUST
from locust import HttpLocust, TaskSet, task
class HitMeTasks(TaskSet):
@task(3)
def index(self):
self.client.get("/")
@task(10)
def test100ms(self):
self.client.get("/100ms")
class HitMeLocust(HttpLocust):
host = "http://hit--me.herokuapp.com"
task_set = HitMeTasks
min_wait = 100
max_wait = 100
PyConCZ’16
LOCUST
68
PyConCZ’16
LOCUST
69
PyConCZ’16 70
http://www.myloadtest.com/performance-testing-memes/
PyConCZ’16
CLOUD
PyConCZ’16
➤ Load Testing as a Service:
➤ loader.io
➤ blazemeter.io
➤ loadimpact.com
➤ and-so-on.com
➤ Server ownership verification
➤ Generally easy to use

72
CLOUD
PyConCZ’16
➤ Distributed
➤ API available
➤ Email results
➤ Free plan
➤ 1 host
➤ 10,000 users
➤ 2 endpoints
➤ 1 minute test
73
LOADER.IO
➤ Pro plan
➤ ∞ hosts
➤ 100,000 users
➤ 10 endpoints
➤ 10 minutes tests
PyConCZ’16 74
LOADER.IO
PyConCZ’16 75
LOADER.IO
PyConCZ’16 76
LOADER.IO
PyConCZ’16 77
LOADER.IO
PyConCZ’16 78
LOADER.IO
PyConCZ’16
➤ Include Load Testing into your workflow
➤ No magic formula, adopt solution to problem
➤ Be rational
➤ Don’t be afraid to break your system!
➤ Don’t Load Test your production!
➤ Don’t “Load Test” other servers!!
79
FINAL THOUGHTS
PyConCZ’16
THANK YOU
Questions?
! DariuszAniszewski
" @aniszewski_eu

More Related Content

PDF
Windows Systems & Code Signing Protection by Paul Rascagneres
PDF
0day hunting a.k.a. The story of a proper CPE test
PDF
Capistrano deploy Magento project in an efficient way
PDF
nullcon 2010 - The evil karmetasploit upgrade
PDF
CloudOpen North America 2013: Vagrant & CFEngine
PDF
Continuous Delivery Workshop with Ansible x GitLab CI (2nd+)
PDF
Automating Mendix application deployments with Nix
PPTX
Shestakov Illia "The Sandbox Theory"
Windows Systems & Code Signing Protection by Paul Rascagneres
0day hunting a.k.a. The story of a proper CPE test
Capistrano deploy Magento project in an efficient way
nullcon 2010 - The evil karmetasploit upgrade
CloudOpen North America 2013: Vagrant & CFEngine
Continuous Delivery Workshop with Ansible x GitLab CI (2nd+)
Automating Mendix application deployments with Nix
Shestakov Illia "The Sandbox Theory"

What's hot (20)

PDF
ZeroNights - SmartTV
PDF
Экспресс-анализ вредоносов / Crowdsourced Malware Triage
PDF
Csw2016 tang virtualization_device emulator testing technology
PDF
Introduction to zc.buildout
PPTX
Michal Kordas "Docker: Good, Bad or Both"
PPTX
Continuous delivery with docker
PPTX
Docker for Java developers at JavaLand
PDF
TriplePlay-WebAppPenTestingTools
PDF
Stupid Buildout Tricks
PPTX
Nginx warhead
PPTX
Getting started with python on Windows
PDF
Hands on iOS developments with jenkins
PPTX
C++ Production Debugging
PDF
Embedded Recipes 2018 - swupdate: update your embedded device - Charles-Anto...
PDF
Anwendungsfälle für Elasticsearch JAX 2015
PDF
Kubernetes on AWS at Zalando: Failures & Learnings - DevOps NRW
PDF
Gitlab - Creating C++ applications with Gitlab CI
PDF
[CB17] Trueseeing: Effective Dataflow Analysis over Dalvik Opcodes
PPTX
How go makes us faster (May 2015)
PPTX
[ENG] OHM2013 - The Quest for the Client-Side Elixir Against Zombie Browsers -
ZeroNights - SmartTV
Экспресс-анализ вредоносов / Crowdsourced Malware Triage
Csw2016 tang virtualization_device emulator testing technology
Introduction to zc.buildout
Michal Kordas "Docker: Good, Bad or Both"
Continuous delivery with docker
Docker for Java developers at JavaLand
TriplePlay-WebAppPenTestingTools
Stupid Buildout Tricks
Nginx warhead
Getting started with python on Windows
Hands on iOS developments with jenkins
C++ Production Debugging
Embedded Recipes 2018 - swupdate: update your embedded device - Charles-Anto...
Anwendungsfälle für Elasticsearch JAX 2015
Kubernetes on AWS at Zalando: Failures & Learnings - DevOps NRW
Gitlab - Creating C++ applications with Gitlab CI
[CB17] Trueseeing: Effective Dataflow Analysis over Dalvik Opcodes
How go makes us faster (May 2015)
[ENG] OHM2013 - The Quest for the Client-Side Elixir Against Zombie Browsers -
Ad

Viewers also liked (18)

PDF
Pattern Discovery - part I
PPT
Debra Purcell-Regis Youth Athletics
PPT
Mvo mkb loket
PDF
WLA Fall Newletter
DOCX
RAVI PEO RESUME OCT 2016
PDF
Twitterlinkedinunipadua
PDF
GurminderBharani
PDF
Light Controlled Vehicle
PDF
Temp Monitoring
PDF
Innovationsdag
PPTX
Presentation1
PDF
ocenka-juridicheskih-lic
PDF
Local SEO- Why & How we do it? A brief by EZ Rankings | Local SEO
PPTX
2014 05 projecte mail art italy
PDF
Gop e orcamento cmc 2017
DOCX
4.giác so do.chuyen cỡ
PPTX
Employee Retention - How having a mentoring program can assist
PDF
Mentoring for Financial Professionals
Pattern Discovery - part I
Debra Purcell-Regis Youth Athletics
Mvo mkb loket
WLA Fall Newletter
RAVI PEO RESUME OCT 2016
Twitterlinkedinunipadua
GurminderBharani
Light Controlled Vehicle
Temp Monitoring
Innovationsdag
Presentation1
ocenka-juridicheskih-lic
Local SEO- Why & How we do it? A brief by EZ Rankings | Local SEO
2014 05 projecte mail art italy
Gop e orcamento cmc 2017
4.giác so do.chuyen cỡ
Employee Retention - How having a mentoring program can assist
Mentoring for Financial Professionals
Ad

Similar to PyConCZ'16 - DoS youtself a.k.a. Load Testing (20)

PDF
High Performance Python 2nd Edition Micha Gorelick
PPTX
Scaling python webapps from 0 to 50 million users - A top-down approach
PPTX
Standard Libraries in Python Programming
PDF
PyPy London Demo Evening 2013
PDF
High Performance Django 1
PDF
High Performance Django
PDF
Monitoring your Python with Prometheus (Python Ireland April 2015)
PDF
Big data berlin
PPTX
Pycon 2011
PDF
Building a Front End for a Sensor Data Cloud
PDF
PyCon Poland 2016: Maintaining a high load Python project: typical mistakes
PDF
High Performance Python 2nd Edition Micha Gorelick Ian Ozsvald
PPTX
Python at Warp Speed
PDF
PyGrunn2013 High Performance Web Applications with TurboGears
PDF
(Ebook) High Performance Python by Micha Gorelick, Ian Ozsvald
PDF
Python performance profiling
PDF
Scaling Django to the sky
PDF
It's the memory, stupid! CodeJam 2014
PDF
Efficient Django
PDF
PyData Paris 2015 - Closing keynote Francesc Alted
High Performance Python 2nd Edition Micha Gorelick
Scaling python webapps from 0 to 50 million users - A top-down approach
Standard Libraries in Python Programming
PyPy London Demo Evening 2013
High Performance Django 1
High Performance Django
Monitoring your Python with Prometheus (Python Ireland April 2015)
Big data berlin
Pycon 2011
Building a Front End for a Sensor Data Cloud
PyCon Poland 2016: Maintaining a high load Python project: typical mistakes
High Performance Python 2nd Edition Micha Gorelick Ian Ozsvald
Python at Warp Speed
PyGrunn2013 High Performance Web Applications with TurboGears
(Ebook) High Performance Python by Micha Gorelick, Ian Ozsvald
Python performance profiling
Scaling Django to the sky
It's the memory, stupid! CodeJam 2014
Efficient Django
PyData Paris 2015 - Closing keynote Francesc Alted

Recently uploaded (20)

PDF
Cost to Outsource Software Development in 2025
PDF
CCleaner 6.39.11548 Crack 2025 License Key
PPTX
Monitoring Stack: Grafana, Loki & Promtail
PDF
Visual explanation of Dijkstra's Algorithm using Python
PDF
The Dynamic Duo Transforming Financial Accounting Systems Through Modern Expe...
PPTX
Patient Appointment Booking in Odoo with online payment
PPTX
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
PPTX
Trending Python Topics for Data Visualization in 2025
PDF
Salesforce Agentforce AI Implementation.pdf
PDF
MCP Security Tutorial - Beginner to Advanced
PDF
EaseUS PDF Editor Pro 6.2.0.2 Crack with License Key 2025
PPTX
Cybersecurity: Protecting the Digital World
PDF
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
PDF
Time Tracking Features That Teams and Organizations Actually Need
PPTX
assetexplorer- product-overview - presentation
PDF
AI/ML Infra Meetup | LLM Agents and Implementation Challenges
PPTX
Why Generative AI is the Future of Content, Code & Creativity?
PDF
Autodesk AutoCAD Crack Free Download 2025
PPTX
Oracle Fusion HCM Cloud Demo for Beginners
PDF
Wondershare Recoverit Full Crack New Version (Latest 2025)
Cost to Outsource Software Development in 2025
CCleaner 6.39.11548 Crack 2025 License Key
Monitoring Stack: Grafana, Loki & Promtail
Visual explanation of Dijkstra's Algorithm using Python
The Dynamic Duo Transforming Financial Accounting Systems Through Modern Expe...
Patient Appointment Booking in Odoo with online payment
AMADEUS TRAVEL AGENT SOFTWARE | AMADEUS TICKETING SYSTEM
Trending Python Topics for Data Visualization in 2025
Salesforce Agentforce AI Implementation.pdf
MCP Security Tutorial - Beginner to Advanced
EaseUS PDF Editor Pro 6.2.0.2 Crack with License Key 2025
Cybersecurity: Protecting the Digital World
AI-Powered Threat Modeling: The Future of Cybersecurity by Arun Kumar Elengov...
Time Tracking Features That Teams and Organizations Actually Need
assetexplorer- product-overview - presentation
AI/ML Infra Meetup | LLM Agents and Implementation Challenges
Why Generative AI is the Future of Content, Code & Creativity?
Autodesk AutoCAD Crack Free Download 2025
Oracle Fusion HCM Cloud Demo for Beginners
Wondershare Recoverit Full Crack New Version (Latest 2025)

PyConCZ'16 - DoS youtself a.k.a. Load Testing

  • 1. PyConCZ’16 DOS YOURSELF a.k.a. Load Testing Dariusz Aniszewski ! DariuszAniszewski " @aniszewski_eu
  • 2. PyConCZ’16 ➤ z polštiny ➤ 9 to 5 ➤ Senior Software Engineer @ Polidea ➤ Python user since 2010 ➤ Load testing aware since 2011/2012 ➤ After hours ➤ Home-brewer ➤ IoT enthusiast 2 $ WHOAMI
  • 4. PyConCZ’16 ➤ Introduction ➤ Example performance problems ➤ Tools 4 AGENDA
  • 5. PyConCZ’16 1. You must not perform load testing on server you are not authorised to test. 2. You should not perform load testing on live, production server, even yours. 5 DISCLAIMER
  • 9. PyConCZ’16 ➤ Load testing is the process of putting demand on a software system or computing device and measuring its response. 9 WIKI SAYS:
  • 10. PyConCZ’16 ➤ Load testing is performed to determine a system's behavior under both normal and anticipated peak load conditions. 10 WIKI SAYS:
  • 11. PyConCZ’16 ➤ Make your users happy ➤ Don’t loose money ➤ Ensure system mets non-functional requirements ➤ usable under expected load ➤ usable under N-times larger than expected load ➤ Ensure your hardware is working efficiently ➤ Ensure your architecture is working efficiently ➤ Determine how much traffic you can handle on single node 11 REAL REASONS
  • 13. PyConCZ’16 ➤ Unit Tests are Awesome ➤ Integration Tests are Awesome too! ➤ But still not enough… ➤ Unit tests are very isolated ➤ Both of them use minimal data 13 AREN’T UNIT TESTS JUST ENOUGH?
  • 15. “ PyConCZ’16 There is absolutely no way that all of them will hit the same API exactly at the same time. - Dariusz Aniszewski, 2011 15
  • 16. PyConCZ’16 ➤ Project for weekly magazine ➤ iPad app & on-premise backend ➤ ~4000 active iPads every week ➤ Everything was running smoothly 16 BACKGROUND
  • 18. PyConCZ’16 ➤ Virtual bookshelf ➤ Introduced in iOS 5 ➤ Workflow: ➤ Silent push that there is new publication available ➤ Application downloads new publication in background ➤ Application displays nice badge on its icon ➤ User opens app and new publication is ready 18 NEWSSTAND
  • 19. “ PyConCZ’16 There is absolutely no way that all of them will hit the same API exactly at the same time. - Dariusz Aniszewski, 2011 19 !! WRONG !!
  • 20. PyConCZ’16 ➤ Every device connected to the Internet hit our API at once ➤ Hundreds of parallel downloads of ~90MB packages ➤ No crash ;-) ➤ Download speed was terrible, usability was poor ➤ On-premise network infrastructure was bottleneck ➤ Moved to S3 week later 20 NEWSSTAND
  • 22. PyConCZ’16 ➤ Gather lots and lots of stats from mobile app ➤ Store them locally for short period of time ➤ Export them to BigTable ➤ Make it readable via Django 22 OBJECTIVES
  • 23. PyConCZ’16 SESSION DATA 23 class SessionData(models.Model): player = models.ForeignKey(PlayerStats) # 1 - 5 start = models.IntegerField(blank=True,null=True) end = models.IntegerField(blank=True,null=True) length = models.IntegerField(blank=True,null=True) since_last = models.IntegerField(blank=True,null=True) referrer = models.CharField(max_length=2000,blank=True,null=True) # 6-7 NoAPS = models.TextField(blank=True,null=True) NoGCPAPS = models.IntegerField(blank=True,null=True)
  • 24. PyConCZ’16 GETTING WORSE 24 # 8 - 23 VoGCPAPS = models.IntegerField(blank=True,null=True) AVoGCPAPS = models.IntegerField(blank=True,null=True) NoDPAPS = models.IntegerField(blank=True,null=True) VoDPAPS = models.IntegerField(blank=True,null=True) AvoDPAPS = models.IntegerField(blank=True,null=True) USDSPS = models.FloatField(blank=True,null=True) VoDPPS_USD = models.FloatField(blank=True,null=True) VoGCPPS_USD = models.FloatField(blank=True,null=True) VoGCPPS_DINARS = models.FloatField(blank=True,null=True) EUPS = models.IntegerField(blank=True,null=True) EDPS = models.IntegerField(blank=True,null=True) EPPS = models.FloatField(blank=True,null=True) NoTAAPS = models.IntegerField(blank=True,null=True) VoTAAPS = models.FloatField(blank=True,null=True) DoTAAPS = models.TextField(blank=True,null=True) GLaSS = models.IntegerField(blank=True,null=True)
  • 25. PyConCZ’16 AND WORSE 25 # 24-40 GLaSE = models.IntegerField(blank=True,null=True) PaSS = models.IntegerField(blank=True,null=True) PaSE = models.IntegerField(blank=True,null=True) SCBaSS = models.IntegerField(blank=True,null=True) SCBaSE = models.IntegerField(blank=True,null=True) GCBaSS = models.IntegerField(blank=True,null=True) GCBaSE = models.IntegerField(blank=True,null=True) GCUPS = models.IntegerField(blank=True,null=True) GCCPS = models.IntegerField(blank=True,null=True) GCBPS = models.TextField(blank=True,null=True) DBaSS = models.IntegerField(blank=True,null=True) DBaSE = models.IntegerField(blank=True,null=True) DUPS = models.IntegerField(blank=True,null=True) DCPS = models.IntegerField(blank=True,null=True) DBPS = models.TextField(blank=True,null=True) EBaSS = models.IntegerField(blank=True,null=True) EBaSE = models.IntegerField(blank=True,null=True) EUPS_all = models.IntegerField(blank=True,null=True)
  • 26. PyConCZ’16 AND WORS… OH COME ON... 26 # 41 - 56 OECOS = models.IntegerField(blank=True,null=True) PECPPS = models.FloatField(blank=True,null=True) EBPS = models.TextField(blank=True,null=True) APPS = models.TextField(blank=True,null=True) VoAAPPS = models.FloatField(blank=True,null=True) APwDPS = models.TextField(blank=True,null=True) VoAAPwDPS = models.FloatField(blank=True,null=True) APwCPS = models.TextField(blank=True,null=True) VoAAPwCPS = models.FloatField(blank=True,null=True) ExPPS = models.IntegerField(blank=True,null=True) VoAEPPS = models.FloatField(blank=True,null=True) EPwCPS = models.IntegerField(blank=True,null=True) VoEPwCPS = models.FloatField(blank=True,null=True) EPwDPS = models.IntegerField(blank=True,null=True) VoEPwDPS = models.FloatField(blank=True,null=True) poAMOBEP = models.TextField(blank=True,null=True)
  • 27. PyConCZ’16 UH. END. 27 # 57 - 63 APADtIF = models.TextField(blank=True,null=True) LABSE = models.CharField(max_length=200,blank=True,null=True) LPCaSS = models.IntegerField(blank=True,null=True) LPCaSE = models.IntegerField(blank=True,null=True) PADaPS = models.IntegerField(blank=True,null=True) LTaSP = models.IntegerField(blank=True,null=True) SPDO = models.IntegerField(blank=True,null=True)
  • 28. PyConCZ’16 Overloaded database with big inserts Drastic decrease of response time Service was unusable Drastic decrease of active users 28 PROBLEM
  • 29. PyConCZ’16 29 HOTFIX def receive_session_stats(request): [...] session = SessionData() session.player = stats # 1 - 5 session.start = data.get("1",0) session.end = data.get("2",0) [...] session.save() return HttpResponse() def receive_session_stats(request): return HttpResponse()
  • 30. PyConCZ’16 class NewSessionData(models.Model): player = models.ForeignKey(PlayerStats) data = models.TextField() ➤ Gather lots and lots of stats from mobile app ➤ Store them locally for short period of time ➤ Export them to BigTable ➤ Make it readable via Django 30 LONG TERM SOLUTION
  • 32. PyConCZ’16 ➤ Is awesome! ➤ Is easy to use, powerful and generally great ➤ Is dangerous! ➤ It makes it very easy to forget about performance ➤ Is magical ➤ You don’t see queries that are generated ➤ Those queries might be not optimal 32 DJANGO ORM
  • 33. PyConCZ’16 33 DJANGO ORM class Author(models.Model): first_name = models.CharField(max_length=64) last_name = models.CharField(max_length=128) class Book(models.Model): title = models.CharField(max_length=128) author = models.ForeignKey(Author) pages = models.IntegerField() def get_books_by_size(request, pages_min, pages_max): books = Book.objects .filter(pages__gte=pages_min, pages__lte=pages_max) return JsonResponse({ "books": [{ "id": book.id, "title": book.title, "pages": book.pages, "author": { "id": book.author.pk, "last_name": book.author.last_name, } } for book in books] })
  • 34. PyConCZ’16 34 DJANGO ORM class Book(models.Model): title = models.CharField(max_length=128) author = models.ForeignKey(Author) pages = models.IntegerField() def get_books_by_size(request, pages_min, pages_max): books = Book.objects .filter(pages__gte=pages_min, pages__lte=pages_max) return JsonResponse({ "books": [{ "id": book.id, "title": book.title, "pages": book.pages, "author": { "id": book.author.pk, "last_name": book.author.last_name, } } for book in books] })
  • 35. PyConCZ’16 35 DJANGO ORM class Book(models.Model): title = models.CharField(max_length=128) author = models.ForeignKey(Author) pages = models.IntegerField() def get_books_by_size(request, pages_min, pages_max): books = Book.objects .filter(pages__gte=pages_min, pages__lte=pages_max) return JsonResponse({ "books": [{ "id": book.id, "title": book.title, "pages": book.pages, "author": { "id": book.author.pk, "last_name": book.author.last_name, } } for book in books] })
  • 36. PyConCZ’16 36 DJANGO ORM class Book(models.Model): title = models.CharField(max_length=128) author = models.ForeignKey(Author) pages = models.IntegerField(db_index=True) def get_books_by_size(request, pages_min, pages_max): books = Book.objects .filter(pages__gte=pages_min, pages__lte=pages_max) return JsonResponse({ "books": [{ "id": book.id, "title": book.title, "pages": book.pages, "author": { "id": book.author.pk, "last_name": book.author.last_name, } } for book in books] })
  • 37. PyConCZ’16 37 DJANGO ORM class Book(models.Model): title = models.CharField(max_length=128) author = models.ForeignKey(Author) pages = models.IntegerField(db_index=True) def get_books_by_size(request, pages_min, pages_max): books = Book.objects .filter(pages__gte=pages_min, pages__lte=pages_max) return JsonResponse({ "books": [{ "id": book.id, "title": book.title, "pages": book.pages, "author": { "id": book.author.pk, "last_name": book.author.last_name, } } for book in books] })
  • 38. PyConCZ’16 38 DJANGO ORM class Book(models.Model): title = models.CharField(max_length=128) author = models.ForeignKey(Author) pages = models.IntegerField(db_index=True) def get_books_by_size(request, pages_min, pages_max): books = Book.objects .select_related('author') .filter(pages__gte=pages_min, pages__lte=pages_max) return JsonResponse({ "books": [{ "id": book.id, "title": book.title, "pages": book.pages, "author": { "id": book.author.pk, "last_name": book.author.last_name, } } for book in books] })
  • 41. PyConCZ’16 ➤ Inside job ➤ You must ➤ Have a deep understanding of system ➤ Set up internal monitoring software on your system ➤ Without it, you just monitor average response time 41 BEFORE YOU BEGIN
  • 42. PyConCZ’16 ➤ Application monitoring ➤ Availability monitoring ➤ Error reporting ➤ SLA calculator ➤ Integrates with your app via agent ➤ Works very well with Python 42 NEW RELIC
  • 46. PyConCZ’16 ➤ Custom breakdown segments available. 46 EVEN MORE DETAILED BREAKDOWN
  • 47. PyConCZ’16 ➤ Good to know ➤ Helps with maintenance planning 47 REQUESTS PER MINUTE
  • 52. PyConCZ’16 ➤ part of Apache Server ➤ ab -n 100 -c 10 http://hit--me.herokuapp.com/100ms ➤ -n <= total number of requests to be made ➤ -c <= maximum concurrency level 52 APACHE BENCH
  • 56. PyConCZ’16 JMETER 56 ➤ Pros: ➤ very powerful load testing tool ➤ tests can be imported to some cloud services ➤ load tests almost everything ➤ Cons: ➤ Complicated ➤ Big entry threshold
  • 64. PyConCZ’16 ➤ Pros: ➤ Can test exactly what you need ➤ Cons: ➤ Possible re-inventing a wheel ➤ Who said your testing script is optimal… :) 64 CUSTOM SCRIPT
  • 66. PyConCZ’16 ➤ locust.io ➤ Python based, using gevent ➤ Well documented ➤ Load testing as Python code ➤ Distributed tests support
 
 ➤ Small problem: Python 2 only 66 LOCUST
  • 67. PyConCZ’16 67 LOCUST from locust import HttpLocust, TaskSet, task class HitMeTasks(TaskSet): @task(3) def index(self): self.client.get("/") @task(10) def test100ms(self): self.client.get("/100ms") class HitMeLocust(HttpLocust): host = "http://hit--me.herokuapp.com" task_set = HitMeTasks min_wait = 100 max_wait = 100
  • 72. PyConCZ’16 ➤ Load Testing as a Service: ➤ loader.io ➤ blazemeter.io ➤ loadimpact.com ➤ and-so-on.com ➤ Server ownership verification ➤ Generally easy to use
 72 CLOUD
  • 73. PyConCZ’16 ➤ Distributed ➤ API available ➤ Email results ➤ Free plan ➤ 1 host ➤ 10,000 users ➤ 2 endpoints ➤ 1 minute test 73 LOADER.IO ➤ Pro plan ➤ ∞ hosts ➤ 100,000 users ➤ 10 endpoints ➤ 10 minutes tests
  • 79. PyConCZ’16 ➤ Include Load Testing into your workflow ➤ No magic formula, adopt solution to problem ➤ Be rational ➤ Don’t be afraid to break your system! ➤ Don’t Load Test your production! ➤ Don’t “Load Test” other servers!! 79 FINAL THOUGHTS