9月1日答疑:
1、InnoDB如何保证数据页写入时,页损坏的数据也能被正常修复。
首先明确以下概念:
页损坏:MySQL的单个page有16k大小,而文件系统的1页只有4k。因此在刷新脏页时,实际上是4次写入,若在中途发生断电之类的故障,就会出现页损坏。
Double write buffer
InnoDB使用了DWB(double write buffer)用于保证在数据真正写入数据页之前,由double write buffer 先落到对应的磁盘,这样即使出现了由于断电引起的页损坏,也能够恢复。
如果是异常退出,Mysql重启过程:
(1)检测到上次为异常关闭
(2)尝试恢复ibd数据,失败(因为出现了页损坏的数据)
(3)从DWB中恢复写了一半的页
相关博文:https://blog.csdn.net/liuxiao723846/article/details/103509226
扩展一个问题:
DWB如果在第二部即 DWB往数据磁盘上存数据时,此时如果断电了,会怎么样?
此时,我们可以考虑一个问题,当我们DWB往数据磁盘上存数据时,还没有将数据页真正的落盘,理论上应该不存在页损坏问题。我们可以考虑使用redolog进行数据恢复。
dirtyPage中持久化到redolog
事务中修改的任何数据,将最新的数据备份存储的位置(RedoLog),重做日志
关于redolog可以参考:https://blog.csdn.net/tiancaideshaonian/article/details/119719734
关于执行顺序:
1 先执行
2、3同时执行
4、执行
这里需要针对两个点
buffer pool中脏页刷盘的行为是通过dwb进行保证的
log buffer 生成 redolog由于数据不丢失需要通过redolog进行保证,因此针对某条记录而言redolog的刷盘行为应该会先于数据刷盘
因此针对上述问题,由于此时实际上的还没开始刷到磁盘,而redolog中会存在重放日志,因此我们可以通过redolog恢复数据。
2、MySQL中的某数据页的磁盘空间仅剩1B。此时,将某VARCHAR字段的值从’1’修改为’100’,也就需要额外的2B空间。但此时数据页没有足够的磁盘空间,这种情况下是否会产生页分裂?
先明确一个概念:
页合并:当你删了一行记录时,实际上记录并没有被物理删除,记录被标记(flaged)为删除并且它的空间变得允许被其他记录声明使用。当页中删除的记录达到MERGE_THRESHOLD
(默认页体积的50%),InnoDB会开始寻找最靠近的页(前或后)看看是否可以将两个页合并以优化空间使用。
规则就是:页合并发生在删除或更新操作中,关联到当前页的相邻页。如果页合并成功,在INFOMATION_SCHEMA.INNODB_METRICS
中的index_page_merge_successful
将会增加。
页分裂:
首先我们知道,innodb中的数据是以页为存储单元。如果此时页中已经存了99%的空间,新的数据需要进来,发现空间不满足(比如第10页),就会找下一页满足的,如果下一个也就是第11页也满了,此时,为了保证数据的顺序性,需要调整页之间的关系
page-9<-page-10<-page-12<-page-11
规律总结:页分裂会发生在插入或更新,并且造成页的错位(dislocation,落入不同的区)
参考资料:https://zhuanlan.zhihu.com/p/98818611
针对上述前半段问题,我们需要引入一个概念:溢出页。
参考资料:https://www.jb51.net/article/200618.htm
MySQL想让一个数据页中能存放更多的数据行,至少也得要存放两行数据。否则就失去了B+Tree的意义。B+Tree也退化成一个低效的链表。
你可以品一下这句蓝色的话,他说的每个数据页至少要存放两行数据的意思不是说 数据页不能只存一行。你确确实实可以只往里面写一行数据,然后去吃个饭,干点别的。一直让这个数据页中只有一行数据。
当你往这个数据页中写入一行数据时,即使它很大将达到了数据页的极限,但是通过行溢出机制。依然能保证你的下一条数据还能写入到这个数据页中。
更改数据类型其实并不会对原有数据产生影响。
3、常用nosql,以及一些使用场景
https://blog.csdn.net/wyz0516071128/article/details/80877984
自己的一些总结:
目前使用较多的相对来说 redis比较多。
mogodb主要用于存储一些文本信息,或者json串之类的。也可以用于解决海量数据的访问效率问题
Hbase 采用列式存储,同样也可以用于海量数据的存储访问。
9月8日答疑
1、问题描述:报表类应用如何设计缓存?
背景:数据库类有约1000W明细数据,包含交易大区,交易小区,城市,业务类型,一级负责人,二级负责人等近10个维度字段。前端提供基于这些维度字段的自由分类,汇总,排序等操作的报表,也会下钻查看明细数据。这样的系统如何进行缓存的设计?
(1)mongodb存储数据。因为MongoDB查询相对于快点,一般修改比较少,存入的数据可以嵌套,然后mongoDB提供了一下聚合函数。
(2)利用ES建立索引
(3)如果使用Redis做一个缓存的话,可以利用Hash (a维度_b维度__c维度 -> value)
之前见过一个 利用ES + HBase 实现快速查询的案例,后面可以翻出来看看
2、关于延时双删的加锁阶段
在更新数据库时,对key进行了加锁操作。
强一致性很难,这个方案也只是追求最终一致性。延时时间内如果有其他线程读取了缓存确实就会读到旧的,但是延时后就是正常的数据了。
3.一个服务挂了配多长时间重试?
针对上述问题从以下两个方面进行分析
1.是自己的服务器挂了
此时需要通过运维,针对自己的应用服务器,以及应用实现实时告警以及CPU预警等。尽量早的参与到修障过程。
2.依赖外部的服务结构
a.是否需要重试
一些不重要的日志信息,可以直接忽略重试机制
b.重试按照什么维度:通知频率?
后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止(在通知一直不成功的情况下,微信总共会发起多次通知,通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h - 总计 24h4m),但微信不保证通知最终一定能成功。
4.对于分库分表,怎么实现分页查询
a.基于一些中间件如shardingjdbc进行分页查询。
1.通过不同的分库规则,实现多个分片,
2.每个分片分别进行分页查询,再在内存中进行汇总,最后再进行一次分页查询,就可以得出最终的结果。
3.分页的总条数,是另一次查询,不在上面的步骤中计算
b.引入es