目录
- 从零开始学架构
- 程序设计与架构设计
- 架构即人性!切勿好大喜功。
- 组件与模块
- 框架Framework和架构Architecture
- 高**的误区
- 以史为鉴
- 架构设计的主要目的
- 高屋建瓴,有的放矢,而非贪大求全
- 任务分配器与业务服务器
- 系统的高可用
- 数据+逻辑=业务
- CAP定理
- 高可用状态决策
- 可扩展性
- 创新
- 安全
- 规模
- 名词解释
- 规范
- 建筑
- 备选方案
- 关系数据库
- CAP
- 正常情况下,不存在CP和AP的选择(即:当P可以舍弃时),可以同时满足CA。
- 分区期间(一年可能5分钟(4个9)、50分钟(5个9))
- BASE
- FMFA(Failure mode and effects analysis)故障模式与影响分析
- 存储高可用
- 主备倒换(主读写,备备份)与主从倒换(主读写,从读)
- 开源的数据集中集群
- 数据分散集群
- 分布式事务算法
- 数据分区
- 计算高可用
- 业务高可用
- 异地多活设计步骤
从零开始学架构
照着做,你也能成为架构师
李运华|著
技术成就梦想,坚持就能成功
程序设计与架构设计
程序设计的关键思维是逻辑
和实现
。
架构设计的关键思维是判断
和取舍
。
架构即人性!切勿好大喜功。
三大原则:
- 合适原则——合适优于业界领先。
- 简单原则——简单优于复杂。
《UNIX编程艺术》Kiss:KeepItSimple,Stupid!
- 演化原则——演化优于一步到位。
系统是其内部的诸多有关联的个体按照相应的规则
运行出的具备新的能力的东西。
组件与模块
从逻辑的角度来拆分系统得到的单元是模块
从物理的角度来拆分系统得到的单元是组件
划分模块的主要目的是职责划分
划分组件的主要目的是单元复用
component组件,零件,属于物理范畴。
框架Framework和架构Architecture
不同角度理解问题,所抽象出的概念是不同的。
高**的误区
不能一味的追求高性能、高可用和高扩展!
Done is better than perfect!
以史为鉴
探索一个事务的目的,最好的方式就是去追寻这个事物出现的
历史背景和推动因素。
屁股决定脑袋,位置决定想法。
事物的量级达到一定程度后,问题也会***变质***。
模块、对象再到组件,差别是随着软件的复杂度不断增加,拆分
的粒度越来越粗,拆分的角度越来越高。
架构设计的主要目的
是为了解决复杂度带来的问题。
低成本是架构设计的附加约束。
高屋建瓴,有的放矢,而非贪大求全
不同架构应该针对不同的复杂点。
任务分配器与业务服务器
任务分配随着量级的增加,性能损耗越来越高,整体收益会大打折扣。
任务分解,拆大为小,进而更容易找到关键性能点进行突破,且不会
牵一发而动全身,方便调优。
拆分后的子系统之间交流也有成本,所以拆分的粒度要适度。
系统的高可用
通过冗余实现无中断。相当于功能备份。
存储高可用的难点不在于如何备份数据,而在于如何减少或规避数据不一致
对业务造成的影响。
数据+逻辑=业务
即便是毫秒级别的传输延时,也会照成数据的不一致,进而导致业务出现问题。
CAP定理
consistency
available
partitionTolerance
存储高可用不可能同时满足一致性
、可用性
、分区容错性
,最多满足
其中两个,在做架构设计时要结合业务进行取舍。由于网络延时等不可避免,
所以通常在一致性
与可用性
之间进行取舍。
高可用状态决策
独裁式:一个决策者与多个上报者
协商式:主从通信问题
民主式:投票选举,脑裂
混乱问题
可扩展性
设计模式
正确预测变化,完美封装变化。
唯一不变的是变化
变与不变,稳定层与变化层的确立。
创新
小公司引入新技术,大公司创造新技术。
安全
功能上的安全,在攻与防的矛盾中逐步完善。
架构上的安全
防火墙一般不适用海量用户访问与高并发。
运营商或云服务商具备强大的带宽和流量清洗能力。
规模
规模的线性增加带来的是复杂度的指数增加。
数据越来越多,系统复杂度也会由量变带来质变。
大数据的三架马车。
传统mysql推荐单表5000万行左右。
名词解释
CDN:Content Delivery Network
GSLB:Global Server Load Balance
规范
凭借个人经验与感觉设计架构。
积累自己的储备库。
大公司具备的平台、资源和积累是架构衍生的关键。
环境逼迫创新。
情境激活灵感。
建筑
对于建筑来说,永恒是主题。
对于软件来说,变化是主题。
条条大路通罗马,要综合选择。
备选方案
3-5个
几乎没有无暇的方案
如果你有一把锤子,那么所有的问题在你看来都是钉子。
不要被既有经验局限。
备选阶段关注技术选型,而不是技术细节。
360度环评:最简派、最牛派、最熟派、领导派
极端情况的出现毕竟是小概率事件,留有较多余力的时候再去考虑。
举例:
1.横向扩展
2.系统拆分
不同的方案,面对不同的公司情况,考虑问题的侧重点应该不同。
权值的设定应该依具体情况而定。
按优先级选择。
详细方案的设计阶段可能显露出备选方案中遗漏的关键点,进而导致
备选方案全局否定。架构师应该在早期看的更深入。
海纳百川,博采众长。
关系数据库
高性能数据库集群:
- 读写分离:将访问压力分散到多个节点。主机读写,从机读操作。
主从复制延迟问题:
1.写操作后的读操作指定发给主机。
2.从机读取失败后再读一次主机,二次读取会增加主机压力。
3.关键业务全部指向主机,非关键业务由从机完成。
- 分库分表:既分散访问压力,又分散存储压力。
join操作问题:无法使用join
事务问题:分布式事务解决方案性能不高。
成本问题:业务分库一般后期进行。前期业务规模小且不稳定。
- 单表数据拆分的两种方式:
垂直拆分:不常用的字段剥离出去。
水平拆分:如果单表行数超过5000万,相对来说可以考虑拆分。
范围路由:单表水平分段建议100万到2000万之间。
最后一张表可能导致分布不均。
Hash路由:所有表分布均匀,但后期扩充要重分布。
配置路由:记录拆分信息,利于扩充,但多一次查询。
拆分难点:粒度选取。
举例:count()
拆分后的多个表求总记录数,需要把每张表的count()
累加求和,性能会受到影响。引入记录数表记录当前表
的行数,又会导致同步更新的问题,复杂度增加。
order by操作无法进行,需要单表排序后引入中间件汇总排序。
- 读写分离实现:
程序代码封装:实现简单,但每个语言都需要自己实现一次,无法通用。
如:TDDL(Taobao Distributed Data Layer)头都大了!
中间件封装:数据库中间件对业务服务器提供的是标准SQL接口。
实现复杂,主从切换服务器无感知。
如:mysql-proxy、mysql-router、奇虎360的Atlas。
- NoSQL
关系数据库的缺点:
1.无法存储数据结构,存储的是行记录。
2.schema扩展不方便。扩充列导致表长时间锁定。
3.大数据场景下IO较高。即使是对某一列进行统计,
关系数据库也会将整行进行读取。
4.且全文搜索能力比较弱。
NoSQL!= no sql 而是 NoSQL = Not only sql
针对上述缺点常见的NoSql方案:
1.k-v存储:Redis
2.文档数据库:MongoDB
3.列式数据库:HBase
4.全文搜索引擎:Elasticsearch
1.Redis事务只支持I(是单进程单线程的工作模式)和C,不支持
A(不支持回滚)和D.
2.no-schema的文档数据库,如JSON数据是自描述的,无需在使用前
定义字段,读取一个JSON中的不存在的字段也不会导致SQL的语法错误。
JSON比起先要执行DDL的关系数据库要方便更多。但某些对事务要求严格
的业务场景是不能使用文档数据库的。通常可以sql+noSql组合使用。
3.行式存储可以同时高效读取多个列,也可以同时在一行中对多个列进行
写操作。但在海量数据进行统计的场景中并不适用。普通行式数据库一般
压缩率在3:1到5:1左右,而列式数据库压缩率一般在8:1到30:1左右。
4.全局搜索引擎技术原理:倒排索引。
正排索引:根据文档名称来查询文档内容。
倒排索引:根据关键词来查询文档内容。
全文搜索引擎的索引对象是单词和文档,而关系数据库的索引对象是键和行。
全文搜索引擎在支持关系型数据全文搜索时需要JSON(不唯一)与表对应转换。
Elasticsearch是分布式的文档存储数据库。它能存储和检索复杂的数据结构
————序列化称为JSON文档————以实时的方式。在Elasticsearch中,每个字
段的所有数据都是默认被索引的。即每个字段都有为了快速索引设置的专用倒
排索引。而且,不像其他多数的数据库,它能在相同的查询中使用所有的倒排
索引,并以惊人的速度返回结果。
- 缓存
将可能重用的数据放到内存中,一次生成,多次使用,避免每次使用都去访问
存储系统。
缓存穿透:故意访问不存在的数据,空值替代。
生成缓存耗费时间和资源,当竞争对手故意爬取所有分页时(通常
缓存前10页比如),会拖慢整体。
缓存雪崩:缓存失效后引起系统性能极具下降。
解决方法:1.更新锁机制:加锁保证只有一个线程进行缓存更新。
2.后台更新机制:后台线程更新缓存而不是由业务线程更新缓存。
缓存本身的有效期设置为永久,后台线程定时更新缓存。
定时读取:频繁查看被踢的数据,及时更新空值。
消息队列通知:业务线程发现缓存丢失主动发消息
通知后台线程更新缓存。相对简单,且可以用于系统
预热。
缓存热点:某明星大咖的消息复制多份缓存,缓解服务器压力。
PPC:Process per Connection,每次有new connection,then fork a new process.
- some problems:
- Fork is expensive.
- IPC:Interprocess Communication is expensive.
- The increasing number of processes are not good for
performance.
- solvable method:
1.prefork,which needs system solve “惊群” phenomenon.
2.TPC:Thread per Connection.
3.进程池:
read操作改为非阻塞,然后进程不断地轮询多个连接,
但这并不优雅,且连接达到几千上万的时候,效率低下。
4.I/O多路复用结合线程池:Reactor 即:反应堆(事件反应)非阻塞
同步网络模型
当多个连接共用一个阻塞对象后,进程只需要在一个阻塞对
象上等待,而无需再轮询所有的连接。
当某条连接有新的数据可以处理时,操作系统会通知进程,
进程从阻塞状态返回,开始进行业务处理。
Reactor模式也称为Dispatcher模式,即:I/O多路复用
统一监听事件,收到事件后分配给某个进程。
实用类型:单Reactor单进程/单线程。
单Reactor多线程。
多Reactor多进程/线程。
上述具体线程还是进程依具体编程环境及平台有
关。java一般使用多线程。
5.Proactor 前摄器 类比proactive主动的,主动器
Reactor:来了事件我通知你,你来处理。
Proactor:来了事件我来处理,处理完了我通知你。
解释:”我“是操作系统,”事件“是新的连接、有数据可读、数据可写。
流程:
1.Proactor Initiator负责创建Proactor和Handler,并
将Proactor和Handler都通过Asynchronous Operation
Processor注册到内核。
2.Asynchronous Operation Processor负责处理注册请
求,并完成I/O操作后通知Proactor。
3.Asynchronous Operation Processor完成I/O操作后
通知Proactor。
4.Proactor根据不同的事件类型回调不同的Handler进行
业务处理。
5.Handler完成业务处理,Handler也可以注册新的
Handler到内核进程。
目前windows下采用IOCP,而linux采用Reactor模式为主
因为linux下的AIO并不完善。
集群高性能:负载均衡不只是为了计算单元的负载达到均衡状态,而是一种综合的考虑。
- DNS负载均衡
地域级别的均衡。就近原则。
- 硬件负载均衡
集群级别负载均衡。昂贵,扩展能力大。
- 软件负载均衡
机器级别负载均衡。通过软件实现负载均衡功能。
- 负载均衡算法
任务平分类:轮询
负载均衡类:权重轮询
性能最优类:按服务器性能分配,适当概率判断服务器性能
Hash类:同IP或者同session id归属到同一服务器
CAP
- What is Partition Tolerance?
System continues to work despite message loss or partial failure.
The System will continue to function when network partitons occur.
- What is CP?当发生分区时,返回错误。
- What is AP?当发生分区时,返回错误值。
CAP理论的实践
- 需要将系统内的数据按照不同的应用场景和要求进行分类,每类数据选择不同的的策略。
- 比如:用户信息数据选择AP,而用户账号数据选择CP。
- AP相当于是放宽了一致性的要求,可用就好。CP由于追求强一致性而导致不可用情况发生。
- CAP是忽略网络延迟的。有时强一致性的要求导致只能单点写入,其他节点备份,无法做到分布式情况下多点写入。但并不意味着系统无法应用分布式架构,可以两个节点各自负责一半业务,同时备份另一半。这样即便其中一个节点发生故障,也只是影响一半的用户。
正常情况下,不存在CP和AP的选择(即:当P可以舍弃时),可以同时满足CA。
- 此情况我们需要考虑分区发生情况下的CP与AP的选择,同时也要考虑P没有发生情况下的CA的实现。
- 不同的数据CA实现方式可能不一样,比如:用户账号数据可以采用消息队列,因为可以比较好的控制实时性。而用户信息数据可以采用数据库同步的方式来实现,因为实现简单。
分区期间(一年可能5分钟(4个9)、50分钟(5个9))
- 分区发生,则记录相关日志。
- 分区故障解决后,系统根据日志进行数据恢复。
- CAP关注的粒度是数据,而不是整个系统。
BASE
- Basically Available 登录比注册重要。
- Soft State 允许数据存在中间状态(CAP理论中的数据不一致),但不影响系统整体可用性。
- Eventual Consistency 系统中的所有副本经过一定时间后,最终能够达到一致性的状态。是对AP方案的一个补充。
FMFA(Failure mode and effects analysis)故障模式与影响分析
- 是一套分析和思考的方法,应用于各个领域。
- 像
登录
、注册
才是功能点。
- 故障模式关注现象和对应影响,即便原因不同。尽量使用量化描述,而非泛化。
- 对于故障现象,殊途同归,殊因同果,应不同对待。
存储高可用
主备倒换(主读写,备备份)与主从倒换(主读写,从读)
- 问题关键点:
状态判断
、倒换决策
和数据冲突修复
。
- 互连式与中介式(MongoDB(A)),还有模拟式(将备机模拟为客户端进而判别主机状态)。
- 主主倒换需要双向复制。
开源的数据集中集群
数据分散集群
- 均衡性
- 容错性
- 可伸缩性
- Hadoop,Namenode是一个中心服务器,负责数据分区的分配。HDFS,master/slave.
分布式事务算法
- 2PC(Two-phase commit protocol)
- 提交请求阶段,看看是否有No存在,都yes则提交执行阶段。
- 强一致性算法,简单,但不好用。
- 3PC(Three-phase commit protocol)
- 在2PC中间插入一个准备阶段。
分布式一致性算法
- Paxos,state machine replication(active replication)各个节点间复制操作
- Raft,state machine replication(active replication)
- ZAB,primary backup(passive replication)Leader节点执行操作,将执行结果复制给其他节点。
数据分区
- 地理级别重大灾害规避风险。每个区域负责一部分数据。
- 国家洲际间分区仅作为备份,而城市之间由于延迟低、业务相似,分区同时适合对外提供服务。
复制规则
- 集中式 所有分区将数据备份到备份中心。
- 互备式 形成闭合链,但如何加入新的一环。
- 独立式 一对一,不同区域。
计算高可用
主备
冷备(未启动)与 温备(已启动)
主从
从机也干活,主机有故障,从机升级主机(一般升级配置),新增从机。
对称集群与非对称集群
业务高可用
- 异地多活,把鸡蛋放到多个篮子里。
- 优先实现核心业务的异地多活架构!
- 物理(地理等)因素导致无法很快。所以取舍:核心数据最终一致性。采用多种手段,保证绝大部分用户的核心业务异地多活!
- 保证最终一致性,不保证实时一致性。
异地多活设计步骤
- 1.业务分级,根据不同标准不同情境(核心、访问量、盈利)区分业务。
- 2.数据分类,根据(数据量、唯一性、实时性、可丢失性、可恢复性)
3.数据同步
- 存储系统同步(延迟高)
- 消息队列同步(无事务性和无时序性业务)
- 重复生成(如:cookie、session)
4.异常处理
- 多通道同步
- 同步和访问结合:本地没有去其他接口找。
- 日志记录
- 用户补偿