《编程之美》
下水道井盖为什么是圆的“下水道井盖是圆的,因为圆形不会掉进井口,而且圆形具有均匀分布压力的优势。” 如何写一个程序让 cpu 占用率保持在 50%?不要用 if-else 来解决,要把比例转成不同的 worktime。 解法的精确与否其实取决于“多久时间内测度一次已占用的时间”和“睡眠”两类 api 的精度。 bash 版本12345678910111213#!/bin/bash# 精简版CPU负载控制器L=${1:-50} # 默认50%[ $L -lt 0 ] || [ $L -gt 100 ] && { echo "用法: $0 [0-100]"; exit 1; }echo "CPU负载${L}%,Ctrl+C停止"trap 'echo -e "\n停止"' INTwhile true; do for i in $(seq $L); do : > /dev/null; done [ $((100-L...
Grokking the System Design
设计一个电梯系统项目链接myElevator 思路1. 这道题考察候选人的什么知识?面试官不是真的想让候选人造一台电梯,而是想通过这个问题评估候选人的综合能力,主要包括: 需求分析与沟通能力:这是最重要的一点。一个优秀的工程师在动手前,会先问问题,明确需求和边界。直接埋头开始写代码的候选人通常会失分。 面向对象设计 (OOD) 能力:这个问题是考察OOD的绝佳场景。如何将现实世界的实体(电梯、楼层、按钮、乘客)抽象成清晰、低耦合的对象和类? 算法与数据结构:电梯调度策略是整个系统的核心,这直接考察候选人的算法设计能力。如何选择合适的数据结构来存储和处理请求,以实现高效的调度? 状态机建模能力:电梯的运行本身就是一个状态机(静止、上升、下降、开门、关门等)。能否清晰地定义这些状态以及它们之间的转换条件,是衡量逻辑思维严谨性的关键。 并发与同步问题:多部电梯、多个乘客请求,这些都是并发场景。候选人是否能意识到可能存在的竞态条件(Race Condition)和资源同步问题? 系统扩展性 (Scalability):设计是只针对一台电梯,还是一个拥有多台电梯的系统?如何将单电梯的设计...
我与 AI 的问答
HTTP 请求体只读一次之谜:Go 与 Java 的应对之道作为一名后端开发者,你几乎肯定会遇到这个经典场景:为了实现日志记录、签名验证或请求重放,你需要在中间件(Middleware/Filter)中读取 HTTP 请求体(Request Body)。然而,当你将请求传递给下一个处理程序时,却发现 Body 变成了空的!程序抛出错误,逻辑中断。 这不是一个 Bug,而是网络 I/O 流处理的一个基本特性。本文将深入探讨这个问题的根源,并详细对比 Go 和 Java 在处理“可重复读 Body”这一问题上的不同解决方案,揭示其背后截然不同的设计哲学。 第一部分:问题的根源——流的“阅后即焚”本质为什么 HTTP 请求体默认只能读取一次? 我们可以把请求体想象成一条从网络连接中实时流淌过来的数据河,而不是一块已经完整存放在硬盘上的文件。 效率至上:当服务器收到一个 HTTP 请求时,特别是像文件上传这样带有巨大请求体的请求,如果需要先把整个几 GB 大小的文件都读到内存里才能开始处理,那将是极其低效且消耗内存的。在繁忙的服务器上,这会轻易导致内存溢出(Out ...
Redis 的神奇用例
二级评论区在现代 Web 应用中,评论系统是用户互动的核心功能之一。一个设计良好的评论系统不仅要能处理大量的读写请求,还需要支持诸如“回复评论”这样的嵌套结构(通常称为二级评论或评论回复)。Redis,作为一个高性能的内存数据库,凭借其丰富的数据结构,非常适合用来构建这样的系统。 本文将探讨如何利用 Redis 的 Hashes(哈希) 和 Sorted Sets(有序集合) 来设计和实现一个高效、可扩展的二级评论系统。 核心设计理念我们设计的核心思想可以概括为两点: 实体存储: 使用 Redis Hash 来存储每条评论(包括一级评论和二级回复)的具体内容-不存博客的具体内容。 关系与排序: 使用 Redis Sorted Set 来维护评论之间的父子关系,并利用其天然的排序能力(基于 Score)来管理评论和回复的顺序(例如按时间倒序)。 数据结构详解存储评论/回复内容 (Hash)我们将每条评论或回复的实际数据存储在一个 Hash 中。 Key: comment:{unique_comment_id} (例如 comment:1001, ...
系统的弹性
背景介绍1999年,Dan Kegel 在互联网上发表了一篇文章,首次将 C10K 问题带入软件工程师的视野。在那个互联网勃兴的年代,计算机的运算处理能力,ISP 能够提供的带宽和网速都还十分有限,用户的数量也很少(那时候一个网站几百个人是很正常的事)。Dan Kegel 却已经敏锐地注意到极端的场景下资源紧张的问题。按照他的观察,某些大型的网络站点需要面对高达10000个客户端的并行请求。以当时的通行系统架构,单机服务器并不足以处理这个这个问题(当时绝大部分系统也没有那么大的流量,所以大部分人也没意识到这个问题)。因此,系统设计者必须为 C10K 问题做好准备。在那篇文章之中, Dan Kegel 提出了使用非阻塞异步 IO 模型,和使用各种内核系统调用黑魔法来提高系统 IO 性能的方式,来提高单机的并行处理能力。不得不说,这篇文章在当时很有先驱意义,它使得大规模网络系统的流量问题浮上了水面,也让人们意识到了系统容量建模和扩容提升性能的重要性。在它的启发下,C10K 问题出现了很多变种,从并发 C10K clients,到并发 C10K connections,到 C10K c...
aws 的分布式系统相关挑战
原文:《分布式系统相关挑战》 早期的亚马逊系统的相关挑战当服务器出现到第二台的时候,分布式系统的挑战就出现了: latencey scalablity 理解网络 API 数据编组和解组 Paxos 算法的复杂性 随着系统的不断快速扩展和分布程度的不断提高,理论上的边缘情况成为了常态。所以小系统不出问题主要是因为分布程度不够高。 开发分布式实用程序计算服务(例如可靠的长途电话网络或 Amazon Web Services (AWS) 服务)比较困难。与其他形式的计算相比,分布式计算也更古怪,而且不够直观,因为它存在两个相互关联的问题。在分布式系统中,造成最大问题的是故障独立性和不确定性。在分布式系统中,除了大多数工程师习以为常的计算故障外,故障还会以许多其他方式出现。更糟糕的是,不可能时刻知晓某事项是否发生了故障。 分布式系统的类型离线分布式系统 批处理系统 大数据分析集群 电影场景渲染农场 蛋白质折叠集群 这种离线系统没有对 request 和 response 之间的强实时要求。 虽然离线分布式系统实现起来并不容易,但它却几乎囊括了分布式计算的所有优点(可扩展性和容错能力...
分布式会话技术
会话技术HTTP协议的本质:无状态(Stateless)。 无状态意味着服务器不会记住任何关于客户端的过往请求。你第一次访问和第一万次访问,对于服务器来说,都是一个全新的、陌生的请求。 问题出现:Web应用很快就需要“记住”用户,比如用户是否登录、购物车里有什么商品。如果无法记住,用户每点击一个链接就需要重新登录一次,购物车也会被清空。 Session的诞生:为了解决这个问题,开发者们引入了“Session”这个逻辑概念。它的目标很简单:在无状态的HTTP之上,人为地创造出一个“有状态的对话(Stateful Conversation)”。 常见的技术有3种: cookie:我们接下来会看到的技术。安全设计比较完备。Set-Cookie和Cookie是对位的header。 url query param:服务器主动把返回的 html 里所有的<a href>都加上 session id。这种方式是特别不安全的,因为分享链接意味着会话状态暴露。 隐藏表单。在生成 HTML 页面时,动态地嵌入一个<input>标签,并将其 type 属性设置为...
Docker in Docker
Why Docker in Docker?最适合的领域应该是持续集成领域,不断地在容器内部产生子容器,加速交付流程。 官方博客里提供的DinD 的解决方案在遥远的年代,需要很多其他的东西来辅助生成一个 docker in docker 的例子,但如今一个 –privileged 的 flag 就搞定一切了。 当前版本正确的 DinD 方案,是这样启动一个 DinD 容器: 12# 我们不能在任意容器里启动子docker,目前都需要dind镜像docker run --privileged -d docker:dind exec 进入这个容器: 1docker exec -it agitated_curran /bin/sh 然后在容器里再跑一个容器: 1docker run -it ubuntu /bin/bash Docker in Docker 为什么难?这有一篇博客《~jpetazzo/Using Docker-in-Docker for your CI or testing environment? Think twice.》,专门解释这个问题。总体看下来...
Unix/Linux 系统的常见目录
一级目录 目录路径 缩写解释 / 全称 用途描述 常见子目录/示例 / Root 根目录,所有其他目录的起点 无 /bin Binaries 基础命令的二进制文件(所有用户必需) ls, cp, mv, cat /boot Boot 系统启动文件(内核、引导加载程序) vmlinuz-*(内核文件)、grub/(GRUB配置)、initramfs /dev Devices 设备文件(物理/虚拟设备接口) sda(磁盘)、tty(终端)、null(空设备)、random(随机数生成器) /etc Etcetera 系统级配置文件(全局配置) passwd(用户账户)、fstab(挂载表)、apt/(APT包管理器配置)、ssh/ /home Home 用户主目录(个人文件和数据) /home/alice(用户 Alice 的目录) /lib Libraries 基础共享库和内核模块(支持 /...
Kubernetes 架构演进:从容器到云原生应用平台的故事
本文由 Claude-3.7-Sonnet 生成。 从裸机到容器:应对复杂性的演进1. 物理服务器时代的困境最初,应用程序直接部署在物理服务器上,导致: 资源利用率低下(一台服务器只运行一个应用) 环境一致性问题(”在我的机器上能运行”) 应用隔离性差 2. 虚拟机的改进虚拟化技术出现,每台物理服务器可运行多个虚拟机: 提高了资源利用率 但启动慢、资源占用大 3. 容器(Container)的革命容器技术解决了关键痛点: 轻量级(共享宿主机OS内核) 快速启动(秒级) 可移植性强(构建一次,到处运行) 资源占用小 但问题出现了: 当容器数量增长,单机管理变得困难,集群管理更是挑战。 Kubernetes组件的逐步演进1. Pod:为什么不直接使用容器?容器本身有局限性: 单个容器难以满足应用的协作需求 需要将紧密关联的功能组合在一起 因此诞生了Pod: Pod是最小部署单元,包含一个或多个容器 共享网络命名空间和存储卷 同一Pod中的容器总是在同一节点上运行 适合边车(sidecar)模式,如日志收集、代理容器 多容器Pod的深度实践当我们需要在一个Pod中运...