1、谈谈mysql的事务隔离级别
事务并发处理可能会带来一些问题,比如:更新丢失、脏读、不可重复读、幻读等。
- 更新丢失
多个事务更新同一行记录,产生更新丢失现象。分为两种情况:
回滚覆盖:一个事务rollback,把其他事务已提交的数据给覆盖了;
提交覆盖:一个事务commit,把其他事务已提交的数据给覆盖了; - 脏读:一个事务读取到了另一个事务修改但未提交的数据;
- 不可重复读:一个事务中多次读取同一行记录不一致,后面读取的跟前面读取的不一致。
- 幻读:一个事务中多次按相同条件查询,结果不一致。后续查询的结果和前面查询结果不同,多了或少了几行记录。
为了解决上述事务并发的问题,数据库引入了隔离级别,设置不同隔离级别,可以解决不同问题。
- 读未提交: Read Uncommitted,解决了回滚覆盖类型的更新丢失,但可能发生脏读现象,也就是可能读取到其他会话中未提交事务修改的数据。
- 已提交读: Read Committed,只能读取到其他会话中已经提交的数据,解决了脏读,但可能发生不可重复读现象,也就是可能在一个事务中两次查询结果不一致。
- 可重复读: Repeatable Read,解决了不可重复读,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据记录。不过理论上会出现幻读,简单的说幻读指的的当用户读取某一范围的数据行时,另一个事务又在该范围插入了新行,当用户在读取该范围的数据时会发现有新的幻影行。
- 可串行化:Serializable,所有的增删改查串行执行。它通过强制事务排序,解决相互冲突,从而解决幻度的问题。这个级别可能导致大量的超时现象的和锁竞争,效率低下。
2、 mysql中分布式ID生成策略有哪些
- UUID:UUID是通用唯一识别码。
UUID在生成时使用到了以太网卡地址、纳秒级时间、芯片ID码和随机数等信息,目的是让分布式系统中的所有元素都能有唯一的识别信息。使用UUID做主键,可以在本地生成,没有网络消耗,所以生成性能高。但是UUID比较长,没有规律性,耗费存储空间。
- COMB(UUID变种):解决UUID无序的问题,性能优于UUID
- SNOWFLAKE:SnowFlake是Twitter开源的分布式ID生成算法,结果是一个long型的ID,能够按照时间有序生成数据库ID表:创建一张表,这张表的ID设置为自动递增,其他地方需要全局唯一ID的时候,就先向这个这张表中模拟插入一条记录,此时ID就会自动递增,然后我们获取刚生成的ID后再进行A1和A2表的插入。
- Redis生成ID:当使用数据库来生成ID性能不够要求的时候,我们可以尝试使用Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。
3、讲一下MySQL的存储引擎,InnoDB和MyISAM的区别
存储引擎负责MySQL中数据的存储和提取,是与文件打交道的子系统,它是根据MySQL提供的文件访问层抽象接口定制的一种文件访问机制,这种机制就叫作存储引擎。
使用show engines
命令,就可以查看当前数据库支持的引擎信息。
在5.5版本之前默认采用MyISAM存储引擎,从5.5开始采用InnoDB存储引擎。
- InnoDB:支持事务,具有提交,回滚和崩溃恢复能力,事务安全
- MyISAM:不支持事务和外键,访问速度快
InnoDB和MyISAM是使用MySQL时最常用的两种引擎类型,我们重点来看下两者区别
。
事务和外键
InnoDB支持事务和外键,具有安全性和完整性,适合大量insert或update操作
MyISAM不支持事务和外键,它提供高速存储和检索,适合大量的select查询操作
-
锁机制
InnoDB支持行级锁,锁定指定记彔。基于索引来加锁实现。
MyISAM支持表级锁,锁定整张表。 -
索引结构
InnoDB使用聚集索引(聚簇索引),索引和记彔在一起存储,既缓存索引,也缓存记彔。
MyISAM使用非聚集索引(非聚簇索引),索引和记彔分开。 -
并发处理能力
MyISAM使用表锁,会导致写操作并发率低,读之间并不阻塞,读写阻塞。
InnoDB读写阻塞可以与隔离级别有关,可以采用多版本并发控制(MVCC)来支持 高并发 -
存储文件
InnoDB表对应两个文件,一个.frm表结构文件,一个.ibd数据文件
。InnoDB表最大支持64TB;
MyISAM表对应三个文件,一个.frm表结构文件,一个MYD表数据文件,一个.MYI索引文件。
从MySQL5.0开始默认限制是256TB。 -
两种引擎该如何选择?
是否需要事务?是,InnoDB
是否存在并发修改?是,InnoDB
是否追求快速查询,且数据修改少?是,MyISAM
在绝大多数情况下,推荐使用InnoDB
4、mysql日志系统
- undo log,事务开始前产生,把要修改的记录放到undo日志里,当事务回滚或数据库崩溃时,可以利用事务对应的undo日志,撤销未提交事务对数据库产生的影响。
- redo log和binlog
- redo log以数据恢复为目的,在数据库发生意外时重现操作。并不是每次事务提交都会立刻持久化到磁盘,而是先记录到redo文件,如果mysql重启,会从redo log恢复。
如果一不小心执行了drop table ***;或者把库删了,redo log就无能为力了,先别急着跑路,考虑下binlog恢复。
- binlog日志最重要的两个场景:主从复制和数据恢复。
- 主从复制:主库开启binlog,默认是关闭的,从库从binlog恢复数据达到主从数据已执行。
- 数据恢复:通过mysqlbinlog工具恢复数据。
- binlog记录的是对数据库的各种修改操作(create/update),用来表示修改操作的数据结构是各种event。
- 两者区别
- redolog是Innodb引擎自带功能,binlog是mysql-server自带功能,并且是以二进制文件记录
- rodolog记录的是物理日志,记录的更新内容,binlog记录的更新过程;
- redolog是循环写,日志空间大小是固定的;binlog是追加写入
- redolog服务器异常宕机后事务数据自动恢复;binlog作为主从复制和数据恢复使用
分布式事务
分布式系统的核心就是处理各种异常情况,这也是分布式系统复杂的地方,所以我们在做分布式系统的时候,最先考虑的就是这种情况。这些异常可能有 机器宕机、网络异常、消息丢失、消息乱序、数据错误、不可靠的TCP、存储数据丢失、其他异常等等。
单个数据库的性能产生瓶颈的时候,我们可能会对数据库进行分区,再想保证集群的ACID几乎是很难达到,CAP定理
提出web服务无法同时满足一致性、可用性和分区容错性。
分布式系统中,可用性的重要程序比一致性要高,BASE理论
是对CAP定理进行进一步扩充,BASE理论是对CAP中的一致性和可用性进行一个权衡的结果。理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性(Eventual consistency)。
分布式事务解决方案
1、两阶段提交(2PC)
:牺牲可用性换取强一致性,不适合高并发高性能场景。
第一阶段是表决阶段,所有参与者都将本事务能否成功的信息反馈发给协调者;第二阶段是执行阶段,协调者根据所有参与者的反馈,通知所有参与者,步调一致地在所有分支上提交或者回滚。
2、补偿事务(TCC)
:一致性较差,需要程序员写一些补偿代码,一些业务场景下,TCC不好定义和处理。
3、本地事务表(异步确保)
:基本思路是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么两者都成功或者都失败,
避免了分布式事务,实现了最终一致性,但是会把消息表耦合到业务系统,如果没有分装好的解决方案,还有一些杂活要处理。
4、mq事务消息
:实现了最终一致性,不需要依赖本地数据库事务。主流mq不支持,rocketmq事务消息部分未开源。
mq事务消息需要考虑的问题:
支付宝向余额宝转账,支付宝扣款后未提交时先发送消息到中间件,中间件不会立即发送,而是等待扣款事务提交成功后收到消息确认发送指令才会发送。
业务与消息解耦
:添加一个消息确认系统,定时去支付宝系统查询这个消息的状态,收到确认发送指令后才发送。
消息重复投递即重复消费
事件表+消息队列实现事务最终一致性
解决方法很简单,在余额宝这边增加消息应用状态表(message_apply),通俗来说就是个账本,用于记录消息的消费情况,每次来一个消息,在真正执行之前,先去消息应用状态表中查询一遍,如果找到说明是重复消息,丢弃即可,如果没找到才执行,同时插入到消息应用状态表(同一事务)。
参考:mysql常见面试题