算法/结构/理论
- 雪花算法
- CAP理论
- BASE理论
- 分布式事务的解决方案
- 数据结构
- 树(Tree)
- 二叉树
- 二叉查找树
- 平衡查找树
- 红黑树(重点)
- BTree(重点)
- B+Tree
雪花算法
雪花算法主要是为了解决在分布式中id的生成问题
分布式id的生成规则是:全局唯一,不可以出现重复的id号,趋势递增
雪花算法指的是一个long的id,64位的2进制组成,第一位指的是0无意义主要是符号位 第二位到第42位的这41个组成的就是时间戳–生成是达到毫秒级别,后面的十位指的是机器的id(数据中心id+服务器的id),最后的12位数指的是序列号(从时间戳里面抽取出来的一连串数字)
再mybatis-plus中已经集成了雪花算法
使用的方法是
@TableId(value="id" ,type=IdType.ID_WORKER)
private Long id;
CAP理论
类别 | 解释说明 |
---|---|
一致性C | 在分布式系统中所有的节点看到的数据都是相同的,系统的状态再任何时刻都是一致的 |
可用性A | 系统不需保证再任何时刻都能处理请求返回正确的结果,即系统一致处于可用的状态 |
分区容错性P | 系统再遇到网络分区故障的时候仍然能够保证正常的工作,即系统能够容忍任意数量的消息丢失或网络分区 |
为什么CAP不可兼得
这是因为在分布式系统中,网络分区是不可避免的,然而保证一致性和可用性就需要对网络的分区进行取舍衡量
例如:当网络分区发生的时候,节点之间可能无法进行一致性的数据同步,因此在这种情况下,要么保证可用性,允许节点继续处理请求并且返回不一致的结果,要么保证一致性,暂停服务知道网络分区恢复
策略 | 放弃 | 说明 |
---|---|---|
CA | 放弃容错性 | 适用于小规模的集中式系统 |
CP | 放弃可用性 | 适用于对数据一致性比较高的系统,如金融系统 |
AP | 放弃一致性 | 适用于对数据实时性要求比较高的系统,如社交网络 |
BASE理论
这里指的是对CAP中AP的一种拓展,即使无法做到强一致性,但每个应用都可以根据自身业务特点采用适当的方式来使系统达到最终一致性
类别 | 解释说明 |
---|---|
Basically Available(基本可用) | 响应时间上的损失:正常情况下,处理用户请求需要0.5s返回结果,但是由于系统出现故障,处理用户请求的时间变成3s。 系统功能上的损失:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系统的非核心功能无法使用。 |
Soft state(软状态) | 数据同步允许一定的延迟。 |
Eventually consistent(最终一致性) | 系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态,不要求实时 |
最终一致性
类别 | 解释说明 |
---|---|
因果一致性(Causal consistency) | 如果节点 A 在更新完某个数据后通知了节点 B,那么节点 B 之后对该数据的访问和修改都是基于 A 更新后的值。于此同时,和节点 A 无因果关系的节点 C 的数据访问则没有这样的限制。 |
读己之所写(Read your writes) | 节点 A 更新一个数据后,它自身总是能访问到自身更新过的最新值,而不会看到旧值。其实也算一种因果一致性。 |
会话一致性(Session consistency) | 会话一致性将对系统数据的访问过程框定在了一个会话当中:系统能保证在同一个有效的会话中实现 “读己之所写” 的一致性,也就是说,执行更新操作之后,客户端能够在同一个会话中始终读取到该数据项的最新值。 |
单调读一致性(Monotonic read consistency) | 单调读一致性是指如果一个节点从系统中读取出一个数据项的某个值后,那么系统对于该节点后续的任何数据访问都不应该返回更旧的值。 |
单调写一致性(Monotonic write consistency) | 指一个系统要能够保证来自同一个节点的写操作被顺序的执行。 |
分布式事务的解决方案
2PC(二阶段提交)
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fa15893823644f318b209312220d1bbf.png
2PC 引入一个事务协调者的角色来协调管理各参与者(也可称之为各本地资源)的提交和回滚,二阶段分别指的是准备(投票)和提交两个阶段。
准备阶段:事务管理器告诉资源管理器准备执行事务,并锁住需要的资源。当准备完成后,资源管理器向事务管理器报告已准备就绪。
提交阶段:如果所有资源管理器都准备成功,第二阶段事务管理器回要求所有的资源管理器执行提交操作。如果任一资源管理器在第一阶段返回准备失败,那么事务管理器回要求所有的资源管理器在第二阶段执行回滚操作。
二阶段看起来能提供原子性操作,但是不幸的是,二阶段提交还是有几个缺点的
1.2PC是一个同步阻塞协议,资源管理器在执行的过程中会锁定资源。其他第三方节点想访问这些资源的时候不得不处于阻塞状态
2.一阶段有超时机制,在第一阶段事务管理器没有收到资源管理的响应,或者资源管理器挂了。超时就会判端事务失效,向所有资源管理器发送回滚命令。但二阶段只能不断重试
3.事务管理器存在单点风险,如果发生故障,则资源管理器会一直阻塞下去。
XA规范
XA规范是X/Open 组织针对二阶段提交协议的实现做的规范。目前几乎所有的主流数据库都对XA规范提供了支持
XA规范的特点是:
1.对代码无侵入,开发比较快速
2.对资源进行了长时间的锁定,并发程度比较低
TCC
TCC这种方案应该是在企业中应用最广泛的一种方案,在业务层面实现分布式事务。TCC是Try、Confirm、Cancel三个词语的缩写。
Try:负责业务资源检查和预留
Confirm:二阶段提交操作,所有的Try都成功了,则执行Confirm操作。Confirm真正执行业务,使用Try预留的资源
Cancel:二阶段回滚操作,只有一个Try失败了,则走到Cancel操作。Cancel释放Try预留的资源
特点:
1.并发程度高,在业务层面锁定资源
2.开发量大,一个业务员需要提供Try/Confirm/Cancel三个方法
本地消息表(异步确保)
我们以买书为例说一下大致流程
1.账号服务扣减账户余额,同时写入一条消息(状态为进行中),注意扣减账户余额和写消息在一个本地事务中
2.账号服务轮询消息表,将进行中的消息发送到消息队列
3.仓库服务收到消息后,扣减相应的库存。扣减完成后将结果通过给账号服务,账号服务将消息的状态更新为已完成(或者删除)
4.当消息发送失败,或者消息消费失败时,会不断重试,因此仓库服务要保证消费的幂等性。
特点 :需要创建额外的消息表,不断对消息表轮询
RocketMQ事务消息
在本地消息表方案中,生产者需要额外创建本地消息表,还要对本地消息进行轮询。RocketMQ在4.3之后的版本正式支持事务消息,该事务消息的本质是把本地消息表放在RocketMQ上,解决生产端消息发送和本地事务执行的原子性问题
RocketMQ实现分布式事务的流程如下:
1.producer向mq server发送一个半消息
2.mq server将消息持久化成功后,向发送方确认消息已经发送成功,此时消息并不会被consumer消费
3.producer开始执行本地事务逻辑
4.producer根据本地事务执行结果向mq server发送二次确认,mq收到commit状态,将消息标记为可投递,consumer会消费该消息。mq收到rollback则删除半消息,consumer将不会消费该消息,如果收到unknow状态,mq会对消息发起回查
5.在断网或者应用重启等特殊情况下,步骤4提交的2次确认有可能没有到达mq server,经过固定时间后mq会对该消息发起回查
6.producer收到回查后,需要检查本地事务的执行状态
7.producer根据本地事务的最终状态,再次提交二次确认,mq仍按照步骤4对半消息进行操作
消息投递到mq server,consumer消费失败怎么办?
如果是消费超时,重试即可。如果是由于代码等原因真的消费失败了,此时就得人工介入,重新手动发送消息,达到最终一致性。
最大努力通知
最大努力通知这种方案在充值系统中经常被使用
充值系统通过不断的重试将充值结果推送给账户系统。因此账户系统接收充值结果的系统要保持幂等。另外充值充值系统还要提供回查接口,让账户系统主动校验充值的状态。
Seata AT模式
这是阿里开源的事务框架Seata中主推的事务模式。Seata AT是一种无侵入的事务解决方案。事务的一阶段和二阶段均由框架自动生成。用户SQL作为分布式事务的一阶段,而二阶段由框架自动生成提交/回滚操作。和XA模式很类似
Seata AT模式特点:
1.对代码无侵入,开发速度较快
2.需要用全局锁来保证隔离性,并发程度较低
数据结构
栈(先进后出)
数据进入栈模型的过程叫做进栈/压栈
数据离开栈模型的过程叫做出栈/弹栈
队列(先进先出)
数组
1 查询数据通过索引定位,查询任意数据耗时相同,查询效率高
2.删除数据的时候,需要将原始的数据删除,同时后面的每一个数据前移,删除效率低
3 添加数据的时候,添加位置后的每一个数据都是需要后移的再添加元素,添加效率极低
链表
对比数组增删快
对比数组查询慢
哈希值
是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
其中object类中的hashCode方法可以获取对象的哈希值
默认情况下,不同对象的哈希值都是不相同的,但是如果重写里面的hashCode的方法的时候是有可能一致的
计算哈希值除以16取余判断放在的位置
由于他的加载因子是0.75所以当数组里面存入了当前长度 * 0.75的元素的时候就会扩容为原来的2倍
哈希表
下面是数组+链表(jdk8之前)
下面是数组+链表+红黑树(jdk8之后)
当链表的长度等于8的时候就会转变为红黑树
树(Tree)
树是由节点和边组成的,不存在环的一种数据结构.每个元素叫做节点;用来相邻的节点之间的关系叫做"父子关系"
二叉树
二叉树就是每个节点最多有2个叉,也就是2个子节点,但是二叉树不是必须要满足2个子节点也可以是一个子节点左子结点或者右子节点
7表示根节点
4表示7的左子结点
10表示为7的右子节点
二叉查找树
二叉排序树/二叉搜索树
每一个节点最多有2个子节点
每一个节点的左边节点都是小于自己的
每一个节点的右边节点都是大于自己的
例如下面的图形就是典型的二叉查找树
平衡查找树
二叉树左右子树的高度差不超过1
任意节点的左右2个树都是一个平衡二叉树
但是下面的第一张图不是平衡二叉树但是第二张图是平衡二叉树
下面就是左旋变为了平衡二叉树了
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/2c1a31dd40044519816f23817bb2fd99.png
红黑树(重点)
是一个二叉B树
每一个节点可以是红或者黑
红黑树不是高度平衡的,这是通过自己的红黑规则进行实现的
红黑规则
1.每一个节点由红黑色组成
2.根节点必须是黑色的
3.如果一个节点没有子节点或者父节点,那么这个节点相应的指针属性值为Nil,这些Nil被视为叶节点,每个叶节点都是黑色的
4.如果有一个节点是红色的,那么他的子节点必须是黑色的,不能出现2个红色节点相连的情况
5.对于每一个节点来说,从该节点到其他所有的后代叶节点的简单路径上,都可以包含相同数目的黑色节点
添加节点
1.添加节点的颜色,可以是红色也可以是黑色,再添加的元素的时候默认为红色的时候效率会高一点
2.添加的节点默认为红色,如果是根节点,那么就将当前的节点变为黑色
3.添加的节点默认为红色,如果不是根节点,这个时候需要判断父节点的颜色,如果父节点是黑色无需操作
BTree(重点)
解释:多路平衡搜索树
特点:
1.树中每个节点最多包含m个孩子
2.除了根节点和叶子结点外,每个节点至少有[ceil(m/2)]个孩子(m/2向上取整)
3.若根节点不是叶子结点,则至少有2个孩子
4.所有的叶子结点都在同一层
5.每个非叶子结点由n个key与n+1个指针组成,其中[ceil(m/2)] <= n <= m-1
下面会以5叉BTree树举例,插入字母为
CNGA H EKQ MFWLTZDPRXYS 数据
公式推到key的数量为2<= n <= 4 所以当n>4的时候,中间的节点分裂到父节点,2遍节点分裂
演变过程:
i.插入前4个字母
ii.插入H,n>4,中间而定字母G向上进行分裂到新的节点上
iii.插入EKQ不需要进行分裂
iv.插入M,中间的字母M向上分裂到父节点G
v.插入FWLT 不需要进行分裂
vi.插入Z,中间的元素T向上进行分裂到父节点
vii.插入D,中间的D向上分裂到父节点,然后再去插入PRXY不需要进行分裂
viii.插入S,NPQR节点中Q向上分裂,但是分裂之后DGMT节点的n>4,所以中间节点M继续向上进行分裂
B+Tree
这个再mysql的索引数据结构使用的就是B+树结构
聚合索引/复合索引/前缀索引/唯一索引默认都是使用的B+Tree索引
B+Tree是Btree的变种
i.n叉B+Tree最多包含有n个key,而BTree最多含有n-1个key
ii.B+Tree的叶子结点保存了所有的key信息,依key大小顺序排列
iii.所有的非叶子节点都可以看做key的索引部分
MySQL索引数据结构是对B+Tree进行了优化,在原来的B+Tree的基础上,增加了指针指向相邻的叶子结点的链表,这样就形成了带有顺序指针的B+Tree,提高了区间的访问效率