← 2026-04-01 📂 All Days 2026-04-03 →
🏗️
🏗️ System Design
🏗️ 系统设计 Day 14 / System Design Day 14

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

API Gateway & Service Mesh


🌍 真实场景 / Real-World Scenario

想象你在优步工作,系统里有 200 个微服务:乘客服务、司机服务、定价服务、路线服务、支付服务……

每个客户端(iOS App、Android App、Web 前端、第三方合作伙伴)直接调用每个服务?噩梦开始了。

这就是为什么优步、Netflix、Amazon 都在用 API Gateway + Service Mesh 这两层抽象。


Imagine you're at Uber with 200 microservices: rider, driver, pricing, routing, payments...

Every client (iOS, Android, web, partners) calling each service directly? Nightmare begins.

This is why Uber, Netflix, and Amazon all use API Gateway + Service Mesh — two layers of abstraction.


🏛️ ASCII 架构图

外部流量 / External Traffic │ ▼ ┌─────────────────────┐ │ API Gateway │ ← 统一入口 / Single Entry Point │ (Kong/AWS API GW) │ 认证、限流、路由、日志 │ │ Auth, Rate Limit, Route, Log └────────┬────────────┘ │ 内部流量 / Internal Traffic ▼ ┌─────────────────────────────────────────┐ │ Service Mesh (Istio/Envoy) │ │ │ │ ┌──────────┐ ┌──────────┐ │ │ │Service A │◄──►│Service B │ │ │ │[sidecar] │ │[sidecar] │ │ │ └──────────┘ └──────────┘ │ │ ↕ ↕ │ │ ┌──────────┐ ┌──────────┐ │ │ │Service C │◄──►│Service D │ │ │ │[sidecar] │ │[sidecar] │ │ │ └──────────┘ └──────────┘ │ │ │ │ 自动 mTLS、熔断、重试、可观测性 │ │ Auto mTLS, Circuit Break, Retry, Obs │ └─────────────────────────────────────────┘

🔍 核心概念 / Core Concepts

#### API Gateway — 对外的门卫

做什么 / What it does:

  • ✅ 认证鉴权 (JWT/OAuth2)
  • ✅ 速率限制 (Rate Limiting) — 防刷
  • ✅ 请求路由 — /api/v1/users → User Service
  • ✅ 协议转换 — REST → gRPC
  • ✅ 请求聚合 — 一次请求,内部调 3 个服务
  • ✅ SSL 终止 (TLS Termination)

常见产品 / Products: Kong, AWS API Gateway, Nginx, Envoy, Traefik

#### Service Mesh — 对内的神经系统

做什么 / What it does:

  • ✅ 服务间 mTLS 加密(零信任网络)
  • ✅ 熔断器 (Circuit Breaker) — 防雪崩
  • ✅ 自动重试 + 超时
  • ✅ 流量管理 (Canary, A/B Test)
  • ✅ 分布式追踪 (Tracing)
  • ✅ 服务发现 (Service Discovery)

实现方式: Sidecar 代理(每个服务旁边注入一个 Envoy 代理)

常见产品 / Products: Istio, Linkerd, Consul Connect


⚖️ 关键权衡 / Key Tradeoffs

方案优点缺点
API Gateway 独立简单,运维成本低服务间通信无管控
Service Mesh 独立内部流量全覆盖复杂度高,sidecar 开销
两者结合 ✅完整的流量控制需要专门的平台团队维护

为什么这样设计?/ Why this design?

API Gateway 和 Service Mesh 解决不同层面的问题:

  • Gateway = 南北流量(外→内)
  • Service Mesh = 东西流量(内→内)

用一个工具同时管两种流量会导致职责不清、配置混乱。


⚠️ 常见踩坑 / Common Mistakes

❌ 把所有业务逻辑放在 API Gateway 里 → Gateway 应该是"哑路由",不应该懂业务 ❌ 在没有可观测性的情况下上 Service Mesh → Mesh 的价值在于追踪和监控,没有这些等于白上 ❌ 用 Service Mesh 替代 API Gateway → Mesh 不做外部认证和速率限制 ❌ 每个团队各自搭 Gateway → 应该是全公司统一,否则安全策略碎片化

📚 References


🧒 ELI5 (像我5岁一样解释)

中文:

想象一个大型游乐园。API Gateway 是大门口的保安,检查你的票、告诉你哪个游乐设施在哪里。Service Mesh 是园区内部的通信系统——每个游乐设施之间如何协调、出故障时怎么绕路。一个管进门,一个管园内。

English:

Imagine a big theme park. The API Gateway is the security guard at the main entrance — checks your ticket, tells you where things are. The Service Mesh is the internal walkie-talkie system between rides — how they coordinate, what happens when one breaks down. One manages getting IN, the other manages moving AROUND.

💻
💻 Algorithms
💻 算法 Day 15 / Algorithms Day 15

💻 算法 Day 15 / Algorithms Day 15

#121 Best Time to Buy and Sell Stock (Easy) — Sliding Window

🔗 LeetCode: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 🟢

📹 NeetCode: https://www.youtube.com/watch?v=1pkOgXD63yU


🧩 新模式 / New Pattern: 滑动窗口模式 (Sliding Window)

📍 This block: 6 problems

什么时候用 / When to use: 连续子数组/子串的最大值、最小值、满足条件的最短/最长

识别信号 / Signals: subarray, substring, contiguous, window, maximum/minimum length

通用模版 / Template:

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

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


🌍 现实类比 / Real-world Analogy

中文:把股价想成每天的“进货价”。你要做的是:先找到历史最低进货价(买入),然后在未来某天卖出(卖出价 - 买入价最大)。

English: Think of prices as daily “cost to buy inventory.” You want the lowest cost so far (buy) and the best future selling day to maximize profit.


🧠 题意拆解 / Problem Restatement

中文:给定数组 prices[i] 表示第 i 天价格。只能买一次、卖一次(卖在买之后)。求最大利润。

English: Given prices[i] as day i price. Buy once, sell once (sell after buy). Return max profit.


🗺️ 映射到滑动窗口 / Map to the Pattern Template

这题看起来不像“窗口里有什么元素集合”,但本质仍是“在线扫描 + 维护一个约束状态”。

  • right = 今天(卖出日)
  • left 不需要显式移动;我们维护“到目前为止最低买入价” = min_price_so_far
  • result = 当前最大利润

关键变化 / Key variation:

  • 不需要 while 收缩窗口,因为约束不是“窗口合法性”,而是“买入必须在卖出之前”。

✅ Python 解法 / Python Solution

from typing import List

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        min_price = float('inf')
        best = 0

        for price in prices:  # price is the current 'sell' candidate
            # Update the best profit if we sell today
            best = max(best, price - min_price)
            # Update the minimum price seen so far (best 'buy')
            min_price = min(min_price, price)

        return best

🔎 手动 Trace / Walkthrough Trace

prices = [7,1,5,3,6,4] 为例:

  • Day1 price=7: min=7, best=max(0, 7-∞)=0
  • Day2 price=1: best=max(0, 1-7)=0, min=1
  • Day3 price=5: best=max(0, 5-1)=4, min=1
  • Day4 price=3: best=max(4, 3-1)=4, min=1
  • Day5 price=6: best=max(4, 6-1)=5, min=1
  • Day6 price=4: best=max(5, 4-1)=5, min=1

答案 = 5


⏱️ 复杂度 / Complexity

  • Time: O(n)
  • Space: O(1)

举一反三 / Connect to Other Problems in This Pattern Block

同一个“右指针扫过去,维护一个状态”的思路,在这个 block 里会逐步升级:

  1. #3 Longest Substring Without Repeating Characters:窗口里维护“无重复”的约束,需要 while 收缩。
  2. #424 Longest Repeating Character Replacement:维护“窗口内最多字符频次”和允许替换次数。
  3. #76 Minimum Window Substring:需要精确覆盖目标字符计数,窗口收缩更讲究。
  4. #239 Sliding Window Maximum:窗口最大值维护通常用单调队列。

今天这题是最简形态:窗口里只需要记住“历史最小值”。


📚 References

  • LeetCode Problem: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/
  • NeetCode Explanation: https://www.youtube.com/watch?v=1pkOgXD63yU
  • Sliding Window Technique (general): https://www.geeksforgeeks.org/window-sliding-technique/

🧒 ELI5

中文:每天你看到一个价格,就问自己两件事:

1)如果我以前最便宜的时候买了,今天卖能赚多少?

2)今天会不会比以前更便宜,适合作为新的“最便宜买入日”?

一路走到最后,你就找到能赚最多的一次买卖。

English: Each day, ask: (1) if I had bought at the cheapest earlier day, what profit do I get selling today? (2) is today the new cheapest day to buy? Keep the best profit.

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

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

How do you handle technical debt? Give me a specific example

类别 / Category: Technical Leadership · Senior/Staff Level


🎯 为什么重要 / Why This Matters

每个工程团队都有技术债。面试官不想听你说"我们应该重构"——他们想听你如何量化债务、说服利益相关者、执行还债计划,同时不停业务开发。

Every eng team has tech debt. Interviewers don't want "we should refactor" — they want to hear how you quantified the debt, persuaded stakeholders, and executed payoff while keeping feature work moving.


⭐ STAR 框架示范 / STAR Example

Situation 情境:

我们的订单服务是 3 年前写的单体模块,每次改价格逻辑都要改 400 行 if-else,每月导致 2-3 次生产事故。

Our order service was a 3-year-old monolith module. Every pricing logic change touched 400 lines of if-else, causing 2-3 production incidents per month.

Task 任务:

作为 Tech Lead,我需要在 Q3 OKR 里推动重构,但产品经理有 12 个新功能排队。

As Tech Lead, I needed to push refactoring into Q3 OKRs while PM had 12 features queued.

Action 行动:

  1. 量化痛苦 / Quantify the pain: 统计过去 6 个月:incident 修复耗时 120 工程师小时,每次 pricing 功能开发耗时是预期的 3x
  2. 用数据说服 / Data-driven pitch: 向 VP Eng 展示"如果不还债,Q4 每个 pricing 功能要 3 周而不是 1 周"
  3. 渐进式重构 / Incremental approach: 不做 Big Bang,设计 Strangler Fig 模式——新功能走新架构,旧功能逐步迁移
  4. 20% 规则 / 20% rule: 每个 sprint 拿出 20% capacity 用于还债,写在 sprint contract 里

Result 结果:

3 个月后 incident rate 降了 70%,新 pricing 功能开发时间从 3 周降到 5 天。VP Eng 在季度 all-hands 上引用这个案例。


❌ Bad vs ✅ Good

❌ "技术债很重要,我们应该分配时间去重构。" → 太泛、没有 evidence、没有具体行动 ✅ "我追踪了6个月的 incident 数据,发现每月120小时 浪费在补丁上。我提出 Strangler Fig 方案,用20% sprint capacity 渐进还债,3个月后 incident 降70%。" → 有数据、有策略、有结果

🏅 Senior/Staff Tips

  1. 永远先量化 / Always quantify first — "技术债导致了 X 小时浪费 / Y 次事故 / Z% 速度下降",不要用模糊感受
  2. 关联业务指标 / Tie to business metrics — "如果我们不修,下季度功能交付速度慢 40%"
  3. Strangler Fig > Big Bang — 渐进式替换比全部重写风险低 10 倍
  4. 建立持续机制 / Build ongoing mechanism — 20% rule、tech debt sprints、quality budget 都是好策略
  5. 展示 leadership / Show leadership — 你不是在"要求时间做技术的事",而是在"保护团队交付速度"

🔑 Key Takeaways

  • 技术债 = 利息在涨的贷款,不是可有可无的清洁工作
  • 量化 + 数据 + 渐进执行 = 让所有人 buy-in 的方程式
  • 最好的还债方式:和新功能开发并行,不是"暂停一切来重构"

📚 References


🧒 ELI5

中文:技术债就像你房间越来越乱。你可以继续往里塞东西(加功能),但找东西越来越难(bug 越来越多)。聪明的做法不是某天请假大扫除,而是每天花10分钟整理一点。

English: Tech debt is like your room getting messier over time. You can keep stuffing things in (adding features), but finding anything gets harder (more bugs). The smart move isn't taking a day off to deep-clean — it's tidying up 10 minutes every day.

🎨
🎨 Frontend
🎨 前端 Day 14 / Frontend Day 14

🎨 前端 Day 14 / Frontend Day 14

React Context — Global State Without Prop Drilling

类别 / Category: React Patterns · Week 3


🌍 真实场景 / Real Scenario

你在做一个 SaaS dashboard。用户登录后,`user` 对象需要在 Header、Sidebar、Settings、ProfileCard 都能访问。你总不能 `<App user={user}> → <Layout user={user}> → <Sidebar user={user}> → <UserAvatar user={user}>` 一路传下去吧?

You're building a SaaS dashboard. After login, the user object needs to be accessible in Header, Sidebar, Settings, ProfileCard. You can't keep passing user prop 4 levels deep.

这就是 Prop Drilling 的痛。Context 来拯救你。


💻 核心代码 / Code Snippet

import { createContext, useContext, useState, ReactNode } from 'react';

// 1. Create the context with a type
interface User { name: string; role: 'admin' | 'user'; }

interface AuthContextType {
  user: User | null;
  login: (user: User) => void;
  logout: () => void;
}

const AuthContext = createContext<AuthContextType | null>(null);

// 2. Create a provider component
function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);

  const login = (u: User) => setUser(u);
  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// 3. Create a custom hook (ALWAYS do this)
function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error('useAuth must be used within AuthProvider');
  return ctx;
}

// 4. Usage — any nested component
function UserAvatar() {
  const { user } = useAuth();
  return <span>{user?.name ?? 'Guest'}</span>;
}

🧠 猜猜这段代码输出什么?/ Quiz

const ThemeContext = createContext('light');

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Parent />
    </ThemeContext.Provider>
  );
}

function Parent() {
  return <Child />;
}

function Child() {
  const theme = useContext(ThemeContext);
  console.log(theme);
  return <div>{theme}</div>;
}

A) undefined

B) 'light'

C) 'dark'

D) Throws an error

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

C) 'dark'

ChildThemeContext.Provider value="dark" 内部,所以 useContext(ThemeContext) 返回 'dark''light' 是 default,只有在没有 Provider 包裹时才生效。

</details>


❌ Bad vs ✅ Good

// ❌ BAD: Putting everything in one giant Context
const AppContext = createContext({
  user: null, theme: 'light', locale: 'en',
  cart: [], notifications: [], settings: {}
});
// Problem: ANY change re-renders ALL consumers

// ✅ GOOD: Split into focused contexts
const AuthContext = createContext<AuthContextType | null>(null);
const ThemeContext = createContext<ThemeContextType>({ theme: 'light' });
const CartContext = createContext<CartContextType>({ items: [] });
// Each context only re-renders its own consumers
// ❌ BAD: Using context for frequently changing values
<PositionContext.Provider value={{ x: mouseX, y: mouseY }}>
// Re-renders EVERY consumer 60 times/sec

// ✅ GOOD: Use useRef + subscription for high-frequency updates
// Or use a state manager like Zustand/Jotai for this case

🧭 什么时候用 / When to Use

用 Context ✅不用 Context ❌
主题 (theme)频繁变化的值 (mouse position)
认证状态 (auth)复杂的全局状态 (use Zustand)
国际化 (locale/i18n)只传 1-2 层的 props
功能开关 (feature flags)需要 selector 优化的场景

经验法则 / Rule of thumb: Context 适合"读多写少"的全局数据。如果值频繁变化,考虑 Zustand 或 Jotai。


📚 References


🧒 ELI5

中文:想象你家有一个"公告板"(Context Provider)。任何家庭成员(子组件)不管在哪个房间,都能直接看到公告板上的信息,不需要一个人传一个人地接力。

English: Think of Context as a family bulletin board. Any family member (child component), no matter which room they're in, can read the bulletin directly — no need for a game of telephone passing the message through each person.

🤖
🤖 AI
🤖 AI Day 16 — CONCEPT

🤖 AI Day 16 — CONCEPT

RAG — Retrieval Augmented Generation

检索增强生成 — 让 AI 说真话的关键技术


💡 直觉解释 / Intuitive Explanation

中文:

LLM 有两个大问题:1) 知识有截止日期 2) 会"一本正经地胡说八道"(幻觉)。

RAG 的思路很简单:先查资料,再回答。

就像一个学生考开卷考试:不用背所有知识,考试时翻书找到相关段落,然后用自己的话回答。LLM 就是那个学生,你的知识库就是那本书。

English:

LLMs have two big problems: 1) knowledge cutoff date 2) they "hallucinate" confidently.

RAG's idea is simple: look it up first, then answer.

Like a student in an open-book exam: instead of memorizing everything, find the relevant passages in the book, then answer in your own words. The LLM is the student, your knowledge base is the book.


⚙️ 工作原理 / How It Works

用户提问 知识库 (文档/网页/DB) "Redis 和 Memcached │ 有什么区别?" │ 预处理:切块 → 向量化 │ │ → 存入向量数据库 ▼ │ ┌───────────┐ ▼ │ 1. Embed │──查询向量──► ┌──────────────┐ │ Query │ │ Vector DB │ └───────────┘ │ (Pinecone/ │ │ │ ChromaDB) │ │ └──────┬───────┘ │ │ │ Top-K 相关片段 │ │ ◄────────────────────────┘ ▼ ┌───────────────────────────────┐ │ 2. 构建 Prompt │ │ "根据以下资料回答用户问题: │ │ [片段1] [片段2] [片段3] │ │ 问题:Redis vs Memcached?" │ └───────────────┬───────────────┘ │ ▼ ┌───────────────────────────────┐ │ 3. LLM 生成带引用的回答 │ │ "根据文档,Redis 支持持久化 │ │ 而 Memcached 是纯内存的..." │ └───────────────────────────────┘

三步流程 / Three Steps:

  1. Retrieve 检索 — 把问题转成向量,在向量数据库中找最相关的文档片段
  2. Augment 增强 — 把检索到的片段塞进 prompt 作为上下文
  3. Generate 生成 — LLM 基于上下文生成回答(不靠猜,靠证据)

🌍 实际应用 / Applications

场景怎么用 RAG
企业知识库内部文档 → 向量化 → 员工用自然语言提问
客服机器人FAQ + 产品手册 → 回答准确率从 60% → 95%
代码助手项目代码 + 文档 → 上下文感知的代码建议
法律/医疗法规/病例库 → 有据可查的回答

为什么不直接 Fine-tune?

  • Fine-tune:慢、贵、知识固化在模型权重里,更新需要重新训练
  • RAG:快、便宜、换文档就换知识,实时更新

🐍 可运行代码 / Runnable Python Snippet

pip install chromadb openai
import chromadb

# 1. Create a local vector DB and add documents
client = chromadb.Client()
collection = client.create_collection("demo")

collection.add(
    documents=[
        "Redis supports persistence (RDB/AOF), Memcached is in-memory only.",
        "Redis has data structures: strings, hashes, lists, sets, sorted sets.",
        "Memcached is multi-threaded; Redis is single-threaded with io_threads.",
    ],
    ids=["doc1", "doc2", "doc3"],
)

# 2. Query — ChromaDB auto-embeds and finds relevant docs
results = collection.query(query_texts=["Redis vs Memcached?"], n_results=2)
print("Retrieved:", results["documents"])
# 3. Feed results["documents"] into your LLM prompt as context

📚 References


🧒 ELI5

中文:

想象你在答一场考试。普通 AI 全靠记忆答题(有时候记错了还很自信)。RAG AI 答题前先翻了一遍参考书,找到最相关的几页,然后根据书上的内容回答。所以它答得更准,还能告诉你"我是从第 42 页看到的"。

English:

Imagine taking a test. Regular AI answers purely from memory (sometimes confidently wrong). RAG AI first flips through a reference book, finds the most relevant pages, then answers based on what the book says. So it's more accurate and can even say "I found this on page 42."