<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk" -->

---
title: System Design Drill Day 7: Rate Limiting APIs, Logins...
description: This interview drill designs Redis-backed rate limits for a marketplace running 3 Laravel servers with shared Redis. It compares five algorithms: fixed window...
canonical: https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: System Design Drill Day 7: Rate Limiting APIs, Logins and OTPs with Redis | daily.dev
og:description: This interview drill designs Redis-backed rate limits for a marketplace running 3 Laravel servers with shared Redis. It compares five algorithms: fixed window...
og:url: https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk
og:image: https://api.daily.dev/og/posts/VWVETNMNk.png
og:image:alt: System Design Drill Day 7: Rate Limiting APIs, Logins and OTPs with Redis
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# System Design Drill Day 7: Rate Limiting APIs, Logins and OTPs with Redis

**[C\# Corner](https://daily.dev/sources/csharpcorner)** · 8 min read · 3 upvotes · 1 comments

## Summary

This interview drill designs Redis-backed rate limits for a marketplace running 3 Laravel servers with shared Redis. It compares five algorithms: fixed window counters, sliding window logs, sliding window counters, token buckets and leaky buckets, picking the sliding window counter as a default and token buckets for API plans. Partner tiers get token buckets of 100 (Basic) and 1,000 (Pro) tokens refilling per 60 seconds, updated atomically via a Lua script. OTP SMS gets a per-number limit plus a 5,000-per-day global budget, failing closed if Redis goes down, while partner limits fail open with a local per-server fallback at a third of the limit.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.c-sharpcorner.com/article/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis>

## Questions this post answers

### How do I implement a token bucket rate limiter atomically in Redis with Lua?

Store the token count and last refill timestamp in a Redis hash keyed by the client, then run a single Lua script that refills tokens based on elapsed time, checks if at least one token is available, and decrements it if so. The script returns whether the request was allowed plus the remaining tokens, keeping refill, check and spend atomic across multiple app servers.

_Building a multi-server rate limiter? Track Redis and Laravel patterns like this on daily.dev._

### Should a rate limiter fail open or fail closed when Redis goes down?

It depends on what being wrong costs for that specific limit. For OTP SMS sending, fail closed, since a short outage costs less than an attacker pumping out paid SMS messages. For paying partner API keys, fail open with a local fallback where each server enforces roughly a third of the limit in memory, since losing access shouldn't be the price of a Redis outage.

_Weighing fail-open versus fail-closed for your own limits? Compare trade-offs like these on daily.dev._

### What's the difference between a fixed window counter and a sliding window counter for rate limiting?

A fixed window counter counts requests per key per time bucket (like per minute) but allows double the limit at window boundaries, for example 60 requests at 10:30:59 and 60 more at 10:31:00 for 120 in two seconds. A sliding window counter avoids this by weighting the previous window against the current one, computing count as prev times 0.7 plus current when 30% into the new minute, giving near-exact results with fixed-window memory cost.

_Choosing a rate-limiting algorithm for an interview or production? Keep comparisons like this on daily.dev._

## Community discussion

Top comments from developers on daily.dev.

**@pdfopsdev** · 0 upvotes

> curious why OTP fails closed but partner limits fail open with a local fallback, feels backwards at first since OTP failures block a login flow directly. guessing it's because a leaked OTP limit is a fraud vector and a partner API hiccup is just degraded throughput, but that tradeoff is worth stating explicitly in the writeup.

## Similar posts on daily.dev

- [Sliding-Window Rate Limiters with TypeScript & Redis](https://daily.dev/posts/sliding-window-rate-limiters-with-typescript-redis-johtnq4x1) · SitePoint · 0 upvotes · 0 comments
- [28 Million Decisions Per Second. Zero Allocations. One Rate Limiter.](https://daily.dev/posts/28-million-decisions-per-second-zero-allocations-one-rate-limiter--a6kmxkmhy) · Medium · 0 upvotes · 0 comments
- [Rate Limiting Algorithms: Token Bucket vs Sliding Window vs Fixed Window](https://daily.dev/posts/rate-limiting-algorithms-token-bucket-vs-sliding-window-vs-fixed-window-c6i3q4jdl) · Arcjet · 0 upvotes · 0 comments
- [High Performance Rate Limiting at Databricks](https://daily.dev/posts/high-performance-rate-limiting-at-databricks-lln88cxlb) · ByteByteGo · 13 upvotes · 0 comments

---

Tags: [#career](https://daily.dev/tags/career), [#laravel](https://daily.dev/tags/laravel), [#distributed-systems](https://daily.dev/tags/distributed-systems), [#redis](https://daily.dev/tags/redis)

[View this post on daily.dev](https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"System Design Drill Day 7: Rate Limiting APIs, Logins and OTPs with Redis","url":"https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk"},"datePublished":"2026-10-25T04:47:23.058Z","dateModified":"2026-10-25T04:47:57.273Z","description":"This interview drill designs Redis-backed rate limits for a marketplace running 3 Laravel servers with shared Redis. It compares five algorithms: fixed window...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/944440328be3025e7d586fc5f5f1dc4f?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/944440328be3025e7d586fc5f5f1dc4f?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"C# Corner","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"C# Corner","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/ada2d584df6241748fc4e71878dc70a3","url":"https://daily.dev/sources/csharpcorner"},"commentCount":1,"discussionUrl":"https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":3},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":1}],"keywords":"career,laravel,distributed-systems,redis","timeRequired":"PT8M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"C# Corner","item":"https://daily.dev/sources/csharpcorner"},{"@type":"ListItem","position":3,"name":"System Design Drill Day 7: Rate Limiting APIs, Logins and OTPs with Redis"}]}
{"@context":"https://schema.org","@type":"WebPage","@id":"https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk","comment":[{"@type":"Comment","text":"curious why OTP fails closed but partner limits fail open with a local fallback, feels backwards at first since OTP failures block a login flow directly. guessing it’s because a leaked OTP limit is a fraud vector and a partner API hiccup is just degraded throughput, but that tradeoff is worth stating explicitly in the writeup.","datePublished":"2026-10-25T18:12:36.252Z","url":"https://daily.dev/posts/VWVETNMNk#c-yx2vSY9xx","author":{"@type":"Person","name":"PDFops","url":"https://daily.dev/pdfopsdev","image":"https://media.daily.dev/image/upload/s---8isRBKc--/f_auto/v1782922291/avatars/avatar_orjMeK8QKaaVZwGq7ScPz?_a=BAMAMicg0"}}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/system-design-drill-day-7-rate-limiting-apis-logins-and-otps-with-redis-vwvetnmnk#faq","mainEntity":[{"@type":"Question","name":"How do I implement a token bucket rate limiter atomically in Redis with Lua?","acceptedAnswer":{"@type":"Answer","text":"Store the token count and last refill timestamp in a Redis hash keyed by the client, then run a single Lua script that refills tokens based on elapsed time, checks if at least one token is available, and decrements it if so. The script returns whether the request was allowed plus the remaining tokens, keeping refill, check and spend atomic across multiple app servers. Building a multi-server rate limiter? Track Redis and Laravel patterns like this on daily.dev."}},{"@type":"Question","name":"Should a rate limiter fail open or fail closed when Redis goes down?","acceptedAnswer":{"@type":"Answer","text":"It depends on what being wrong costs for that specific limit. For OTP SMS sending, fail closed, since a short outage costs less than an attacker pumping out paid SMS messages. For paying partner API keys, fail open with a local fallback where each server enforces roughly a third of the limit in memory, since losing access shouldn't be the price of a Redis outage. Weighing fail-open versus fail-closed for your own limits? Compare trade-offs like these on daily.dev."}},{"@type":"Question","name":"What's the difference between a fixed window counter and a sliding window counter for rate limiting?","acceptedAnswer":{"@type":"Answer","text":"A fixed window counter counts requests per key per time bucket (like per minute) but allows double the limit at window boundaries, for example 60 requests at 10:30:59 and 60 more at 10:31:00 for 120 in two seconds. A sliding window counter avoids this by weighting the previous window against the current one, computing count as prev times 0.7 plus current when 30% into the new minute, giving near-exact results with fixed-window memory cost. Choosing a rate-limiting algorithm for an interview or production? Keep comparisons like this on daily.dev."}}]}
```

