1、Mysql和Redis如何保持数据一致性?
答:一般情况下redis是作为缓存层,减少数据库的IO。正常的查询逻辑是先看能否命中redis中的缓存,如果命中就返回,如果未命中,就去mysql中查询,并写入redis中。正常我们的操作是先更新数据库,再删除缓存。但是由于上述操作并不是一个原子性的操作,如果非要保证一致性,那就需要使用最终一致性的方案。比如使用rocketmq的异步重试机制,或者使用读取mysql的binlog的机制(使用canal组件)
2、Mysql索引的优点和缺点?
答:Mysql的innoDB引擎使用的是B+树来存储索引。索引的优点 1)B+树的存储结构可以有效的减低查询的层级,加快查询的速度 2)B+树在范围查询中表现也很优秀,只需要找到起始节点,然后根据链表向后或向前查询 3)唯一索引可以数据库的唯一约束
缺点:1)索引是需要单独空间维护的,那么数据的增删改都会造成索引的修改,如果数据量比较大的时候会影响数据库的性能 2)索引的数量不能太多 3) 要考虑创建索引的开销,对于区分度不大的字段不建议添加索引
3、Mysql如何解决幻读问题?
答:数据库的幻读的产生原因是事务A进行一个范围查询,获得10条数据,此时另一个事务B插入了一条数据,此时事务A再次进行相同的查询,得到的数据是11条,这样就产生了幻读。Mysql是使用MVVC来解决幻读问题(RR级别),简单来说就是针对每一个事务生成一个事务版本并制定一个访问规则,根据访问规则,高版本可以看到低版本的事务变更,低版本不能看到高版本的事务变更,就避免了幻读的产生。具体什么是MVVC后面还有具体的解释。
4、Mysql的事务原理?
答:事务主要是ACID四个方面。
A:原子性,mysql使用undolog日志记录了要回滚的数据记录,如果事务失败,就使用undolog来回滚;
C:一致性,主要通过应用来完成;
I:隔离性,RR可重复读,主要是通过MVCC多版本控制和锁机制来完成,锁包括行锁,表锁,间隙锁,临键锁;
D: 持久性,主要通过redolog日志加内存,修改数据的同时会修改redolog日志和内存,保证宕机后还能后恢复;
5、update是行锁还是表锁?
答:既可以是行锁也可以是表锁。
1) 如果where条件包含了索引列且包含一行的数据,就会加行锁。
2)如果where条件中不包含索引列,就会加表锁。
3)针对主键索引的for update操作,mysql会加一个临键锁来锁定一个区间(左开右闭)
4)针对索引区间的查询或者修改,例如between and,mysql会加一个间隙锁(左右开)
6、InnoDB和MyISAM的区别?
答:1)存储方式不同:MyISAM是以二进制存储在磁盘中,主要有两类文件,一个是.myd文件是数据文件,一个是.myi文件,是索引文件;InnoDB只有一个idb文件,使用B+树存储,数据存储在叶子节点上;
2)事务支持不同,InnoDB支持事务,MyISAM不支持事务;
3)锁的粒度不同,MyISAM只有表锁,InnoDB有行锁,表锁,间隙锁,临键锁;
4)InnoDB支持外键,MyISAM不支持外键;
5)如果都多写少,不需要事务,可以选用MyISAM引擎;
7、索引什么时候失效?
答:InnoDB中使用B+树来存储索引。造成索引失效的原因有很多。
1)在索引列上加函数运算;
2)数据隐式转换,例如字符串隐式转换为数字时索引失效;
3)联合索引没有最左匹配
4)在where条件中有不等于这个条件
5)like子句中百分号在最开头
8、Mysql的MVVC机制?
答:MVVC机制就是多版本并发控制机制,主要是针对读取数据的问题。首先Mysql默认的事务隔离级别是RR,也就是不可重复读,在这个隔离级别下,在事务开始的时候,会创建一个readview,这个readview维护了当前活动的所有事务id和自身的事务id,并形成一个事务数组。当访问数据的时候,会对比这条数据的事务id和readview中事务id数据数据的大小。如果事务id小于这个数组中的最小值表示这条数据可以被访问到,如果事务id在数组中或者大于数组中的事务id,则不可以访问。不可以访问的时候就要通过一个roll_pointer的指针指向更老的版本,然后查看老的版本的事务id是否符合可见规则。
RC的隔离级别下,就是每次查询数据就会生成一个readview
9、Mysql主从同步机制?如何保证数据不丢失?
答:主从同步机制, 是通过复制主服务器的binlog日志到需要同步的从服务器,具体步骤如下:
1)master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events)
2)slave将master的binary log events拷贝到它的中继日志(relay log)
3)slave重做中继日志中的事件,将改变反映它自己的数据
以上所有的操作默认都是异步的,如果想要保证数据不丢失,也就是说保证主节点挂了之后,从节点一定有之前更新的数据,就要启用半同步或者全同步策略。mysql让master在某一个时间点等待slave节点的ack消息,接收到ack后才进行事务提交,这也是半同步复制的基础
10、何时分库分表?如何分库分表?
答:
1)单表数据量大的时候,比如单表数量超过了1000万条,每次查询扫描的行数太多,sql效率比较低,此时要考虑水平分表,把数据分散到不同的表中,降低每个表的行数;
2)如果出现了服务器的IO瓶颈,也就是说单台数据库的请求量很大,网络带宽不够,此时就要考虑分库,把数据分散到不同的数据库中,降低单台服务器的压力;
3)如果随着业务的发展,单表的字段出现了过多的情况,同时还有大文本字段等,可以对单表进行垂直拆分,针对某些字段抽离成一个单独的表,降低单表频繁更新的压力。
如何分库分表?
1)如果是水平分表,就要考虑分区键,可以使用id取模的方式,也可以使用主键步长不同的自增模式,也可以根据时间作为分区键。或者为了方便未来扩容,可以使用一致性Hash算法来计算;
2)分布式id的方法,可以使用UUID(不建议),基于redis或者zk的分布式id,或者雪花算法