本文已参与「新人创作礼」活动,一起开启掘金创作之路。
1. 如何保证 幂等 操作****
幂等性就是同一个操作执行多次,产生的效果一样。如http的get请求,数据库的select请求就是幂等的
在分布式系统中,保证接口的幂等性非常重要,如提交订单,扣款等接口都要保证幂等性,不然会造成重复创建订单,重复扣款,那么如何保证接口的幂等性呢?
(1) 幂等性的方法****
前端保证幂等性的方法
①按钮只能点击一次,用户点击按钮后将按钮置灰,或者显示loading状态
②当客户提交表单后,去执行一个客户端的重定向,转到提交成功页面。避免用户按F5刷新导致的重复提交
后端保证幂等性的方法
①使用唯一索引,对业务唯一的字段加上唯一索引,这样当数据重复时,插入数据库会抛异常
②使用状态机幂等,设计时最好只支持状态的单向改变,多次提交也只会执行一次,例如想把订单状态更新为支付成功,则之前的状态必须为支付中
③乐观锁实现幂等,数据库加上版本号字段了,通过版本号去更新,版本号匹配则更新,版本号不匹配则不更新
④使用分布式锁,执行方法时,先根据业务唯一的id获取分布式锁,获取成功,则执行,失败则不执行。
(2) 幂等性注意事项****
幂等性的实现与判断需要消耗一定的资源,因此不应该给每个接口都增加幂等性判断,要根据实际的业务情况和操作类型来进行区分。
(3) 幂等性的关键步骤****
实现幂等性的关键步骤分为以下三个:
①每个请求操作必须有唯一的 ID,而这个 ID 就是用来表示此业务是否被执行过的关键凭证,例如,订单支付业务的请求,就要使用订单的 ID 作为幂等性验证的 Key;
②每次执行业务之前必须要先判断此业务是否已经被处理过;
③第一次业务处理完成之后,要把此业务处理的状态进行保存,比如存储到 Redis 中或者是数据库中,这样才能防止业务被重复处理。
(4) 常见面试题****
(1) 什么是幂等性?如何保证接口的幂等性?
(2) 幂等性需要注意什么问题?
(3) 实现幂等性的关键步骤有哪些?
(4) 说一说数据库实现幂等性的执行细节?
(5) 项目用到幂等性得场景?怎么处理得?
(6) mq重复消费怎么处理?
原文链接:blog.csdn.net/bamboo_cqh/…
2. 高并发-解决方案****
高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。
高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。
提高系统并发能力的方式,方法论上主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。
前者垂直扩展可以通过提升单机硬件性能,或者提升单机架构性能,来提高并发性,但单机性能总是有极限的
互联网分布式架构设计高并发终极解决方案还是后者:水平扩展。
(1) 垂直扩展****
提升单机处理能力。垂直扩展的方式又有两种:
①增强单机硬件性能,例如:增加CPU核数如32核,升级更好的网卡如万兆,升级更好的硬盘如SSD,扩充硬盘容量如2T,扩充系统内存如128G;
②提升单机架构性能,例如:使用Cache来减少IO次数,使用异步来增加单服务吞吐量,使用无锁数据结构来减少响应时间;
(2) 水平扩展****
水平扩展:只要增加服务器数量,就能线性扩充系统性能。
常见的互联网分层架构
每个层次都有对应的扩展策略
①反向代理层的水平扩展****
反向代理层的水平扩展,是通过“DNS轮询”实现的:dns-server对于一个域名配置了多个解析ip,
每次DNS解析请求来访问dns-server,会轮询返回这些ip。
当nginx成为瓶颈的时候,只要增加服务器数量,新增nginx服务的部署,增加一个ip,就能扩展反向代理层的性能,做到理论上的无限高并发。
② 站点层的水平扩展****
站点层的水平扩展,是通过“nginx”实现的。通过修改nginx.conf,可以设置多个web后端。
当web后端成为瓶颈的时候,只要增加服务器数量,新增web服务的部署,在nginx配置中配置上新的web后端,
就能扩展站点层的性能,做到理论上的无限高并发。
③服务层的水平扩展****
服务层的水平扩展,是通过“服务连接池”实现的。
站点层通过RPC-client调用下游的服务层RPC-server时,RPC-client中的连接池会建立与下游服务多个连接,当服务成为瓶颈的时候,
只要增加服务器数量,新增服务部署,在RPC-client处建立新的下游服务连接,就能扩展服务层性能,做到理论上的无限高并发。
如果需要优雅的进行服务层自动扩容,这里可能需要配置中心里服务自动发现功能的支持。
④ 数据层的水平扩展****
在数据量很大的情况下,数据层(缓存,数据库)涉及数据的水平扩展,
将原本存储在一台服务器上的数据(缓存,数据库)水平拆分到不同服务器上去,以达到扩充系统性能的目的。
一般有3种方式:
a单表按业务拆分,然后放到不同的服务节点的数据库去,同一个表跟进策略放在不同的库
b水平拆分扩展数据库性能,n个服务器上的数据没有交集,所有服务器上数据的并集是数据的全集
c通过主从同步读写分离扩展数据库性能,一套数据库,多个副本,理论上读性能扩充了n倍,写仍然是单点,写性能不变
(3) 总结****
互联网分层架构中,各层次水平扩展的实践又有所不同:
(1)反向代理层可以通过“DNS轮询”的方式来进行水平扩展;
(2)站点层可以通过nginx来进行水平扩展;
(3)服务层可以通过服务连接池来进行水平扩展;
(4)数据库可以按照数据范围,或者数据哈希的方式来进行水平扩展;
各层实施水平扩展后,能够通过增加服务器数量的方式来提升系统的性能,做到理论上的性能无限。
3. 高可用架构 设计****
计算高可用的主要设计目的是当出现硬件故障时候,系统依然可以继续运行。
因此计算高可用的本质是通过冗余(服务器)来规避部分故障的风险。单台服务器肯定不行的,一旦宕机业务直接不可用了。
总的来说 高可用=增加冗余服务器。
(1) 高可用的关键****
计算高可用的复杂度主要体现在如何任务管理方面,即当任务在某个服务器上执行失败后,如何将任务重新分配到新的服务器上运行。因此,高可用架构的主要一下两个关键点。
① 哪些服务器可以执行任务****
第一种方式和计算高性能中的集群类似,每个服务器都可以执行任务。例如,常见的访问网站的某个页面。
第二种方式和存储高可用中的集群类似,只有特定服务器(通常叫“主机”)可以执行任务。当执行任务的服务器故障后,系统需要挑选新的服务器来执行任务。例如,ZooKeeper 的 Leader 才能处理写操作请求。
② 任务如何重新执行****
第一种策略是对于已经分配的任务即使执行失败也不做任何处理,系统只需要保证新的任务能够分配到其他非故障服务器上执行即可。
第二种策略是设计一个任务管理器来管理需要执行的计算任务,服务器执行完任务后,需要向任务管理器反馈任务执行结果,任务管理器根据任务执行结果来决定是否需要将任务重新分配到另外的服务器上执行。
需要注意的是:“任务分配器”是一个逻辑的概念,并不一定要求系统存在一个独立的任务分配器模块。例如:
A、Nginx 将页面请求发送给 Web 服务器,而 CSS/JS 等静态文件直接读取本地缓存。
这里的 Nginx 角色是反向代理系统,但是承担了任务分配器的职责,而不需要后面再来一个实体的任务分配器。
B、ZooKeeper 中的 Follower 节点,当接收到写请求时会将请求转发给 Leader 节点处理,当接收到读请求时就自己处理,这里的 Follower 就相当于一个逻辑上的任务分配器。
C、对于一些后台批量运算的任务,也可以设计一个独立的任务分配系统来管理这些批处理任务的执行和分配。
(2) 常见的计算高可用架构:主备、主从和集群。
1) 主备
主备架构是计算高可用最简单的架构,和存储高可用的主备复制架构类似,但是要更简单一些,因为计算高可用的主备架构无须数据复制(同步)
主备方案的详细设计:
主机执行所有计算任务。例如,读写数据、执行操作等。
当主机故障(例如,主机宕机)时,任务分配器不会自动将计算任务发送给备机,此时系统处于不可用状态。
如果主机能够恢复(不管是人工恢复还是自动恢复),任务分配器继续将任务发送给主机。
如果主机不能够恢复(例如,机器硬盘损坏,短时间内无法恢复),则需要人工操作,将备机升为主机,然后让任务分配器将任务发送给新的主机(即原来的备机);同时,为了继续保持主备架构,需要人工增加新的机器作为备机。根据备机状态的不同,主备架构又可以细分为冷备架构和温备架构。
其基本的架构示意图如下:
2) 主从
和存储高可用中的主从复制架构类似,计算高可用的主从架构中的从机也是要执行任务的。任务分配器需要将任务进行分类,确定哪些任务可以发送给主机执行,哪些任务可以发送给备机执行
主从方案详细设计:
①【正常分配】正常情况下,主机执行部分计算任务(如图中的“计算任务 A”),备机执行部分计算任务(如图中的“计算任务 B”)。
②【主机故障照发】当主机故障(例如,主机宕机)时,任务分配器不会自动转发给从机,而是继续发送给主机,不管执行是否成功。
③【恢复后继续】如果主机能够恢复(不管是人工恢复还是自动恢复),任务分配器继续按照原有的设计策略分配任务,即 A 发给主机,B 发给从机。
④如果主机不能够恢复(例如,机器硬盘损坏,短时间内无法恢复),则需要人工操作,将原来的从机升级为主机(一般只是修改配置即可),增加新的机器作为从机,新的从机准备就绪后,任务分配器继续按照原有的设计策略分配任务。
主从架构与主备架构相比,优缺点有:
优点:主从架构的从机也执行任务,发挥了从机的硬件性能。
缺点:主从架构需要将任务分类,任务分配器会复杂一些。
3) 集群
在可用性要求更加严格的场景中,我们需要系统能够自动完成切换操作,这就是高可用集群方案。
高可用计算的集群方案根据集群中服务器节点角色的不同,可以分为两类:
一类是对称集群,即集群中每个服务器的角色都是一样的,都可以执行所有任务;
另一类是非对称集群,集群中的服务器分为多个不同的角色,不同的角色执行不同的任务,例如最常见的 Master-Slave 角色。
① 对称集群****
对称集群更通俗的叫法是负载均衡集群,因此接下来我使用“负载均衡集群”这个通俗的说法,架构示意图如下:
负载均衡集群详细设计:****
A、正常情况下,任务分配器采取某种策略(随机、轮询等)将计算任务分配给集群中的不同服务器。
B、当集群中的某台服务器故障后,任务分配器不再将任务分配给它,而是将任务分配给其他服务器执行。
C、当故障的服务器恢复后,任务分配器重新将任务分配给它执行。
负载均衡集群的设计关键点在于两点:****
任务分配器需要选取分配策略。
任务分配器需要检测服务器状态。
任务分配策略比较简单,轮询和随机基本就够了。
状态检测稍微复杂一些,既要检测服务器的状态,例如服务器是否宕机、网络是否正常等;同时还要检测任务的执行状态,例如任务是否卡死、是否执行时间过长等。不同业务场景的状态判断条件差异很大,实际设计时要根据业务需求来进行设计和调优。
② 非对称集群****
非对称集群中不同服务器的角色是不同的,不同角色的服务器承担不同的职责。以 Master-Slave 为例,部分任务是 Master 服务器才能执行,部分任务是 Slave 服务器才能执行。非对称集群的基本架构示意图如下:
非对称集群架构详细设计:****
A、集群通过某种方式来区分不同服务器的角色。例如,通过ZAB算法选举,或者简单地取当前存活服务器中节点ID最小的服务器作为Master服务器。
B、任务分配器将不同任务发送给不同服务器。例如,图中的计算任务 A 发送给 Master 服务器,计算任务 B 发送给 Slave 服务器。
C、当指定类型的服务器故障时,需要重新分配角色。例如,Master 服务器故障后,需要将剩余的 Slave 服务器中的一个重新指定为 Master 服务器;如果是 Slave 服务器故障,则并不需要重新分配角色,只需要将故障服务器从集群剔除即可。
非对称集群相比负载均衡集群,设计复杂度主要体现在两个方面:****
A、任务分配策略更加复杂:需要将任务划分为不同类型并分配给不同角色的集群节点。
B、角色分配策略实现比较复杂:例如,可能需要使用 ZAB、Raft 这类复杂的算法来实现 Leader 的选举。
以 ZooKeeper 为例:任务分配器:ZooKeeper 中不存在独立的任务分配器节点,每个 Server 都是任务分配器,Follower 收到请求后会进行判断,如果是写请求就转发给 Leader,如果是读请求就自己处理。
角色指定:ZooKeeper 通过 ZAB 算法来选举 Leader,当 Leader 故障后,所有的 Follower 节点会暂停读写操作,开始进行选举,直到新的 Leader 选举出来后才继续对Client 提供服务。