设计一个亿级 IM 即时通讯系统
如何设计一个支撑亿级用户的即时通讯(IM)系统?这是系统设计面试中最经典的题目之一,也是实际工程中最复杂的分布式系统之一。本文将从需求分析出发,逐步构建一个完整的 IM 系统架构,涵盖长连接管理、消息投递、在线状态、多设备同步、群聊优化等核心问题。 Part 1: 需求分析与容量估算 功能需求 功能 优先级 说明 单聊 P0 一对一实时消息 群聊 P0 多人群组消息(最大 500 人) 在线状态 P1 显示用户是否在线 消息已读 P1 已读/未读状态 多设备同步 P1 手机、电脑、平板同时在线 离线消息 P0 离线用户上线后拉取未读消息 消息类型 P0 文本、图片、语音、视频、文件 消息搜索 P2 全文搜索历史消息 推送通知 P1 离线时通过 APNs/FCM 推送 非功能需求 指标 目标 DAU 1 亿 同时在线 2000 万 消息延迟 P99 < 200ms 消息可靠性 不丢消息(at-least-once) 消息有序性 单会话内有序 可用性 99.99%(全年停机 < 53 ...
原码·反码·补码——从环形数轴到 CPU 减法器
CPU 只有加法器,没有减法器。为了让 A - B 直接变成 A + (-B),人们发明了补码;原码、反码只是推导脚手架。本文将从最基础的原码出发,经过反码的过渡,最终抵达补码的本质——环形数轴上的模运算,并深入探讨补码在不同编程语言中的体现。 Part 1: 原码——人类的直觉 符号位 + 绝对值 原码是最直观的有符号整数表示方法:最高位表示符号(0 正 1 负),其余位表示绝对值。 以 8 位为例: 十进制 原码 说明 +5 0000 0101 符号位 0(正),绝对值 5 -5 1000 0101 符号位 1(负),绝对值 5 +0 0000 0000 正零 -0 1000 0000 负零 +127 0111 1111 最大正数 -127 1111 1111 最小负数 表示范围:-127 到 +127,共 255 个不同的值(因为 +0 和 -0 占了两个编码)。 原码的致命缺陷 缺陷一:双零问题 +0(0000 0000)和 -0(1000 0000)是两个不同的编码,但它们表示的是同一个数学值 0。这给硬件判断"结果是...
Redis 经典用例全解:从数据结构到系统设计
Redis 最容易被误解成“更快的数据库”。这个理解只对了一小半。Redis 更适合放在系统的热路径上,处理短生命周期状态、派生索引、原子协调、近实时统计和少量高频列表;完整事实仍然应该由数据库、日志或对象存储承载。 系统设计面试里,Redis 的价值也不在命令背诵。更重要的是把业务需求翻译成几个稳定的问题模型: 这份数据是否可以过期 这份数据丢了能否重建 读路径是否远热于写路径 是否需要排序、范围查询、集合运算或原子判断 Redis 故障时,系统还能不能保持核心正确性 答案如果把 Redis 当成事实库,通常会在持久性、审核追溯、深页查询或跨 key 一致性上掉坑。更可靠的边界是:数据库保存事实,Redis 保存热路径和派生状态。 Redis 的系统设计位置 Redis 方案设计可以按四步落地: 步骤 要回答的问题 常见错误 抽象操作 业务本质是读写单值、排序、集合、位图、消息流,还是原子判断 上来先套命令 设计 Key Key 的粒度、生命周期、hash slot、热点边界是什么 一个业务对象塞进一个大 key 明确事实源 哪些数据必须落数据库,哪...
系统的弹性
背景介绍 1999年,Dan Kegel 在互联网上发表了一篇文章,首次将 C10K 问题带入软件工程师的视野。在那个互联网勃兴的年代,计算机的运算处理能力,ISP 能够提供的带宽和网速都还十分有限,用户的数量也很少(那时候一个网站几百个人是很正常的事)。Dan Kegel 却已经敏锐地注意到极端的场景下资源紧张的问题。按照他的观察,某些大型的网络站点需要面对高达10000个客户端的并行请求。以当时的通行系统架构,单机服务器并不足以处理这个这个问题(当时绝大部分系统也没有那么大的流量,所以大部分人也没意识到这个问题)。因此,系统设计者必须为 C10K 问题做好准备。在那篇文章之中, Dan Kegel 提出了使用非阻塞异步 IO 模型,和使用各种内核系统调用黑魔法来提高系统 IO 性能的方式,来提高单机的并行处理能力。不得不说,这篇文章在当时很有先驱意义,它使得大规模网络系统的流量问题浮上了水面,也让人们意识到了系统容量建模和扩容提升性能的重要性。在它的启发下,C10K 问题出现了很多变种,从并发 C10K clients,到并发 C10K connections,到 C10K ...
aws 的分布式系统相关挑战
原文:《分布式系统相关挑战》 早期的亚马逊系统的相关挑战 当服务器出现到第二台的时候,分布式系统的挑战就出现了: latencey scalablity 理解网络 API 数据编组和解组 Paxos 算法的复杂性 随着系统的不断快速扩展和分布程度的不断提高,理论上的边缘情况成为了常态。所以小系统不出问题主要是因为分布程度不够高。 开发分布式实用程序计算服务(例如可靠的长途电话网络或 Amazon Web Services (AWS) 服务)比较困难。与其他形式的计算相比,分布式计算也更古怪,而且不够直观,因为它存在两个相互关联的问题。在分布式系统中,造成最大问题的是故障独立性和不确定性。在分布式系统中,除了大多数工程师习以为常的计算故障外,故障还会以许多其他方式出现。更糟糕的是,不可能时刻知晓某事项是否发生了故障。 分布式系统的类型 离线分布式系统 批处理系统 大数据分析集群 电影场景渲染农场 蛋白质折叠集群 这种离线系统没有对 request 和 response 之间的强实时要求。 虽然离线分布式系统实现起来并不容易,但它却几乎囊括了分布式计算的所有优点(可扩展性和容...
Web 会话与身份认证全景
Web 会话与身份认证全景 HTTP 协议是无状态的(RFC 7230 §2.3)。每一次请求对服务器而言都是全新的,服务器不会记住上一次请求来自谁。这个设计简化了协议本身,却把"如何记住用户"的问题留给了应用层。 围绕这个核心问题,衍生出一条完整的技术问题链: 1记住用户 → 安全地记住 → 跨系统记住 → 授权第三方 → 凭证选型 → 浏览器隔离 → 攻击与防护 本文沿着这条问题链,从会话管理到身份认证,从安全边界到攻防实战,构建一幅完整的技术全景图。 全景问题链 模式总览 问题 模式 口诀 覆盖章节 HTTP 无状态,如何记住用户? 载体 + 服务端存储 Cookie 传 ID,Session 存数据 Part 1 Cookie 如何安全传输? 六大属性三开关 域路径定范围,过期定寿命,三开关定安全 Part 1 单机 Session 如何扩展? 集中存储 + 无状态令牌 存 Redis 或签 JWT Part 1 HTTP 层如何传递凭证? 认证头 + 质询-响应 Basic 明文,Digest 哈希,Bearer 令牌 P...
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 基础共享库和内核模块(支持 /bin 和 /sbin) libc.so(C标准库)、modules/(内核模块) /media Media 可移动设备挂载点(自动挂载) usb/(U...
Kubernetes 架构演进:从容器到云原生应用平台的故事
本文由 Claude-3.7-Sonnet 生成。 从裸机到容器:应对复杂性的演进 1. 物理服务器时代的困境 最初,应用程序直接部署在物理服务器上,导致: 资源利用率低下(一台服务器只运行一个应用) 环境一致性问题(“在我的机器上能运行”) 应用隔离性差 2. 虚拟机的改进 虚拟化技术出现,每台物理服务器可运行多个虚拟机: 提高了资源利用率 但启动慢、资源占用大 3. 容器(Container)的革命 容器技术解决了关键痛点: 轻量级(共享宿主机OS内核) 快速启动(秒级) 可移植性强(构建一次,到处运行) 资源占用小 但问题出现了: 当容器数量增长,单机管理变得困难,集群管理更是挑战。 Kubernetes组件的逐步演进 1. Pod:为什么不直接使用容器? 容器本身有局限性: 单个容器难以满足应用的协作需求 需要将紧密关联的功能组合在一起 因此诞生了Pod: Pod是最小部署单元,包含一个或多个容器 共享网络命名空间和存储卷 同一Pod中的容器总是在同一节点上运行 适合边车(sidecar)模式,如日志收集、代理容器 多容器Pod的深度实践 当我们需要在...
Go 语言学习
#《Go 语言编程》学习笔记 Herb Sutter 在2003年写的《免费午餐已经结束》,言犹在耳,尽量通过并发来压榨硬件性能是大势所趋。但是并发难写。 并发执行是有执行体的。process、thread 和 coroutine 都是执行体。线程是轻量级进程,协程是轻量级线程。但大多数语言在语法层面上并不支持创建协程,而通过库的方式支持的协程功能也不完善。Go 语言提供的协程叫 Goroutine。Go 语言标准库提供的所有系统调用(syscall)操作,当然也包括所有同步 IO 操作,都会出让 CPU 给其他 goroutine,这让事情变得非常简单(哪里简单了,它自动产生了 yield 吗?)。 执行体间的通信,包括几个方式: 执行体之间的互斥与同步 执行体之间的消息传递 执行体之间存在共享资源时,为保证内存访问逻辑的确定性,需要对访问该共享资源的相关执行体进行互斥。当多个执行体之间的逻辑存在时序上的依赖时,也往往需要在执行体之间进行同步。护持与同步是执行体间最基础的交互方式。 在并发编程模型的选择上,有两个流派,一个是共享内存模型,一个是消息传递模型。多数传统语言选择...
秦晖:21世纪全球化危机
本文原载思想,引自公众号。 2018年4月2日晚,清华大学人文学院历史系教授秦晖在上海喜马拉雅美术馆发表了题为“21世纪的全球化危机”的学术演讲。秦晖教授认为,全球化在西方那里造成了社会不平等的加剧,在中国这里本来应该增加社会平等的一些功能,也没有真正能够落实。这样,全球化在全球都造成了不平等加剧的现象。秦晖教授提醒听众,在全球化进行了一段时间以后,如果我们说,以前中国改革决定的是中国的命运的话,那么现在,中国改革在某种意义上还决定着世界的命运,决定着全球化到底趋向于一种良性的进步,还是趋向于劣币驱逐良币。以下为演讲内容: 今天晚上我们讲的是21世纪的全球化危机,当然也可以说是困境。 从两三年前开始,就是2016年吧,大家就开始感到,有很多异乎寻常的事情发生。第一件事,英国脱欧,这个事情出乎很多人意料。当时的英国保守党政府本来的估计是大家会反对脱欧,但结果在脱欧公投中,脱欧居然就是成为多数的民意。 再就是,美国选出一个既不是传统左派、也不是传统右派的奇葩总统,这也是出乎很多人意料的。而且他上台以后提出的一系列主张也非常令人吃惊,不管是传统的左派还是右派,不管是民主党的主流派还是共...





