When dynamic becomes static

Post on 15-Jul-2015

164 views 0 download

transcript

When dynamic becomes static(the next step in web caching techniques)

Wim GoddenCu.be Solutions

@wimgtr

Who am I ?

Wim Godden (@wimgtr)

Where I'm from

Where I'm from

Where I'm from

Where I'm from

Where I'm from

Where I'm from

My town

My town

Belgium – the traffic

Who am I ?

Wim Godden (@wimgtr)

Founder of Cu.be Solutions (http://cu.be)

Open Source developer since 1997

Developer of OpenX, PHPCompatibility, PHPConsistent, ...

Speaker at Open Source conferences

Who are you ?

Developers ?

System/network engineers ?

Managers ?

Quick note

Whenever you see

feel free to think

To understand the present

Understand the past

The Stone Age

New blog post by : caveman003

Pre-dynamic : draw it and make html

The Egyptian Era

Old-school dynamic : 'rebuild-every-time'

The Industrial Revolution

Dynamic : let's cache

Extra ! Extra !

Dynamic content in static content

The Modern Era

More load, more webservers

Pushing updates to cache

Today

Adding reverse proxy caching

Typical website structure

Article content page

Page content

Header

Latest news

Navigation

Caching blocks with individual TTLs

Article content page

Page content

Top header(TTL = 2h)

Latest news

Navigation(TTL = 1h)

Caching blocks with individual TTLs

Article content page

Page content (TTL = 30m)

Top header(TTL = 2h)

Latest news (TTL = 2m)

Navigation(TTL = 1h)

ESI – how it works

GET /pageGET /page

ESI – how it works

<html>...<esi:include src="/top"/><esi:include src="/nav"/><div id=”something”> <esi:include src="/latest-news"/></div><esi:include src="/article/id/732"/>...</html>

GET /pageGET /page

ESI – how it works

<div id=”top-part”> <a href=”/login”>Login</a></div>

GET /top

ESI – how it works

<html>...<esi:include src="/top"/><esi:include src="/nav"/><div id=”something”> <esi:include src="/latest-news"/></div><esi:include src="/article/id/732"/>...</html>

GET /pageGET /page

ESI – how it works

<html>...<div id=”top-part”> <a href=”/login”>Login</a></div><esi:include src="/nav"/><div id=”something”> <esi:include src="/latest-news"/></div><esi:include src="/article/id/732"/>...</html>

GET /pageGET /page

Varnish - what can/can't be cached ?

Can :Static pages

Images, js, css

Static parts of pages that don't change often (ESI)

Can't :POST requests

Very large files (it's not a file server !)

Requests with Set-Cookie

User-specific content

ESI → no caching on user-specific content ?

Logged in as : Wim Godden

5 messages

TTL = 5minTTL=1h

TTL = 0s ?

Error... does not compute !

The semi-functional Varnish way

Use VCL to attach session id or UUID to cache entriesif( req.http.Cookie ~ "myapp_unique_user_id" ) {

set req.http.X-Varnish-Hashed-On =

regsub( req.http.Cookie, "^.*?

myapp_unique_user_id=([^;]*);*.*$", "\1" );

}

Painful, messy configuration

Inefficient and messy way to update data

POST /sendmessagePOST /sendmessage

PURGE /top?UUID

GET /page GET /top?UUID

DB

The almost functional Varnish way

Varnish module : VMOD-Memcached

Connects Varnish directly to Memcached

Advantage :It works

It will speed a few things up

Disadvantage :A pain to set up

No plug&play → DIY !

Only works on info stored in session

Back in 2010

Avoid hitting the backend

GET /page

DB

No more backend

GET /page+ SLIC

Requesting /page (1st time)

Nginx

Shared memory

1

2

3

4

/page

/page

<html>...<slic:include src="/top" key=”top” session=”true”/><slic:include src="/nav" key=”nav”/><slic:include src="/article/id/732" key=”article732”/>...</html>

Requesting /page SLIC subrequests (1st time)

Nginx1

2

3/nav/article732/top (in SLIC session)

/nav/article/id/732/top (with session cookie)

Requesting /page (next time)

Nginx

Shared memory1

2

/page/nav/article732/top (in SLIC session)

/page

SLIC on Nginx

<slic:include key="article732" src="/article/732" /><slic:includekey="nav"src="/nav" />

<slic:include key="top" src="/top" session="true" />Logged in as : Wim Godden

5 messages ???

New message is sent...

POST /send

DB

insert i

nto... set(...)

top (in SLIC session)

Advantages

No repeated GET hits to webserver anymore !At login : POST → warm up the cache !

No repeated hits for user-specific content

Not even for non-specific content

News added

addnews() method

DB

insert i

nto... set(...)

Memcache key /news

First release : ESI

Part of the ESI 1.0 spec

Only relevant features implemented

Extension for dynamic session support

But : unavailable for copyright reasons

Rebuilt from scratch : SLIC

Control structures : if/else, switch/case, foreach

Variable handling

Strings : concatenation, substring, …

Exception handling, header manipulation, …

JSON support !

SLIC code samples

You are logged in as : <slic:session_var("person_name") />

SLIC code samples

<slic:switch var="session_var('isAdmin')">

<slic:case value="1"> <slic:include key="admin-buttons" src="/admin-buttons.php" /> </slic:case>

<slic:default> <div id="just-a-user"> <slic:include key="user-buttons" src="/user-buttons.php" /> </div> </slic:default>

</slic:switch>

SLIC code samples

<slic:foreach item="messageId" src="global_var('thread' + query_var('threadId'))">

<slic:include key="'thread-message_' + messageId" src="'/thread/message.php?id=' + messageId" />

</slic:foreach>

Approaches – full block

<p id=”LoggedInAs”> You are logged in as : Wim Godden</p><p id=”MessageCount”> 5 messages</p>

Logged in as : Wim Godden

5 messages

top_432

Approaches – individual variables

<p id=”LoggedInAs”> You are logged in as : <slic:session_var("person_name") /></p><p id=”MessageCount”> <slic:session_var(“messages”) /> messages</p>

Logged in as : Wim Godden

5 messages

Approaches – JSON

<p id=”LoggedInAs”> You are logged in as : <slic:session_var("userData").person_name /></p><p id=”MessageCount”> <slic:session_var(“userData”).message_count /> messages</p>

Logged in as : Wim Godden

5 messages

Identifying the user

In Nginx configuration :slic_session_cookie <name> → Defined by language (or configurable)

slic_session_identifier <string> → Defined by you

Example for PHP :slic_session_cookie PHPSESSID

slic_session_identifier UserID

Identifying the user

Nginx + SLIC

Cookie :PHPSESSID =jpsidc1po35sq9q3og4f3hi6e2

get UserID_jpsidc1po35sq9q3og4f3hi6e2432

Retrieving user specific content

Nginx + SLIC

get userData_432

Cookie :PHPSESSID =jpsidc1po35sq9q3og4f3hi6e2

What's the result ?

Figures

2nd customer :No. of web servers : 72 → 8

No. of db servers : 15 → 4

Total : 87 → 12 (86% reduction !)

Last customer :No. of total servers : +/- 1350

Expected reduction : 1350 → 380

Expected savings : €1.5 Million per year

Why is it so much faster ?

Code changes

Required

Template conversion

Push-to-DB → Push-to-DB + Push-to-Cache

Choice :If user is logged in → push updates to cache

If user is not logged in → warm up cache on login

Availability

Good news :The concept is solid : ESI version stable at 4 customers

Open Source

Bad news :First customer holds copyrights

Total rebuild

March : v0.1 (include, variable handling, …)

Final release : Q2-3 2015 (?)

Site : http://slic.cu.be

Code : Github

Some technical details

Written in Lua (with LuaJIT)Each SLIC:include is a subrequest

Groups cache key requests together for multiget

Shares cache results across all subrequests

Template compilation (!!)

Memcached implemented

Redis and others in the pipeline

Not RFC compliant yet

Unit tested

Future (1.0 or beyond) :Translation functionality

...

So...

Questions ?

Questions ?

Thanks !

@wimgtr

wim@cu.be

Please provide some feedback : http://joind.in/13203