Successfully reported this slideshow.

Caching and tuning fun for high scalability @ phpBenelux 2011

39

Share

Loading in …3
×
1 of 136
1 of 136

Caching and tuning fun for high scalability @ phpBenelux 2011

39

Share

Description

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.

Transcript

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

Description

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.

Transcript

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

More Related Content

Related Books

Free with a 30 day trial from Scribd

See all

×