<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: David Marby</title>
    <description>The latest articles on Forem by David Marby (@dmarby).</description>
    <link>https://forem.com/dmarby</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4386%2Fd2b39cf0-a989-4972-9eaa-55421e1a52c6.jpg</url>
      <title>Forem: David Marby</title>
      <link>https://forem.com/dmarby</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/dmarby"/>
    <language>en</language>
    <item>
      <title>Lorem Picsum, death by a million pixel-gigabits</title>
      <dc:creator>David Marby</dc:creator>
      <pubDate>Sun, 11 Aug 2019 00:00:00 +0000</pubDate>
      <link>https://forem.com/dmarby/lorem-picsum-death-by-a-million-pixel-gigabits-jgm</link>
      <guid>https://forem.com/dmarby/lorem-picsum-death-by-a-million-pixel-gigabits-jgm</guid>
      <description>&lt;p&gt;Or how to serve half a billion placeholder images a month on a budget.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://picsum.photos"&gt;Lorem Picsum&lt;/a&gt; is one of the most popular placeholder sites on the internet. It started as a small side project written in NodeJS &lt;a href="https://github.com/DMarby/picsum-photos/commit/a444d8d3f235c877ac3e3302d04de42388d6d619"&gt;five years ago&lt;/a&gt; to cover my own needs and has since gone through several iterations as it has grown. In this post, I'll be going through the architecture and inner-workings of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenges
&lt;/h2&gt;

&lt;p&gt;Processing images is very CPU intensive. As Lorem Picsum runs on a very small budget, to cope with all the requests as the service became more popular, we wanted to avoid doing so as much as possible. This meant adding caching to multiple layers of the architecture. We added two separate layers of caching: A CDN in front, as well as a second cache layer using &lt;a href="https://varnish-cache.org/"&gt;Varnish Cache&lt;/a&gt;. To make the image processing as efficient as possible, we decided to use &lt;a href="https://libvips.github.io/libvips/"&gt;libvips&lt;/a&gt;, as it's very fast and resource-efficient.&lt;/p&gt;

&lt;p&gt;As part of making Lorem Picsum as easy to use as possible, we've never required any registration, API keys, or enforced any usage limits. This has generally worked out well, but once in a while a high traffic site deploys production code calling our API, usually accidentally, which leads to two main problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extreme load on the service: One site used Lorem Picsum for fallback images when they failed to serve an image. At some point, their image service broke, leading to several hundred millions of requests per month hitting Lorem Picsum, without them noticing. They were however very quick in rectifying this error once we contacted them.&lt;/li&gt;
&lt;li&gt;Privacy concerns. In the past, some sites have included an image from Lorem Picsum on every page in production, leaking user information and activity through the URL in the Referral header.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While we allow the use of Lorem Picsum for pretty much anything, when someone has used the service to the point of instability/very high load, we've tried to contact them and ask them to stop. This has generally worked out well, and in most cases the usage was accidental. However, in a few cases, we've gotten no responses to such attempts, which lead to us needing to block the sites in our cache layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--B_ncem2S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dmarby.se/_saber/images/lorem-ipsum-architecture.a112f42a.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--B_ncem2S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dmarby.se/_saber/images/lorem-ipsum-architecture.a112f42a.svg" alt="img"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Lorem Picsum is designed to be stateless, and runs on top of &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;. The overall system consists of a few different components, as can be seen in the diagram above.&lt;/p&gt;

&lt;p&gt;When a user requests an image, the request starts at our CDN. Upon a CDN cache miss, the request continues to our &lt;a href="https://dev.to/blog/lorem-picsum/#load-balancer"&gt;load balancer&lt;/a&gt; where it is forwarded to our &lt;a href="https://dev.to/blog/lorem-picsum/#caching"&gt;cache layer&lt;/a&gt; which, upon cache miss, passes it on to the &lt;a href="https://dev.to/blog/lorem-picsum/#application"&gt;application&lt;/a&gt;. The &lt;a href="https://dev.to/blog/lorem-picsum/#application"&gt;application&lt;/a&gt; verifies that the requested image exists in the &lt;a href="https://dev.to/blog/lorem-picsum/#image-database"&gt;image database&lt;/a&gt;, and checks if the image is cached by the &lt;a href="https://dev.to/blog/lorem-picsum/#image-storage-cache"&gt;image storage cache&lt;/a&gt;. If not, it fetches it from the &lt;a href="https://dev.to/blog/lorem-picsum/#image-storage"&gt;image storage&lt;/a&gt;, processes the image and returns it to the user.&lt;/p&gt;

&lt;h4&gt;
  
  
  Load balancing
&lt;/h4&gt;

&lt;p&gt;We use &lt;a href="https://www.digitalocean.com/products/load-balancer/"&gt;DigitalOcean's load balancer&lt;/a&gt; to handle incoming requests and pass them on to our cache layer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Caching
&lt;/h4&gt;

&lt;p&gt;To reduce the load on the system, on top of the caching provided by our CDN, we use &lt;a href="https://varnish-cache.org/"&gt;Varnish Cache&lt;/a&gt; to cache processed images. This also allows us to cache more efficiently by using optimizations, such as rewriting query parameters.&lt;/p&gt;

&lt;h4&gt;
  
  
  Application
&lt;/h4&gt;

&lt;p&gt;The Lorem Picsum application, written in &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt;, is responsible for processing images and serving up files for the website. The website is statically generated during build-time using &lt;a href="https://gulpjs.com/"&gt;Gulp&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Image database
&lt;/h4&gt;

&lt;p&gt;To store information about the images, such as width and height, we use &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;. We use &lt;a href="https://www.digitalocean.com/products/managed-databases"&gt;DigitalOcean's managed databases&lt;/a&gt; to avoid having to maintain and scale it ourselves.&lt;/p&gt;

&lt;h4&gt;
  
  
  Image storage
&lt;/h4&gt;

&lt;p&gt;We use an object storage to store the source images, namely &lt;a href="https://www.digitalocean.com/products/spaces/"&gt;DigitalOcean Spaces&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Image storage cache
&lt;/h4&gt;

&lt;p&gt;We store all source images in &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt; to avoid fetching them from the image storage on every request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Orchestration
&lt;/h2&gt;

&lt;p&gt;We use &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt; for orchestration; to set up and configure all the services on DigitalOcean. This allows any changes to be versioned in the git repo and makes it easy to re-create the environment if needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open source
&lt;/h2&gt;

&lt;p&gt;Lorem Picsum is fully open source and licensed under MIT. Source code and documentation can be found in the &lt;a href="https://github.com/DMarby/picsum-photos"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;Lorem Picsum wouldn't exist without the support of &lt;a href="https://www.digitalocean.com"&gt;DigitalOcean&lt;/a&gt;. Big thanks to them for providing the infrastructure for Picsum for the past four years.&lt;/p&gt;

</description>
      <category>go</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
