Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Caching and tuning fun for high scalability @ phpBenelux 2011

17,010 views

Published on

Slides for "Caching and Tuning fun for high scalability" talk, given @ phpBenelux Conference - Jan 28, 2011

Note that a lot of things were explained with each slide... that content is ofcourse not in the slides, so it might make some slides very unclear.

Published in: Technology
  • excellent information.
    Thank you very much
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • thank you very much, offline reading isbeautiful :)
    really good information.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Check out the FrOScon version of the presentation, which is nearly identical. It has a download option : http://www.slideshare.net/wimg/caching-and-tuning-fun-for-high-scalability-froscon-2011-8977796
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • any chance to get a download option?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Caching and tuning fun for high scalability @ phpBenelux 2011

  1. 1. Caching and tuning fun for high scalability Wim Godden Cu.be Solutions Conference Jan 28, 2011
  2. 2. Who am I ? <ul><li>Wim Godden
  3. 3. Owner of Cu.be Solutions (http://cu.be)
  4. 4. PHP developer since 1997
  5. 5. Developer of OpenX
  6. 6. Zend Certified Engineer
  7. 7. Zend Framework Certified Engineer
  8. 8. MySQL Certified Developer </li></ul>
  9. 9. Who are you ? <ul><li>Developers ?
  10. 10. System/network engineers ?
  11. 11. Managers ?
  12. 12. Caching experience ? </li></ul>
  13. 13. Caching and tuning fun for high scalability Wim Godden Cu.be Solutions Conference Jan 28, 2011
  14. 14. Goals of this tutorial <ul><li>Everything about caching and tuning
  15. 15. A few techniques
  16. 16. -> Increase reliability, performance and scalability
  17. 17. 5 visitors/day -> 5 million visitors/day
  18. 18. (Don't expect miracle cure !) </li></ul>
  19. 19. Goals of this tutorial <ul><li>Concepts & techniques
  20. 20. How to do stuff
  21. 21. How NOT to do stuff </li></ul>
  22. 22. LAMP
  23. 23. LAMP
  24. 24. LAMP
  25. 25. LAMP
  26. 26. Architecture
  27. 27. Caching
  28. 28. What's caching ?
  29. 29. What is caching ? select * from article join user on article.user_id = user.id order by created desc limit 10
  30. 30. Caching goals - 1 st goal <ul><li>Reduce # of request
  31. 31. Reduce the load </li></ul>
  32. 32. Caching goals - 2 nd goal
  33. 33. Some figures <ul><li>Pageviews : 5000 (4000 on 10 pages)
  34. 34. Avg. loading time : 200ms
  35. 35. Cache 10 pages
  36. 36. Avg. loading time : 20ms
  37. 37. -> Total avg. loading time : 56ms
  38. 38. Worth it ? </li></ul>
  39. 39. Caching goals - 3 rd goal <ul>Send less data across the network / Internet <li>You benefit -> lower bill from upstream provider
  40. 40. Users benefit -> faster page load
  41. 41. Wait a second... that's mostly frontend stuff ! </li></ul>
  42. 42. Theory of caching DB
  43. 43. Theory of caching DB
  44. 44. Caching techniques <ul>#1 : Store entire pages <li>Company Websites
  45. 45. Blogs
  46. 46. Full pages that don't change
  47. 47. Render -> Store in cache -> retrieve from cache </li></ul>
  48. 48. Caching techniques <ul>#1 : Store entire pages </ul>
  49. 49. Caching techniques <ul>#2 : Store parts of a page <li>Most common technique
  50. 50. Usually a small block in a page
  51. 51. Best effect : reused on lots of pages
  52. 52. Can be inserted on dynamic pages </li></ul>
  53. 53. Caching techniques <ul>#2 : Store parts of a page </ul>
  54. 54. Caching techniques <ul>#3 : Store SQL queries <li>↔ SQL query cache </li><ul><ul><li>Limited in size </li></ul></ul></ul>
  55. 55. Caching techniques <ul>#3 : Store SQL queries <li>↔ SQL query cache </li><ul><ul><li>Limited in size
  56. 56. Resets on every insert/update/delete
  57. 57. Server and connection overhead </li></ul></ul><li>Goal : </li><ul><li>not to get rid of DB
  58. 58. free up DB resources for more hits ! </li></ul><li>Better : </li><ul><li>store returned object
  59. 59. store group of objects </li></ul></ul>
  60. 60. Caching techniques <ul>#3 : Store SQL queries </ul>
  61. 61. Caching techniques <ul>#4 : Store complex PHP results <li>Not just calculations
  62. 62. CPU intensive tasks : </li><ul><li>Config file parsing
  63. 63. XML file parsing
  64. 64. Loading CSV in an array </li></ul><li>Save resources -> more resources available </li></ul>
  65. 65. Caching techniques <ul>#4 : Store complex PHP results </ul>
  66. 66. Caching techniques <ul>#xx : Your call Only limited by your imagination ! When you have data, think : <li>Creating time ?
  67. 67. Modification frequency ?
  68. 68. Retrieval frequency ? </li></ul>
  69. 69. How to find cacheable data <ul><li>New projects : start from 'cache anything'
  70. 70. Existing projects : </li><ul><li>Look at MySQL slow query log
  71. 71. Make a complete query log (don't forget to turn it off !)
  72. 72. Check page loading times </li></ul></ul>
  73. 73. Caching storage - MySQL query cache <ul><li>Use it
  74. 74. Don't rely on it
  75. 75. Good if you have : </li><ul><li>lots of reads
  76. 76. few different queries </li></ul><li>Bad if you have : </li><ul><li>lots of insert/update/delete
  77. 77. lots of different queries </li></ul></ul>
  78. 78. Caching storage - Database memory tables <ul><li>Tables stored in memory
  79. 79. In MySQL : memory/heap table
  80. 80. ↔ temporary table : </li><ul><li>memory tables are persistent
  81. 81. temporary tables are session-specific </li></ul><li>Faster than disk-based tables
  82. 82. Can be joined with disk-based tables
  83. 83. But : </li><ul><li>default 16MByte limit
  84. 84. master-slave = trouble
  85. 85. if you don't need join -> overhead of DB software </li></ul><li>So : don't use it unless you need to join </li></ul>
  86. 86. Caching storage - Opcode caching <ul>DO ! </ul>
  87. 87. Caching storage - Opcode caching <ul><li>APC </li><ul><li>De-facto standard
  88. 88. Will be in PHP core in 5.4 ? 5.5 ? 6.0 ?
  89. 89. PECL or packages </li></ul><li>eAccelerator
  90. 90. Zend Accelerator </li></ul>
  91. 91. Caching storage - Opcode caching <ul><li>APC </li><ul><li>De-facto standard
  92. 92. Will be in PHP core in 5.4 ? 5.5 ? 6.0 ?
  93. 93. PECL or packages </li></ul><li>eAccelerator
  94. 94. Zend Accelerator
  95. 95. X-Cache
  96. 96. WinCacheForPhp </li></ul>PHP PHP + APC PHP + eAccelerator 42.18 req/sec 206.20 req/sec 211.49 req/sec
  97. 97. Caching storage - Disk <ul><li>Data with few updates : good
  98. 98. Caching SQL queries : preferably not
  99. 99. DON'T use NFS or other network file systems </li><ul><li>especially for sessions
  100. 100. high latency
  101. 101. locking issues ! </li></ul></ul>
  102. 102. Caching storage - Memory disk (ramdisk) <ul><li>Usually faster than physical disk
  103. 103. But : OS file caching makes difference minimal </li></ul>
  104. 104. Caching storage - Disk / ramdisk <ul><li>Overhead : filesystem access
  105. 105. Limited number of files per directory </li><ul><li>-> Subdirectories </li></ul><li>Local </li><ul><li>5 Webservers -> 5 local caches
  106. 106. -> Hard to scale
  107. 107. How will you keep them synchronized ? </li><ul><li>-> Don't say NFS or rsync ! </li></ul></ul></ul>
  108. 108. Caching storage - APC variable cache <ul><li>More than an opcode cache
  109. 109. Store user data in memory
  110. 110. apc_add / apc_store to add/update
  111. 111. apc_fetch to retrieve
  112. 112. apc_delete
  113. 113. Fast -> huge performance impact </li></ul>
  114. 114. Caching storage - APC variable cache <ul><li>More than an opcode cache
  115. 115. Store user data in memory
  116. 116. apc_add / apc_store to add/update
  117. 117. apc_fetch to retrieve
  118. 118. apc_delete
  119. 119. Fast -> huge performance impact
  120. 120. Session support !
  121. 121. Downside : </li><ul><li>local storage -> hard to scale
  122. 122. restart Apache -> cache = empty </li></ul></ul>
  123. 123. Caching storage - Memcache <ul><li>Facebook, Twitter, Slashdot, … -> need we say more ?
  124. 124. Distributed memory caching system
  125. 125. Key-value storage system </li><ul><li>Keys - max. 250bytes
  126. 126. Values - max. 1Mbyte </li></ul></ul>
  127. 127. Caching storage - Memcache <ul><li>Facebook, Twitter, Slashdot, … -> need we say more ?
  128. 128. Distributed memory caching system
  129. 129. Multiple machines ↔ 1 big memory-based hash-table
  130. 130. Key-value storage system </li><ul><li>Keys - max. 250bytes
  131. 131. Values - max. 1Mbyte </li></ul><li>Extremely fast... non-blocking, UDP (!) </li></ul>
  132. 132. Memcache - where to install
  133. 133. Memcache - where to install
  134. 134. Memcache - installation & running it <ul><li>Installation </li><ul><li>Distribution package
  135. 135. PECL
  136. 136. Windows : binaries </li></ul><li>Running </li><ul><li>No config-files
  137. 137. memcached -d -m <mem> -l <ip> -p <port>
  138. 138. ex. : memcached -d -m 2048 -l 127.0.0.1 -p 11211 </li></ul></ul>
  139. 139. Caching storage - Memcache - some notes <ul><li>Not fault-tolerant </li><ul><li>Lose session data
  140. 140. Lose shopping cart data
  141. 141. ... </li></ul></ul>
  142. 142. Caching storage - Memcache - some notes <ul><li>Not fault-tolerant </li><ul><li>Lose session data
  143. 143. Lose shopping cart data
  144. 144. … </li></ul><li>Different libraries </li><ul><li>Original : libmemcache
  145. 145. New : libmemcached (consistent hashing, UDP, binary protocol, …) </li></ul><li>Firewall your Memcache port ! </li></ul>
  146. 146. Caching in PHP <?php $memcache = new Memcache(); $memcache->addServer( '172.16.0.1' , 11211); $memcache->addServer( '172.16.0.2' , 11211); $myData = $memcache->get( 'myKey' ); if ($myData === false ) { $myData = GetMyDataFromDB(); // Put it in Memcache as 'myKey', without compression, with no expiration $memcache->set( 'myKey' , $myData, false , 0); } echo $myData;
  147. 147. Where's the data ? <ul><li>Memcache client decides (!)
  148. 148. 2 hashing algorithms : </li><ul><li>Traditional </li><ul><li>Server failure -> all data must be rehashed </li></ul><li>Consistent </li><ul><li>Server failure -> 1/x of data must be rehashed (x = # of servers) </li></ul></ul><li>No replication ! </li></ul>
  149. 149. Memcache slabs <ul>(or why Memcache says it's full when it's not) <li>Multiple slabs of different sizes : </li><ul><li>Slab 1 : 400 bytes
  150. 150. Slab 2 : 480 bytes (400 * 1.2)
  151. 151. Slab 3 : 576 bytes (480 * 1.2) (and so on...) </li></ul><li>Multiplier (1.2 here) can be configured
  152. 152. Each larger slab has room for fewer items (chunks)
  153. 153. -> Store a lot of very large objects
  154. 154. -> Large slabs might be full
  155. 155. -> Rest of slabs might be free
  156. 156. -> Try to store more -> eviction of data ! </li></ul>
  157. 157. Memcache - Is it working ? <ul><li>Connect to it using telnet </li><ul><li>&quot;stats&quot; command ->
  158. 158. Use Cacti or other monitoring tools </li></ul></ul>STAT pid 2941 STAT uptime 10878 STAT time 1296074240 STAT version 1.4.5 STAT pointer_size 64 STAT rusage_user 20.089945 STAT rusage_system 58.499106 STAT curr_connections 16 STAT total_connections 276950 STAT connection_structures 96 STAT cmd_get 276931 STAT cmd_set 584148 STAT cmd_flush 0 STAT get_hits 211106 STAT get_misses 65825 STAT delete_misses 101 STAT delete_hits 276829 STAT incr_misses 0 STAT incr_hits 0 STAT decr_misses 0 STAT decr_hits 0 STAT cas_misses 0 STAT cas_hits 0 STAT cas_badval 0 STAT auth_cmds 0 STAT auth_errors 0 STAT bytes_read 613193860 STAT bytes_written 553991373 STAT limit_maxbytes 268435456 STAT accepting_conns 1 STAT listen_disabled_num 0 STAT threads 4 STAT conn_yields 0 STAT bytes 20418140 STAT curr_items 65826 STAT total_items 553856 STAT evictions 0 STAT reclaimed 0
  159. 159. Memcache - backing up
  160. 160. Memcache - deleting <?php $memcache = new Memcache(); $memcache->delete( 'myKey' ); $myData = $memcache->get( 'myKey' ); // $myData === false
  161. 161. Memcache - caching a page <?php $output = $memcache->get( 'page_' . $page_id); if ($output === false ) { ob_start(); GetMyPageInRegularWay($page_id); $output = ob_get_contents(); ob_end_clean(); $memcache->set( 'page_' . $page_id, $output, false , 600); // Cache 10 mins } echo $output;
  162. 162. Memcache - tip <ul>Page with multiple blocks ? -> use Memcached::getMulti() Warning : what if you get some hits and some misses ? </ul>
  163. 163. Naming your keys <ul><li>Key names must be unique
  164. 164. Prefix / namespace your keys !
  165. 165. Only letters, numbers and underscore
  166. 166. md5() is useful </li><ul><li>-> BUT : harder to debug </li></ul><li>Use clear names
  167. 167. Document your key names ! </li></ul>
  168. 168. Adding/updating data
  169. 169. Adding/updating data
  170. 170. Adding/updating data $memcache->delete( 'ArticleDetails__Toshiba_32C100U_32_Inch' ); $memcache->delete( 'Homepage_Popular_Product_List' );
  171. 171. Adding/updating data
  172. 172. Adding/updating data - Why it crashed
  173. 173. Adding/updating data - Why it crashed
  174. 174. Adding/updating data - Why it crashed
  175. 175. Cache stampeding
  176. 176. Cache stampeding
  177. 177. Memcache code ? DB
  178. 178. Memcache code ? DB
  179. 179. Memcache code ? DB
  180. 180. Creating cache methods static protected function getArticle ($id) { $cache = Zend_Registry:: get ( 'Zend_Cache' ); if (!$article = $cache->load( 'article_' . $id )) { $db = Zend_Registry:: get ( 'Zend_DB' ); $query = ' select article.id as art_id, article.title as art_title, article.body as art_body, date_format(article.created, &quot;%d/%m/%Y %H:%i&quot;) as art_created, user.username as use_username from article join user on article.user_id = user.id where article.id = ? ' ; $artice = $db->fetchRow($query, $id); $cache->save($articleList, 'article_' . $id ); } return $articleList; }
  181. 181. Creating cache methods static protected function getArticleUncached ($id) { $db = Zend_Registry:: get ( 'Zend_DB' ); $query = ' select article.id as art_id, article.title as art_title, article.body as art_body, date_format(article.created, &quot;%d/%m/%Y %H:%i&quot;) as art_created, user.username as use_username from article join user on article.user_id = user.id where article.id = ? ' ; return $db->fetchRow($query, $id); } static public function getArticle ($id) { if (Zend_Registry:: isRegistered ( 'Zend_Cache' )) { $cache = Zend_Registry:: get ( 'Zend_Cache' ); if (!$articleList = $cache->load( 'article_' . $id )) { $articleList = self :: getArticleUncached ($id); $cache->save($articleList, 'article_' . $id ); } } else { $articleList = self :: getArticleUncached ($id); } return $articleList; }
  182. 182. Cache stampeding - what about locking ? <ul>Seems like a nice idea, but... <li>Lock in place
  183. 183. -> lots of new connections
  184. 184. -> memory spike
  185. 185. What if the PHP process that created the lock fails ?
  186. 186. Avoids needing caching code in admin part
  187. 187. -> but what about warmup script(s) ? </li></ul>
  188. 188. Cache warmup scripts <ul><li>Used to fill your cache when it's empty
  189. 189. Run it before starting Webserver !
  190. 190. 2 ways : </li><ul><li>Visit all URLs </li><ul><li>Error-prone
  191. 191. Hard to maintain </li></ul><li>Call all cache-updating methods </li><ul><li>Means your caching code should be centralized ! </li></ul></ul><li>Make sure you have a warmup script ! </li></ul>
  192. 192. Quick word about expiration <ul><li>General rule : don't let things expire
  193. 193. Exception to the rule : things that have an end date (calendar items) </li></ul>
  194. 194. So... <ul>DON'T DELETE FROM CACHE (and don't expire unless usefull) </ul>
  195. 195. Quick-tip <ul><li>Start small -> disk or APC
  196. 196. Move to Memcache later
  197. 197. But : is your code ready ?
  198. 198. -> Use a component like Zend_Cache to switch easily ! </li></ul>
  199. 199. Time for... <ul>a break (10 min) </ul>
  200. 200. LAMP... <ul>-> LAMMP -> LANMMP </ul>
  201. 201. Nginx <ul><li>Web server
  202. 202. Reverse proxy
  203. 203. Lightweight, fast
  204. 204. 7.5% of all Websites </li></ul>
  205. 205. Nginx <ul><li>No threads, event-driven
  206. 206. Uses epoll / kqueue
  207. 207. Low memory footprint
  208. 208. 10000 active connections = normal </li></ul>
  209. 209. Nginx - a true alternative to Apache ? <ul><li>Not all Apache modules </li><ul><li>mod_auth_*
  210. 210. mod_dav*
  211. 211. … </li></ul><li>Basic modules are available
  212. 212. Some 3 rd party modules (needs recompilation !) </li></ul>
  213. 213. Nginx - Installation <ul><li>Packages
  214. 214. Win32 binaries
  215. 215. Build from source (./configure; make; make install) </li></ul>
  216. 216. Nginx - Configuration server { listen 80; server_name www.phpbenelux.eu *.phpbenelux.eu; index index.html; root /home/phpbenelux.eu/www; } server { listen 80; server_name conference.phpbenelux.eu; index index.html; root /home/phpbenelux.eu/conference; }
  217. 217. Nginx - Configuration server { listen 80; server_name www.phpbenelux.eu; root /home/phpbenelux.eu/www; location /conference { # We capture the URI and redirect it to the subdomain. rewrite conference(.*) http://conference.phpbenelux.eu$1 permanent; } }
  218. 218. Nginx - phase 1 <ul><li>Move Apache to a different port (8080)
  219. 219. Put Nginx at port 80
  220. 220. Nginx serves all statics (images, css, js, …)
  221. 221. Forward dynamic requests to Apache </li></ul>
  222. 222. Nginx - phase 1 <ul><li>Move Apache to a different port (8080)
  223. 223. Put Nginx at port 80
  224. 224. Nginx serves all statics (images, css, js, …)
  225. 225. Forward dynamic requests to Apache </li></ul>
  226. 226. Nginx for static files only server { listen 80; server_name www.phpbenelux.eu; location ~* ^.*.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|pdf|ppt|txt|tar|rtf|js)$ { expires 30d; root /home/www.phpbenelux.eu; } location / { proxy_pass http://www.phpbenelux.eu:8080; proxy_pass_header Set-Cookie; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
  227. 227. Nginx for PHP ? <ul><li>Bottleneck = PHP ? Keep it in Apache
  228. 228. Bottleneck = memory ? Go for it !
  229. 229. LANMMP to... LNMPP
  230. 230. (ok, this is getting ridiculous) </li></ul>
  231. 231. Nginx with PHP <ul><li>In the past : spawn-fcgi (from Lighttpd)
  232. 232. Now : PHP-FPM (in PHP 5.3.3 !)
  233. 233. Runs on port 9000
  234. 234. Nginx connects using fastcgi method </li></ul>location / { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_FILENAME /home/www.phpbenelux.eu/$fastcgi_script_name; fastcgi_param SERVER_NAME $host; fastcgi_intercept_errors on; }
  235. 235. Nginx with PHP <ul><li>In the past : spawn-fcgi (from Lighttpd)
  236. 236. Now : PHP-FPM (in PHP 5.3.3 !)
  237. 237. Runs on port 9000
  238. 238. Nginx connects using fastcgi method </li></ul>location / { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_NAME $fastcgi_script_name; fastcgi_param SCRIPT_FILENAME /home/www.phpbenelux.eu/$fastcgi_script_name; fastcgi_param SERVER_NAME $host; fastcgi_intercept_errors on; }
  239. 239. Nginx + PHP-FPM features <ul><li>Graceful upgrade
  240. 240. Spawn new processes under high load
  241. 241. Chroot
  242. 242. Slow request log ! </li></ul>
  243. 243. Nginx + PHP-FPM features <ul><li>Graceful upgrade
  244. 244. Spawn new processed under high load
  245. 245. Chroot
  246. 246. Slow request log !
  247. 247. fastcgi_finish_request() -> offline processing </li></ul>
  248. 248. Nginx + PHP-FPM - Downside <ul><li>PHP vs PHP-FPM = no performance difference
  249. 249. But : Apache + mod_php = faster
  250. 250. Why ? fastcgi connection overhead
  251. 251. Difference : 10-15%
  252. 252. Balance : Apache's memory overhead vs. fastcgi performance </li></ul>
  253. 253. LAMP
  254. 254. LAMP
  255. 255. Varnish <ul><li>Not just a load balancer
  256. 256. Reverse proxy cache / http accelerator / …
  257. 257. Caches (parts of) pages in memory
  258. 258. Careful : </li><ul><li>uses threads
  259. 259. Nginx might be faster (but doesn't have VCL) </li></ul></ul>
  260. 260. Varnish - Installation & configuration <ul><li>Installation </li><ul><li>Packages
  261. 261. Source : ./configure && make && make install </li></ul><li>Configuration </li><ul><li>/etc/default/varnish
  262. 262. /etc/varnish/*.vcl </li></ul></ul>
  263. 263. Varnish - backends + load balancing backend server1 { .host = &quot;192.168.0.10&quot;; } backend server2{ .host = &quot;192.168.0.11&quot;; } director example_director round-robin { { .backend = server1; } { .backend = server2; } }
  264. 264. Varnish - backends + load balancing backend server1 { .host = &quot;192.168.0.10&quot;; .probe = { .url = &quot;/&quot;; .interval = 5s; .timeout = 1 s; .window = 5; .threshold = 3; } }
  265. 265. Varnish - VCL <ul><li>Varnish Configuration Language
  266. 266. DSL (Domain Specific Language) </li><ul><li>-> compiled to C </li></ul><li>Hooks into each request
  267. 267. Defines : </li><ul><li>Backends (web servers)
  268. 268. ACLs
  269. 269. Load balancing strategy </li></ul><li>Can be reloaded while running </li></ul>
  270. 270. Varnish - whatever you want <ul><li>Extremely flexible through VCL </li><ul><li>Manipulate headers, request, response, ...
  271. 271. Introduce ACL
  272. 272. Detect flooding (& ban visitors)
  273. 273. Lots of hooks you can plug code onto </li></ul><li>Real-time statistics (varnishtop, varnishhist, ...)
  274. 274. ESI </li></ul>
  275. 275. Varnish - ESI <ul>Perfect for caching pages </ul>In your article page output : <esi:include src=&quot;/latest-news&quot;/>
  276. 276. Varnish - what can/can't be cached ? <ul><li>Can : </li><ul><li>Static pages
  277. 277. Images, js, css
  278. 278. Pages or parts of pages that don't change often (ESI) </li></ul><li>Can't : </li><ul><li>POST requests
  279. 279. Requests with Set-Cookie
  280. 280. Very large files (it's not a file server !)
  281. 281. User-specific content </li></ul></ul>
  282. 282. Varnish - want more ? <ul>-> &quot;Varnish, the high performance valhalla ?&quot; <ul>by Jeroen Van Dijck Tomorrow @ 13h40 </ul></ul>
  283. 283. Apache - tuning tips <ul><li>Disable unused modules -> fixes 10% of performance issues
  284. 284. Set AllowOverride to None . Enable only where needed !
  285. 285. Disable SymLinksIfOwnerMatch . Enable only where needed !
  286. 286. MinSpareServers, MaxSpareServers, StartServers, MaxClients, MPM selection -> a whole session of its own ;-)
  287. 287. Don't mod_proxy -> use Nginx or Varnish !
  288. 288. High load on an SSL-site ? -> put SSL on a reverse proxy </li></ul>
  289. 289. PHP speed - some tips <ul><li>Upgrade PHP - every minor release has 5-15% speed gain !
  290. 290. Profile your code </li><ul><li>XHProf
  291. 291. Xdebug </li></ul><li>But : turn off profilers on acceptance/production platforms ! </li></ul>
  292. 292. KCachegrind is your friend
  293. 293. PHP speed - some tips <ul><li>Most performance issues are in DB queries -> look there first !
  294. 294. Log PHP errors and review those logs !
  295. 295. Shorter code != faster code -> keep your code readable !
  296. 296. Hardware cost < Manpower cost </li><ul><li>-> 1 more server < 30 mandays of labor </li></ul><li>Keep micro-optimizations in code = last thing on list </li></ul>
  297. 297. DB speed - some tips <ul><li>Avoid NOW() -> use PHP date(&quot;Y-m-d&quot;) as a parameter </li><ul><li>Why ? Query cache ! </li></ul><li>Index, index, index ! (where needed only)
  298. 298. Use same types for joins </li><ul><li>i.e. don't join decimal with int </li></ul><li>RAND() is evil !
  299. 299. Select the right storage engine
  300. 300. Don't use mysql_pconnect()
  301. 301. Other tips -> see slides &quot;MySQL performance tuning&quot;
  302. 302. by Geert Vanderkelen </li></ul>
  303. 303. One more for the backend... HipHop <ul><li>Developed @ Facebook (runs 95% of servers)
  304. 304. Source code transformer
  305. 305. Converts PHP to C++
  306. 306. Compiles C++ (using g++) into binary code
  307. 307. Has a built-in Webserver
  308. 308. Not for you, unless > 1.000.000 views/day
  309. 309. Want more ? </li><ul><li>-> &quot;HipHop for PHP&quot; - Tomorrow @ 10h10 (Scott McVicar) </li></ul></ul>
  310. 310. Caching & Tuning @ frontend http://www.websiteoptimization.com/speed/tweak/average-web-page/
  311. 311. Caching in the browser <ul><li>HTTP 304 (Not modified)
  312. 312. Expires/Cache-Control header
  313. 313. 2 notes : </li><ul><li>Don't use POST if you want to cache
  314. 314. Don't cache user-specific pages in browser (security !) </li></ul></ul>
  315. 315. HTTP 304 First request Next requests
  316. 316. HTTP 304 with ETag First request Next requests
  317. 317. Expires/Cache-control header <ul>Cache-Control <ul><li>HTTP/1.1
  318. 318. Seconds to expiry
  319. 319. Used by browsers </li></ul></ul>First request Next requests No requests until item expires <ul>Expires <ul><li>HTTP/1.0
  320. 320. Date to expire on
  321. 321. Used by old proxies
  322. 322. Requires clock to be accurate ! </li></ul></ul>
  323. 323. Pragma: no-cache = evil <ul><li>&quot;Pragma: no cache&quot; doesn't make it uncacheable
  324. 324. Don't want caching on a page ? </li><ul><li>HTTP/1.0 : &quot;Expires : Fri, 30 Oct 1998 00:00:00 GMT&quot; (in the past)
  325. 325. HTTP/1.1 : &quot;Cache-Control: no-store&quot; </li></ul></ul>
  326. 326. Frontend tuning <ul>1. You optimize backend 2. Frontend engineers messes up -> havoc on backend 3. Don't forget : frontend sends requests to backend ! </ul>
  327. 327. Frontend tuning <ul>All frontend code impacts backend ! <li>Care about frontend
  328. 328. Test frontend
  329. 329. Check what requests frontend sends to backend </li></ul>
  330. 330. Tuning frontend <ul><li>Minimize requests </li><ul><li>Combine CSS/JavaScript files
  331. 331. Use inline images in CSS/XHTML (not supported on all browsers yet) </li></ul></ul>
  332. 332. Frontend tuning - inline CSS/XHTML images #navbar span { width: 31px; height: 31px; display: inline; float: left; margin-right: 4px; } .home { background-image: url(data:image/gif;base64,R0lGODlhHwAfAPcAAAAAAIxKAKVjCLW1tb29tcbGvc7OxtZ7ANbWztbW1tbe1t7e1uelMefn1ufn3ufn5+fv3u+MAO/v5+/v7/fGCPf35/f37//nY////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////........MEl0nGVUC6tObNnPceSFBaQVMJAxC4lo3gNOrUaFnTHoAxNm3XVxPfRq139e8BEGAjWD5bgIALw287T8AcAXLly2kjOACdc17higXSIKDO/Lpv7Qq4bw7APgBq8eOzX69InrZ6xe3dbxZffyTGkb8tdx8F+b0Xn2sFsCSBAgTM5lp63RHYnoHUudZgRgkGOGCB+43nGk4OGcQTabKx5dyJKJ7ImoUNCaRRAZYN1ppsrT3Y2gIwyjSQBAtUpABml/0IJGYd6VjQUDH9uBFkGxGm5I8dPQaRUAQUMBdhhBV25ZYUJZBcSAtSJBddWZZ5UAGPOTXlgkNVOSZdBxEwIkYu7VhYnAol5GaadRqF0Uaz0TgXnX2umVFyGakJUUAAADs=); margin-left: 4px; } <img border=0 src=&quot;data:image/gif;base64,R0lGODlhHwAfAPcAAAAAAIxKAKVjCLW1tb29tcbGvc7OxtZ7ANbWztbW1tbe1t7e1uelMefn1ufn3ufn5+fv3u+MAO/v5+/v7/fGCPf35/f37//nY/......Uaz0TgXnX2umVFyGakJUUAAADs=&quot;>
  333. 333. Tuning frontend <ul><li>Minimize requests </li><ul><li>Combine CSS/JavaScript files
  334. 334. Use inline images in CSS (not supported on all browsers yet)
  335. 335. Use CSS Sprites </li></ul></ul>
  336. 336. Tuning content - CSS sprites 11 images 11 HTTP requests 24KByte 1 images 1 HTTP requests 14KByte
  337. 337. Tuning content - CSS sprites
  338. 338. Tuning frontend <ul><li>Minimize requests </li><ul><li>Combine CSS/JavaScript files
  339. 339. Use inline images in CSS (not supported on all browsers yet)
  340. 340. Use CSS Sprites (horizontally if possible) </li></ul><li>Put CSS at top
  341. 341. Put JavaScript at bottom </li><ul><li>Max. no connections
  342. 342. Especially if JavaScript does Ajax (advertising-scripts, …) ! </li></ul><li>Avoid iFrames </li><ul><li>Again : max no. of connections
  343. 343. JavaScript onLoad() won't be triggered until loaded ! </li></ul><li>Don't scale images in HTML
  344. 344. Have a favicon.ico and cache it (don't 404 it !) </li></ul>
  345. 345. Tuning frontend <ul><li>Don't use inline CSS/JavaScript </li><ul><li>CSS/JavaScript need to be external files (minified, merged)
  346. 346. Why ? -> Cacheable by browser / reverse proxy </li></ul><li>Use GET for Ajax retrieval requests (and cache them !)
  347. 347. Optimize images (average 50-60% !)
  348. 348. Split requests across subdomains
  349. 349. Put statics on a separate subdomain (without cookies !) </li></ul>www.phpbenelux.eu www.phpbenelux.eu images.phpbenelux.eu
  350. 350. Tuning miscellaneous <ul><li>Avoid DNS lookups </li><ul><li>Frontend : don't use too many subdomains (2 = ideal)
  351. 351. Backend : </li><ul><li>Turn off DNS resolution in Apache : HostnameLookups Off
  352. 352. If your app uses external data </li><ul><li>Run a local DNS cache (timeout danger !)
  353. 353. Make sure you can trust DNS servers (preferable run your own) </li></ul></ul></ul><li>Compress non-binary content (GZIP) </li><ul><li>mod_deflate in Apache
  354. 354. HttpGzipModule in Nginx (HttpGzipStaticModule for pre-zipped statics !)
  355. 355. No native support in Varnish </li></ul></ul>
  356. 356. What else can kill your site ? <ul><li>Redirect loops </li><ul><li>Multiple requests </li><ul><li>More load on Webserver
  357. 357. More PHP to process </li></ul><li>Additional latency for visitor
  358. 358. Try to avoid redirects anyway
  359. 359. -> In ZF : use $this->_forward instead of $this->_redirect </li></ul><li>Watch your logs, but equally important...
  360. 360. Watch the logging process ->
  361. 361. Logging = disk I/O -> can kill your site !
  362. 362. Slashdot effect </li></ul>
  363. 363. Above all else... be prepared ! <ul><li>Have a monitoring system
  364. 364. Use a cache abstraction layer (disk -> APC -> Memcache)
  365. 365. Don't install for the worst -> prepare for the worst </li><ul><li>Code abstraction
  366. 366. Code separation
  367. 367. Have a plan
  368. 368. Have a test-setup
  369. 369. Be ready to go cloud (experiment !)
  370. 370. Look at business critical level </li></ul><li>Have fallbacks </li><ul><li>Turn off non-critical functionality
  371. 371. Turn on queueing for non-critical updates </li></ul></ul>
  372. 372. Interested in actual benchmark results ? <ul><li>Join me for a Webcast with : </li><ul><li>Benchmark of an actual site
  373. 373. Step-by-step implementation of caching, Nginx and lots of tuning
  374. 374. See results for yourself </li></ul><li>Date : first half of March
  375. 375. Follow me : </li><ul><li>Twitter : @wimgtr
  376. 376. Blog : http://techblog.wimgodden.be </li></ul></ul>
  377. 377. <ul>Questions ? </ul>
  378. 378. Cu.be Solutions <ul><li>Founded in 2010
  379. 379. Spinoff of FirstLink Networks (founded in 2000)
  380. 380. High-quality open source solutions
  381. 381. Centered around PHP
  382. 382. Contribute to open source projects
  383. 383. (ZF, PHPUnit, PHP_CodeSniffer, OpenX, ...) </li></ul>
  384. 384. Cu.be Solutions - we're hiring ! <ul><li>PHP developers
  385. 385. Go beyond just PHP -> entire PHP ecosystem
  386. 386. Work with latest tools
  387. 387. Exciting projects (Webservices, mobile, high-traffic, ...)
  388. 388. Focus on highest possible quality !
  389. 389. Interested ?
  390. 390. -> http://cu.be/jobs
  391. 391. -> info@cu.be </li></ul>
  392. 392. Contact <ul><li>Web http://techblog.wimgodden.be
  393. 393. Slides http://www.slideshare.net/wimg
  394. 394. Twitter @wimgtr
  395. 395. E-mail [email_address] </li></ul>
  396. 396. Please... <ul><li>Rate my talk (evaluation forms)
  397. 397. Rate my talk : http://joind.in/talk/view/2491 </li></ul>
  398. 398. <ul>Thanks ! </ul>

×