← 2026-04-02 📂 All Days 2026-04-04 →
🏗️
🏗️ System Design
🏗️ 系统设计 Day 15 / System Design Day 15

🏗️ 系统设计 Day 15 / System Design Day 15

Rate Limiting & Throttling — 保护你的 API / Protecting Your API


🌏 真实场景 / Real-World Scenario

想象你在 Twitter(X)做工程师。某个下午,一个爬虫脚本突然对你的搜索 API 发起每秒 10,000 次请求,导致数据库崩溃,所有用户无法刷推。

你需要一个限流系统——在不影响正常用户的前提下,拒绝滥用流量。

Imagine you're an engineer at Twitter (X). One afternoon, a scraper script hammers your search API at 10,000 requests/second, crashing the database for all users. You need a rate limiting system — one that blocks abuse without affecting normal users.


📐 架构图 / Architecture Diagram

┌─────────────────────┐ Client Request ───────►│ API Gateway / │ │ Rate Limiter │ │ │ │ 1. Identify client │ │ (IP / User ID / │ │ API Key) │ │ 2. Check counter │ │ in Redis │ │ 3. Allow or Block │ └──────────┬───────────┘ │ Allowed ┌──────────▼───────────┐ │ Backend Service │ └──────────────────────┘ Redis Counter Example (Sliding Window): key: "ratelimit:user123:2026-04-03T08" value: 47 (requests this hour) TTL: 3600s

⚙️ 主要算法 / Key Algorithms

算法原理优点缺点
Token Bucket令牌以固定速率补充,请求消耗令牌允许突发流量实现稍复杂
Leaky Bucket请求以固定速率流出(队列)输出极平滑不允许突发
Fixed Window每个时间窗重置计数器最简单边界突破问题
Sliding Window精确追踪过去 N 秒最精确内存占用高

推荐:Token Bucket(令牌桶) — 生产中最常用,兼顾突发和平均速率。


🔑 关键权衡 / Key Tradeoffs

为什么用 Redis 而不是本地内存?/ Why Redis, not local memory?

  • 多台服务器共享同一计数器 → 分布式限流
  • 原子操作(INCR + EXPIRE)避免竞态条件
  • Redis 单线程模型保证计数器一致性

限流粒度选择 / Granularity choices:

  • Per IP — 防爬虫,但误伤 NAT 用户(办公室)
  • Per User ID — 最精确,需要认证
  • Per API Key — B2B 场景首选
  • Per Endpoint — 写接口比读接口更严格

❌ 常见错误 / Common Mistakes

坑 1:Fixed Window 边界问题

Window 1 (0:00-1:00): 99 requests ← allowed Window 2 (1:00-2:00): 99 requests ← allowed But at 0:59 + 1:01 = 198 requests in 2 seconds! ← spike!

→ 用 Sliding Window Log 或 Sliding Window Counter 解决

坑 2:忘记 HTTP 响应头

X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 47 X-RateLimit-Reset: 1743685200 Retry-After: 3600 ← 429 时必须包含

客户端需要知道何时重试!

坑 3:硬拒绝 vs 降级

不要直接返回 503,试试 queue、degrade(返回缓存数据)或 soft-limit(超出后降速)。


📚 References


🧒 ELI5

就像游乐场的入口检票员:每个小时只放 100 个人进去。人满了就让你在外面等,而不是把游乐场挤爆。

It's like a bouncer at a club: "100 people per hour max." When it's full, you wait outside — the club doesn't collapse.

💻
💻 Algorithms
💻 算法 Day 16 / Algorithms Day 16

💻 算法 Day 16 / Algorithms Day 16

🧩 滑动窗口模式 (2/6) — Building on the template from Day 15

#3 Longest Substring Without Repeating Characters 🟡 Medium

🔗 LeetCode #3

📹 NeetCode Video


今天的问题是模式的第 2 题(共 6 题),我们继续用滑动窗口模板。相比昨天的 #121(股票买卖,只追踪一个 min 值),今天窗口需要追踪「一个集合」——这是滑动窗口真正的威力所在。

Today is problem 2/6 in the Sliding Window block. Unlike #121 (tracking a single min value), today's window tracks a set of characters — this is where the pattern gets powerful.


🗺️ 模板回顾 / Template Recap

left = 0
for right in range(len(arr)):
    window.add(arr[right])      # expand right
    while CONDITION_VIOLATED:
        window.remove(arr[left])  # shrink left
        left += 1
    result = max(result, right - left + 1)

核心洞察 / Key Insight: 右指针扩张探索,左指针收缩维护约束。每个元素最多进出窗口各一次 → O(n)。


🌍 真实类比 / Real-World Analogy

想象你在刷 Spotify 播放历史,想找「连续播放、没有重复歌曲」的最长片段。当出现重复时,你从头开始,直到重复歌曲被移出窗口之外。

Imagine scanning your Spotify history for the longest streak where no song repeats. The moment a duplicate appears, you slide your start forward until the duplicate is gone.


📝 问题 / Problem

给定字符串 s,找出不含重复字符的最长子串的长度。

Given string s, find the length of the longest substring without repeating characters.

Input:  s = "abcabcbb"
Output: 3  ("abc")

Input:  s = "pwwkew"
Output: 3  ("wke")

🗂️ 映射到模板 / Mapping to Template

模板元素本题对应
windowset() — 当前窗口中的字符
CONDITION_VIOLATEDarr[right] in window(出现重复)
扩张s[right] 加入 set
收缩s[left] 从 set 移除,left += 1
resultmax(result, right - left + 1)

🐍 Python 解法 + 追踪 / Python Solution + Trace

def lengthOfLongestSubstring(s: str) -> int:
    window = set()       # characters currently in window
    left = 0
    result = 0

    for right in range(len(s)):
        # Shrink window until no duplicate
        while s[right] in window:
            window.remove(s[left])
            left += 1

        # Expand: add new character
        window.add(s[right])
        result = max(result, right - left + 1)

    return result

追踪 "abcabcbb" / Trace:

right=0: window={'a'}, len=1 right=1: window={'a','b'}, len=2 right=2: window={'a','b','c'}, len=3 ← result=3 right=3: 'a' dup! → remove 'a', left=1 → window={'b','c','a'}, len=3 right=4: 'b' dup! → remove 'b', left=2 → window={'c','a','b'}, len=3 right=5: 'c' dup! → remove 'c', left=3 → window={'a','b','c'}, len=3 right=6: 'b' dup! → remove 'a','b', left=5 → window={'c','b'}, len=2 right=7: 'b' dup! → remove 'c','b', left=7 → window={'b'}, len=1 Final: 3 ✅

复杂度 / Complexity:

  • Time: O(n) — each char enters/exits window at most once
  • Space: O(min(m, n)) where m = charset size (26 for lowercase)

优化版 / Optimized (HashMap for O(1) jump):

def lengthOfLongestSubstring(s: str) -> int:
    char_index = {}  # char → last seen index
    left = 0
    result = 0

    for right, ch in enumerate(s):
        # Jump left past the duplicate directly
        if ch in char_index and char_index[ch] >= left:
            left = char_index[ch] + 1
        char_index[ch] = right
        result = max(result, right - left + 1)

    return result

→ 避免 while 循环,直接跳跃 left,同样 O(n) 但常数更小。


🔄 举一反三 / This Pattern Block

题目窗口内容约束条件
#121 (Day 15)单个 min 值无,只追踪最小值
#3 (今天)字符集合无重复
#424 (下期)字符频率 map替换次数 ≤ k
#567字符频率 map频率完全匹配
#76 (Hard)字符频率 map包含所有目标字符

🧒 ELI5

用两根手指夹住一段字符串,右手不断向右扩张。一旦右手摸到一个和窗口内重复的字母,左手就往右收缩,直到没有重复为止。全程记录最宽的窗口宽度。

Use two fingers on a string. Right finger keeps expanding right. The moment it hits a duplicate, the left finger moves right to shrink the window until no duplicates remain. Track the max width you ever saw.


📚 References

🗣️
🗣️ Soft Skills
🗣️ 软技能 Day 15 / Soft Skills Day 15

🗣️ 软技能 Day 15 / Soft Skills Day 15

适应性:快速学习新技术 / Adaptability: Learning New Tech Fast

面试题 / Question:

"Describe a time you had to learn a new technology quickly to solve a problem."


🎯 为什么面试官问这个 / Why Interviewers Ask This

技术栈变化极快。面试官想知道:

  1. 你面对陌生技术时会恐慌还是系统地应对?
  2. 你的学习方法是否高效?
  3. 你能否在压力下交付?

Tech stacks evolve fast. Interviewers want to know: Do you panic or adapt? Do you have a system for learning under pressure? Can you still deliver?


⭐ STAR 框架 / STAR Breakdown

Situation(情境):

描述具体的业务压力 — 不要说"我需要学习新技术",要说"我们有 2 周的 deadline,而现有的技术栈无法满足需求"。

Task(任务):

你的具体职责是什么?是主导学习还是支援?

Action(行动)— 这是重点!

面试官最想听的是你的学习策略

  • 你怎么快速搭建 mental model?(官方文档 → 官方示例 → 一个真实小项目)
  • 你怎么判断"够用了"?(能解决当前问题即可,不追求精通)
  • 你遇到障碍时怎么求助?(Stack Overflow → 同事 → 官方 issue)

Result(结果):

量化交付:时间、质量、影响。


❌ Bad Answer vs ✅ Good Answer

❌ 差劲的回答:

"我们需要用 Kubernetes,我就去学了 K8s,然后把服务迁移过去了,很顺利。"

问题:没有细节,没有困难,没有学习过程——听起来是在背稿。


✅ 优秀的回答 (示例):

"We were 3 weeks from launching a real-time feature, and our backend team decided mid-project to use WebSockets via Socket.io — something I'd never touched. I had 4 days before my frontend piece needed to integrate.
I started with the official docs to get a mental model (30 min), then built a tiny chat demo locally to feel the API (2 hours). I identified the 3 patterns I'd actually need: emit, on, and room-based broadcasting. I skipped everything else.
Day 2, I hit a race condition where events fired before the socket connected. I found the root cause via the Socket.io FAQ, added a connection guard, and documented it for the team.
We shipped on time. The feature had zero WebSocket-related bugs in production. I also wrote an internal doc that helped 2 other engineers onboard faster."

💡 Senior/Staff 级加分点 / Senior/Staff Tips

  1. 展示元认知 / Show metacognition — 不只是"我学了 X",而是"我用了 Y 策略学 X,因为 Z"
  2. 说明你如何判断边界 / Scope your learning — "我在 40% 的时间里掌握了 80% 的需求场景——这是故意的选择"
  3. 团队放大效应 / Multiply impact — "我写了文档/做了分享,减少了团队学习成本"
  4. 展示迁移能力 / Show transfer — "这次学 Redis Streams 的经验,让我 3 个月后学 Kafka 快了 3 倍"

🔑 关键要点 / Key Takeaways

  • 学习要有系统:mental model → 最小可用知识 → 实战 → 总结
  • 面试时强调trade-off:你选择了快速上手而不是全面掌握
  • 量化:时间节省、错误减少、团队效率提升

📚 References


🧒 ELI5

面试官在问:"当你碰到从没见过的东西,你会怎么办?" 正确答案不是"我啥都会",而是"我有一套靠谱的方法,让我快速从零变成够用。"

The interviewer asks: "What happens when you hit something you've never seen?" The right answer isn't "I know everything." It's "I have a reliable method to go from zero to useful, fast."

🎨
🎨 Frontend
🎨 前端 Day 15 / Frontend Day 15

🎨 前端 Day 15 / Frontend Day 15

React Composition — Children, Render Props, HOCs

React 组合模式 — 子组件、渲染属性、高阶组件


🌏 真实场景 / Real Scenario

你在做一个 Dashboard,需要一个 Card 组件——有时里面是图表,有时是表格,有时是表单。你不想为每种情况写 ChartCardTableCardFormCard……

You're building a Dashboard. You need a Card component — sometimes it holds a chart, sometimes a table, sometimes a form. You don't want to write ChartCard, TableCard, FormCard separately.

React Composition(组合) 是解决方案。


📦 Pattern 1: Children Props(最常用)

// Generic Card shell — accepts anything as children
interface CardProps {
  title: string;
  children: React.ReactNode; // <-- the magic
}

function Card({ title, children }: CardProps) {
  return (
    <div className="card">
      <h2>{title}</h2>
      <div className="card-body">{children}</div>
    </div>
  );
}

// Usage: inject any content
function Dashboard() {
  return (
    <Card title="用户增长 / User Growth">
      <LineChart data={chartData} />
    </Card>
  );
}

何时用 / When to use: 容器/布局组件,内容不确定。


🎯 Pattern 2: Render Props(渲染属性)

当父组件需要向子内容传递数据时:

When the parent needs to pass data into the child content:

interface DataFetcherProps<T> {
  url: string;
  render: (data: T | null, loading: boolean) => React.ReactNode;
}

function DataFetcher<T>({ url, render }: DataFetcherProps<T>) {
  const [data, setData] = useState<T | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch(url).then(r => r.json()).then(d => {
      setData(d);
      setLoading(false);
    });
  }, [url]);

  return <>{render(data, loading)}</>;
}

// Usage
<DataFetcher<User[]>
  url="/api/users"
  render={(users, loading) =>
    loading ? <Spinner /> : <UserTable data={users!} />
  }
/>
💡 现代 React 里,Custom Hooks 通常比 Render Props 更清晰。Render Props 更多见于老代码或需要 JSX 层控制的场景。

🔧 Pattern 3: Higher-Order Components (HOC)

// withAuth: wraps any component to require authentication
function withAuth<P extends object>(
  WrappedComponent: React.ComponentType<P>
) {
  return function AuthenticatedComponent(props: P) {
    const { isLoggedIn } = useAuth();

    if (!isLoggedIn) {
      return <Navigate to="/login" />;
    }

    return <WrappedComponent {...props} />;
  };
}

// Usage
const ProtectedDashboard = withAuth(Dashboard);

🎮 猜猜输出 / Quiz

function Wrapper({ children }: { children: React.ReactNode }) {
  console.log("Wrapper rendered");
  return <div>{children}</div>;
}

function App() {
  const [count, setCount] = useState(0);
  return (
    <Wrapper>
      <button onClick={() => setCount(c => c + 1)}>
        Count: {count}
      </button>
    </Wrapper>
  );
}

点击按钮时,"Wrapper rendered" 会打印吗?/ Does "Wrapper rendered" print on button click?

A) 每次点击都打印

B) 只在初始渲染打印

C) 每次点击都打印(因为 children 是新 JSX 对象)

D) 取决于 React 版本

<details>

<summary>显示答案 / Show Answer</summary>

答案:CWrapper 每次都会重新渲染。

虽然 Wrapper 本身没有 state,但每次 App 渲染时,<button>Count: {count}</button> 是一个新的 JSX 元素(新的对象引用),所以 Wrapper 也会重新渲染。

要阻止这种行为,需要把 Wrapper 包裹在 React.memo并且 确保 children 引用不变(实际上很难)。

In React, children is a new JSX object on every parent render — so Wrapper re-renders too. To prevent this, you'd need React.memo AND stable children refs.

</details>


❌ vs ✅ 常见错误 / Common Mistakes

❌ Prop Drilling Hell:

// Passing title 5 levels deep just to show it in a card
<Page title="Dashboard">
  <Layout title="Dashboard">
    <Section title="Dashboard">
      <Card title="Dashboard"> ... </Card>

✅ Composition with Children:

<Card>
  <CardHeader>Dashboard</CardHeader>
  <CardBody>...</CardBody>
</Card>

⚖️ 何时用哪个 / When to Use Which

场景推荐模式
容器/布局,内容不定children props
共享逻辑,不共享 UICustom Hook (首选)
需要向内容注入数据Render Props 或 Custom Hook
跨组件横切关注点(认证、日志)HOC
老 class component 代码HOC(因为 hooks 不能用于 class)

📚 References


🧒 ELI5

就像乐高积木:children props 让你把任意积木放进一个盒子;Render Props 让盒子告诉你"我准备好了,你可以放这种积木";HOC 像是给积木套一个外壳(防水壳、认证壳)。

Like Lego: children props = drop any brick into a box. Render Props = box tells you what brick fits. HOC = wrap a brick in a protective shell.

🤖
🤖 AI
🤖 AI Day 17 — 本周 AI 大事件 / AI News Roundup

🤖 AI Day 17 — 本周 AI 大事件 / AI News Roundup

来源 / Sources: web search, April 2026


📰 Story 1: OpenAI 收购科技脱口秀 TBPN,首次进军媒体 / OpenAI acquires tech talk show TBPN, its first move into media

来源: https://openai.com/index/openai-acquires-tbpn/

OpenAI 宣布收购每日科技谈话节目 TBPN,并表示将保持其编辑独立性;此举被视为公司在“塑造 AI 叙事”和公共沟通上的战略加码。

OpenAI announced it acquired the daily tech talk show TBPN and said it will preserve editorial independence—signaling a strategic push to shape the public AI narrative.

为什么你应该关心: 未来 AI 竞争不只在模型能力,也在“谁掌握公众理解与信任”;媒体渠道会影响监管、人才、客户与舆论风向。/ AI competition isn’t only about model quality—control over narrative and trust can influence regulation, hiring, customer adoption, and public sentiment.


📰 Story 2: Google 推出 Gemini API 的 Flex / Priority Inference,帮助企业控成本与稳定性 / Google adds Flex & Priority Inference tiers to the Gemini API

来源: https://www.infoworld.com/article/4154145/google-gives-enterprises-new-controls-to-manage-ai-inference-costs-and-reliability.html

Google 为 Gemini API 增加新的推理服务分层,让企业在成本、延迟与可靠性之间做更细粒度的取舍,面向更复杂的多步骤“Agent 工作流”。

Google introduced new inference service tiers for the Gemini API, letting enterprises trade off cost, latency, and reliability—especially for complex, multi-step agent workflows.

为什么你应该关心: “AI 变贵”是落地最大障碍之一;更灵活的推理定价与 QoS 会决定哪些产品能规模化、哪些只能停留在 demo。/ Inference economics often decide whether AI products scale or stay demos; pricing/QoS controls directly shape what’s viable in production.


📰 Story 3: Google Research 发布 TurboQuant:大模型推理内存压缩 6 倍 / Google Research unveils TurboQuant memory compression for LLM inference

来源: https://www.networkworld.com/article/4154034/google-research-talks-compression-technology-it-says-will-greatly-reduce-memory-needed-for-ai-processing.html

TurboQuant 据称可将大模型推理所需内存降低 6 倍,并在相同 GPU 数量下提升速度,同时尽量不牺牲精度;这类压缩技术有望推动更多“端侧 AI”能力。

TurboQuant reportedly cuts LLM inference memory by 6× and boosts speed with the same GPU count while preserving accuracy—potentially accelerating more capable on-device AI.

为什么你应该关心: 算法层面的“省内存/省算力”会直接改变硬件需求与成本结构,决定 AI 是集中在云端,还是能更广泛地下沉到手机、PC 与边缘设备。/ Efficiency breakthroughs reshape hardware demand and unit economics, determining whether AI stays cloud-only or becomes truly ubiquitous on phones, PCs, and edge devices.


📰 Story 4: 医疗 AI 新进展:Noah Labs 的 Vox 获 FDA 认定,可用 5 秒语音筛查心衰 / Healthcare AI: Noah Labs’ Vox gets FDA designation for detecting heart failure from a 5-second voice sample

来源: https://www.buildez.ai/blog/ai-trending-april-2026-developments

报道指出 Noah Labs 的 Vox 获得 FDA 相关认定,可通过短短 5 秒语音信号进行心衰风险检测;这展示了 AI 在临床前筛查与远程健康管理的潜力。

Reports say Noah Labs’ Vox received an FDA-related designation and can detect heart failure risk from a 5-second voice sample, highlighting AI’s potential in pre-clinical screening and remote care.

为什么你应该关心: 当 AI 开始进入受监管医疗体系,它的价值不再只是“更聪明”,而是能否真正改善结果、降低成本并通过合规审查。/ As AI enters regulated healthcare, the bar shifts from “smart” to clinically useful, cost-effective, and compliant—opening massive markets (and responsibilities).


📚 References

  1. https://openai.com/index/openai-acquires-tbpn/
  2. https://www.infoworld.com/article/4154145/google-gives-enterprises-new-controls-to-manage-ai-inference-costs-and-reliability.html
  3. https://www.networkworld.com/article/4154034/google-research-talks-compression-technology-it-says-will-greatly-reduce-memory-needed-for-ai-processing.html
  4. https://www.buildez.ai/blog/ai-trending-april-2026-developments

🧒 ELI5: 这周 AI 的重点是:大公司在“更省钱更稳定地跑 AI”、以及把 AI 推进现实世界(媒体与医疗)上同时加速。/ This week’s theme: big players are making AI cheaper and more reliable to run—and pushing it deeper into the real world (media and healthcare).