架构设计简单学习

对架构设计的认知

为什么做架构拆分? ----》 为什么要做系统解耦? ----》 为什么要做职责单一? ----》 为什么要关注开发效率?

架构拆分其实是管理在技术上提效的一种手段

总结---------------学会思考,善于思考,单节点学习认知,多节点整合,融会贯通

提高对系统架构设计的认知能力

提高分析系统问题的认知能力

扩大能够驾驭系统的边界

你之前是如何设计这个系统的?

  1. 谈复杂来源
  • 功能性复杂度:要解决业务发展带来的系统耦合、开发效率缓慢问题
  • 非功能性复杂度:要保证系统的高可用性
  1. 谈解决方案
  • 采用开源的MQ消息管道
  • 采用开源的Redis实现消息队列
  • 采用内存队列+MySQL来实现
  1. 谈评估标准

        谈技术实现

  • 在确定了具体的架构解决方案之后,需要进一步说明技术上的落地实现方式和深层原理

CAP理论

Consistency:数据一致性

Availability:服务可用性

Partition tolerance:分区容错性

BASE理论

Basically Available:基本可用

Soft state:软状态

Eventually Consistent:最终一致性

分布式系统的知识体系

存储器:即分布式存储系统,如NoSQL数据库存储

运算器:即分布式计算,如分布式并行计算

输入输出:即分布式系统通信,如同步RPC调用和异步消息队列

控制器:即调度管理,如流量调度、任务调度与资源调度

面试官会用“如何设计海量商品数据的存储?”这样一个问题,向面试者提问,从而考察分布式系统中数据的存储、分布、复制,以及相关协议和算法等考点

  1. 分布式数据存储
  2. 数据分片
  3. 数据复制
  4. 数据副本
  5. 数据容错
  6. 数据一致性
  7. 协议算法

Hash分片

商品存储扩容的设计问题,也就是重新设计数据的分片规则,从这一点出发会考察你Hash(哈希)分片的具体实现原理

如何解决Hash分片的缺点,既保证数据均匀分布,又保证扩展性?

使用一致性Hash:将存储节点和数据都映射到一个首尾相连的哈希环上,存储节点一般可以根据IP地址进行Hash计算,数据的存储位置是从数据映射在环上的位置开始,依照顺时针方向所找到的第一个存储节点。

一致性Hash分片的优点是数据可以较为均匀的分配到各节点,其并发写入性能表现也不错,虽然一致性Hash提升了稳定性,但通过Hash分片的方式很难针对热点商品做单独的架构设计

如何解决单一热点问题?

做Range(范围)分片

要达到这种灵活性,更好的方式是基于分片元数据,请求分片元数据获取的信息也不仅仅只有数据分片信息,还包括数据量、读写QPS和分片副本的健康状态等

如何保证分片元数据服务的可用性和数据一致性?

最直接的方式就是专门给元数据做一个服务集群,并通过一致性算法复制数据

  • 给分片元数据做集群服务,并通过ETCD存储数据分片信息
  • 每个数据存储实例节点定时向元数据服务集群同步心跳和分片信息
  • 当调用端的请求过来时,元数据服务节点只需要做好高可用和缓存即可

ETCD

Etcd使用的是Raft算法

Etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库,基于Go语言实现。 接触过分布式系统的读者应该知道,分布式系统中,最基本最重要的问题就是各种信息的一致性,包括对服务的配置信息的管理、服务的发现、更新、同步等等。而要解决这些问题,往往需要基于一套能保证一致性的分布式数据库系统,比如经典的Apache ZooKeeper项目,通过维护文件目录信息来实现数据的一致性。

Etcd就是专门为集群环境设计,可以很好地实现数据一致性,提供集群节点状态管理和服务自动发现等。

受到Apache ZooKeeper项目和doozer项目 的启发,Etcd在进行设计的时候重点考虑了下面四个要素:

·简单:支持REST风格的HTTP+JSON API;

·安全:支持HTTPS方式的访问;

·快速:支持并发每秒一千次的写操作;

·可靠:支持分布式结构,基于Raft算法实现一致性。

Paxos算法解决了什么问题?

简单来说,paxos算法解决的就是一个最终一致性问题。假设一个集群有三个节点,Paxos可以让三个节点更快的达成一致。因为在Paxos中规定,如果某个节点写操作执行之前其他两个节点(也就是大多数的节点)的值已经相等并记为V,那么除非这次写入的值也为V,否则操作不能进行。而当其他两个节点的意见不统一时,采用高编号的节点的值。因此,最终一定会达到三个节点意见统一的状态。

(高编码的值:请求响应中编号最大的提案的值)

Basic Paxos算法的工作流程是什么?

  1. 提议者不管在第一阶段,还是第二阶段,收到大部分的同意选票后,就算成功
  2. 提议者 发送给各个接受者,接受者接受比自己目前记录的最大提议值大的提议,大多数节点同意后,发送给提议者,第一阶段提议结束
  3. 第二阶段,发送的提议,如果接受者当前记录的最大提议编号比当前发送的提议要大,直接抛弃这个执行提议
  4. 第一阶段,发送给接受者节点,根据响应中提案编号最大的提案的值,来设置接受请求中的值,如果当前没有接受者发过来的值,就设置自己的值。 如果接受者节点有值,根据该规则,提议者把自己的值改掉,然后执行第二阶段流程。

总结: Basic Paxos 算法是 分布式共识算法的基础,它的一些思想渗透进,其他 mutlip paxos算法的方方面面,虽然Basic Paxos算法没有什么落地价值,但是基于它的 Mutliple paxos算法具有很强的价值,Mutiple Paxos并不是一种特定的算法,它是一种思想,

Multiple paxos和Basic paxos的区别

个人理解:Multiple paxos是一种比较大的想法,就是3各节点,同时接收了3个请求,这3个请求对同一个值设置,选出一个值,3个节点设置一致。

这种选择某个值的具体算法,就是Basic paxos完成的任务。

Paxos算法和Raft算法的区别又是什么?

1.算法复杂度:Paxos算法相对来说比较复杂,需要理解多个阶段的消息交互过程,而Raft算法则相对简单,只需要理解Leader选举和日志复制两个基本概念。

2.Leader选举:在Paxos算法中,Leader的选举是通过多轮消息交互来完成的,而在Raft算法中,Leader的选举是通过心跳机制和超时机制来完成的。

3.日志复制:在Paxos算法中,每个节点都可以提议一个值,但只有一个值会被选中,而在Raft算法中,Leader节点负责接收客户端请求并将其转化为日志条目,然后将日志条目复制到其他节点。

4.可读性:由于Raft算法的设计目标是易于理解和实现,因此它的代码和文档更容易理解和阅读。

总的来说,Paxos算法相对来说更为复杂,但是在某些场景下可能更加高效,而Raft算法则更加易于理解和实现,适用于大多数分布式系统场景。

有没有更好的架构思路呢?

可以选择基于Gossip协议的实现方式

谣言传播,最终一致性

总结:

介绍了分布式系统的数据存储、分片,与数据一致性等分布式问题

  • 面试官往往会通过“海量数据的存储设计”问题考察候选人对分布式系统技术的掌握情况,而回答号基于Hash取模、一致性Hash实现分库分表的解决方案
  • 当你掌握了常规的Hash取模分片方式后,面试官会引入一个场景问题来考察你解决架构设计问题的思路,因为分布式系统架构设计离不开系统可用性与一致性之间的权衡,所以你的解题思路要站在这两个技术点之上
  • 如果面试官满意你的表现,会进一步考察你算法原理,所以对于分布式系统中的一致性共识算法,如Basic Paxos、Multi Paxos、Raft、Zab、Gossip也是你要提前掌握的

一次完整的RPC流程

RPC通信流程中的核心组成部分包括了协议、序列化与反序列化,以及网络通信

步骤:

1.调用方持续把请求参数对象序列化成二进制数据,经过TCP传输到服务提供方;

2.服务提供方从TCP通道里面接收到二进制数据

3.根据RPC协议,服务提供方将二进制数据分割出不同的请求数据,经过反序列化将二进制数据还原出请求对象,找到对应的实现类,完成真正的方法调用

4.然后服务提供方再把执行结果序列化后,回写到对应的TCP通道里面

5.调用方获取到应答的数据包后,再反序列化成应答对象

如何设计一个高并发高吞吐的RPC框架

  1. 优化RPC的网络通信性能:高并发下选择高性能的网络编程I/O模型
  2. 选型合适的RPC序列化方式:选择合适的序列化方式,进而提升封包和解包的性能

如何选型序列化方式(考虑时间与空间开销,切勿忽略兼容性,首选Protobuf,Hessian)

  1. JSON:Key-Value结构的文本序列化框架,易用且应用最广泛,基于HTTP协议的RPC框架都会选择JSON序列化方式,但它的空间开销很大,在通信时需要更多的内存
  2. Hessian:一种紧凑的二进制序列化框架,在性能和体积上表现比较好
  3. Protobuf:Google公司的序列化标准,序列化后体积相比JSON、Hessian还要小,兼容性也做得不错

如何提升网络通信性能(实际开发中最常用的是 BIO和NIO)

  • 同步阻塞I/O(BIO)
  • 同步非阻塞I/O
  • I/O多路复用(NIO)
  • 信号驱动
  • 异步I/O(AIO)

BIO:BIO的网络模型中,每当客户端发送一个连接请求给服务端,服务端都会启动一个新的线程去处理客户端连接的读写操作,这会导致服务器的资源不够用,无法实现高并发下的网络开发,所以BIO的网络模型只适用于Socket连接不多的场景

BIO网络模型的问题:

  1. Socket连接数量受限,不适用于高并发场景
  2. 有两处阻塞,分别是等待用户发起连接,和等待用户发送数据

NIO:NIO比BIO提高了服务端工作线程的利用率,并增加了一个调度者,来实现Socket连接与Socket数据读写之间的分离

个人理解:一个工作线程服务与多个Socket,增加的调度者来协调这些工作线程。

在面试中,对于高级研发工程师的考察,还会有两个技术扩展考核点

  1. Reactor模型,以及Reactor的3种线程模型,分别是单线程Reactor线程模型、多线程Reactor线程模型,以及主从Reactor线程模型
  2. Java中的高性能网络编程框架Netty

Reactor模型简单理解

1.单Reactor单线程,前台接待员和服务员是同一个人,全程为顾客服务

2.单Reactor多线程,1个前台接待员,多个服务员,接待员只负责接待

3.主从Reactor多线程,多个前台接待员,多个服务员

案例串联,如何让系统抗住双十一的预约抢购活动?

1.商品预约阶段:要掌握如何在高并发的场景下通过锁的方式,让每一个用户都获取到抢购资格,结合业务场景对于并发控制的需求诉求和成本的考虑,在商品预约阶段,你可以基于Redis来实现分布式锁

2.等待抢购阶段:此阶段对页面的查询请求会很高,尤其是临近抢购倒计时的流量突增,解决方案是做页面静态化和服务端限流

3.商品抢购阶段:瞬时流量会带来极大的压力,所以通过MQ做了同步转异步,实现对流量的削峰,从而让请求排队等待,然后有序且有限地进入到后端服务,而你必须掌握消息队列丢失、重复和积压问题的解决方案;另外在扣减库存的时候,为了解决扣减库存不超售的问题,同样还需要引入锁的机制

4.订单支付阶段:在用户支付完成后,系统通常还需要处理一些非核心操作,你可以通过MQ通知的方式来实现系统间的解耦和异步通信,但依旧要保证消息的可靠性(当然也可以通过RPC同步调用的方式来实现),所以你也要掌握RPC和MQ的相关知识点

通过非主键(辅助索引)查询商品数据的过程

如果你用商品编码查询商品,会先检索辅助索引中的B+Tree的商品编码,找到对应的叶子节点,获取主键值,然后再通过主键索引中的B+Tree树,查询到对应的叶子节点,然后获取整行数据,这个过程叫回表

索引失效

  • 索引列上做了计算、函数、类型转换操作,这些情况下索引失效是因为查询过程需要扫描整个索引并回表,代价高于直接全表扫描;
  • like匹配使用了前缀匹配符'%abc';
  • 字符串不加引号导致类型转换;

如果MySQL查询优化器预估走索引的代价比全表扫描的代价还要大,则不走对应的索引,直接全表扫描,如果走索引比全表扫描代价小,则使用索引

常见优化索引的方法

前缀索引优化:前缀索引就是用某个字段中,字符串的前几个字符建立索引,比如我们可以在订单表上对商品名称字段的前5个字符建立索引。使用前缀索引是为了减小索引字段大小,可以增加一个索引页中存储的索引值,有效提高索引的查询速度。在一些大字符串的字段作为索引时,使用前缀索引可以帮助我们减小索引项的大小。

但是,前缀索引有一定的局限性,例如order by就无法是使用前缀索引,无法把前缀索引用作覆盖索引。

覆盖索引优化:覆盖索引是指SQL中query的所有字段,在索引B+Tree的叶子节点上都能找得到的那些索引,从辅助索引中查询得到记录,而不需要通过聚簇索引查询获得。假设我们只需要查询商品的名称、价格,有什么方式可以避免回表呢

我们可以建立一个组合索引,即商品ID、名称、价格作为一个组合索引。如果索引中存在这些数据,查询将不会再次检索主键索引,从而避免回表。所以,使用覆盖索引的好处很明显,即不需要查询出包含整行记录的所有信息,也就减少了大量的I/O操作

联合索引:联合索引时,存在最左匹配原则,也就是按照最左优先的方式进行索引的匹配。比如联合索引(userpin,username),如果查询条件时WHERE userpin = 1 AND username = 2,就可以匹配联合索引;或者查询条件是WHERE userpin = 1,也能匹配上联合索引,但是如果查询条件是WHERE username=2,就无法匹配上联合索引。

另外,建立联合索引时的字段顺序,对索引效率也有很大影响。越靠前的字段被用于索引过滤的概率越高,实际开发工作中建立联合索引时,要把区分度大的字段排在前面,这样区分大的字段越有可能被更多的SQL使用到 区分度 = distinct(column) / count(*) ,区分度就是某个字段column不同值的个数除以表的总行数,比如性别的区分度就很小,不适合建立索引或不适合排在联合索引列的靠前的位置,而uuid这类字段就比较适合做索引或排在联合索引列的靠前的位置。

MVCC(Multi-Version Concurrency Control)是一种数据库并发控制的机制,它允许读操作与写操作同时进行,提高了数据库的并发性能。MVCC采用了快照读和当前读两种方式来实现并发控制。

快照读是指普通的SELECT语句,它在读写时不需要加锁,但可能会读取到历史数据。而当前读是一种悲观锁的操作,它会对当前读取的数据进行加锁,确保读取的数据是最新的,主要包括SELECT…FOR UPDATE、SELECT…LOCK IN SHARE MODE、UPDATE、INSERT和DELETE等操作。

在数据库并发的场景下,存在着读-读、读-写和写-写三种情况。在读-读的场景中,不会存在任何问题。但在读-写和写-写的场景中,会出现线程安全问题,例如脏读、幻读和不可重复读等。因此,通过使用MVCC机制,可以有效地解决这些并发问题,提高数据库的并发性能。

MySQL主从复制的原理

  1. MySQL主库在收到客户端提交事务的请求之后,会先写入binlog,再提交事务,更新存储引擎中的数据,事务提交完成之后,返回给客户端“操作成功”的响应
  2. 从库会创建一个专门的I/O线程,连接主库的log dump线程,来接收主库的binlog日志,再把binlog信息写入relay log的中继日志里,再返回给主库“复制成功”的响应
  3. 从库会创建一个用于回放binlog的线程,去读relay log中继日志,然后回放binlog更新存储引擎中的数据,最终实现主从的数据一致性

分库分表使用的场景不一样:分表是因为数据量比较大,导致事务执行缓慢,分库是因为单库的性能无法满足要求

NewSQL:NewSQL是新一代的分布式数据库,具备分布式存储系统的高性能、高可用,弹性扩容等能力,兼容传统关系型数据库的SQL标准。还提供了和传统关系型数据库不相上下的事务保证,是具备了支撑未来交易类业务能力的。

Redis只有单线程吗?

Redis是单线程的,主要是指Redis的网络I/O线程,Redis的持久化、集群同步等操作,则是由另外的线程来执行

Redis采用单线程为什么还这么快?

  • Redis的大部分操作都在内存中完成
  • 单线程模型避免了多线程之间的竞争
  • Redis采用了I/O多路复用机制处理大量的客户端Socket请求

Redis版本

  • Redis4.0版本之前,使用单线程速度快的原因就是上述的几个原因
  • Redis4.0版本之后,Redis添加了多线程的支持,但这时的多线程主要体现在大数据的异步删除功能上
  • Redis6.0版本之后,新增了多线程I/O的读写并发能力,在面试中如果你能补充Redis6.0多线程的原理,势必会增加面试官对你的认可

Redis为什么先执行命令,再把数据写入日志呢?

因为,Redis在写入日志之前,不对命令进行语法检查,所以,只记录执行成功的命令,避免了出现记录错误命令的情况,并且,在命令执行完之后再记录,不会阻塞当前的写操作

RDB做快照时会阻塞线程吗?

为了解决阻塞线程问题,Redis提供了两个命令来生成RDB快照文件,分别是save和bgsave。save命令在主线程中执行,会导致阻塞。而bgsave命令则会创建一个子进程,用于写入RDB文件的操作,避免了对主线程的阻塞。

RDB做快照的时候数据能修改吗?

如果主线程执行读操作,则主线程和bgsave子进程互相不影响。

如果主线程执行写操作,则被修改的数据会复制一份副本,然后bgsave子进程会把该副本数据写入RDB文件,在这个过程中,主线程仍然可以直接修改原来的数据

熔断设计的原理

  • “关闭”转换“打开”:当服务调用失败的次数累计到一定的阈值时,服务熔断状态,将从关闭态切换到打开态
  • “打开”转换“半打开”:当熔断处于打开状态时,我们会启动一个超时计时器,当计时器超时后,状态切换到半打开状态
  • “半打开”转换“关闭”:在熔断处于半打开状态时,请求可以达到后端服务,如果累计一定的成功次数后,状态切换到关闭态

降级设计的原理

降级设计是站在系统整体可用性上考虑问题:当资源和访问量出现矛盾时,在有限的资源下,放弃部分非核心功能或者服务,保证整体的可用性,熔断也是降级的一种手段

服务降级可以分为读操作降级和写操作降级

  • 读操作降级:做数据兜底服务,将兜底数据提前存储在缓存中,当系统触发降级时,读操作直接降级到缓存,从缓存中读取兜底数据,如果此时缓存中也不存在查询的数据,则返回默认值,不再请求数据库
  • 写操作降级:将之前直接同步调用写数据库的操作,降级为先写缓存,然后再异步写入数据库

功能降级

功能降级就是在做产品功能上的取舍,既然在做服务降级时,已经取舍掉了非核心服务,那么同样的产品功能层面也要相应的进行简化。可以通过降级开关控制功能的可用或不可用。另外,在设计降级时,离不开降级开关的配置,一般是通过参数化配置的方式存储在配置中心,手动或自动开启开关,实现系统降级

用架构师的视角分析系统性能指标

高性能设计中的“术”

前端优化:

  • 减少请求次数
  • 页面静态化
  • 边缘计算

后端优化:

  • 基础设施层面
  • 网络层面
  • 架构层面

架构师知识体系

学习架构设计知识思路

  1. 从自己熟知的领域出发,这样你才有不断的正反馈,从而更有信心,容易理解新的知识
  2. 形成知识网络图谱,把自己的核心知识梳理出一个脉络清晰的结构图,然后结合已有知识,再逐步将零散的知识点补充到这张图谱之上
  3. 养成对技术判断力,针对同一问题有不同方法,不同维度、不同角度的分析和对比,以此提升在工作中对技术的领悟力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值