seckill是一个老生常谈的场景
它一般出现在电商系统中,在某些特定的节日,限定特定商品数量以超低折扣进行促销引流
按照秒杀的特性,特价商品一般在一两秒内被抢光,剩下的人只会出现售罄页面
这一两秒会出现一个瞬间峰值,因为是短暂的活动,不能消耗太多服务器资源,所以需要达到最小代价做到最大的抗压,不直接冲垮服务器,还得保证不超卖,不丢单,不宕机等问题
多次调用方法或者接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致
通过Token机制实现接口的幂等性,这是一种比较通用性的实现方法
- 客户端会先发送一个请求去获取Token,服务端会生成一个全局唯一的UUID作为Token保存在Redis中,同时把这个UUID返回给客户端,并缓存到session
- 客户端第二次调用业务请求的时候必须携带这个Token
- 服务端会校验这个Token,如果校验成功,则执行业务,并删除Redis中的Token
- 如果校验失败,说明Redis中已经没有对应的Token,则表示重复操作,直接返回指定的结果给客户端
注意:
对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值
高峰值流量是压垮系统很重要的原因【会造成雪崩效应】,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路
常见削峰方案
预约制:
用户在提前固定时间内预约使用服务,在预约时间内服务繁忙时不再接受新的请求,以此来削峰。
问答式验证:
在请求访问服务时要求用户回答一些简单的问题,以此来减少恶意请求,并降低系统的峰值压力。
动态限流:
根据实时的系统负载情况动态调整请求的限流策略,以此来减少系统的峰值压力。
动态分配资源:
根据实时的系统负载情况动态分配资源,以此来减少系统的峰值压力。
分段限流:
将请求分为几个段,分别对每个段设置不同的限流策略,以此来减少系统的峰值压力。
平时用户访问的地址是直接指向我们的服务器,中间会经过多层转发,而距离比较远的用户访问我们的服务器可能会有网络拥堵
CDN的服务商在各地都有服务器群,可以解析DNS计算距离用户最近的服务器来获取缓存资源,以避免网络拥堵
我们可以把静态资源(图片,js,css等)丢到CDN服务商上面,以减少我们的服务器压力【解耦】
使用CDN的好处就是不浪费自己服务器资源和带宽,并且响应速度快,直接实现了动静分离
现在由于市场需求量大技术日渐成熟,CDN的收费也越来越便宜
一般做动静分离主要是为了提高用户访问静态资源的速度,降低直接对后台应用的访问
最基本的做法就是用nginx来指向静态资源,因为nginx的吞吐量比tomcat高,响应更快
具体可以参考:
负载均衡的目的是将请求分摊到多台服务器上,从而降低单台服务器的负载,提高系统的吞吐量和响应速度。
通常在 Web 应用、数据库应用、邮件服务器、文件服务器等高并发环境中使用负载均衡技术
常用的负载一般是Nginx,Netflix Ribbon,Netflix Eureka,Apache Zookeeper
如果有钱也可以买云服务商的,比如亚马逊,微软,谷歌,阿里巴巴,腾讯云等
网关过滤方案
对系统而言,如果我们可以在网关层面拦截掉用户请求,可以说这个方案的性价比很高。要是能在这层过滤 95% 以上的请求,整个系统也就很稳定
算法过滤方案
在秒杀模块中,一般使用令牌桶算法或者固定窗口算法
一.令牌桶
每次请求需要消耗一个令牌,令牌生成速率是固定的,当令牌桶满时,请求将被阻塞或拒绝
可以通过Google Guava 的 RateLimiter 实现了令牌桶算法,它提供了一种简单的方式来限流RateLimiter 支持两种限流方式:
SmoothBursty 限流算法通过适当地调整令牌生成速率,以适应系统的需求情况,并同时保证在令牌桶中令牌的有效利用。它可以帮助实现更好的资源利用率,同时保证系统的稳定性。
二.漏桶算法
将请求缓存到漏桶中,漏桶的容量有限,请求以固定速率从漏桶中流出
在一段时间内,对请求数量进行限制,并随时间窗口的滑动而改变限制的数量
在固定时间窗口内,对请求数量进行限制
随机接受或者拒绝
注意:
漏桶算法和固定窗口算法都是限流算法,但它们有一些重要的差异:
总的来说,漏桶算法和固定窗口算法都是有效的限流算法,选择哪种算法取决于应用场景和限流需求。如果需要处理突发请求,漏桶算法可能更合适;如果需要动态调整请求处理速率,则固定窗口算法可能更合适。
为什么使用MQ进行削峰操作
常见的MQ有ActiveMQ,RocketMQ,RabbitMQ和Kafka
使用MQ所需要注意的问题
出现死信队列怎么办
死信队列一般是某些消息无法在规定时间内正常处理
MQ消费不过来怎么办
出现这种情况一般是消息生产过快或者消费端处理能力不足,导致消息积压
通过配置confirm的发送确认机制,当消息发送到消费者并且确认收到消息,通知生产者该消息已消费
在生产者或者broker或者消费者保留一份,当消费者消费成功后再删除【 在消息的传输链路上每个节点冗余消息 】
如果 Broker 是集群部署,有多副本机制,即消息不仅仅要写入当前 Broker ,还需要写入副本机中。那配置成至少写入两台机子后再给生产者响应。这样基本上就能保证存储的可靠了。一台挂了另一台还在。
1.将channel设置为事务模式
channel.txSelect();
2.提交事务
channel.txCommit();
3.事务回滚
channel.txRollback();
如果消息入队列后MQ宕机此时就需要:持久化,不止消息的持久化,还有队列和Exchange的持久化
MQ出现重复消费怎么办
秒杀是一个典型的读多写少的应用场景,非常适用缓存
【一件商品只有10件的库存,有200w人来抢,实际就只有10个人可以下单成功,其它的都是查询库存】
缓存可以在秒杀前先缓存商品信息,库存信息和预热用户对该商品的请求,这样可以防止请求直接打到数据库里面,从而提高系统的效率
对于读请求,无论是 Memcached 还是 Redis ,单机抗10wQPS问题都不大,在上层的限流,削峰,人机校验,幂等中已经筛选掉了90%的请求,所以真正能打入数据库的数据量是很少的
基于Redis实现缓存 Cache-Aside Pattern(旁路缓存模式)
在请求达到后端之后,防止请求直接面向传统数据库【RDBMS】(传统数据库处理读写效果比较慢),一般会做一层NoSQL缓存操作。
先去Redis找有没有数据,如果有就返回,没有就去RDBMS里面查询数据,然后存入Redis并返回,方便下次直接从Redis拿到数据
**强一致性:**这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大
**弱一致性:**这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态
**最终一致性:**最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型
线程1:先更新缓存成功,但是网络原因写数据库失败,就会导致缓存是最新数据,而数据库的数据为旧数据,那缓存就是脏数据
线程2:读取缓存中数据,而这个数据数据库中却不存在,数据库都不存在的数据,缓存并返回客户端就毫无意义了。
线程1:先更新数据库成功,但是由于网络卡顿更新缓存失败,从而导致缓存中的数据为旧数据
线程2:从缓存中读取数据,缓存中的数据为旧数,从而导致数据库与缓存数据不一致。
线程1:先删除缓存成功,但是由于网络卡顿原因,更新数据库异常。
线程2:读取缓存由于缓存数据为空,则会查询数据库中的数据,查询成功并写入缓存,从而导致数据不一致。
线程1:写入数据库成功,由于网络卡顿原因,导致删除缓存数据失败
线程2:读取数据,读取为缓存中的数据,但是当网络恢复正常后,缓存中的数据会被删除,所以可能会存在短暂的数据不一致
先删除缓存,再更新数据库,确保数据库事务提交成功,然后休眠一段时间在删除缓存。
我们都知道第三种情况是因为网络卡顿导致数据库更新失败,当网络恢复正常后,我们在执行更新数据库操作,然后再删除缓存,那么出现数据不一致的情况也就是在休眠的这短暂的时间内
在延时双删的方案上引入队列,需要删除失败的key存入消息队列中,采用异步的方式来进行删除,如果删除失败的次数已经超过了最大次数,发送警告邮件,需要人工介入解决【重试机制】
以 mysql 为例 可以使用阿里的 canal 将 binlog 日志采集发送到 MQ 队列里面,然后通过 ACK 机制确认处理这条更新消息,删除缓存,保证数据缓存一致性
如何防止穿透,击穿,雪崩
缓存穿透:请求在redis没命中缓存,在mysql也没有命中,查询失败,当请求量大的时候,一直有这种请求进来就会给数据库很大压力
1.使用布隆过滤器【如果布隆过滤器存在就进行请求,不存在直接进行空值或者失败】
2.缓存空对象,并且设置过期时间【缓存失效不宜过长,当数据库数据被写入时候要及时刷新,避免数据不一致的情况出现】
3.非法请求校验【前端页面和后台请求参数校验,避免出现非法请求直接打入数据库】
4.黑名单【对于请求频率过高不正常的进行黑名单限制】
缓存击穿:大量热点key值同时失效或者单个热点key,在不停抗着大并发,这个key失效的瞬间,大量的请求就会击破缓存,打入数据库
1.使用互斥锁【建议使用Redission分布式锁】,单机可以通过synchronized或者lock来实现,只让一个请求去请求数据库,其它的等待缓存构建后再去请求缓存
2.热点key不设置过期时间,后代定时异步更新缓存【适用于弱一致性场景】
3.续失效时长,在value内部设置一个比缓存过期时间短的标识,当异步线程发现该值快过期了,用互斥锁内置时间,并且重新去数据库加载该数据
缓存雪崩:当缓存中大量热点缓存同时失效,会导致缓存在某个时间达到峰值,请求全都去请求数据库,导致数据库压力骤增,甚至宕机。从而形成连锁反应,导致系统崩溃
一般是大量热点key同时过期或者缓存服务故障
1.热点key随机失效时间,防止同时失效
2.分布式锁读数据库
3.Redis采用高可用集群(必要时采用异地多活)
4.限流,降级,容灾,削峰等措施
热点key
请求次数过多,频率过高,又过于集中的一些key
大key(Big Key)
Big Key就是某个key对应的value很大,占用的redis空间很大,本质上是大value问题
原因:
解决方式:
数据预热【提前做好热点探测】
缓存预热是指系统上线后,提前将相关的缓存数据加载到缓存系统。
避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题,用户直接查询事先被预热的缓存数据。
数据库同步问题
缓存和数据库一致性问题 在上面已经提及
数据库扩容问题
业务系统在设计初期一般数据量小,会采取单服务+单数据库
但是随着访问量上升,为了达到数据库的最佳储存容量,需要对数据库做垂直或者水平拆分,来提升服务响应速度,这时候就涉及到了扩容问题
难点
解决方式
【适用于简单业务,数据库较少的时候】
停止服务 -》新增数据库,修改分片规则,迁移数据 -》重启服务
优点:简单,停机风险操作低
缺点:缺乏高可用,如果没配置好,容易造成数据丢失,难以修复
【保持高可用】
平滑扩容可以实现n库扩容2n库,增加数据库服务能力
新增数据库 -》配置双主进行数据同步 -》数据同步完成后配置双主双写 -》删除双主同步,修改数据库配置并重启 -》 清空数据库多余数据
优点:不用停机,保持高可用,扩容遇到问题容易解决,不影响线上服务,可以减少每个数据库数据量
缺点:程序复杂,数据量大时,代价高
数据库冷热分离
冷热分离就是在处理数据时,数据库分为冷库和热库
**冷库:**存放那些走到了终态的数据的数据库
**热库:**还需要修改的数据的数据库
建议用es或者clickhouse作为冷库,因为冷库一般存储的数据量比较大,es属于数据量越多优势越大的数据库
可通过监听数据库变更日志binlog的方式来触发(数据库触发器也可)
jvm级别的锁 Synchronized 是无法在分布式微服务下解决超卖问题,只能解决当前进程的超卖问题
这种时候就需要引入分布式锁
在redis中有一条命令 setnx (set if not exists):如果不存在key,则可以设置成功,存在则失败
这种情况可以实现普通的分布式锁,但是遇到了极端情况比如断电,超时,宕机等会造成不释放锁或者死锁
在redisson中有一种看门狗机制,可以实现锁续命
这是一种已经造好的轮子,开箱即用,它也可以使用多redis实现分布式锁,防止单点故障
RedLock为了保证高可用,在设置key的时候,会创建多个节点,单节点设置成功不会告诉程序获取到了锁,只有超过半数节点设置成功才会告诉程序获取到了锁
顾名思义,想让某个接口某个人在某段时间内只能请求N次。 在项目中比较常见的问题也有,那就是连点按钮导致请求多次,以前在web端有表单重复提交,可以通过token 来解决。 除了上面的方法外,前后端配合的方法。现在全部由后端来控制
隐藏URL并不能完全防止爬虫的恶意攻击,因为这些攻击者可能通过大量的尝试来猜测正确的URL
但是加密URL的意义在于增加攻击者猜测到URL的难度,无法轻易拿到正确的URL
防止大请求量打入顶不住导致集体宕机
一般分为监控,限流,熔断
监控:对系统的各个关键指标进行监控采集,包括响应时间,请求量,错误率等
限流:对系统的并发请求进行限制,控制系统的处理能力,防止系统超负荷运行导致的宕机或者响应变慢,推荐使用guava限流
熔断:当服务或者下游出现故障或者网络异常,自动切断该服务的调用,并且返回提前设置好的错误响应,防止服务调用的连锁反应,导致系统崩溃,并且给用户体验不好,推荐使用Hystrix或者Sentinel
秒杀系统在高并发的情况下,很容易因为大量的请求同时涌入导致服务不可用
例如,在秒杀活动开始前,大量用户会提前准备,不断刷新商品页面,导致大量请求涌入系统,使得系统崩溃
因此,在秒杀系统中使用服务降级是必要的,以保证系统的可用性和稳定性
当系统出现异常或者超负荷的情况下,通过降低服务质量或者停用部分服务来保证核心服务的可用性
当请求量过大时,单机无法承受,需要通过自动扩缩容来保证系统的正常运行
自动扩缩容是指根据系统的负载情况自动增加或减少系统的节点,以适应不同的负载情况
通过监控系统实时监控系统的负载情况,当负载超过一定阈值时,自动触发扩容操作,当负载降低时,自动触发缩容操作
在云原生架构中,可以通过云平台提供的自动扩缩容功能来实现秒杀系统的自动扩缩容,例如 Kubernetes 提供了自动扩缩容的功能,可以根据负载情况自动增加或减少容器的数量
通过弹性计算来实现自动扩缩容,例如云服务器 ECS 提供了自动伸缩组的功能,可以根据负载情况自动增加或减少实例的数量
下单事务:秒杀下单需要进行扣减库存和创建订单两个操作,这两个操作需要在同一个事务中完成,否则可能会出现库存扣减成功但是订单创建失败的情况。在分布式场景下,可以使用分布式事务来保证这两个操作的原子性,常用的分布式事务解决方案有 TCC、XA、SAGA 等。
支付事务:当用户下单成功后需要进行支付,支付也是一个需要保证原子性的操作。在分布式场景下,可以使用分布式事务来保证支付的原子性,但是相比于下单事务更为复杂,因为支付涉及到第三方支付平台的交互,可能需要处理退款等异常情况。
最经典的事务就是数据库事务(ACID)
一个事务中间执行的操作要么全部成功,要么全部失败,不会结束在某个环节【不可分割的执行单元】
事务在执行的过程中如果发生错误,会进行回滚(Rollback)到事务开始前的状态,就像这个事务没有执行过一样
一个事务执行之前和执行之后数据库都必须处于一致性状态,数据库的完整性约束没有被破坏
事务与事务之间是互相独立的,它们不会互相干扰,一个事务不会影响到另外一个事务的数据,也不会看到另外一个事务的数据
当一个事务完成之后,执行的结果必须持久化保存,即使数据库崩溃,在数据库恢复后事务提交的结果仍然存在
注意:
事务只能保证数据库的高可靠性,即数据库本身发生问题后,事务提交后的数据仍然能恢复;而如果不是数据库本身的故障,如硬盘损坏了,那么事务提交的数据可能就丢失了。这属于『高可用性』的范畴。因此,事务只能保证数据库的『高可靠性』,而『高可用性』需要整个系统共同配合实现。
更新丢失
当有两个并发执行的事务,更新同一行数据,那么其中一个事务会覆盖另外一个事务的数据【当数据库没有加任何锁操作的情况下会发生】
脏读
一个事务读到另外一个未提交事务的数据【当第一个事务回滚时候,第二个事务拿着失效的数据去处理就会出现脏读】
不可重复读(虚读,幻读)
一个事务对同一行数据读两次,却拿到了不同的结果
注意:
脏读是尚未提交的数据,不可重复读是已提交的数据
一个事务对一行数据修改的过程中,不允许另外一个事务对该行数据进行修改,但是允许读取该行数据
不会出现更新丢失,但是会出现脏读,不可重复读
未提交的写事务不允许其它事务访问该行,但是读取数据的事务允许其它的事务进行访问该行数据
不会出现脏读,但是会出现不可重复读
该级别禁止写事务,但是允许读事务
不会出现不可重复读
所有事务都必须串行执行
能避免一切因为并发引起的问题,但是效率低
隔离级别越高,越能保证数据的完整性和一致性,但是,对于并发性能的影响也越大
大多数情况下选择读提交【Read committed】,它能避免脏数据,并且有较好的并发性能,虽然它会导致不可重复读,丢失更新的并发问题,可以通过采用悲观锁或者乐观锁来控制
上面的事务介绍的是数据库事务,目前数据库只支持单库事务,不支持跨库事务
随着微服务架构的普及,一个大型的业务系统往往是多个服务组成,每个服务都有自己的数据库,现在一整套业务流程走下去需要多个服务来共同完成,这种跨库的事务支持就是“分布式事务”
比较常见的就是:商品系统,订单系统,支付系统,积分系统等等
一致性【Consistency】
同一数据的多个副本是否相同,所有的变化都是同步的
可用性【Availability】
在可以接受的时间范围内正确的响应用户请求,请求不能无限被阻塞
分区容错性【Partition tolerance】
当出现网络分区后,系统还是能继续工作,满足一致性和可用性
注意
熟悉CAP的人都知道,三者不能共存,一般是AP或者CP
在分布式系统中,网络无法100%可靠,分区其实是一个必然现象
如果我们选择了CA而放弃了P,那么当发生分区现象时,为了保证一致性,这个时候必须拒绝请求
但是A又不允许,所以分布式系统理论上不可能选择CA架构,只能选择CP或者AP架构
CP
放弃可用性,追求一致性和分区容错性,例:Zookeeper就是追求的强一致性
单一节点 或 多个节点处于相同的网络环境下,那么会存在一定的风险,万一该机房断电、该地区发生自然灾害,那么业务系统就全面瘫痪了。
为了防止这一问题,采用分布式系统,将多个子系统分布在不同的地域、不同的机房中,从而保证系统高可用性。
AP
放弃一致性【这里的一致性是强一致性】,追求分区容错性和可用性,这是很多分布式系统设计时候的选择,后面的BASE理论也是根据AP扩展
BASE解决了CAP中理论没有网络延迟,在BASE中用软状态和最终一致,保证了延迟后的一致性。
BASE和 ACID 是相反的,它完全不同于ACID的强一致性模型,而是通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。
基本可用【Basically Available】
在分布式系统中出现故障时,允许损失部分功能,保证核心功能可用【比如延长响应时间】
软状态【Soft state】
同一数据的不同副本的状态,可以不需要实时一致性【状态可以一段时间不同步】
最终一致性【Eventually consistent】
经过一段时间后,所有节点数据最后都会达到一致【不是强一致性】
注意
ACID能够保证事务的强一致性,即数据是实时一致的,在本地事务中是没有问题的,在分布式事务中,强一致性会极大影响分布式系统的性能,因此分布式系统中遵循BASE理论即可
但分布式系统的不同业务场景对一致性的要求也不同。如交易场景下,就要求强一致性,此时就需要遵循ACID理论,而在注册成功后发送短信验证码等场景下,并不需要实时一致,因此遵循BASE理论即可。
因此要根据具体业务场景,在ACID和BASE之间寻求平衡
一般出现分布式事务的原因就是微服务过多
随着互联网快速发展,微服务,SOA等服务架构模式正在被大规模的使用,举个简单的例子,一个公司之内,用户的资产可能分为好多个部分,比如余额,积分,优惠券等等。在公司内部有可能积分功能由一个微服务团队维护,优惠券又是另外的团队维护
我们的Mysql一般来说装千万级的数据就得进行分库分表,对于一个支付宝的转账业务来说,你给的朋友转钱,有可能你的数据库是在北京,而你的朋友的钱是存在上海,所以我们依然无法保证他们能同时成功。
因为事务会增加系统的复杂度,并且会导致响应变慢,这样的成本实在是太高了,不要因为追求某些设计,而引入不必要的成本
第一阶段:事务管理器通知所有资源管理器进行预备【prepare】,如果收到就绪状态则进入下一步,有一个未就绪则回滚
第二阶段:事务管理器收到所有资源管理器都准备完毕,通知资源管理器进行提交操作,如果有一个失败则进行回滚
优点:尽量的保证了数据的强一致性,实现成本低,现在各大主流数据库都有自己的实现
缺点:
三段提交(3PC)是对两段提交(2PC)的一种升级优化,3PC在2PC的第一阶段和第二阶段中插入一个准备阶段。保证了在最后提交阶段之前,各参与者节点的状态都一致。
同时在协调者和参与者中都引入超时机制,当参与者各种原因未收到协调者的commit请求后,会对本地事务进行commit,不会一直阻塞等待,解决了2PC的单点故障问题,但3PC 还是没能从根本上解决数据一致性的问题。
3PC 的三个阶段分别是CanCommit、PreCommit、DoCommit
CanCommit:协调者向所有参与者发送CanCommit命令,询问是否可以执行事务提交操作。如果全部响应YES则进入下一个阶段。
3PC的CanCommit阶段其实和2PC的准备阶段很像。
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
- 事务询问 协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
- 响应反馈 参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态。否则反馈No
PreCommit:协调者向所有参与者发送PreCommit命令,询问是否可以进行事务的预提交操作,参与者接收到PreCommit请求后,如参与者成功的执行了事务操作,则返回Yes响应,进入最终commit阶段。一旦参与者中有向协调者发送了No响应,或因网络造成超时,协调者没有接到参与者的响应,协调者向所有参与者发送abort请求,参与者接受abort命令执行事务的中断。
协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。 假如协调者从所有的参与者获得的反馈都是Yes响应,那么就会执行事务的预执行。
- 发送预提交请求 协调者向参与者发送PreCommit请求,并进入Prepared阶段。
- 事务预提交 参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
- 响应反馈 如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
假如有任何一个参与者向协调者发送了No响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断。
- 发送中断请求 协调者向所有参与者发送abort请求。
- 中断事务 参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
DoCommit: 在前两个阶段中所有参与者的响应反馈均是YES后,协调者向参与者发送DoCommit命令正式提交事务,如协调者没有接收到参与者发送的ACK响应,会向所有参与者发送abort请求命令,执行事务的中断。
TCC【二段式提交,补偿型】
TCC【Try-Confirm-Cancel】又被称为补偿事务,
TCC与2PC的思想很相似,事务处理流程也很相似,但是2PC应用于DB层面,TCC则应用于应用层面,需要编写业务逻辑来实现
它的核心思想:针对每个操作都要注册一个与其对应的确认(try)和补偿(cancel)
Try阶段:尝试执行,完成所有的业务检查(一致性),预留必须业务资源(准隔离性)
Confirm阶段:确认执行业务,不做任何业务检查,只使用try阶段预留的业务资源,Confirm阶段需要满足幂等性要求幂等设计,失败后进行重试或者其它处理
Cancel阶段:取消执行,释放try阶段预留的业务资源,并进行回滚
小结:
缺点是应用侵入性强,每个操作都需要try-confirm-cancel,其次开发难度大,代码量多,需要保证幂等性和数据一致性【对于程序员水平要求较高】
本地消息表:将需要分布式处理的任务通过消息日志的方式进行异步执行。
消息日志可以存储到本地文本,数据库或者消息队列,再通过业务规则自动或者人工发起重试
本地消息表对应的是BASE理论,追求的是最终一致性,适用于对一致性要求不高的
MQ事务就是本地消息表的升级版
中间如果存在消息确认失败或者没有确认的情况,会进行一个重试机制,需要保证幂等
Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。AT模式是阿里首推的模式,阿里云上有商用版本的GTS(Global Transaction Service 全局事务服务)
官网:seata.io/zh-cn/index…
源码: github.com/seata/seata
官方Demo: github.com/seata/seata…
黄牛为什么难防
- 模拟器作弊:模拟硬件设备,可以修改设备信息
- 设备牧场作弊:工作室里面一大批移动设备同时抢
- 人工作弊:靠佣金吸引兼职人员刷单
解决方案:
https://cloud.tencent.com/developer/article/1762003
https://blog.51cto.com/u_8238263/6020353#:~:text=使用%E2%80%8B%20%E2%80%8BToken%E2%80%8B%20%E2%80%8B%E2%80%8B机制,或使用%E2%80%8B%20%E2%80%8BToken%E2%80%8B%20%E2%80%8B%20%2B%20分布式锁的方案来解决幂等性问题%E3%80%82,4-幂等性解决方案实现思路%204-1-%20Token机制实现%20通过%E2%80%8B%20%E2%80%8BToken%E2%80%8B%20%E2%80%8B%20机制实现接口的幂等性,这是一种比较通用性的实现方法%E3%80%82
https://blog.csdn.net/a419240016/article/details/117236135
https://blog.csdn.net/wyouwd1/article/details/125705646
https://blog.csdn.net/qq_65567681/article/details/127712631
https://blog.csdn.net/weixin_35835508/article/details/112668412
https://www.cnblogs.com/hanease/p/15863393.html
https://juejin.cn/post/7112466891335008270
https://juejin.cn/post/6998416509026435108
https://blog.csdn.net/qq1309664161/article/details/118650154
https://juejin.cn/post/7126188464713760776#heading-7
https://juejin.cn/post/6862875289786662926
https://juejin.cn/post/6844903933182214151#heading-3
https://juejin.cn/post/6844903843516383245
https://juejin.cn/post/6844904087390011405#heading-5
https://juejin.cn/post/6844903573667446797#heading-13
https://juejin.cn/post/6844903647197806605#heading-15
https://juejin.cn/post/6899645923024355336#heading-1
https://juejin.cn/post/6844904176430874632
https://juejin.cn/post/6992767837702111269
https://juejin.cn/post/7044032901662375949#heading-10