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.
Tata AIG General Insurance Company - Insurer Innovation Award 2024
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
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, ...
Speaker at PHP and Open Source conferences
14. Who are you ?
Developers ?
System/network engineers ?
Managers ?
33. 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
34. ESI – how it works
<div id=”top-part”>
<a href=”/login”>Login</a>
</div>
GET /top
35. 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
36. 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
39. 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
40. ESI → no caching on user-specific content ?
Logged in as : Wim Godden
5 messages
TTL = 5minTTL=1h
TTL = 0s ?
48. New message is sent...
POST /send
DB
insert into...
set(...)
top (in SLIC session)
49. 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
51. 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
No TTLs for non-specific content
52. How many Memcached requests ?
Logged in as : Wim Godden
5 messages
<slic:include key="news" src="/news" />
<slic:include
key="menu"
src="/menu" />
<slic:include key="top" src="/top" session="true" />
53. First release : ESI
Part of the ESI 1.0 spec
Only relevant features implemented
Extension for dynamic session support
But : unavailable for copyright reasons
54. Rebuilt from scratch : SLIC
Control structures : if/else, switch/case, foreach
Variable handling
Strings : concatenation, substring, …
Exception handling, header manipulation, …
JSON support !
55. SLIC code samples
You are logged in as : <slic:session_var("person_name") />
You are logged in as : <@s("person_name") />
58. Approaches – full block
<p id=”LoggedInAs”>
You are logged in as : <slic:session_var("person_name") />
</p>
<p id=”MessageCount”>
You have 5 messages
</p>
Logged in as : Wim Godden
5 messages
<slic:include key="top" src="/top" session="true" />
59. Approaches – individual variables
<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>
Logged in as : Wim Godden
5 messages
<slic:include key="top" src="/top" session="true" />
60. Approaches – JSON
<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>
Logged in as : Wim Godden
5 messages
<slic:include key="top" src="/top" session="true" />
61. 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 UID
62. Identifying the user
Nginx + SLIC
Cookie :
PHPSESSID =
jpsidc1po35sq9q3og4f3hi6e2
get UID_jpsidc1po35sq9q3og4f3hi6e2432
63. Retrieving user specific content
Nginx + SLIC
Cookie :
PHPSESSID =
jpsidc1po35sq9q3og4f3hi6e2
get userData_432
64. 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
66. 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
69. A real example : vBulletin
Post
isModerator session variable
isAdmin session variable
70. A real example : vBulletin
DB Server Load Web Server Load Max Requests/sec (1 = 282)
0
5
10
15
20
25
30
35
Standard install
With Memcached
Nginx + SCL + memcached
72. Availability
Good news :
It will become Open Source
It's solid : ESI version stable at 4 customers
PHP version (currently for dev, later for docs and learning)
Bad news :
First customer holds copyrights
Total rebuild
→ Open Source release
No current projects, so spare time
Anyone feel like sponsoring ?
Beta : Aug 14 (?)
Stable : Oct 14 (?) - on Github