# 1.支付公司和银行之间清结算流程是怎样的
# 2.如何保证银行清结算文件可信,如何确保不被篡改
# 3.Redis的分布式锁
# 4.Redis的“一主二从三哨兵”
# 5.如何不用db、redis、zk解决分布式锁
# 5.1 Map本地高可用缓存
# 5.2 Map缓存扩展到分布式如何保证数据一致性和高可用
# 5.3 Map缓存分布式如何扩容、一致性哈希、虚拟node等实施方案
# 5.4 Map缓存宕机重启数据持久化磁盘(RDB、AOF)时,你会如何实现
# 6.Redis主从同步和cluster
# 7.ConcurrentHashMap用到了哪些锁
# 8.HashMap的数据扩容迁移
- capacity 容量16
- loadFactor 扩容因子0.75
- threshold 阈值 = 容量 * 扩容因子。(put时元素超过阈值会触发扩容)
# JDK7扩容机制
- 空参构造
- 有参构造
- 后需扩容直接容量2倍,阈值2倍。
- 需要注意首次put时,先触发扩容初始化,然后存入数据,判断是否需要扩容。
- 非首次操作,不进行触发扩容初始化,直接存入数据,然后判断是否需要扩容。
- 元素迁移
- 遍历每一个entity,重新计算hash,找到新的位置使用头插法。
- 头插法,新旧链表元素位置会发生改
- 元素迁移过程中,并发情况下会触发死循环(无限链表反转)
# JDK8扩容机制
- 实现以2的幂次方扩容
- entity在扩容时,要么在原位置,要么在原长度+原位置的位置上。
- JDK8元素迁移是正序的,不会发生链表转置问题。
- 如果entity内元素超过8个,链表转换为红黑树,增加查询效率。
# 9.如何设计去中心化存储(分布式缓存存储)
# 10.RabbitMQ 如何实现分布式事务
# 11.分布式事务中的2PC和TCC
# 事务ACID
- 事务必须严格遵循ACID原则
- 原子性(Atomicity) 事务内所有操作必须是原子化不可拆分的,要么执行成功,要么执行失败
- 一致性(Consistency) 数据完整性的约束,不会存在中间状态的数据
- 隔离性(Isolation) 多个事务在并发状态下不会进行相互干扰,一个事务内的数据相对于其他事务来说是隔离的
- 持久性(Durability) 事务执行完成后数据便永久保存,不会因为故障或者其他操作对该事务结果造成影响。
# 分布式事务
分布式事务顾名思义是分布在不同节点应用上的事务,其实是由多个本地事务组成的,无法满足ACID原则,那么就需要系列解决方案
2PC(二阶段提交)
- 2PC是一种强一致性设计,引入了事务的协调者的角色来协调管理各个参与者(本地事务资源)的提交和回滚。并且2PC分别是准备(投票)和提交两阶段。
- 2PC是一种同步阻塞的,无论提交或者回滚都需要协调者知道所有参与者都有响应才会进行下一步操作,当然一阶段时的协调者超时机制会保证有参与者超时或Down掉时,进行通知所有参与者回滚提交。
- 协调者单点问题,存在故障时可通过选举得到新的协调者。
3PC
- 参与者增加了超时机制
- 准备阶段(CanCommit)、预提交阶段(PreCommit)、提交阶段(DoCommit)
- 2PC 3PC均是数据库层面的,下面TCC是从业务层面来解决分布式事务
TCC(Try-Comfirm-Cancel)
TCC是一种尝试性执行,若所有参与结点都有事务执行的条件,那么直接执行事务。否则Cancel回滚操作。
- Try-预留,事务执行资源的预留和锁定
- Confirm-确认操作,这一步执行成功
- Cancel-撤销操作,对预留阶段锁定的资源进行撤销。
- 对业务的操作入侵比较大,耦合性高,对于Try和Cancel可能需要重试
- 需要业务系统保证操作的幂等性
- 从业务角度的实现方案,因此可以跨数据库、跨业务系统。
本地消息表
本地消息表是利用各系统本地事务来实现分布式事务。
- 业务系统的执行和消息均放入本地消息表中,确保本地业务执行和消息表的操作在一个事务中。
- 不尝机制重试读取本地消息表,调用远程应用操作。
- 需要加入重试机制、最大执行次数、报警机制。
- 本地消息表容忍数据暂时不一致,期望数据的最终一致性。
消息事务
消息事务的执行实现方案也是数据最终一致性。
- 第一步先给 Broker 发送事务消息即半消息,发送成功后发送方再执行本地事务。
- 本地事务的结果向 Broker 发送 Commit 或者 RollBack 命令。
- 提供反事务查询接口,超时时会根据该接口判断事务是否执行成功,然后在执行Commit或Rollback操作。
最大努力通知
对于时间不敏感的业务,短信、邮件通知等。尽最大努力进行推送消息保证事务数据的最终一致性。
# 12.简单介绍一下RabbitMQ的Push和Pull模式
# Push
- 服务端主动推送消息给客户端,及时性较高.
- 若客户端处理能力较弱时会产生消息堆积、处理缓慢、甚至于崩溃。
- 避免该情况产生,需要根据客户端消费能力做流控(rabbitMQ-Qos).
- 服务端需要维护每次推送消息的状态,推送失败后需要进行重试。
# pull
- 客户端可根据自身性能进行消费。
- 数据传输失败时消息不会丢失,只需客户端重新从服务端进行拉取即可。
- 确保客户端主动到服务端拉取消息的时间间隔设置合适,避免高频拉取对服务端造成压力。间隔时间过长会造成数据延迟和堆积。
# 不同业务场景选择
- 服务端消息过大,客户端对消息处理逻辑流程复杂,消费性能较弱时可选择pull模式。
- 对于数据实时性要求较高时,可采用push进行实时推送。
# 13.索引如何使用的
# 13.1 索引失效
- MySQL引擎结算全表扫描更快
- Where中存在函数
- Where中索引列存在运算
- 需要类型转换时
- 联合索引时未使用左字段(联合索引最左原则)
- 使用like关键字时 第一个字符
%
开始索引失效 - 使用or时必须两边字段全有索引
# 14.索引下推和索引覆盖
当sql语句select password from table where username = 'cong'
的所求查询字段(select列)和查询条件字段(where子句)全都包含在一个索引(username,password)
中,可以直接使用索引查询而不需要回表。这就是覆盖索引,通过使用覆盖索引,可以减少搜索树的次数,是常用的性能优化手段。
联合索引最左原则: 联合索引的多个字段中,只有当查询条件为联合索引的一个字段时,查询才能使用该索引。
索引可以用于查询条件字段为索引字段,根据字段值最左若干个字符进行的模糊查询。
username like %cong
需要回表查询的全行数据比较少,这就是mysql的索引下推。