架构
架构
对架构的一些看法
- 架构设计关注的是取舍。业务开发关注的是逻辑和实现。
- 架构设计没有体系化的培训和训练机制。
- 架构没有那么高大上。不是一定要技术天分,创造力;架构设计可以不高大上,可以没有高可用、高性能。
架构内容:
架构基础
背景,目的,复杂度来源,设计原则、流程
高可用架构
高性能架构
可扩展架构
架构实战
任何能力的提升都离不开知行合一,架构设计也不例外。架构设计可以有多种方式:
亲自负责一个系统的架构设计
这种机会最锻炼人,但不可能一个工程师从来没做过架构设计然后某天突然被委以重任,必须要先有一定的积累才会有这样的机会;
参与某个系统的架构设计,在总架构师的指导下,负责其中一部分的设计;
在设计好的架构下进行开发
虽然没有亲自参与架构设计,但如果能理解和看懂架构设计,对开发本身也很有帮助,如果能看出和分析出架构存在的问题,那就是一个展现自己的机会。
因此,在没有进行架构设计的时候要做好“知”的储备,并尝试运用这些知识技能去分析和研究已有系统的架构,通过这种方式逐步积累和提升,等到真正有机会的时候,能够做到快速开始,快速把握机会,然后在实践中逐步提升自己的能力。
语言演进&软件多次危机
机器语言:直接由01组成。难以排查。出现过火箭发射问题。
汇编语言:指令转化为英文。编写同一用途的程序,需要针对不对的CPU指令写不同的实现。
高级语言:由编译器统一处理多套CPU指令之间的不同。
20世纪60年代出现的第一次危机,出现了结构化编程。
解决:代码开发复杂性
特性:自顶向下(执行顺序),逐步细化,模块化(函数)
80年代第二次危机,面对对象开始流行。
解决:软件的扩展性
特性:万物皆对象,封装、继承、多态
90年代第三次危机,软件架构开始流行
解决:大型公司当时多部分软件组成的系统带来的问题。
内部耦合严重,开发和排查效率低
- 理解代码慢
- 难以修改、扩展
- 新增修改出现问题多
- 难以排查出现的问题
模块”“对象”“组件”本质上都是对达到一定规模的软件进行拆分,差别只是在于随着软件的复杂度不断增加,拆分的粒度越来越粗,拆分的层次越来越高。
软件开发需要用有限的资源应对随时间变化而增加的复杂性。
“银弹”产生于一定的历史背景和大环境,而历史和环境总是会变化的
2架构设计的目的
架构设计不是为了什么?
- 炫技
- 有事干
- 不是要按着大公司的架构来
- 不是每个系统都需要架构设计。架构设计需要时间,不做设计开发更快
- 不是为了使用流行技术
- 不是最新的就是最好的
架构设计可能导致的问题:
- 推迟项目进度,项目上线遥遥无期
- 成员每天争吵
主要目的:识别软件系统的主要复杂度,综合考量软件系统的复杂度,提供解决软件系统复杂度问题的架构方案。
3架构知识
软件复杂度
复杂度种类
- 性能
- 延迟
- 并发量
- 数据量
- 实时性
- 服务可用性
- 功能扩展性
- 数据安全性。
- 不丢失数据
- 隐私数据。手机号、身份证、地址隐私数据保密,但达不到隐私照片、金融数据的保密性
- 数据权限
- 成本
- 业务复杂度
- 核心业务流、扩展点位置
复杂度分析案例
学生管理系统复杂度分析案例:
- 性能:使用人1万左右,平均每天访问一次,无需特殊考虑。mysql足够,缓存可以不用,nginx也足够
- 服务可用性:宕机2小时也影响不大,无需考虑
- 功能扩展性:功能比较固定,无需考虑
- 数据安全性:
- 需要不丢失大量数据,主备+备用机房
- 访问数据要做控制,账号密码,数据库权限
- 成本:仅需几台服务器,对于大学来说不是问题。

一个架构师一般可以支撑20人以上的团队。(2018 黄洲君 UC架构师)
一个项目已经在持续推进,而当前的每个迭代只是不停地增加新的业务功能,一般不涉及任何底层设施的变动,此时开发人员设计代码架构图,如业务的活动图和类图。架构师无需考虑因开发新业务而引入的复杂度。
复杂度-高性能
单机内高性能
单机发展:
速度:每秒几次逐渐到每秒几亿次
业务种类:简单的科学计算到每秒几万次的搜索
软件系统规模:单机到上万台计算机
操作系统:用户单工字符界面到windows11多用户图形操作系统
组件
- 等待手工输入、计算、输出
- 从存储读取输入、计算、输出。CPU无需等待人直接输入
- 从存储读取输入、多进程计算。A任务计算依赖并等待别的读取时,B任务开始计算。进程间通信被设计出来,包括管道、消息队列、信号量、共享存储等。
- 从存储读取输入、多进程多线程计算。共享进程数据。为了保证数据的正确性,发明了互斥锁机制
- 从存储读取输入、多CPU多进程多线程计算
单机性能:
多进程、多线程、进程间通信、多线程并发。Nginx 可以用多进程也可以用多线程,JBoss 采用的是多线程;Redis 采用的是单进程,Memcache 采用的是多线程,这些系统都实现了高性能,但内部实现差异却很大。
集群高性能
计算机硬件的性能快速发展,但和业务的发展速度相比,还是小巫见大巫了,尤其是进入互联网时代后,业务的发展速度远远超过了硬件的发展速度。
任务分配
- 任务分配器
- 硬件网络设备,如F5,交换机
- 软件网络设备,如LVS
- 负载均衡软件,如Nginx,Gateway
- 任务分配器和业务服务器连接交互
- 分配算法
- 轮询
- 权重分配
- 负载分配。需要业务服务器上报状态
- 1台任务分配不够,多台任务分配器
- 任务分配器
任务分解。微服务
优点:改动影响小,也降低了风险
缺点:增加代码量,增加调用链路,增加排查难度
任务分解带来的性能收益是有一个度的,并不是任务分解越细越好,而对于架构设计来说,如何把握这个粒度非常关键。
复杂度-高可用
无中断。
导致中断的因素:
- 硬件。硬件老化,服务器、路由器、线路
- 软件。bug
- 基础设施。光缆
- 天灾。断电、地震、火灾、洪水
硬件:冗余处理单元
软件:提升质量
计算高可用:
双机算法有主备、主主,主备方案又可以细分为冷备、温备、热备。
分配算法需要结合实际业务需求来分析和判断。例如,ZooKeeper 采用的就是 1 主多备,而 Memcached 采用的就是全主 0 备。
存储高可用:
将数据从一台机器搬到到另一台机器,需要经过线路进行传输,也就需要一定的时间。
这意味着整个系统在某个时间点上,数据肯定是不一致的。按照“数据 + 逻辑 = 业务”这个公式来套的话,数据不一致,即使逻辑一致,最后的业务表现就不一样了。
线路传输的速度:
- 同一机房内部能够做到几毫秒;
- 分布在不同地方的机房,传输耗时需要几十甚至上百毫秒。例如,从广州机房到北京机房,稳定情况下 ping 延时大约是 50ms,不稳定情况下可能达到 1s 甚至更多。
传输线路故障:短的十几分钟,长的几个小时的。例如,2015 年支付宝因为光缆被挖断,业务影响超过 4 个小时;2016 年中美海底光缆中断 3 小时等。
软件故障:如:2023双十一后,因底层组件问题,阿里云故障1小时。
正常情况下的传输延迟,会导致系统的数据在某个时间点或者时间段是不一致的,而数据的不一致又会导致业务问题;但如果完全不做冗余,系统的整体高可用又无法保证,所以存储高可用的难点不在于如何备份数据,而在于如何减少或者规避数据不一致对业务造成的影响。
高可用状态决策:
- 独裁
- 协商
- 民主选举,多数取胜。如:zoopkeeper
复杂度-可扩展性
结合未来的需求做设计,达到未来做需求时仅需小的改动,或者仅需配置即可实现需求。
- 不能所有的变化都考虑
- 不能一点变化也不考虑
- 预测有可能错误
做法:
预测变化
实现变化
隔离变化,将变化和稳定层分开,即封装变化。
将“变化”封装在一个“变化层”,将不变的部分封装在一个独立的“稳定层”。
- 系统需要拆分出变化层和稳定层
- 设计变化层和稳定层之间的接口
提炼出一个“抽象层”和一个“实现层”
抽象层是稳定的,实现层可以根据具体业务需要定制开发,当加入新的功能时,只需要增加新的实现,无须修改抽象层。典型的实践就是设计模式和规则引擎。
如何把握预测的程度和提升预测结果的准确性,是一件很复杂的事情,没有通用的标准可以简单套上去,更多是靠自己的经验、直觉
示例:装饰者模式
复杂度-其他:成本、安全、规模
成本
几台十几台服务器一般不考虑服务器成本。
从10000台降低到8000台差20%的2000台,成本会是4000万左右。
低成本是高性能的约束。
一般先定一个成本。架构设计好后,超出成本时,重新设计,多次设计都不行,找老板提高成本预算。
技术和成本:
新技术可以降低成本,需要成员学习新技术,与已有技术结合
如:
- NoSQL(Memcache、Redis 等)的出现是为了解决关系型数据库无法应对高并发访问带来的访问压力。
- 解决mysql的like查询效率的全文搜索引擎ES,solor
创造技术,需要研发出质变的技术。需要投入大量人力、技术、时间。
如:
- facebook解决php低效研发的php转c++,php转字节码后在虚拟机中运行
- linkedin解决每天5000万消息处理研发的Kafaka
不同公司降低成本的方式:
- 中小公司:引入新技术
- 大公司:可能去创造技术。
安全
软件安全:
用途:防止漏洞攻击
漏洞:xss,crsf,sql注入,windows漏洞,密码破解,框架漏洞:Struts2多次远程代码执行漏洞,fastjson远程代码执行漏洞
攻防对抗中不断补漏洞。
架构安全:
- 攻击案例:
- 2016安全博客网站被攻击的流量,每秒665Gbps
- 2018年,美国东部时间 2 月 28 日,GitHub 在一瞬间遭到高达 1.35Tbps
- 用途:防止强盗,DDos攻击
- 实现
- 传统公司:使用云厂商提供的服务
- 银行:分层多级防火墙
规模
功能:
功能越多,功能之间联系越多,功能迭代时间越长越复杂。
逻辑分支多,功能应用场景不清楚,细节无法掌握。黑盒系统
数据:
mysql在数据量大(2018年写的,单表大于10亿)之后,会出现
- 插入索引需要几个小时
- 条件查询很慢的情况
- 表备份慢
- 修改表结构慢
google解决大量数据研发的:大数据计算mapreduce理论,大数据存储,大数据文档存储
架构设计原则
选择难点示例:
- 要选择业界最先进的技术,还是选择团队目前最熟悉的技术?如果选了最先进的技术后出了问题怎么办?如果选了目前最熟悉的技术,后续技术演进怎么办?
- 选择 Google 的 Angular 的方案来做,还是选择 Facebook 的 React 来做?Angular 看起来更强大,但 React 看起来更灵活?
- 选 MySQL 还是 MongoDB?团队对 MySQL 很熟悉,但是 MongoDB 更加适合业务场景?
- 淘宝的电商网站架构很完善,我们新做一个电商网站,是否简单地照搬淘宝就可以了?
满足当下不过度
不因追求先进而设计远超当前需要的设计。
追求架构大而精美的问题:
- 人员不足
- 没有时间实战
- 需要时间埋坑
- 真实业务场景
演进
随着业务的变化,而逐渐调整架构
软件架构分析
识别复杂度
将主要的复杂度问题列出来,然后根据业务、技术、团队等综合情况进行排序,优先解决当前面临的最主要的复杂度问题。
- 系统稳定性不高,经常出各种莫名的小问题;
- 系统子系统数量太多,系统关系复杂,开发效率低;
- 不支持异地多活,机房级别的故障会导致业务整体不可用。
一次最好只解决1-2个问题
背景信息罗列:
- 中间件团队规模不大,大约 6 人左右。
- 中间件团队熟悉 Java 语言,但有一个新同事 C/C++ 很牛。
- 开发平台是 Linux,数据库是 MySQL。
- 目前整个业务系统是单机房部署,没有双机房。
QPS:峰值一般考虑是日均的3倍
性能扩展性:微博这种的消息中间件可以考虑设计为峰值的4倍。一般不设定在10倍以上
TPS:1000不算高性能
QPS:10000算高性能
设计备选方案
三种错误设计:
要设计最强大的架构,架构本身最优
没有备选方案
解决:防止思维狭隘,目光短浅,思维盲区等决策陷阱
缺点:
可能因为一个缺点就把某个方案否决。实际上没有完美的方案。
自身的评估和经验可能不准确
单一方案无法避免过度辩护
备选方案3-5个;备选方案需要有差异;备选方案可以考虑新技术,不是手里的锤子,遇到的问题都是钉子;
备选方案过于详细
缺点:耗费时间长,评审容易陷在细节里边。
架构师的技术储备越丰富、经验越多,备选方案也会更多,从而才能更好地设计备选方案。
前浪微博2013消息系统设计方案:
- 引入Kafaka
- 集群+Mysql存储
- 集群+自研存储系统
评估和选择备选方案
如:简单,最牛,最熟悉,领导
评分:评判维度给出权重分,计算总分
优先级:评判维度按优先级排列,不满足的依次排除
消息系统评判示例:
评判人员:架构设计师、中间件研发人员、测试、运维、业务主管

最终选择方案2.
- 排除备选方案 1 的主要原因是可运维性,因为再成熟的系统,上线后都可能出问题,如果出问题无法快速解决,则无法满足业务的需求;并且 Kafka 的主要设计目标是高性能日志传输,而我们的消息队列设计的主要目标是业务消息的可靠传输。
- 排除备选方案 3 的主要原因是复杂度,目前团队技术实力和人员规模(总共 6 人,还有其他中间件系统需要开发和维护)无法支撑自研存储系统(参考架构设计原则 2:简单原则)。
备选方案2缺点:
- 备选方案 2 的第一个缺点是性能,业务目前需要的性能并不是非常高,方案 2 能够满足,即使后面性能需求增加,方案 2 的数据分组方案也能够平行扩展进行支撑(参考架构设计原则 3:演化原则)。
- 备选方案 2 的第二个缺点是成本,一个分组就需要 4 台机器,支撑目前的业务需求可能需要 12 台服务器,但实际上备机(包括服务器和数据库)主要用作备份,可以和其他系统并行部署在同一台机器上。
- 备选方案 2 的第三个缺点是技术上看起来并不很优越,但我们的设计目的不是为了证明自己(参考架构设计原则 1:合适原则),而是更快更好地满足业务需求。
个人博客图床选择:
搭建博客
hexo+github搭建博客
2018作为学生,为了博客版权归属自己,使用hexo+github搭建博客,图片存在github上
github图床切换为免费图床sm.ms
搭建后发现github空间只有300M,一张截图十几KB,一天截图十几张,怕不够用。考虑空间功能性、使用成本,找到了免费图床sm.ms
sm.ms迁移到阿里云oss
2022已工作,美国制裁,担心免费图床挂了,无法使用,数据丢失。使用过程也偶现过无法访问。考虑稳定性,存储安全性,切换到了国内付费阿里云oss.
图片从sm.ms迁移到阿里云oss没有成熟可用的代码,自己写了一套。查询指定文件夹md文件,记录其中的https://*.png,下载并上传到阿里云oss,将返回的url替换
详细方案设计
中间件内的技术选型。
如:
- nginx选择负载均衡策略。默认轮询,权重适合机器性能不一致,IP hash适合购物车、电商架构后端有session,根据响应时间分配不容器将某个服务器打卦。
数据库表设计。
- 使用日志表追加记录的方式存储消息
- 消息表异步拉取日志表,存储30天。日志表被拉取后,清楚记录。
- 消息表本身主备
- 字段设计
主备如何切换。
采用 ZooKeeper 来做主备决策,主备服务器都连接到 ZooKeeper 建立自己的节点,主服务器的路径规则为“/MQ/server/ 分区编号 /master”,备机为“/MQ/server/ 分区编号 /slave”,节点类型为 EPHEMERAL。
备机监听主机的节点消息,当发现主服务器节点断连后,备服务器修改自己的状态,对外提供消息读取服务。
业务服务器如何写入消息
消息队列系统提供 SDK 供各业务系统调用,SDK 从配置中读取所有消息队列系统的服务器信息,SDK 采取轮询算法发起消息写入请求给主服务器。
业务服务器如何读取消息?
消息队列系统提供 SDK 供各业务系统调用,SDK 从配置中读取所有消息队列系统的服务器信息,轮流向所有服务器发起消息读取请求。
业务服务器和消息队列服务器之间的通信协议如何设计
消息队列系统后续可能会对接多种不同编程语言编写的系统,为了提升兼容性,传输协议用 TCP,数据格式为 ProtocolBuffer。
架构设计对技术点掌握度要求:
- 使用
- 基本原理,关键设计
- 优缺点
确定选型后,要进行性能和可用性测试
4架构高级知识
成熟架构模式
高性能架构-读写分离
目的:分散读压力。一般在优化慢查询,调整不合理的业务逻辑,引入缓存之后
场景:单机并发无法支撑读请求。如:运营频繁查看大量统计数据。
基本实现:
- 数据库服务器搭建主从集群,一主一从、一主多从都可以。
- 数据库主机负责读写操作,从机只负责读操作。
- 数据库主机通过复制将数据同步到从机,每台数据库服务器都存储了所有的业务数据。
- 业务服务器将写操作发给数据库主机,将读操作发给数据库从机。
缺点:主从复制延时,业务写入后,读取从库读不到。
解决:有一致性要求的指定主库。
- 写操作后的读操作指定发给数据库主服务器。业务的侵入和影响较大
- 读从机失败后再读一次主机。二次读取和业务无绑定,只需要对底层数据库访问的 API 进行封装即可,实现代价较小,不足之处在于如果有很多二次读取,将大大增加主机的读操作压力。黑客暴力破解账号,会导致大量的二次读取操作
- 关键业务读写操作全部指向主机,非关键业务采用读写分离
分配主机查询机制
代码封装。
优点:实现简单,而且可以根据业务做较多定制化的功能。
缺点:故障情况下,如果主从发生切换,则可能需要所有系统都修改配置并重启。
案例:淘宝的 TDDL,sharding-jdbc
中间件封装
优点:数据库主从切换对业务服务器无感知
缺点:所有的数据库操作请求都要经过中间件,中间件的性能要求也很高。实现比较复杂,细节特别多,很容易出现 bug,需要较长的时间才能稳定。
案例:mysql官方MySQL Proxy,奇虎 360 公司数据库中间件 Atlas
高性能架构-分库分表
TiDB与mysql对比 todo
目的:降低查询和写入压力。一般在提升硬件设备,优化慢查询,调整不合理的业务逻辑,引入缓存,读写分离,分库后再分表
场景:单机并发无法支撑读和写请求。如:订单表每月10亿数据。
小公司初创业务,一开始不适合拆分。业界成熟的大公司的预估规模大的业务,可以考虑一开始就拆分。
关系型数据库优势:sql查询、join、事务
分库
按业务拆分库到不同实例
分库案例:
因为电商业务数据库选择了主从分离。
因大节促销防止供应链不受电商业务影响选择了实例分离。
因运营查询数据量大的压力,运营数据,运营sql查询直接查询业务增加指定从库。
主从分离使用阿里云RDS,在mapper中增加特定注释查询主库。
分表
- 垂直切分
- 优点:关系性数据库不常用字段、大字段可以避免查询到内存中。
- 缺点:
- 多一次查询
- 事务无法使用,只能自己模拟。A库写成功,B库失败,需要人工介入。
- 增加成本
- 水平切分
- 切分维度
- 范围
- hash
- 订单表可以按订单号分表,也可以按照买家id或者卖家id分表,还可以按照时间分表
- 配置表
- 实现:ShadingJdbc、mycat
- 缺点:增加查询次数。如select、count、group by、order by、join
- 切分维度
高性能NoSQL
关系数据库缺点:
- 行记录,无法直接存储数据结构。
- schema 强约束导致扩展麻烦。操作不存在的列会报错,业务变化时扩充列也比较麻烦,需要执行 DDL
- 关系数据库在大数据场景下 I/O 较高
- 全文搜索功能比较弱。like查询效率低,多条件查询慢,消耗资源大。
K-V存储
redis
缺点:事务没有原子性和持久性。现在应该有?
大部分业务也不需要严格遵循 ACID 原则
文档数据库
MongoDB
特点:no-schema,可以存储和读取任意的数据。
用途:
场景:
电商的商品数据
不同商品的属性差异很大。
游戏
缺点:无事务,不能join。2023现在应该可以了?实现事务不是完全没有代价的,要么性能降低,要么灵活性降低
优点:
- 新增字段简单,无需执行DDL
- 历史数据不会出错,无字段返回空
- 可以很容易存储复杂数据
列式数据库
HBase
用途:离线海量数据分析统计。
实现:一列的数据在磁盘上是连续的,不同列在磁盘分开存储。
优点:
列读取I/O低。不需要同关系型数据库需要读取其他列字段。
数据压缩率高,占用存储低。
普通的行式数据库一般压缩率在 3:1 到 5:1 左右,而列式数据库的压缩率一般在 8:1 到 30:1 左右
缺点:修改多个列速度慢,多个列修改没有一致性
全文搜索引擎
ES
正排索引:
将某个字段作为1个索引,字段中的值对应n行
倒排索引:
一条数据是一个json;将全部json中的所有单词作为索引值,对应n条json
Elastcisearch 是分布式的文档存储方式。它能存储和检索复杂的数据结构——序列化成为 JSON 文档——以实时的方式。
在 Elasticsearch 中,每个字段的所有数据都是默认被索引的。即每个字段都有为了快速检索设置的专用倒排索引。
高性能架构-缓存架构
目的:降低查询压力。
场景:能容忍短暂数据不一致的查多写少业务。微博、微信
引入复杂度:
缓存击穿
数据不存在。
解决:查询数据库也不存在时,缓存中添加空值
数据量大,分页缓存,爬虫访问所有信息,不常访问的数据把常访问的数据挤出去了
监控缓存命中率。容器化动态增加服务器、限流、业务降级
识别爬虫然后禁止访问,这可能会影响 SEO 和推广
缓存雪崩
单个缓存过期时,加载缓存期间大量请求发送到数据库,数据库扛不住,响应变慢或者直接宕机,影响到其他系统。
解决:加载缓存时机器少,增加sychronized;机器多,增加分布式锁;
缓存设置永久,后台定时任务更新缓存;业务线程发现缓存失效用定时消息通知后台线程更新缓存。
后台定时任务更新还可用于缓存预热
大批量缓存同时过期。
缓存设置固定时间+随机30-80毫秒
缓存热点
缓存数据集中在一个分区上。如:1000万粉丝的微博发重要消息
解决:
- 对缓存复制100份,设置不同过期时间,编号后分开存储到不同服务器上,随机读取。
- 多级缓存。前端:CDN加local storage。后端:二级缓存
其他:
同步刷新缓存:当更新了某些信息后,立刻让缓存失效。
这种做法的优点是用户体验好,缺点是修改一个数据可能需要让很多缓存失效适当容忍不一致:例如某东的商品就是这样,查询的时候显示有货,详情提示没货了
关键信息不缓存:库存,价格等不缓存。这类信息查询简单,效率高
单服务器高性能模式
并发模型
链接、请求
海量连接(成千上万)海量请求:例如抢购,双十一等
常量连接(几十上百)海量请求:例如中间件,mysql,redis,mq
常量连接常量请求:例如内部运营系统,管理系统
PPC 多进程
read -> 业务处理 -> write 。当前连接没有数据可以读,则进程就阻塞在 read 操作上
TPC 多线程
示例:Mysql链接
Reactor同步非阻塞
非阻塞:操作系统read 操作(数据加载到内核缓存)改为非阻塞,当连接上有数据的时候进程才去处理。
同步:用户进程在执行 read(从内核加载到进程空间) 和 send 这类 I/O 操作的时候是同步。
数据加载到内核缓存时间远大于从内核加载到进程空间。
I/O 多路复用结合线程池。I/O 多路复用统一监听事件,收到事件后分配(Dispatch)给某个进程。
单Reactor单进程/线程
示例:单进程redis。不适合处理大value,会阻塞其他请求,可以使用MemaCache
单Reactor多线程
示例:
单 Reator 多线程方案能够充分利用多核多 CPU 的处理能力。
缺点:
- 多线程数据共享和访问比较复杂。
- Reactor 承担所有事件的监听和响应,只在主线程中运行,瞬间高并发时会成为性能瓶颈。
多Reactor多进程/线程
示例:
- 多Reactor多进程:Nginx
- 多Reactor多线程:MemaCache、Netty
Proactor异步非阻塞
bio:阻塞io,PPC和TPC属于这种
NIO:多路复用io,reactor就是基于这种技术
aio:异步io,Proactor就是基于这种技术
TPC计算可支持的并发数:可以根据系统的总资源和每个线程所需的资源来估算。例如,如果系统有8GB内存和4个CPU核心,每个线程需要0.5GB内存和0.5个CPU核心,那么可支持的并发数可能是16个
高性能-负载均衡分类、架构、算法
负载均衡其实是任务分配,不是让不同服务器的负载达到均衡。
DNS负载均衡
优点:简单
缺点:
- 扩展性差,掌控权在域名服务商手中
- 实时性差
- 功能简单,分配策略简单,不能根据服务器差异分配
硬件复杂均衡
设备:F5
量级:百万,200万-800万
优点:
- 性能强,支持并发量大
- 功能强,负载均衡策略丰富。还支持安全功能,防火墙、防DDos攻击
- 稳定。商用,且经过严格测试和市场检验
缺点:
- 贵
- 扩展能力差,可以根据业务进行配置,但无法进行扩展和定制
软件复杂均衡
nginx
量级:万,5万左右
优点:
- 便宜,买linux服务器部署即可
- 灵活,可以用插件实现业务的定制化功能
- 简单:部署和维护简单
支持7层协议,Http
LVS
量级:十万,20万左右。号称80万
支持4层协议
多级负载均衡
DNS做南北地理负载均衡,F5做不同集群负载均衡,LVS、Nginx做不同机器负载均衡

论坛日活1000万用户负载均衡分析
1000万日活 *100pv(请求/每人) / (86400/每秒) * (3/峰值) = 3.6万 峰值QPS
DNS + nginx足够
负载均衡算法
轮询、加权轮询、负载最低优先、响应最低优先、
源地址hash:适合于存在事务、会话的业务。
ID哈希:将某个 ID 标识的业务分配到同一个服务器中进行处理。
高可用-理论
CAP
互联和分享读写数据的分布式系统。如:mysql集群。不是memcache集群
C:分布式同一条数据的一致性
- 具体细节
CAP针对的是分开存储的数据
部分数据选择CP,部分数据选择AP,不是整个系统要设计成CP或AP
如:库存需要CP。用户昵称、爱好需要AP
CAP没有考虑时延。
同机房时延几毫秒,广州、北京机房时延几十毫秒
分区一致性无法严格保证。但可以将不用一块访问的数据分区。比如:1-100的用户存在A实例,101-200存在B实例。
双写一致的时候,A集群挂了,如何去掉双写一致,只让B集群写入,并正常提供服务,前边增加一个服务器又陷入单点故障了。
C没有的时候可以做一些事来方便后续补偿
记录日志,挂调的节点起来后,用日志来同步数据
ACID
针对数据库事务
原子性:一系列操作共同成功,共同失败
一致性:事务开始之前和事务结束以后,数据的完整性没有被破坏。
隔离性:多个并发事务同时对数据进行读写和修改的能力。隔离级别:RU,RC,RR,串行化
持久性:对数据库的修改将永久保存,不因软件故障丢失数据。
原子性、隔离性、持久性是一致性的基础。
涉及到跨多个数据源或多个操作的业务场景时,原子性、隔离性和持久性不足以保证数据的一致性。
Base理论
基本可用
分布式系统在出现故障时,允许损失部分可用性,即保证核心可用。
软状态
允许数据不一致,但不能影响系统整理可用性
最终一致性
所有数据副本经过一定时间后,最终能够达到一致的状态。
高可用-FEMA分析系统可用性方法论
通用分析方法
- 功能点
- 故障点
- 故障影响
- 严重程度
- 故障原因
- 发生概率
- 风险程度
- 已有措施
- 告警后人工干预、容错-备份、自恢复-主从自动切换
- 非法访问白名单控制
- 密码暴力破解的重试次数限制
- 防止磁盘坏道,2年更换
- 后续规划
- 敏感数据加密

高可用存储架构-双机架构
主备
备机只备份数据,主机出现问题时,可手动将服务端指向数据库的地址改为备用机。
场景:内部后台管理系统。如:学生管理系统、员工管理系统
优点:简单
缺点:
- 故障需人工干预
- 1年1-2次的操作不熟练可能出错。
- 备机没有读写浪费资源
主从
场景:论坛,政府官网,门户
优点:
- 主机挂了,读业务仍可用
- 丛机负担读,不浪费资源
缺点:
- 故障需人工干预
- 客户端需感知主从关系,复杂度稍高
- 主从延时出现的数据不一致可能导致业务问题
主备/主从自动切换
实现
状态判断
通知渠道
互连式
中介式
优点:连接管理、状态决策简单
缺点:本身需要高可用。如zookeeper多数选举
模拟式
模拟成一个客户端。备/从写数据到主检查
优点:实现简单
缺点:检查状态少
检测内容:机器掉电、进程是否存在、响应是否缓慢
切换决策
- 切换时机
- 切换策略
- 自动程度
数据冲突解决
数据还没有复制到备机,此时发生切换。主备都有ID=100的数据
优点:无需人工切换
缺点:
- 复杂
- 可能有数据冲突
主主
适用场景少,需要数据能够双向复制。如:用户登录session数据,用户行为的日志数据,论坛草稿数据
高可用存储架构-集群
数据集中集群
介绍:一主多从,数据量单台服务器就可以承担
缺点:
- 多从对主库复制压力大。
- 多个从库数据不一致
- 多个从对主状态判定可能不同
示例:zookeeper集群
数据分散集群
介绍:
业务分实例,不同实例存储在不同地点,避免地理级别的灾害导致数据全部丢失。
同城仍需做备份,或同城双活。
- 复杂点
- 数据存储均衡性
- 容错性,故障服务器数据处理
- 可伸缩性,扩容服务器时数据处理
- 备份机制
- 互相备份
- 优点:成本低
- 缺点:扩展性低,扩展需考虑备份迁移;设计复杂;各地区互相影响
- 集中备份
- 优点:设计简单;扩展容易;各地区互不影响
- 缺点:成本较高
- 单独备份
- 优点:
- 缺点:成本高
- 互相备份
- 复杂点
用途:成百上千台服务器
示例:
大数据Hadoop集群
使用独立主机分配
ES集群
选举其中一台做数据分区分配
rocketMQ
使用客户端轮询发送分配给不同的master
高可用架构
主备
- 冷备
- 温备
主从
集群
2个和2个以上
状态检测,任务分配
对称集群
集群中每个节点可以处理所有类型的请求
非对称集群
节点类型不同处理请求不同。
如:zookeeper
高可用-异地多活架构
仍有分钟级的影响
金融系统大部分使用主备架构,不算业余但也算不上先进。(2018 CIPS(人民币跨境支付系统))
oceanbase保证异地多个节点中大部分节点写成功。未写成功的节点异步恢复。未恢复前不可发生新的交易。???
oceanbase采用了两阶段提交来实现跨区多机分布式事务。当协调器出现故障时,其通过查询所有参与者的状态来恢复分布式事务。当某个分区故障或网络中断时,事务会长时间挂起,直到故障修复,这段时间内部分其实是不可用的。虽然其声称强一致性和高可用,当发生故障和网络中断,依然会导致服务不可用。???
缺点:
- 增加系统复杂度
- 成本高
同城异区
用途:防止机房级别的故障。如:机房火灾、机房断电、空调故障
实现:搭建专用高速网络,两个机房科实现和同一个机房几乎一样的网络传输速度。逻辑上可以看成是一个机房
复杂度:
切换前需要做流量限制,缓慢放量
跨城异地
用途:部分业务应对极端灾难事件
时延:光纤中传输的速度大约是每秒 20 万千米,再加上传输中的各种网络设备的处理,实际还远远达不到理论上的速度。2000千米,不算网络设备需10毫秒。广州机房到北京机房,正常情况下 RTT 大约是 50 毫秒左右,遇到网络波动,回到500毫秒甚至1秒。
业务限制:可接受数据短时间不一致的情况。
可跨城异地多活:用户登录、新闻类网站、微博
不可跨城异地多活:银行存款余额、支付宝余额无法做异地多活。
设计
保证绝大多数用户核心业务异地多活。
保证核心业务
注册、修改用户信息、登录中只保证登录
核心数据最终一致性
- 减小异地多活机房距离,搭建高速网络
- 减少数据同步量。只同步核心业务相关数据
- 保证最终一致性,不保证实时一致性
- 正常情况下5分钟同步至所有机房即可,异常可允许1小时或者1天
- 根据不同的数据特征,进行差异化处理
数据多种方式同步
- 数据库自带的同步
- 消息队列
- 查两次,A登录后,B再登录时,多去A查一次
- 回源读取
- 重新生成数据。如A挂了,在B需重新登录
只保证绝大部分用户
业务降级
- 实时转账替换为转账申请,申请结果发短信通知用户
设计步骤
业务分级
维度:
- 访问量大的业务
- 核心业务
- 产生大量收入
如:QQ聊天对用户更重要,影响用户数量大;QQ空间对用户重要性低,但影响收入(插入了广告);
核心商业模式、公司阶段性目标、和公司具体业务有关,没有绝对的答案。
数据分类
数据量
唯一性
如果数据不需要唯一,那就说明两个地方都产生同类数据是可能的;如果数据要求必须唯一,要么只能一个中心点产生数据,要么需要设计一个数据唯一生成的算法
实时性
可丢失性
可恢复性
微博可以重发。密码丢失可以重置。账号丢失,系统也无法恢复数据就真的丢失了

数据同步方式
消息队列
适合不需要事务一致性、时间顺序一致的数据。如:适合注册用户,不适合修改密码
存储自带同步
如:适合修改密码
查询
示例:

异常处理
双同步
适合可覆盖的数据。如:适合注册用户,不适合修改密码。
不走同一网络。如:消息队列走公网。存储自同步走内网
同步+访问结合
优先读取本地数据,读取不到时读取远程数据
日志记录
每个关键操作前后都记录日志,故障恢复后,数据库数据和日志数据对比修复数据。
存储位置:
- 服务器。应对单台数据库服务器故障
- 本地独立系统。应对业务服务器、数据库同时宕机。如:服务器和数据库在同一机架、同一电源线路。
- 日志异地保存
用户补偿
高可用-接口级故障
系统并没有宕机,网络也没有中断,但业务却出现问题了。例如,业务响应缓慢、大量访问超时、大量访问出现异常(给用户弹出提示“无法连接数据库”),这类问题的主要原因在于系统压力太大、负载太高,导致无法快速处理业务请求,由此引发更多的后续问题。
例如:数据库慢查询将数据库的服务器资源耗尽,导致读写超时。
故障原因:
- 程序bug
- 黑客攻击
- 促销、抢购人数超出预估10倍
- 第三方系统大量请求,第三方系统响应缓慢
降级
实现:通过关闭非核心业务,优先保证核心业务。如:注册,修改用户信息
关闭方式:
后门接口
缺点:多个服务器需要多次调用;需要做安全性校验
同一系统如nacos
熔断
问题:A服务调用B服务超时,导致A服务大量请求阻塞占用资源越来越多后,A服务也宕机
实现:在统一的如网关处,统计到B服务1分钟30%的请求超过1秒后,所有调用B服务的请求立马返回失败。提示10分钟后再尝试
用途:外部服务、第三方服务
先根据分析确定阈值,然后上线观察效果,再进行调优。
限流
用途:更适合简单系统,如:网关系统、负载均衡系统、抢购系统
方式
请求限流
- 总量。如:直播间只允许100万人
- 时间量。如:每秒请求10万。
分析后设定一个阈值,测试上线后,再观察调优。
缺点:
- 未测试到的接口调用情况。
- 限流值不合理。限流6000,实际5000系统就扛不住了;或者限流6000,实际可以到1万
资源限流
分析资源瓶颈,如连接数、文件句柄、线程数、请求队列、CPU、内存。如达到CPU70%时,后续请求都抛弃
分析后设定一个阈值,测试上线后,再观察调优
排队
排队实际上是限流的一个变种,限流是直接拒绝用户,排队是让用户等待一段时间。
排队后如何返回客户端:
- 轮询,2. Long polling,3. HTTP/2推送
可扩展架构模式基本思想和模式
思想:拆,将变化的部分单独放在一个地方。做到修改时不影响其他部分
模式:
- 按流程拆。横拆。如:分层架构、TCP/IP四层模型
- 按功能拆。竖拆。如:登录微服务和注册微服务,规则引擎
拆出来的部分,可以用设计模式、单独的服务
可扩展架构模式-分层架构&SOA架构
分层架构
介绍:两两调用,隔离解耦。
分层方法:完全穷尽,互不相同
示例:
- C/S架构。B/S架构将客户端和服务端隔离。
- 操作系统文件接口单独一层隔离,屏蔽不同文件的差异。上层功能调用统一的VFS文件接口。VFS适配下层不同的文件接口。效果:新接入文件系统时,上层功能不需要修改
优点:强制将分层依赖限定为两两依赖,降低了整体系统复杂度
缺点:
- 冗余。简单的查询功能也需要层层实现一次。
- 性能。20世纪80年代是问题,现在不是了
SOA
介绍:为了解决多个相同功能不同协议已有系统与其他系统交互时的重复开发,是特定场景产生的架构。
实现:所有系统都通过总线系统ESB转换为统一协议后,再和其他系统交互
优点:已有大量不同协议系统要交互时,无法重新开发原有系统。
缺点:ESB容易成为系统卡点。
可扩展架构-微服务
SOA和微服务区别:
| 微服务 | SOA | |
|---|---|---|
| 服务粒度 | 细 | 粗 |
| 服务通信 | 轻量级。http rest、RPC | 重量级。由ESB统一路由、消息转换、消息传递 |
| 服务交付 | 理念是快速交付,相应的要求持续集成、持续部署、自动化测试等敏捷开发相关最佳实践。 | 无特殊要求,主要考虑兼容已有系统 |
| 应用场景 | 更适合快速、轻量级、基于Web的互联网系统,没有历史包袱的企业数据化 | 庞大、复杂、异构的企业级系统。系统已开发多年,无法完全推到重来或进行大规模的优化和重构。成本、相关影响太大 |
微服务陷阱:
部署成本
没有敏捷开发基础能力相关支撑,微服务数量一但变大(如:20个),部署成本呈指数上升。
系统复杂度
服务划分过细,单个服务的复杂度确实下降了,但整个系统的复杂度却上升了,因为微服务将系统内的复杂度转移为系统间的复杂度了。
团队效率
如:团队人员规模是 5 ~ 6 个人,拆分出 30 多个微服务,每个人平均维护 5 个以上的微服务。一个简单的需求开发就需要涉及多个微服务,光是微服务之间的接口就有 6 ~ 7 个,无论是设计、开发、测试、部署,都需要工程师不停地在不同的服务间切换。
性能
调用链太长,性能下降。微服务之间都是通过 HTTP 或者 RPC 调用的,每次调用必须经过网络。一般线上的业务接口之间的调用,平均响应时间大约为 50 毫秒
问题定位困难
一次用户请求需要多个微服务协同处理,任意微服务的故障都将导致整个业务失败。然而由于微服务数量较多,且故障存在扩散现象,快速定位到底是哪个微服务故障是一件复杂的事情。
无法快速交付
如果没有相应的自动化系统进行支撑,都是靠人工去操作,那么微服务不但达不到快速交付的目的,甚至还不如一个大而全的系统效率高。自动化测试、自动化部署、自动化监控()、服务治理(nacos、gateway、sentinel)
可扩展架构-微服务-实践方法
微服务:小、轻,需要自动化基础设施。
拆分方法
- 按业务拆分
- 按人员拆分。每3个人可以拆一个微服务。6个人的团队,2个微服务。
- 系统规模:3个人开一个系统,系统复杂度刚好达到每个人全面理解整个系统。
- 团队管理:3个人可以形成一个稳定的备份;1个人是单点,某些情况下很危险。
- 技术提升:3个人能够形成有效的讨论。少了想法不够,容易陷入思维盲区;多了人员没有认真参与。
- 按可扩展拆分。稳定和变动
- 按可靠性拆分。可靠性要求高和低
- 按性能拆分
基础设施
服务发现、服务路由、服务容错:这是最基本的微服务基础设施。
接口框架、API 网关:主要是为了提升开发效率,接口框架是提升内部服务的开发效率,API 网关是为了提升与外部服务对接的效率。
接口框架:如约定http/rest 并且数据格式是json,数据封装是
Result<T>,统一使用提供Jar包自动化部署、自动化测试、配置中心:主要是为了提升测试和运维效率。
自动化测试:如果每次更新都靠人工回归整个系统,则工作量大,效率低下,达不到“快速交付”的目的,因此必须通过自动化测试系统来完成绝大部分测试回归的工作。自动化测试涵盖的范围包括代码级的单元测试、单个系统级的集成测试、系统间的接口测试,理想情况是每类测试都自动化。如果因为团队规模和人力的原因无法全面覆盖,至少要做到接口测试自动化。
服务监控、服务跟踪、服务安全:主要是为了进一步提升运维效率。
3 和 4 两类基础设施,重要性会随着微服务节点数量增加而越来越重要,但在微服务节点数量较少的时候,可以通过人工的方式支撑。
可扩展架构-微内核架构
微内核架构(Microkernel Architecture),也被称为插件化架构(Plug-in Architecture),是一种面向功能进行拆分的可扩展性架构。如:Eclipse、Idea、Unix操作系统,保险公司的保险核算逻辑系统,不同保险品种可以将逻辑封装成插件。

设计关键点
- 插件管理
- 插件连接
- 插件通信
规则引擎
如:drools,需要将规则封装成下面的页面供用户使用
1 | import com.xiaoruiit.knowledge.point.rule.drools.Person |

架构重构
什么时候重构(重构背景)
因为各种历史原因和历史问题没有及时处理,遗留下来逐渐积累,然后到了一个临界点,各种问题开始互相作用,集中爆发。
系统不断出现各种问题,轻微一点的如系统响应慢、数据错误、某些用户访问失败等,严重的可能是宕机、数据库瘫痪、数据丢失等,或者系统的开发效率很低。
是否需要重构
假设我们现在需要从 0 开始设计当前系统,新架构和老架构是否类似?如果差异不大,说明采取系统优化即可;如果差异很大,那可能就要进行系统重构了。
架构重构不能解决所有问题,架构师的首要任务是从一大堆纷繁复杂的问题中识别出真正要通过架构重构来解决的问题,集中力量快速解决。
系统架构问题分析+重构架构的案例
不合理耦合

重构方案:

全局单点的可用性问题

重构方案

重构后系统的可用性从 3 个 9 提升到 4 个 9,重构前最夸张的一个月有 4 次较大的线上故障,重构后虽然也经历了机房交换机宕机、运营商线路故障、机柜断电等问题,但对业务都没有什么大的影响。
大系统问题
开发效率
系统可扩展性不足。
所有功能都在一个系统中,也可能导致一个功能出问题,整站不可用。
比如说某个功能把数据库拖慢了,整站所有业务跟着都慢了。
多年复杂系统去O
一个运行18年的.net业务系统,业务一刻不能停止,大约2000张oracle表,大量的存储过程函数等实现的业务逻辑,现在要用java来重构,面临的问题就是好多大表都在Oracle中,想去o就涉及到很多表关联,做不到垂直拆分,业务耦合太紧。
数据先不动,先拆分代码到多个子系统,然后再拆分数据。
优点:风险小
缺点:周期长
重写一套新的,然后做数据割接
优点:周期短
缺点:风险大
重构步骤
收集问题
重构需要处理的问题
- 分析架构重构可以解决的核心问题
- 处理核心问题需要的前置条件
区分优先级,问题分类,划分难易程度,最多半年一个周期
相关方游说(shui4)(沟通协调)
重构步骤案例
大系统
收集系统目前存在的问题
可用性、性能、安全、用户体验。每个细分十几二十个子项。
重构需要处理的问题
- 庞大的系统继承了太多功能,可扩展性不足
- 系统可用性不高,经常出线上问题,需要耗费大量人力处理
- 重构需要系统处于一个比较稳定的状态,线上问题不频繁。
- 部分服务硬件资源不够用
- 系统组件使用不合理
- 架构上的问题
优先级、问题分类、难易划分、时间周期、效果衡量后的总策略

重构难点
- 业务不能停,一边在开发新需求,一边完成架构调整
- 关联方多,难以统一行动
- 旧架构的约束
- 大重构需要老板拍板
架构重构对架构师的综合能力要求非常高,业务上要求架构师能够说服产品经理暂缓甚至暂停业务来进行架构重构;团队上需要架构师能够与其他团队达成一致的架构重构计划和步骤;技术上需要架构师给出让技术团队认可的架构重构方案。架构重构需要架构师既要说得动老板,也要镇得住同事;既要技术攻关,又要协调资源;既要保证业务正常发展,又要在指定时间内完成目标。
沟通协调
人员:产品经理、项目经理、运营人员、开发人员。
跨领域沟通需要用通用语言;沟通需要用数据。
沟通如:
- 可扩展性”转换为“版本开发速度很慢,每次设计都要考虑是否对门户有影响,是否要考虑对其他业务有影响”,然后我们还收集了 1 个月里的版本情况,发现有几个版本设计阶段讨论 1 周甚至 2 周时间,但开发只有 2 天时间;而且一个月才做了 4 个版本,最极端的一个版本讨论 2 周,开发 2 天,然后等了 1 个月才和门户系统一起上线。
- 可用性是几个 9转换为整理线上故障的次数、每次影响的时长,影响的用户,客服的反馈意见等,然后再拿其他系统的数据进行对比
协调阻力:这对我有什么好处,这部分我这边不着急
- 分析出对其他团队的好处
- 公司或者部门有利,对某个小组不利的情况。协调更高层级的管理者推动
- 有其他更重要的业务。
- 等待策略,但要明确正式启动的时间。
- 先不做这个系统相关的重构。
错误重构
多模块聚合
问题:版本开发和测试部署一样比较麻烦
正确做法:应该将公共功能独立为服务。
没有区分问题的优先级,所有问题一视同仁,没有集中有限资源去解决最重要或者关键的问题。
问题:做了大半年,好像做了很多事情,但没取得什么阶段性的成果。如同一直做业务完善的小需求和支撑新业务的大需求的区别
没有将问题分类
问题:方案重复,浪费人力,效率低
迫于业务版本压力,挑容易做的实施
问题:达不到重构目的。重构分析差不多白做了
业务发展中的技术演进
架构实战-架构演进方向
技术和业务
产品类业务,服务类业务
创新技术能带来新的业务时,这一刻是技术驱动业务的。如:iPhone智能机、淘宝线上购物
技术是由业务驱动的。
架构演进方向
企业业务发展面对的复杂度就是架构演进的方向。
淘宝是100分。小公司从20分开始演进,大公司可以从60分开始演进。
按照企业当前的业务发展阶段衡量当前复杂度,逐步推演,设计合适的架构。
如果有对手系统可以参考,企业自身业务能够达到一个高度,老板给时间,就预见性的设计,为后续升级留出通路。
业务的不断创新和改进,对技术会提出越来越高的要求,因此是业务驱动了技术发展。
架构实战-互联网业务发展过程中的技术演进
业务复杂性
| 业务标志 | 技术要求 | |||
|---|---|---|---|---|
| 初创期 | 创新的业务点 | 能买则买,能用开源就用开源 | 对技术就一个要求:“快” | |
| 发展期 | 业务推出后经过市场验证可行,业务就进入快速发展的时期。 | 1. 堆功能期; | 团队规模不大,业务需求很紧 | |
| 2.优化期(换磁盘,增加机器,代码优化,增加缓存); | 优点:对系统改动较小,优化可以比较快速地实施;缺点:过不了多久,系统又撑不住了。 | 保证当下的竞争力是最主要的问题 | ||
| 3.架构期(开发速度慢,无法忍受了)。拆功能、拆数据库、拆服务器 | 优点:一次调整可以支撑比较长期的业务发展;缺点:动作较大、耗时较长,对业务的发展影响比较大。 | |||
| 竞争期 | 竞争对手开始加入行业来竞争. 内部问题:1.重复造轮子 2.系统交互一团乱麻 | 解决:1.平台化(存储平台化,淘宝的TFS;数据库平台化,百度的DBProxy)。2.服务化(消息队列,RocketMQ,开源Kafka;服务框架,Facebook的thrift) | 由于竞争的压力,对技术的要求更上一层楼 | |
| 成熟期 | 行业的领头羊。业务创新的机会已经不大,竞争压力也没有那么激烈,此时求快求新已经没有很大空间,业务上开始转向为“求精”。响应时间是否比竞争对手快?我们的用户体验是否比竞争对手好?我们的成本是否比竞争对手低 | 技术上能做的大动作其实也不多了,更多的是进行优化。这个时候的技术优化没有固定的套路,只能按照竞争的要求,找出自己的弱项,然后逐项优化。 |
用户规模
性能、可用性

架构实战-互联网架构图模板
存储层,开发层,服务层,网络层,用户层,业务层;平台层

| 存储层 | 数据库,集群,封装集群后提供服务 | |
| 开发层 | 成熟框架,Web服务器(如:tomcat),容器(K8s,Docker) | |
| 服务层 | 服务治理(配置中心、服务注册、消息队列等) | |
| 网络层 | 负载均衡、CDN、多机房 | |
| 用户层 | 单点登录CAS,授权登录Oauth2,存储云,图片云 | |
| 业务层 | 拆;合(服务太多,多个服务合并为一个域,通过网关对外提供服务);DDD | |
| 平台层 | 运维平台、测试平台、数据平台、管理平台 |
平台层
运维平台
职责:
配置
主要负责资源的管理。例如,机器管理、IP 地址管理、虚拟机管理等。
部署
要负责将系统发布到线上。例如,包管理、灰度发布管理、回滚等。
监控
主要负责收集系统上线运行后的相关数据并进行监控,以便及时发现问题。
应急
主要负责系统出故障后的处理。例如,停止程序、下线故障机器、切换 IP 等。
要求:
标准化
规范配置管理、部署流程、监控指标、应急能力等
平台化
自动化
可视化
测试平台
用例管理
单元测试:代码
接口测试:python
可靠性测试:shell
测试平台需要将用例管理起来,管理的维度包括业务、系统、测试类型、用例代码。例如,网购业务的订单系统的接口测试用例。
资源管理
任务管理。任务管理是测试平台设计的核心,它将测试平台的各个部分串联起来从而完成自动化测试。
数据管理
测试任务执行完成后,需要记录各种相关的数据(例如,执行时间、执行结果、用例执行期间的 CPU、内存占用情况等)
数据平台
数据管理
数据采集
从业务系统搜集各类数据。例如,日志、用户行为、业务数据等
数据存储
数据访问
数据安全
数据平台都是多个业务共享的,部分业务敏感数据需要加以保护
数据分析
数据统计
根据原始数据统计出相关的总览数据。例如,PV、UV、交易额等
数据挖掘
经典的数据挖掘案例就是沃尔玛的啤酒与尿布的关联关系的发现。
机器学习、深度学习
数据应用
例如,推荐、广告等属于在线应用,报表、欺诈检测、异常检测等属于离线应用。
管理平台
身份认证、权限控制
如何选择开源项目做二次开发
为什么选开源项目
避免重复造轮子,提升效率
开源项目的问题
开源项目的质量是未知的。
任何程序员写的项目都有bug。bug轻则造成半小时宕机,严重可能丢失部分数据,甚至丢失全部数据
如何选择开源项目
是否满足业务需求
已有框架满足业务需求时,没必要引入新开源项目
- 功能
- 性能
成熟度
- 使用的公司
- 社区活跃度
- 发帖数
- 回复数
- 问题响应速度
- 版本号,尽量不选0.X的,至少1.X版本
是否有运维工具
- 日志是否齐全。只有启动、停止几行的不好
- 运行时查看。如命令行、管理控制台查看系统运行时情况
- 故障检测和恢复能力。如:告警
如何使用开源项目
深入研究
通过设计文档、白皮书了解设计原理;核对每个配置项的作用和影响,识别出关键配置项
仔细测试
多场景测试。
压力测试:连续跑几天,观察CPU、内存、磁盘I/O指标波动
故障测试:kill、断电、拔网线、重启100次以上
灰度发布
先在非核心业务上线
做好应急
做好数据备份
二次开发
扩展而不修改
增加一个 proxy 层来实现需要的新功能
开发辅助系统:监控、报警、负载均衡、管理等
不着急的时候给开源项目提需求或者bug
造轮子
对于细分需求没有已有轮子时,自己造轮子。
5架构设计案例
淘宝
- 2003年4月7日,为了快。买php+mysql,1个月后5月10日上线。
- 2003年底,mysql扛不住,换成了Oracle
- PHP开源数据库连接池导致Oracle经常死锁,无法解决。请Sun公司专家热切换为Java1.0,使用EJB,Oracle。Java当时是很多主流网站使用的语言
- 性能优化,节约成本。Java2.0,数据分库,切换为Spring,缓存、CDN,开源的JBoss。2005年,商品数量1600多万,PV8931万,会员1390万。已经不是靠“买”就能够解决问题了,此时必须从整个架构上去进行调整和优化。
- Java3.0,去IOE化,技术从商用转向自研。去IBM服务器,去Oracle数据库软件,去EMC存储设备
十万级用户

百万级用户
内存瓶颈,2GB只能支撑1百万用户的在线状态。
CPU/网卡包量/交换机流量瓶颈
单台服务支撑不下所有在线用户

千万级用户
状态服务器同步状态遇到单机瓶颈
单台状态同步服务器支撑不下所有在线用户。

亿级用户
2010年3月重新设计。
- 灵活性很差,比如“昵称”长度增加一半,需要两个月;增加“故乡”字段,需要两个月;最大好友数从 500 变成 1000,需要三个月。
- 无法支撑某些关键功能,比如好友数上万、隐私权限控制、PC QQ 与手机 QQ 不可互踢、微信与 QQ 互通、异地容灾。
- 1.0-3.5都是原来基础上做改造升级,补丁打不动了
微信红包架构
https://www.infoq.cn/article/2017hongbao-weixin/ 资金安全系统解决方案
2017 年 1 月 28 日,正月初一,用户在除夕当天收发微信红包的数量——142 亿个,收发峰值76 万每秒。
类似业务秒杀:
- 发红包相当于秒杀活动的商品上架
- 抢红包相当于秒杀活动的查询库存
- 拆红包相当于下单
业务特点:
并发量比普通秒杀业务更高。
10万人同时发红包,10万个微信群同时抢红包
安全性要求更高
秒杀允许超卖和少卖。拆红包严格不允许超发金额,未发的24小时后金额准确退回
技术难点:
- 并发请求锁
- 事务操作量级大
- 事务性要求严格
常用高并发方案:
内存操作代替DB操作,异步持久化。
优点:磁盘操作转为内存操作
缺点:持久化不能保证
乐观锁代替悲观锁
优点:
缺点:
- 增加资源消耗。并发量大时,产生大量无效请求
- 用户体验低,抢红包不可接受。并发抢到相同版本号的拆红包请求中,只有一个能拆红包成功,其他的请求将事务回滚并返回失败,给用户报错。
- 可能手慢后抢成功,用户体验不好。
主要技术点:
根据红包ID做set分化,分而治之。全国抢一个红包会被分为10000个红包
相同红包ID hash后,发送同同一组服务器、数据库中。解决了海量事务级操作。
请求FIFO队列
服务器增加队列请求排队,写事务串行化访问DB;同一个红包ID路由到同一台机器
增加memacache控制并发,用cas自增统计抢同一红包人数,超过一定值后降级,返回抢红包失败。
数据库双维度分库分表
分库表规则像 db_xx.t_y_dd 设计,其中,xx/y 是红包 ID 的 hash 值后三位,dd 的取值范围在 01~31,代表一个月天数最多 31 天。
结果:
- 单库提升8倍性能。
- 2017每秒76万并发
- 2015、2016、2017无故障
移动端架构演进
2010年前后,受限于设备、网络速度,PC互联网是主流。移动端一开始在Web业务上包装一个APP的壳,即WebApp。
2013年前后用户体验差据越来越大,原生APP(Android、IOS、windows Phone)成为主流。
用户体验差距:
- 移动设备的发展速度远远超过 Web 技术的发展速度
- App 承载的业务逻辑越来越复杂
- 移动设备在用户体验方面有很多优化和改进,而 Web App 无法利用这些技术优势
在移动互联网更具竞争力又开始需要开发速度,出现Hybrid App
组件化、容器化
WebApp
原理:基于 web 技术(HTML、CSS、JavaScript)开发的应用。
优点:开发快,跨平台,成本低
缺点:体验差
原生App
原理:使用特定平台(如iOS、Android)的原生编程语言
优点:体验好
缺点:开发慢,不同平台需要重复开发
Hybrid App
原理:使用 web 技术(HTML、CSS、JavaScript)开发应用的一部分,并使用桥接技术将其集成到原生应用中。
优点:可以在体验和开发速度上均衡
缺点:开发速度WebApp慢,体验比原生APP差
开源项目的学习
1,2,3步骤,在研究开源项目的时候必不可少。
安装
获取依赖组件
依赖组件是系统设计和实现的基础。nginx依赖的库有pcre、pcre-devel、openssl、openssl-devel、zlib;openssl与https有关,zlib与压缩有关。
安装后的目录
conf会存放配置文件,logs会存放日志,sbin存放运行程序;
redis的redis-benchmark、redis-check-aof,这些工具在后面故障定位和处理、性能测试等场景可能非常方便。
运行
通过命令行和配置文件了解系统具备的能力和如何运行。
了解配置项的原理、作用、影响,并且尝试去修改配置项然后看看系统会有什么变化。
每个命令行参数和配置项的作用和原理都全部掌握清楚时,对系统已经很熟悉了。
原理研究
研究命令行和配置项的时候已经涉及一部分原理。
接下来针对原理进行系统性的研究。
关键特性实现原理
白皮书,设计文档;为了学习只需要看设计相关的;
网上已有的分析文档,可以站在前人的基础上,避免大量的重复投入;但需要多篇文章做对比;
Demo验证;
优缺点分析
掌握了技术方案的优缺点后才能在架构设计的时候做出合理的选择。
将两个类似的系统进行对比,实现差异,以及不同的实现优缺点都是什么;
测试
需要在掌握参数配置,关键原理之后进行测试。
根据业务特点,掌握的原理,编写测试用例。
可以在准备在生产项目中使用时,再进行测试。
源码研究
带着明确目的去研究源码。学习关键特性的代码实现。
写demo,调试查看调用栈理解基础库的处理逻辑和过程,这比单纯看代码去理解逻辑要高效一些。
可以在有时间精力时再做。
架构师内功
内功内容:
找出问题
项目架构上指的是找出复杂度在哪
解决问题
第一种:作出合适的方案解决已有复杂度问题
第二种:作出创新的方案解决复杂度
内功来源:
经历
设计过的系统越多、系统越复杂,架构师的内功也就越强,不管是成功的架构,还是失败的架构,不管是踩坑的经验,还是填坑的经验,都将成为架构师内功的一部分。
技能
掌握的技能越多,技能越深,内功越强。
思考
经历需要经过思考转化为经验。技能需要思考后为我所用。
将经历和技能中的模式、判断、选择、技巧等提炼出来为我所用。
架构师岗位成长
不同阶段有不同的针对性方法
工程师
特征:基础技能积累
技能经验
Java语法
开发工具
数据库CRUD、缓存使用
业务系统基本流程
学习方法:书籍
学习内容:经典书籍,《Java编程思想》、《Java核心技术》、《TCP/IP协议》
高级工程师
- 时间:2-5年
- 特征:已有架构下独立完成开发
- 技能经验
- 设计理论:数据库表设计3范式、面对对象设计模式、SOLID设计原则、缓存设计理论
- 技术原理:如:Java数据结构实现原理
- 需求分析,设计方案(表设计,2个表还是3个表),编码实现
- 积累表、缓存、业务流程、接口设计经验。根据设计理论、技术原理设计
- 学习方法:书籍、源码
- 学习内容:《深入理解Java虚拟机》、《MySQL技术内幕:InnoDB存储引擎》、HashMap源码
技术专家
领域内
初级架构师
分系统架构、简单系统架构
中级架构师
大型分布式系统架构,架构可以支撑100人团队干活
高级架构师
总结
复杂度与解决整理
性能-写请求扛不住:
- 分库分表,读扛不住读写分离+缓存就够了。
- 瞬时流量:分区顺序MQ,异步通知结果
扩展性-解耦:
- 微服务
- 消息队列
- DDD
可扩展:
- 微服务
- 分层
- 消息队列
- 设计模式-策略模式、观察者模式等
- 规则引擎
- 工作流引擎
日志占了百分之二十的cpu:
- 日志压缩,采样,隔离
架构升级
单机→集群:对单机进行性能测试,获得单机性能的极限数据,当业务实际性能达到极限的80%时,开始考虑扩容。
常见性能
- nginx:3万
- kafaka:百万
- redis:10万
- http:2万
- zookeeper:写入读取2万以上
- 业务系统:有的会是500
画好架构图的方法:4+1视图
架构师需要五项全能:技术,沟通,推动,管理,撕逼
一分析二讨论三开会四汇报五审批
数据聚合位置
首页有多个资源聚合,是应该app端去请求多个资源服务,然后聚合出来展示;还是有个后台服务去聚合后端的各个基础服务,然后只提供一个接口给app访问?
访问量大的,核心业务用服务器聚合,性能好;
访问量小的,非核心业务用app聚合,可扩展性好;
书
《伟大的计算原理》《人月神话》《淘宝技术这十年》
《UNIX编程艺术》
《异类》:个人成长