Although tools like Varnish can improve performance and scalability for static sites, when user-specific content is needed, a hit to the PHP/Ruby/Python/.Net backend is still required, causing scalability issues. We’ll look at a brand-new Nginx module which implements an ultra-fast and scalable solution to this problem, changing the way developers think about designing sites with user-specific content.
Developer Data Modeling Mistakes: From Postgres to NoSQL
When dynamic becomes static : the next step in web caching techniques
1. When dynamic becomes static
(the next step in web caching techniques)
Wim Godden
Cu.be Solutions
@wimgtr
2. Disclaimer
The next step
As in : what you will be doing in the future
Not as in : go home and run it ;-)
Language of choice : PHP
But : think Perl, Python, Ruby, Java, .Net, …
13. 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
14. Who are you ?
Developers ?
System/network engineers ?
Managers ?
33. ESI – how it works
GET /page GET /page
<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>
34. ESI – how it works
GET /top
<div id=”top-part”>
<a href=”/login”>Login</a>
</div>
35. ESI – how it works
GET /page GET /page
<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>
36. ESI – how it works
GET /page GET /page
<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>
37. 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
38. ESI → no caching on user-specific content ?
Logged in as : Wim Godden
5 messages
TTL = 0s ?
TTL=1h TTL = 5min
50. SLIC on Nginx
<slic:include key="top" src="/top" session="true" />
<slic:include key="news" src="/news" />
<slic:include
key="menu"
src="/menu" />
Logged in as : Wim Godden
5 messages ???
51. New message is sent...
POST /send
DB
insert into...
set(...)
top (in SLIC session)
52. 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
54. How many Memcached requests ?
Logged in as : Wim Godden
5 messages
<slic:include key="top" src="/top" session="true" />
<slic:include key="news" src="/news" />
<slic:include
key="menu"
src="/menu" />
55. First release : ESI
Part of the ESI 1.0 spec
Only relevant features implemented
Extension for dynamic session support
But : unavailable for copyright reasons
56. Rebuilt from scratch : SLIC
Control structures : if/else, switch/case, foreach
Variable handling
Strings : concatenation, substring, …
Exception handling, header manipulation, …
JSON support !
57. SLIC code samples
You are logged in as : <slic:session_var("person_name") />
You are logged in as : <@s("person_name") />
60. Approaches – full block
Logged in as : Wim Godden
<p id=”LoggedInAs”>
You are logged in as : <slic:session_var("person_name") />
</p>
<p id=”MessageCount”>
You have 5 messages
</p>
5 messages
<slic:include key="top" src="/top" session="true" />
top_31
61. Approaches – individual variables
Logged in as : Wim Godden
<p id=”LoggedInAs”>
You are logged in as : <slic:session_var("person_name") />
</p>
<p id=”MessageCount”>
You have <slic:session_var(“messages”) /> messages
</p>
5 messages
<slic:include key="top" src="/top" session="true" />
62. Approaches – JSON
Logged in as : Wim Godden
5 messages
<slic:include key="top" src="/top" session="true" />
<p id=”LoggedInAs”>
You are logged in as : <slic:session_var("userData").person_name />
</p>
<p id=”MessageCount”>
You have <slic:session_var(“userData”).message_count /> messages
</p>
63. 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
64. Identifying the user
Cookie :
PHPSESSID =
jpsidc1po35sq9q3og4f3hi6e2
Nginx + SLIC
4g3e2t UserID_jpsidc1po35sq9q3og4f3hi6e2
65. Retrieving user specific content
Nginx + SLIC
get userData_432
Cookie :
PHPSESSID =
jpsidc1po35sq9q3og4f3hi6e2
66. Why Nginx ?
Native Memcached support
Excellent and superfast subrequest system
Including parallel subrequests
Handles thousands of connections per worker
With minimal memory footprint
Integrates with php-fpm
Additional features (chroot, slow request log, offline processing, ...)
Graceful rolling upgrades
68. 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
71. A real example : vBulletin
Post
isAdmin session variable
isModerator session variable
72. A real example : vBulletin
DB Server Load Web Server Load Max Requests/sec (1 = 282)
35
30
25
20
15
10
5
0
Standard install
With Memcached
Nginx + SCL + memcached
73. 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
74. Availability
Good news :
It will become Open Source
The concept is solid : ESI version stable at 4 customers
Bad news :
First customer holds copyrights
Total rebuild
→ Open Source release
No current projects, so spare time
Anyone feel like sponsoring ?
Beta : October !
Stable : January