高并发分布式
高并发是指并行处理大量请求。
性能指标
1.TPS(吞吐量)
TPS是指每秒事务数,一个事务数可以是一个接口,也可以是一个业务流程。从第一个请求发送到接收到最后一个请求的响应的过程。
2.QPS
每秒查询率。是服务器每秒能够响应的查询次数。
3.并发数
指系统可以同时承载的用户数量。并发量=QPS*平均响应时间
CAP理论
Consistency(一致性):从任意节点读取到的数据都是最新的状态。
Availability(可用性):所有操作都有预期的响应。
Partition tolerance(分区容错性):即使某个组件不可用,系统依然可以正常使用。
在分布式系统中,最多只能实现上面两点。因此,我们只能在一致性和可用性之间进行权衡。
BASE理论
Basically Available(基本可用)
Soft state(软状态)
Eventual consistency(最终一致性)
对CAP一致性和可用性进行一个权衡的结果,核心思想是:我们无法做到强一致性,但可以采用适当的方式让系统达到最终一致性。
高并发常用措施:缓存、降级、限流
缓存:提高系统响应速度。
降级:流量大时,优先保证核心服务,对于非核心服务可以选择将其关闭。
限流:只允许指定的流量进入系统,超过部分将被拒绝服务,排队或者降级处理。常见限流算法有计数器、滑动窗口、漏桶算法、令牌桶算法,也可做nginx限流。
一、分布式事务
事务的四个特性:ACID
原子性(Atomicity):原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。
一致性(Consistency):事务必须使数据库从一个一致性状态变换到另外一个一致性状态。换一种方式理解就是:事务按照预期生效,数据的状态是预期的状态。
隔离性(Isolation):并发访问数据库时,多个事务之间要相互隔离,不受其它事务的干扰。
持久性(Durability):事务一旦被提交,它对数据库中数据的改变是永久性的,即使数据库发生故障也不应该对其有影响。
事务并发带来的问题
1.脏读
一个事务读到另一个事务还没有提交的数据。
2.不可重复读
一个事务两次读取同一条数据,两次读取到的数据不一致。
3.幻读
一个事务两次读取同一份数据,两次读取到的数据量不一致。
4.更新丢失
一个事务的更新覆盖了另一个事务的更新。
什么是分布式事务?
分布式事务用于保证不同节点间的数据一致性。
分布式事务解决方案
两阶段提交(2PC)
两阶段提交是一种强一致性设计,包含两个角色:事务协调者和事务参与者
正常流程:
1.事务协调者向所有的参与者发送Prepare请求。参与者接到请求后,各自执行业务操作。如果参与者执行成功,暂时不提交事务,而是向事务协调者返回“完成”消息。
2.事务协调者向所有的参与者发送Commit请求。参与者接到请求后,各自进行本地的事务提交,并释放锁资源,向事务协调者返回”完成“消息。
失败流程:
若第1步某个参与者返回”失败“消息,则第2步事务协调者发送Abort请求,各个事务参与者进行回滚操作。
XA两阶段提交的不足
1.性能问题
XA协议遵循强一致性。在事务执行过程中,各个节点占用着数据库资源,只有当所有节点准备完毕,事务协调者才会通知提交,参与者提交后释放资源。这样的过程有着非常明显的性能问题,不适合高并发高性能场景。
2.协调者单点故障问题
事务协调者是整个XA模型的核心,一旦事务协调者节点挂掉,参与者收不到提交或是回滚通知,参与者会一直处于中间状态无法完成事务。
3.丢失消息导致的不一致问题
在XA协议的第二个阶段,如果发生局部网络问题,一部分事务参与者收到了提交消息,另一部分事务参与者没收到提交消息,那么就导致了节点之间数据的不一致。
XA三阶段提交(3PC)
XA三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制。一旦事务参与者迟迟没有接到协调者的commit请求,会自动进行本地commit。这样有效解决了协调者单点故障的问题。但是性能问题和不一致的问题仍然没有根本解决。
MQ事务(消息事务+最终一致性)
利用消息中间件来异步完成事务的后一半更新,实现系统的最终一致性。这个方式避免了像XA协议那样的性能问题。
补偿事务(TCC)
TCC事务是Try、Commit、Cancel三种指令的缩写,其逻辑模式类似于XA两阶段提交,但是实现方式是在代码层面来人为实现。
本地消息表
添加本地消息表实现最终一致性。比如商城系统,一个订单服务,一个库存服务。订单服务产生订单后,往消息表中添加一条数据,标记状态为发送中。然后写数据到MQ,库存服务MQ接收到数据进行扣库存操作,再写数据到MQ,订单服务MQ接收消息标记消息表中的状态为已完成。为了确保消息投递不丢失,添加一个定时任务扫描订单服务中的消息表,将发送中的订单重新投递。
优点
实现逻辑简单,开发成本较低。
缺点
与业务场景绑定,高耦合,不能公用。
二、分布式锁
锁是一种控制共享资源争抢的机制,采用互斥方式防止并发造成的冲突。
分布式锁的实现方式
1.数据库
2.Redis
3.Zookeeper
分布式锁需要注意什么?
互斥:只有一个事务能获取锁。
防止死锁:异常或超时能释放锁。
可重入:同一线程可多次获取同一锁。如递归场景。
高可用:在节点故障时能正常工作。
悲观锁和乐观锁的区别
悲观锁和乐观锁都是用于解决并发场景下的数据竞争问题,但是却是两种完全不同的思想。它们的使用非常广泛,也不局限于某种编程语言或数据库。
1.悲观锁
指的是在操作数据的时候比较悲观,认为别人一定会同时修改数据,因此悲观锁在操作数据时是直接把数据上锁,直到操作完成之后才释放锁,在上锁期间其它人不能操作数据。适用于频繁写入的场景。悲观锁的实现方式就是加锁,Java中的synchronized、MySQL中的排他锁。
2.乐观锁
指的是在操作数据的时候非常乐观,认为别人不会同时修改数据,因此乐观锁默认不上锁,只有在执行更新的时候才会去判断在此期间别人是否修改了数据,如果别人修改了数据则放弃操作,否则执行操作。适用于读多写少的场景。乐观锁的实现方式主要有2种,CAS和版本号机制。
MySQL中的锁
a.按模式分类:悲观锁、乐观锁
b.按粒度分类:
全局锁
整个数据库可读不可写。
表锁
对整个表加锁,MyISAM默认的锁机制。其它事务无法读写该表。
行锁
对单行加锁,InnoDB默认的锁机制。除锁定的行外,其它行可被其它事务读写。
c.按属性分类:
共享锁
也称为读锁,多个事务可以同时持有共享锁,可读不可写。
排他锁
也称为写锁,事务持有者可读写,其它事务不可读写。
三、秒杀
秒杀的特点:瞬时大并发、防止超卖、带宽问题。
秒杀解决方案
1.缓存
热点数据缓存、商品页面缓存在CDN中。
2.限流
令牌桶算法(网关限流)
以一个恒定的速度往桶中放入令牌,当来一个请求的时候,需要先从桶中获取一个令牌,桶中没有令牌可取时,就拒绝服务。需配置令牌桶的容量、允许每秒处理请求数。
漏桶算法
把请求放入漏桶中,漏桶以一定的频率处理请求,当漏桶中的请求满的时候,就拒绝请求。
3.异步
服务端收到秒杀请求后,立即返回‘正在秒杀中’,客户端轮询显示秒杀结果。
4.库存上锁
5.数据库读写分离
负载均衡策略
1.轮询
每个请求按时间顺序逐一分配到不同的服务器,如果某个服务器down掉,则自动剔除。
2.指定权重
指定轮询几率,weight和访问比率成正比,用于服务器性能不均的情况。
3.ip hash
同一个IP分配到同一个服务器,可解决分布式session问题。
4.随机
5.最小连接数