传统架构
-
传统架构会出现的问题
配置烦琐,上线容易出错
加机器要重启
负载均衡单点
管理困难 -
CAP原则。
-
CAP原则是指在一个分布式系统中,Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性)三者不可得兼。
-
1)一致性(C):是指分布式系统中的所有数据副本在同一时刻是否一致,也就是说,访问所有数据副本的节点,是否都会返回一样的结果。
-
2)可用性(A):集群中一部分节点发生故障后,集群整体是否还能响应客户端的读写请求。
-
3)分区容错性(P):这个概念比较抽象,简单来说,假设集群有两个节点对外提供服务,理论上,这两个节点之间是可以互相通信的,
-
因为要同步数据副本。但是,如果它们之间的网络出现问题,其数据就不能同步,从而出现不同的版本,这时怎么办?
-
可以使用以下两种方案:
-
①集群先停止服务,等其内部恢复,这个方案牺牲了A(可用性);
-
②继续服务,让数据不一致,这个方案牺牲了C(一致性)
全链路日志
熔断
-
熔断一般发生在服务调用方
-
熔断机制类似于电路中的熔断器,当某个服务出现故障或响应时间过长时,熔断器会“熔断”,阻止后续请求继续访问该服务,从而避免整个系统的崩溃。
-
熔断器会监控服务的状态,当发现服务出现故障或响应时间超过预设阈值时,会触发熔断。
-
熔断后,请求将不再转发到故障服务,而是直接返回错误或执行备用逻辑(如服务降级)。
-
经过一段时间后,熔断器会尝试恢复服务调用,如果服务已恢复正常,则熔断器关闭,允许请求再次通过。
-
可以通过开源库如Hystrix等来实现熔断机制。
-
这些库通常提供了丰富的配置选项,以便根据具体需求调整熔断策略。
限流 -
限流一般发生在服务被调用方。且主要在网关层做限流操作
-
限流的算法:固定时间窗口计数、滑动时间窗口计数、漏桶、令牌桶4种
-
固定时间窗口计数(Fixed Time Window Counting)
原理:固定时间窗口计数算法是最简单的限流算法之一。
它规定了一个单位时间窗口(如1分钟),并维护一个计数器来记录该时间窗口内的请求数量。
每当有请求到达时,计数器加1;当计数器超过预设的阈值时,拒绝新的请求。时间窗口结束后,计数器重置为0。
存在问题:固定时间窗口计数算法无法处理时间窗口边界的突发流量。
例如,如果阈值设置为每分钟10个请求,且所有请求都在时间窗口的最后几秒内到达,那么这些请求仍然会被接受,可能导致系统过载。 -
滑动时间窗口计数(Sliding Time Window Counting)
原理:滑动时间窗口计数算法是对固定时间窗口计数算法的改进。
它将时间窗口划分为多个更小的子窗口(如每秒一个子窗口),并维护一个滑动窗口来记录最近一段时间内的请求数量。
当新的请求到达时,滑动窗口向前移动,并更新窗口内的计数器。如果滑动窗口内的请求数量超过阈值,则拒绝新的请求。
优点:滑动时间窗口计数算法可以更有效地处理时间窗口边界的突发流量,因为它基于最近一段时间的请求数量来进行判断。 -
漏桶算法(Leaky Bucket)
原理:漏桶算法是一种流量整形(Traffic Shaping)或速率限制(Rate Limiting)算法。
它模拟了一个具有固定容量的漏桶, 并允许以一 定的速率从桶中漏出请求。当请求到达时,如果桶未满,则将其放入桶中;
如果桶已满,则拒绝新的请求或将其排队等待。同时,漏桶会以恒定的速率将请求从桶中漏出。
特点:漏桶算法可以平滑突发流量,确保系统以稳定的速率处理请求。即使在高并发场景下,漏桶算法也能保持系统的稳定性和可靠性。
-
令牌桶算法(Token Bucket)
原理:令牌桶算法是另一种常用的限流算法。它模拟了一个具有固定容量的令牌桶,并允许以一定的速率向桶中添加令牌。
当请求到达时,需要消耗一定数量的令牌才能被处理;如果没有足够的令牌可用,则拒绝该请求或将其排队等待。
特点:令牌桶算法在限制数据的平均传输速率的同时,还允许一定程度的突发传输。
它允许在令牌桶中有足够令牌的情况下,以较高的速率处理突发流量。
这使得令牌桶算法在处理具有突发特性的流量时更加灵活和高效。
微服务的好处 -
1)易于扩展:某个模块的服务器处理能力不足时,在该模块所处应用的服务器中增加节点即可。
-
2)发布简单:只需要保证对外契约不变即可, 发布过程变得非常简单。
-
3)技术异构:因为各个服务之间相互独立、互不影响,所以只需要保证外部契约(一般指接口)不变即可,
-
而内部可以使用各自不同的语言或框架。
-
4)便于重构:在微服务架构中,因为把模块间的影响进行了隔离,所以大大增加了重构的灵活性。
微服务的痛点
-
微服务的职责划分
1.根据存放主要数据的服务所在进行划分
2.业务逻辑服务归属与业务人员的划分可能存在关系
3.业务逻辑服务归属与产品人员的划分可能存在关系
4.业务逻辑服务归属与工期可能存在关系
5.业务逻辑服务归属还可能与组织架构存在关系 -
微服务粒度拆分
-
没人知道系统整体架构的全貌
-
没人知道系统整体架构的全貌
-
耗费更多服务器资源
-
分布式事务
-
服务之间的依赖
-
联调的痛苦
-
部署上的难题
数据一致性
-
1.实时数据不一致可以接受,但要保证数据的最终一致性
对于数据要求最终一致性的场景,实现思路是这样的。
1)每个步骤完成后,生产一条消息给MQ,告知下一步处理接下来的数据。
2)消费者收到这条消息,将数据处理完成后,与步骤1)一样触发下一步。
3)消费者收到这条消息后,如果数据处理失败,这条消息应该保留,直到消费者下次重试 -
2.实时一致性:就是常说的分布式事务
TCC模式中,会把原来的一个接口分为Try接口、Confirm接口、Cancel接口。
1)Try接口:用来检查数据、预留业务资源。
2)Confirm接口:用来确认实际业务操作、更新业务资源。
3)Cancel接口:是指释放Try接口中预留的资源。
TCC模式是一个实施起来很麻烦的方案,除了每个业务代码的工作量乘3之外,还需要通过相应逻辑应对上面的注意事项,这样出错的概率就太高了
-
Seata中AT模式的自动回滚自动回滚
在触发整个事务的业务发起方的方法中加入@GlobalTransactional标注,
并且使用普通的@Transactional包装好分布式事务中相关服务的相关方法即可。 -
对于Seata的内在机制,AT模式的自动回滚往往需要执行以下步骤(分为3个阶段)。
-
阶段1
1)解析每个服务方法执行的SQL,记录SQL的类型(Update、Insert或Delete),修改表并更新SQL条件等信息。
2)根据前面的条件信息生成查询语句,并记录修改前的数据镜像。
3)执行业务的SQL。
4)记录修改后的数据镜像。
5)插入回滚日志:把前后镜像数据及业务SQL相关的信息组成一条回滚日志记录,插入UNDOLOG表中。
6)提交前,向TC注册分支,并申请相关修改数据行的全局锁。
7)本地事务提交:业务数据的更新与前面步骤生成的UNDOLOG一并提交。
8)将本地事务提交的结果上报给事务控制器。 -
阶段2
收到事务控制器的分支回滚请求后,开启一个本地事务,执行如下操作。
1)查找相应的UNDOLOG记录。
2)数据校验:将UNDOLOG中的后镜像数据与当前数据进行对比,如果存在不同,说明数据被当前全局事务之外的动作做了修改,此时需要根据配置策略进行处理。
3)根据UNDOLOG中的前镜像数据和业务SQL的相关信息生成回滚语句并执行。
4)提交本地事务,并把本地事务的执行结果(即分支事务回滚的结果)上报事务控制器。 -
阶段3
1)收到事务控制器的分支提交请求后,将请求放入一个异步任务队列中,并马上返回提交成功的结果给事务控制器。
2)异步任务阶段的分支提交请求将异步、批量地删除相应的UNDOLOG记录。
数据同步
- 数据冗余
同步冗余的数据呢:
1)每次更新时,更新冗余数据。
2)每次更新时,发布一条消息,各自更新商品的冗余数据
- 数据同步这个方案注意事项:
1.数据同步的延时:所以如果业务对同步功能有高时效的要求,那么尽量不要使用这个方案
2.同步过来的数据是只读的
3.监控一定要到位
4.核心逻辑不建议依赖同步数据
如何缓解服务依赖复杂度
-
抽象出一个API层
-
.2 API层一般来说,客户端的接口会有以下需求。
1)聚合:一个接口需要聚合多个后台服务返回的数据,然后再返回给客户端。
2)分布式调用:一个接口可能需要依次调用多个后台服务,去修改多个后台服务的数据。
3)装饰:一个接口需要重新装饰一下后台返回的数据,删除一些字段,或者对某些字段再加一个封装,组成客户端需要的数据。
这个API层没有自己的数据库,它做的事情就是去调用其他后台服务
-
BFF(BackendforFront)BFF不是一个架构,而是一个设计模式
主要理念是专门为前端设计优雅的后台服务(也就是API)。换句话说,就是每一种客户端有自己的API服务 -
不同的客户端请求经过同一个网关后会分别重定向到专门为这种客户端设计的API服务(WX API即用于微信小程序的API)
-
API之间的代码重复怎么解决
-
将这些重复的代码放在一个JAR里面,让几个API服务共用
-
将这些重复的代码抽取在一个独立的称为CommonAPI的API服务中,其他API服务调用这个CommonAPI
-
有的因为重复逻辑占少数,所以就是保留这些重复代码
接口Mock
- 它主要用于在接口尚未完成或不可用时,帮助开发人员和测试人员进行测试和开发工作
- Mock接口是指模拟后端接口行为的一种技术手段。通过模拟接口的请求和响应,开发人员和测试人员可以在接口未实现或不可用的情况下,进行测试和开发工作。
- Mock接口的主要理念是在接口开发或测试过程中,提供一个稳定的、可预期的接口行为模拟,以加速开发流程和提高测试效率。
- 快速开发:在接口尚未完成的情况下,使用Mock接口可以帮助开发人员进行测试和验证,从而加快开发速度。
- 独立开发:Mock接口可以减少对其他模块的依赖,使开发人员能够更独立地进行工作。
- 模拟不同场景:Mock接口可以模拟不同的接口行为场景,如成功、失败、异常等,从而更全面地测试系统的健壮性
- Mock接口的注意事项
数据一致性:在使用Mock接口时,需要确保模拟数据与真实数据的一致性。这有助于在后期联调阶段减少数据格式和内容不一致的问题。
接口权限控制:在将Mock接口替换为真实接口时,需要注意接口权限的控制,确保数据的安全性和保密性。