系统的弹性
背景介绍 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>标签,并将其 type 属性设置为 hid...
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.》,专门解释这个问题。总体看下来, Din...
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 可移动设备挂载点(自动挂载) ...
Kubernetes 架构演进:从容器到云原生应用平台的故事
本文由 Claude-3.7-Sonnet 生成。 从裸机到容器:应对复杂性的演进 1. 物理服务器时代的困境 最初,应用程序直接部署在物理服务器上,导致: 资源利用率低下(一台服务器只运行一个应用) 环境一致性问题(“在我的机器上能运行”) 应用隔离性差 2. 虚拟机的改进 虚拟化技术出现,每台物理服务器可运行多个虚拟机: 提高了资源利用率 但启动慢、资源占用大 3. 容器(Container)的革命 容器技术解决了关键痛点: 轻量级(共享宿主机OS内核) 快速启动(秒级) 可移植性强(构建一次,到处运行) 资源占用小 但问题出现了: 当容器数量增长,单机管理变得困难,集群管理更是挑战。 Kubernetes组件的逐步演进 1. Pod:为什么不直接使用容器? 容器本身有局限性: 单个容器难以满足应用的协作需求 需要将紧密关联的功能组合在一起 因此诞生了Pod: Pod是最小部署单元,包含一个或多个容器 共享网络命名空间和存储卷 同一Pod中的容器总是在同一节点上运行 适合边车(sidecar)模式,如日志收集、代理容器 2. ReplicaSet:确保可用...
Go 语言学习
#《Go 语言编程》学习笔记 Herb Sutter 在2003年写的《免费午餐已经结束》,言犹在耳,尽量通过并发来压榨硬件性能是大势所趋。但是并发难写。 并发执行是有执行体的。process、thread 和 coroutine 都是执行体。线程是轻量级进程,协程是轻量级线程。但大多数语言在语法层面上并不支持创建协程,而通过库的方式支持的协程功能也不完善。Go 语言提供的协程叫 Goroutine。Go 语言标准库提供的所有系统调用(syscall)操作,当然也包括所有同步 IO 操作,都会出让 CPU 给其他 goroutine,这让事情变得非常简单(哪里简单了,它自动产生了 yield 吗?)。 执行体间的通信,包括几个方式: 1. 执行体之间的互斥与同步 2. 执行体之间的消息传递 执行体之间存在共享资源时,为保证内存访问逻辑的确定性,需要对访问该共享资源的相关执行体进行互斥。当多个执行体之间的逻辑存在时序上的依赖时,也往往需要在执行体之间进行同步。护持与同步是执行体间最基础的交互方式。 在并发编程模型的选择上,有两个流派,一个是共享内存模型,一个是消息传递模型。多数传统...
秦晖:21世纪全球化危机
本文原载思想,引自公众号。 2018年4月2日晚,清华大学人文学院历史系教授秦晖在上海喜马拉雅美术馆发表了题为“21世纪的全球化危机”的学术演讲。秦晖教授认为,全球化在西方那里造成了社会不平等的加剧,在中国这里本来应该增加社会平等的一些功能,也没有真正能够落实。这样,全球化在全球都造成了不平等加剧的现象。秦晖教授提醒听众,在全球化进行了一段时间以后,如果我们说,以前中国改革决定的是中国的命运的话,那么现在,中国改革在某种意义上还决定着世界的命运,决定着全球化到底趋向于一种良性的进步,还是趋向于劣币驱逐良币。以下为演讲内容: 今天晚上我们讲的是21世纪的全球化危机,当然也可以说是困境。 从两三年前开始,就是2016年吧,大家就开始感到,有很多异乎寻常的事情发生。第一件事,英国脱欧,这个事情出乎很多人意料。当时的英国保守党政府本来的估计是大家会反对脱欧,但结果在脱欧公投中,脱欧居然就是成为多数的民意。 再就是,美国选出一个既不是传统左派、也不是传统右派的奇葩总统,这也是出乎很多人意料的。而且他上台以后提出的一系列主张也非常令人吃惊,不管是传统的左派还是右派,不管是民主党的主流派还是共...
灵机一动的程序设计
怎样用此列表来排序彼列表 123456789101112131415161718192021222324252627282930313233private List<TagGroup> reorder(Long id, List<TagGroup> entities) { final AccountSettings accountSettings = getAccountSetting( id); final List<Long> tagGroupOrders = accountSettings.getTagGroupOrders(); // 根据 tagGroupOrders 里提供的 tagGroupId 对 entities 排序 if (CollectionUtils.isNotEmpty(tagGroupOrders)) { entities.sort((o1, o2) -> { int index1 = tagGro...
Redis 开发与运维
Redis 特性 Redis 高性能的原因 Redis 的读写性能达到 10w/s,主要基于以下原因: 数据主要放在内存中。 Redis 使用距离 OS “层次更近”的 C 语言实现。 Redis 使用单线程架构,没有很高的 lock contention。 IO 多路复用技术 Redis 的代码实现得优雅而兼顾性能 Redis 的数据结构 Redis 本身是 Remote Dictionary Server 的简称,其中,老的、常见的数据结构有: - 字符串 - 哈希 - 列表 - set(集合) - zset(有序集合) 但后来追加了几种新颖的数据机构,包括:bitmap、hyperloglog,更后来更添加了 GEO 地理信息相关的工具。 基于这些数据结构,我们可以实现一些常见的功能: 键过期,可以用来实现缓存,进而实现分布式锁。 发布订阅功能,进而实现消息系统(TODO)。 Lua 脚本功能,可以实现自定义的 Redis 命令(TODO)。 实现简单的事务功能,能在一定程度上实现事务特性。 提供流水线功能,能够让客户端一次性把一批命令一次性上传到 Redis 里,能...