【高频常见问题】
1、事务的特性
- 原子性:即不可分割性,事务要么全部被执行,要么就全部不被执行。
- 一致性或可串性:事务的执行使得数据库从一种正确状态转换成另一种正确状态
- 隔离性:在事务正确提交之前,不允许把该事务对数据的任何改变提供给任何其他事务,
- 持久性:事务正确提交后,其结果将永久保存在数据库中,即使在事务提交后有了其他故障,事务的处理结果也会得到保存。
2、事务的隔离级别
- 读未提交(Read Uncommitted):可以读取未提交的记录。
如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据,该隔离级别可以通过“排他写锁”,但是不排斥读线程实现。这样就避免了更新丢失,却可能出现脏读,也就是说事务B读取到了事务A未提交的数据。
解决了更新丢失,但还是可能会出现脏读
- 读已提交(Read Committed):事务中只能看到已提交的修改。
如果是一个读事务(线程),则允许其他事务读写,如果是写事务将会禁止其他事务访问该行数据,该隔离级别避免了脏读,但是可能出现不可重复读。事务A事先读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据已经发生了改变。
解决了更新丢失和脏读问题
- 可重复读(Repeatable Read):解决了不可重复读问题(MySQL 默认隔离级别)
可重复读取是指在一个事务内,多次读同一个数据,在这个事务还没结束时,其他事务不能访问该数据(包括了读写),这样就可以在同一个事务内两次读到的数据是一样的,因此称为是可重复读隔离级别,读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务(包括了读写),这样避免了不可重复读和脏读,但是有时可能会出现幻读。(读取数据的事务)可以通过“共享读镜”和“排他写锁”实现。
解决了更新丢失、脏读、不可重复读、但是还会出现幻读
- 序列化(Serializable):最高隔离级别。
提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无法实现序列化的,必须通过其他机制保证新插入的数据不会被执行查询操作的事务访问到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,一般很少使用,在该级别下,事务顺序执行,不仅可以避免脏读、不可重复读,还避免了幻读
解决了更新丢失、脏读、不可重复读、幻读(虚读)
3、分布式事务实现
一个实际案列,电商平台分为订单中心,商品中心,提交订单时需要同时扣减库存和生成订单,
扣减库存先采用预扣库存(预占),然后生成预提交,然后扣减库存,最后订单正式提交,预订单有定时取消功能,30分钟未正式提交的订单取消,同时释放库存。
跨库2pc(准备,提交 ),跨库3pc(准备,预提交,提交),跨应用分布式事务TCC(预留,提交,撤回),RocketMQ 事务消息 本地发送一个half消息到mq-->mq返回成功-->执行本地事务-->提交事务消息给mq 结束,如果出现超时,mq会使用通知补偿方式联系生产者,会重试15次。
4、数据库优化
建索引,合适的组合索引,排序和where条件用一个索引,不要使用<>、 !=、 not null、 not in 、 null、 ‘like %%’等条件,少用子查询使用join代替,使用合适的聚合索引。
执行计划说明:
5、分布式技术
分布式分为分布式缓存(Redis)、分布式锁(Redis 或 Zookeeper)、分布式服务(Dubbo 或 SpringCloud)、分布式服务协调(zookeeper,nacos)、分布式消息队列(Kafka 、RocketMq)、分布式 Session 、分布式事务、分布式搜索(Elasticsearch)等
CAP ,分布式 CAP 理论,任何一个分布式系统都无法同时满足 Consistency(一致性)、Availability(可用性)、Partition tolerance(分区容错性) 这三个基本需求;
而 Partition tolerance(分区容错性) 是必须的,因此一般是 CP ,或者 AP。
分布式消息队列:
kafka和RocketMq区别
1)、Kafka是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式消息系统,比较常用于日志收集系统,和消息系统等,不支持事务消息;kafka对与zookeeper是强依赖的,是以zookeeper作为基础的,即使不做集群,也需要zk的支持。每个主题可以有多个区,每个区数据保证数据有序,分区之间不保证有序;而Kafka在达到几百个topic的时候吞吐量就会大幅下降,因为Kafka的topic数量不能太多,受到zookeeper协调策略和消息文件存储设计的制约;
2)、RocketMQ由NameServer注册中⼼集群、Producer⽣产者集群、Consumer消费者集群和若⼲Broker(RocketMQ进程)组成,支持事务消息;消息发送应该弱依赖注册中⼼,⽣产者在第⼀次发送消息的时候从NameServer获取到Broker地址后缓存到本地,如果NameServer整个集群不可⽤,短时间内对于⽣产者和消费者并不会产⽣太⼤影响;每个主题一个文件; rocketmq可以支持成百上千的topic;
6、缓存穿透,缓存击穿,缓存雪崩都是咋回事?解决办法?
- 缓存穿透
问题:大量并发查询不存在的 KEY,在缓存和数据库中都不存在,同时给缓存和数据库
带来压力。
原因:一般而言,缓存穿透有 2 种可能性:业务数据被误删,导致缓存和数据库中都没
有数据。恶意进行 ddos 攻击。
分析:为什么会多次透传呢?不存在 一直为空,需要注意让缓存能够区分 KEY 不存在和查询到一个空值。
解决办法:缓存空值的 KEY,这样第一次不存在也会被加载会记录,下次拿到有这个
KEY。Bloom 过滤或 RoaingBitmap 判断 KEY 是否存在,如果布隆过滤器中没有查到
这个数据,就不去数据库中查。在处理请求前增加恶意请求检查,如果检测到是恶意攻击,
则拒绝进行服务。完全以缓存为准,使用延迟异步加载的策略(异步线程负责维护缓存的
数据,定期或根据条件触发更新),这样就不会触发更新。
- 缓存击穿
问题:某个 KEY 失效的时候,正好有大量并发请求访问这个 KEY。
分析:跟穿透其实很像,属于比较偶然的。
解决办法:KEY 的更新操作添加全局互斥锁。完全以缓存为准,使用延迟异步加载的策略(异步线程负责维护缓存的数据,定期或根据条件触发更新),这样就不会触发更新。
- 缓存雪崩
问题:当某一时刻发生大规模的缓存失效的情况,导致大量的请求无法获取数据,从而将流量压力传导到数据库上,导致数据库压力过大甚至宕机。
原因:一般而言,缓存雪崩有 2 种可能性:大量的数据同一个时间失效:比如业务关系强相关的数据要求同时失效 Redis 宕机
分析:一般来说,由于更新策略、或者数据热点、缓存服务宕机等原因,可能会导致缓存
数据同一个时间点大规模不可用,或者都更新。所以,需要我们的更新策略要在时间上合适,数据要均匀分享,缓存服务器要多台高可用。
解决办法:更新策略在时间上做到比较平均。如果数据需要同一时间失效,可以给这批数据加上一些随机值,使得这批数据不要在同一个时间过期,降低数据库的压力。使用的热数据尽量分散到不同的机器上。多台机器做主从复制或者多副本,实现高可用。做好主从的部署,当主节点挂掉后,能快速的使用从结点顶上。实现熔断限流机制,对系统进行负载能力控制。对于非核心功能的业务,拒绝其请求,只允许核心功能业务访问数据库获取数据。服务降价:提供默认返回值,或简单的提示信息。
【互联网大厂面试题合集】
未完 待续。。。。。。