Date post: | 15-Jul-2015 |
Category: |
Documents |
Upload: | wim-godden |
View: | 164 times |
Download: | 0 times |
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 ?