分布式事务
问题定义 对经典的电商场景而言:下单是个插入操作,扣减金额和库存是个更新操作,操作的模型不同,如果进行分布式的服务拆分,则可能无法在一个本地事务里操作几个模型,涉及跨库事务。 CAP 定义 根据 Eric Brewer 提出的 CAP 理论: Consistency:All Nodes see the same data at the same time。所有节点看到同一份最新数据(线性一致性)。 Availability:Reads and writes always succeed。非故障节点必须在合理时间内响应。 Partition tolerance:System continues to operate despite arbitrary message loss or failure of part of the system。网络分区时系统继续运行。 由此诞生三种设计约束和取舍方向: CA:放弃P,仅适用于单点系统,非分布式,如 MySQL主从同步。 AP:放弃强一致性,保证高可用。Cassandra,DynamoDB。Gossip协议可实现最终一致性。 CP...
系统设计
System Design 总结 面试前你需要了解的16个系统设计知识 《搞定系统设计:面试敲开大厂的门》 从 0 到 100 万用户的扩展 数据库的选择 先把服务器里计算和存储的服务器分离开来。 在如下情况下,可以考虑 NoSQL: 低延迟。 非结构化非关系型。 只需要序列化格式-或者对序列化格式友好。 需要存储海量数据。 《你到底用 NoSQL 来做什么?》 scale up vs scale out 纵向扩展的缺点: 有硬性限制。 没有冗余。 横向扩展对大型应用更合适。 负载均衡器 failover 基于负载均衡器就够了,有了 LB 我们才能装多台服务器。 数据库复制 从换主很容易丢失数据,先要恢复脚本才能实现对数据的合法写和读。 缓存 读写模式 我们常用的缓存策略叫 Cache-Aside Cache,完整介绍在《Caching Strategies and How to Choose the Right One》。 如果是应用自己加在缓存,就是 cache aside;如果缓存自己带有 load 方法-比如 guava 的 loader 实现,则意味着 ...
《编程之美》
序言 下水道井盖为什么是圆的 “下水道井盖是圆的,因为圆形不会掉进井口,而且圆形具有均匀分布压力的优势。” 一个屋子有一个门(门是关闭的)和3盏电灯。屋外有3个开关,分别与这3盏灯相连。你可以随意操纵这些开关,可一旦你将门打开,就不能变换开关了。确定每个开关具体管哪盏灯? 答:将一盏灯开一段时间,再关掉,在剩余2盏灯里随机开一盏,进屋去看,发热的灯对应第一个碰的开关,亮着的灯对应开关开着的开关,灭的灯对应没碰过的开关。 游戏之乐 如何写一个程序让 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; }...
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 of Memor...
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 ...
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>标签,并将其 typ...
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.》,专门解释这个问题。总体看下来, Di...