index.md (3673B)
1 --- 2 title: "PUMA on Redis" 3 date: 2011-07-27T00:00:00+00:00 4 draft: false 5 canonical_url: https://www.viget.com/articles/puma-on-redis/ 6 --- 7 8 A few weeks ago, we celebrated the launch of [the new 9 PUMA.com](https://www.viget.com/blog/relaunching-pumacom-startup-style/), 10 the culmination of a nearly two-year effort here at Viget. The whole 11 site is driven by a CMS written in Rails, and I'm very proud of the 12 technological platform we've developed. I want to focus on one piece of 13 that platform, [Redis](http://redis.io/), and how it makes the site both 14 rock solid and screaming fast. 15 16 ## Fragment Caching 17 18 The app was initially created to serve category marketing sites like 19 [Running](http://www.puma.com/running) and 20 [Football](http://www.puma.com/football). When we set out to overhaul it 21 to serve the main PUMA site, we knew performance was of paramount 22 importance. We made extensive use of fragment caching throughout the 23 site, using Redis as our cache store. [Some 24 claim](http://stackoverflow.com/questions/4221735/rails-and-caching-is-it-easy-to-switch-between-memcache-and-redis/4342279#4342279) 25 that Redis is not as well suited for this purpose as Memcached, but it 26 held up well in our pre-launch testing and continues to perform well in 27 production. 28 29 We used Redis as our cache store for two reasons. First, we were already 30 using it for other purposes, so reusing it kept the technology stack 31 simpler. But more importantly, Redis' wildcard key matching makes cache 32 expiration a snap. It's well known that cache expiration is one of [two 33 hard things in computer 34 science](http://martinfowler.com/bliki/TwoHardThings.html), but using 35 wildcard key searching, it's dirt simple to pull back all keys that 36 begin with "views" and contain the word "articles" and expire them 37 every time an article is changed. Memcached has no such ability. 38 39 ## API Caching 40 41 The PUMA site leverages third-party APIs to pull in product 42 availability, retail store information, and marketing campaigns, among 43 other things. External APIs are good for only two things: being slow and 44 returning unexpected results. In a defensive masterstroke, we developed 45 [CacheBar](https://github.com/vigetlabs/cachebar) to keep our responses 46 speedy and stable. 47 48 CacheBar sits between [HTTParty](http://httparty.rubyforge.org/) and the 49 web. When it receives a successful response, it stores it in Redis in 50 two places: as a normal string value with an expiration set on a per-API 51 basis (usually between an hour and a day) and in a hash of all that 52 API's responses. When the primary key expires, we attempt to fetch the 53 data from the API. Successful responses are again stored in both 54 locations, but if the response is unsuccessful, we pull the saved 55 response from the hash and set it as the value for the primary key with 56 a five-minute expiration. This way, we avoid the backup that happens as 57 a result of too many slow responses. 58 59 More information is available on the [CacheBar GitHub 60 page](https://github.com/vigetlabs/cachebar). 61 62 ## Data Structures 63 64 The PUMA app uses Redis' hashes, lists, and sets (sorted and unsorted) 65 as well as normal string values. Having all these data structures at our 66 disposal has proven incredibly useful, not to mention damn fun to use. 67 68 *** 69 70 Redis has far exceeded my expectations in both usefulness and 71 performance. Add it to your stack, and you'll be amazed at the ways it 72 can make your app faster and more robust. 73 74 If you're in North Carolina's Triangle region and you'd like to hear 75 more about the PUMA project, come out to tomorrow night's [Refresh the 76 Triangle](http://refreshthetriangle.org/) meeting, where I'll be talking 77 about this stuff alongside several other team members.