44
S CALABLE W EB A PPLICATION A RCHITECTURE ( USING D JANGO + E XT JS) Michał Karzyński, PyWaw #27

Scalable web application architecture

Embed Size (px)

DESCRIPTION

Talk describing a web application architecture based on Django and ExtJS. Presentation focuses on code organisation, deployment and scaling.

Citation preview

Page 1: Scalable web application architecture

SCALABLE WEB APPLICATION ARCHITECTURE

(USING DJANGO + EXTJS)

Michał Karzyński, PyWaw #27

Page 2: Scalable web application architecture

TALK OUTLINE

1. Application architecture

2. Backend code organization (Django)

3. Frontend code organization (ExtJS)

4. Communication APIs

5. Deployment and Scaling

Page 3: Scalable web application architecture

YOURS TRULYMichał Karzyński

• project manager at Politechnika Gdańska

• freelance developer and consultant

• polyglot, currently: Python and JavaScript

• web developer since 1996

• @postrational

• http://michal.karzynski.pl

Page 4: Scalable web application architecture

APPLICATION ARCHITECTURE

Backend API Frontend

Server Cloud Browser

Python JSON JavaScript

Django ExtJS

I/O GUITransport

Page 5: Scalable web application architecture

BACKEND (DJANGO)CODE STRUCTURE

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

HTTP Request

HTTP Response

Model (ORM)

Page 6: Scalable web application architecture

MIDDLEWARE

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

• Processes incoming requests and outgoing responses

• Hooks in before or after the controller function

• e.g. SessionMiddleware, CacheMiddleware

Page 7: Scalable web application architecture

MIDDLEWAREEXAMPLE

class SessionMiddleware(object): def process_request(self, request): engine = import_module(settings.SESSION_ENGINE) session_key = request.COOKIES.get( settings.SESSION_COOKIE_NAME, None) request.session = engine.SessionStore(session_key)

Page 8: Scalable web application architecture

ROUTER

• Maps URL patterns to controller function calls

• Uses regular expressions

• Can use positional and named parameters

• Routes with default parameter values

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

Page 9: Scalable web application architecture

ROUTEREXAMPLE

urlpatterns = patterns('myapp.views', url(r'^$', home_page), # simple pattern url(r'^admin/', include(admin.site.urls)), # pattern inclusion url(r'^item/(\w+)/(\d+)/$', display_item), # positional params url(r'^info/(?P<slug>[-\w]+)/$', display_page), # named params url(r'^info/$', display_page, { 'slug' : 'index' }), # default value)

Page 10: Scalable web application architecture

DECORATORS

• Wrap controller functions in additional logic

• Can modify request object or cause a redirect

• e.g. login_required, permission_required, cache_page

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

Page 11: Scalable web application architecture

CONTROLLER (VIEW)

• Main application logic

• Functions receive an HTTP request and returns an HTTP response

• Communicates with the model layer, session store, etc.

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

Page 12: Scalable web application architecture

CONTROLLER (VIEW)EXAMPLE

def display_institute(request, id): institute = get_object_or_404(Institute, pk=safeint(id))

return render_to_response('institute_display.html', { 'institute' : institute })

Page 13: Scalable web application architecture

CONTROLLER (VIEW)EXAMPLE

def save_offer(self, request): form_data = json_deserialize(request.read())

# Validate incoming offer data offer_form = OfferForm(form_data) validation_errors = offer_form.errors

if not validation_errors: offer = offer_form.save() response = { 'success' : True, 'offer_url' : offer.get_absolute_url() }

if validation_errors: for key in validation_errors.keys(): validation_errors[key] = " ".join(validation_errors[key]) response = { 'success' : False, 'errors' : validation_errors }

return HttpResponse(json_serialize(response), mimetype='application/json')

Page 14: Scalable web application architecture

MODEL (ORM)

• Database abstraction layer

• Converts DB rows into Python objects

• Generates DB structure and lazy-loading SQL queries

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

Page 15: Scalable web application architecture

MODEL (ORM)EXAMPLE

class Person(models.Model): first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) email = models.EmailField(_('email address'), blank=True)

def get_full_name(self): """ Returns the first_name plus the last_name, with a space in between. """ full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip()

Offer.objects.filter(deadline__date__gte=datetime.date.today())\ .distinct().annotate(closest_deadline=Min('deadline__date'))\ .order_by('closest_deadline').select_related()

Page 16: Scalable web application architecture

TEMPLATE

• Generate HTML

• Use Django’s templating language

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

Page 17: Scalable web application architecture

TEMPLATEEXAMPLE

{% extends "base.html" %}{% load markup_textile %}

{% block title %}{{ page.title }} {% endblock %}

{% block body %} <div class="page-header"> <h3>{{ page.title }}</h3> </div>

<div class="span7"> <p> {{ page.body|textile }} </p> </div>

{% if page.comments %} <div id="disqus_thread" class="span7"></div> {% endif %}{% endblock %}

Page 18: Scalable web application architecture

SERIALIZER

• Convert objects into strings for easy transport and data exchange

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model (ORM)

return HttpResponse(json_serialize(data), mimetype='application/json')

Page 19: Scalable web application architecture

APPLICATION ARCHITECTURE

Django ExtJS

Decorators

Router

Middleware

Controller (a.k.a View)

Template / Serializer

Middleware

Model

Controller

View

Store

Browser event

click

APIrequest

response

viewupdate

Model (ORM)

Page 20: Scalable web application architecture

FRONTEND (EXTJS)CODE STRUCTURE

Model

Controller

View

Store

HTTPrequest

HTTPresponse

event viewupdate

Page 21: Scalable web application architecture

VIEW

Model

Controller

View

Store

HTTPrequest

HTTPresponse

event viewupdate

• Sets up visible GUI widgets

• Binds collection views to data stores

Page 22: Scalable web application architecture

VIEWEXAMPLE

Ext.create('Ext.grid.Panel', { title: 'People', alias : 'widget.peoplepanel', store: Ext.data.StoreManager.lookup('peopleStore'),

columns: [ { text: 'First name', dataIndex: 'first_name' }, { text: 'Last name', dataIndex: 'last_name' }, { text: 'Email', dataIndex: 'email', flex: 1 } ], height: 200, width: 400, renderTo: Ext.getBody()});

Page 23: Scalable web application architecture

VIEWEXAMPLE

Page 24: Scalable web application architecture

CONTROLLER

• Main application logic

• Sets up event listeners

• Interacts with models

• ...or sends custom requests to the API, processes responses, updates the GUI

Model

Controller

View

Store

HTTPrequest

HTTPresponse

event viewupdate

Page 25: Scalable web application architecture

CONTROLLEREXAMPLE

Ext.define('MyApp.controller.People', { extend:'Ext.app.Controller',

init: function() { this.control({ 'peoplepanel':{ itemclick : this.onPersonClicked } }); },

onPersonClicked: function(view, record, item, index, e, eOpts){ console.log('Person item clicked:' record.get('firstName')); record.set('was_clicked', true); record.save(); }});

Page 26: Scalable web application architecture

MODEL

• Represents API data as JavaScript objects

• Client-side representation of server-side models

• Performs data validation

Model

Controller

View

Store

HTTPrequest

HTTPresponse

event viewupdate

Page 27: Scalable web application architecture

MODELEXAMPLE

Ext.define('Person', { extend: 'Ext.data.Model', idProperty: 'id', fields: [ {name: 'id', type: 'int'}, {name: 'first_name', type: 'string'}, {name: 'last_name', type: 'string'}, {name: 'age', type: 'int'}, {name: 'was_clicked',type: 'bool'} ], get_full_name: function() { return this.get('first_name') + ' ' + this.get('last_name'); } });

Page 28: Scalable web application architecture

STORE

• Communicates with the API

• Enables UI data binding

• Converts API responses to instances of models

Model

Controller

View

Store

HTTPrequest

HTTPresponse

event viewupdate

Page 29: Scalable web application architecture

STOREEXAMPLE

Ext.define('MyApp.store.Persons',{ extend : 'Ext.data.Store', storeId:'peopleStore', model: 'MyApp.model.Person' proxy: { type: 'ajax', api: { create : '/api/person/new', read : '/api/person/load', update : '/api/person/update', destroy : '/api/person/destroy' }, reader: { type: 'json', root: 'person', successProperty: 'success' } }});

Page 30: Scalable web application architecture

HTTP API DESIGN

headers

body

method URL

headers

body

status

HTTP request HTTP response

CookiesUser-agent

Language prefs

GET, POST, PUT, DELETE, etc.

protocol, host port, resource, GET params

uploaded files, JSON data, etc.

CookiesCache-control

200, 302, 404, 500, etc.

HTML, JSON, binary data. etc.

Page 31: Scalable web application architecture

TRADITIONAL HTTP

request response

headers

URLGET

headers

HTML

200

Page 32: Scalable web application architecture

AJAXIFIED WEBSITE

request response

headers

POSTparameters

POST URL

headers

partial HTML

200

Page 33: Scalable web application architecture

REST

request response

Resource GET PUT POST DELETE

Collection URI List elements Replace collection Create element Delete collection

Element URI Retrieve element Replace or create Delete element

headers

objectJSON

method resource

headers

objectJSON

200, 201, 400, 409, etc.

Page 34: Scalable web application architecture

SOAP / JSON-RPCREMOTE PROCEDURE CALL

request response

headers

method-calland parameters

in an XML or JSONenvelope

POST API endpoint

headers

method responseobject

in an XML or JSONenvelope

200

Page 35: Scalable web application architecture

EXTJS-STYLE API

request response

headers

functionarguments

JSON

method function URI

headers

responseobjectJSON

200

Page 36: Scalable web application architecture

Demo

Page 37: Scalable web application architecture

READY... SET... DEPLOY!!!

Gunicorn

Nginx

Django

PostgreSQL

Virtualenv

Page 38: Scalable web application architecture

SCALING

Step 1: Optimize your code

• optimize number of DB queries

• rewrite slower ORM queries as native SQL (stored procedures)

• use cacheing

Gunicorn

Nginx

Django

PostgreSQL

Virtualenv

Page 39: Scalable web application architecture

SCALING

Step 2: Add Redis

• in memory key-value store

• as session store

• as cache backend

Gunicorn

Nginx

Django

Redis

PostgreSQL

Virtualenv

Page 40: Scalable web application architecture

SCALING

Step 3: Add Varnish

• in-memory cache

• speed up serving static files

Gunicorn

Nginx

Django

Redis

PostgreSQL

Virtualenv

Varnish

Page 41: Scalable web application architecture

SCALING

Step 4:

Split up your servers

Gunicorn

Nginx

Django

Virtualenv

Varnish

Nginx

Static files

Varnish

PostgreSQLRedis

Backend

Frontend

DBCache

Page 42: Scalable web application architecture

SCALINGStep 5:

Clusters

PostgreSQL

Redis

App-node cluster

DB ClusterRedis cluster(coming soon)

Gunicorn

Nginx

Django

Virtualenv

Varnish

Gunicorn

Nginx

Django

Virtualenv

Nginx

Static files

Varnish

Nginx

Static files

Static files clusteror use a CDN

Redis

PostgreSQL

Page 43: Scalable web application architecture

Thank youhttp://michal.karzynski.pl

Page 44: Scalable web application architecture