当然MySQL也认识到5.6这种并行的瓶颈所在,所以在5.7引入了另外一种并行复制方式,基于logical timestamp的并行复制,并行复制不再受限于库的个数,效率会大大提升。
上图是5.7的logical timestamp的复制原理图
刚才我也提到MySQL原来只支持异步复制,这种数据安全性是非常差的,所以后来引入了半同步复制,从5.5开始支持。
上图是原生异步复制和半同步复制的区别。可以看到半同步通过从库返回ACK这种方式确认从库收到数据,数据安全性大大提高。
在5.7之后,半同步也可以配置你指定多个从库参与半同步复制,之前版本都是默认一个从库。
对于半同步复制效率问题有一个小的优化,就是使用5.6+的mysqlbinlog以daemon方式作为从库,同步效率会好很多。
关于更安全的复制,MySQL 5.7也是有方案的,方案名叫Group replication 官方多主方案,基于Corosync实现。
主从延时问题
原因:一般都会做读写分离,其实从库压力反而比主库大/从库读写压力大非常容易导致延时。
解决方案:
首先定位延时瓶颈 如果是IO压力,可以通过升级硬件解决,比如替换SSD等 如果IO和CPU都不是瓶颈,非常有可能是SQL单线程问题,解决方案可以考虑刚才提到的并行复制方案 如果还有问题,可以考虑sharding拆分方案
提到延时不得不提到很坑人的Seconds behind master,使用过MySQL的应该很熟悉。
这个值的源码里算法
long time_diff= ((long)(time(0) – mi->rli.last_master_timestamp) – mi->clock_diff_with_master);
Secondsbehindmaster来判断延时不可靠,在网络抖动或者一些特殊参数配置情况下,会造成这个值是0但其实延时很大了。通过heartbeat表插入时间戳这种机制判断延时是更靠谱的
复制注意点:
Binlog格式,建议都采用row格式,数据一致性更好 Replication filter应用
主从数据一致性问题:
row格式下的数据恢复问题
InnoDB优化
成熟开源事务存储引擎,支持ACID,支持事务四个隔离级别,更好的数据安全性,高性能高并发,MVCC,细粒度锁,支持O_DIRECT。
主要优化参数:
innodbfileper_table =1 innodbbufferpool_size,根据数据量和内存合理设置 innodbflushlog_attrxcommit= 0 1 2 innodblogfile_size,可以设置大一些 innodbpagesize Innodbflushmethod = o_direct innodbundodirectory 放到高速设备(5.6+) innodbbufferpool_dump atshutdown ,bufferpool dump (5.6+)
上图是5.5 4G的redo log和5.6 设置大于4G redo log文件性能对比,可以看到稳定性更好了。innodblogfile_size设置还是很有意义的。
InnoDB比较好的特性:
Bufferpool预热和动态调整大小,动态调整大小需要5.7支持 Page size自定义调整,适应目前硬件 InnoDB压缩,大大降低数据容量,一般可以压缩50%,节省存储空间和IO,用CPU换空间 Transportable tablespaces,迁移ibd文件,用于快速单表恢复 Memcached API,full text,GIS等
InnoDB在SSD上的优化:
在5.5以上,提高innodbwriteiothreads和innodbreadiothreads innodbiocapacity需要调大* 日志文件和redo放到机械硬盘,undo放到SSD,建议这样,但必要性不大 atomic write,不需要Double Write Buffer InnoDB压缩 单机多实例
也要搞清楚InnoDB哪些文件是顺序读写,哪些是随机读写。
随机读写:
datadir innodbdata file_path innodbundo directory
顺序读写:
innodbloggrouphomedir log-bin
InnoDB VS MyISAM:
数据安全性至关重要,InnoDB完胜,曾经遇到过一次90G的MyISAM表repair,花了两天时间,如果在线上几乎不可忍受 并发度高 MySQL 5.5默认引擎改为InnoDB,标志着MyISAM时代的落幕
TokuDB:
支持事务 ACID 特性,支持多版本控制(MVCC) 基于Fractal Tree Index,非常适合写入密集场景 高压缩比,原生支持Online DDL 主流分支都支持,收费转开源 。目前可以和InnoDB媲美的存储引擎
目前主流使用TokuDB主要是看中了它的高压缩比,Tokudb有三种压缩方式:quicklz、zlib、lzma,压缩比依次更高。现在很多使用zabbix的后端数据表都采用的TokuDB,写入性能好,压缩比高。
下图是我之前做的测试对比和InnoDB
上图是sysbench测试的和InnoDB性能对比图,可以看到TokuDB在测试过程中写入稳定性是非常好的。
tokudb存在的问题:
官方分支还没很好的支持 热备方案问题,目前只有企业版才有 还是有bug的,版本更新比较快,不建议在核心业务上用
比如我们之前遇到过一个问题:TokuDB的内部状态显示上一次完成的checkpoint时间是“Jul 17 12:04:11 2014”,距离当时发现现在都快5个月了,结果堆积了大量redo log不能删除,后来只能重启实例,结果重启还花了七八个小时。
MySQL优化相关的case
Query cache,MySQL内置的查询加速缓存,理念是好的,但设计不够合理,有点out。
锁的粒度非常大MySQL 5.6默认已经关闭
When the query cache helps, it can help a lot. When it hurts, it can hurt a lot.明显前半句已经没有太大用处,在高并发下非常容易遇到瓶颈。
关于事务隔离级别 ,InnoDB默认隔离级别是可重复读级别,当然InnoDB虽然是设置的可重复读,但是也是解决了幻读的,建议改成读已提交级别,可以满足大多数场景需求,有利于更高的并发,修改transaction-isolation。
上图是一个比较经典的死锁case,有兴趣可以测试下。
关于SSD
关于SSD,还是提一下吧。某知名大V说过“最近10年对数据库性能影响最大的是闪存”,稳定性和性能可靠性已经得到大规模验证,多块SATA SSD做Raid5,推荐使用。采用PCIe SSD,主流云平台都提供SSD云硬盘支持。
最后说一下大家关注的单表60亿记录问题,表里数据也是线上比较核心的。
先说下当时情况,表结构比较简单,都是bigint这种整型,索引比较多,应该有2-3个,单表行数60亿+,单表容量1.2TB左右,当然内部肯定是有碎片的。
形成原因:历史遗留问题,按照我们前面讲的开发规范,这个应该早拆分了,当然不拆有几个原因:
性能未遇到瓶颈 ,主要原因
DBA比较“懒“
想看看InnoDB的极限,挑战一下。不过风险也是很大的,想想如果在一个1.2TB表上加个字段加个索引,那感觉绝对酸爽。还有就是单表恢复的问题,恢复时间不可控。
我们后续做的优化 ,采用了刚才提到的TokuDB,单表容量在InnoDB下1TB+,使用Tokudb的lzma压缩到80GB,压缩效果非常好。这样也解决了单表过大恢复时间问题,也支持online DDL,基本达到我们预期。
今天讲的主要针对MySQL本身优化和规范性质的东西,还有一些比较好的运维经验,希望大家能有所收获。今天这些内容是为后续数据库做平台化的基础。我今天分享就到这里,谢谢大家。
QA
**Q1:use schema;select * from table; 和select * from schema.table;两种写法有什么不一样吗?会对主从同步有影响吗?**对于主从复制来说执行效率上差别不大,不过在使用replication filter时候这种情况需要小心,应该要使用ReplicateWildIgnoreTable这种参数,如果不使用带wildignore,第一种方式会有问题,过滤不起作用。
Q2:对于用于MySQL的ssd,测试方式和ssd的参数配置方面,有没有好的建议?主要针对ssd的配置哈
关于SATA SSD配置参数,建议使用Raid5,想更保险使用Raid50,更土豪使用Raid 10
上图是主要的参数优化,性能提升最大的是第一个修改调度算法的
Q3:数据库规范已制定好,如何保证开发人员必须按照规范来开发?
关于数据库规范实施问题,也是有两个方面吧,第一、定期给开发培训开发规范,让开发能更了解。第二、还是在流程上规范,比如把我们日常通用的建表和字段策略固化到程序,做成自动化审核系统。这两方面结合 效果会比较好。
Q4:如何最大限度提高innodb的命中率?
这个问题前提是你的数据要有热点,读写热点要有交集,否则命中率很难提高。在有热点的前提下,也要求你的你的内存要足够大,能够存更多的热点数据。尽量不要做一些可能污染bufferpool的操作,比如全表扫描这种。
Q5:主从复制的情况下,如果有CAS这样的需求,是不是只能强制连主库?因为有延迟的存在,如果读写不在一起的话,会有脏数据。
如果有CAS需求,确实还是直接读主库好一些,因为异步复制还是会有延迟的。只要SQL优化的比较好,读写都在主库也是没什么问题的。
Q6:关于开发规范,是否有必要买国标?
这个国标是什么东西,不太了解。不过从字面看,国标应该也是偏学术方面的,在具体工程实施时候未必能用好。
Q7:主从集群能不能再细化一点那?不知道这样问合适不?
看具体哪方面吧。主从集群每个小集群一般都是采用一主多从方式,每个小集群对应特定的一组业务。然后监控备份和HA都是在每个小集群实现。
Q8:如何跟踪数据库table某个字段值发生变化?
追踪字段值变化可以通过分析row格式binlog好一些。比如以前同事就是通过自己开发的工具来解析row格式binlog,跟踪数据行变化。
Q9:对超大表水平拆分,在使用MySQL中间件方面有什么建议和经验分享?
对于超大表水平拆分,在中间件上经验不是很多,早期人肉搞过几次。也使用过自己研发的数据库中间件,不过线上应用的规模不大。关于目前众多的开源中间件里,360的atlas是目前还不错的,他们公司内部应用的比较多。
Q10:我们用的MySQL proxy做读负载,但是少量数据压力下并没有负载,请问有这回事吗?
少量数据压力下,并没有负载 ,这个没测试过,不好评价
Q11:对于binlog格式,为什么只推荐row,而不用网上大部分文章推荐的Mix ?
这个主要是考虑数据复制的可靠性,row更好。mixed含义是指如果有一些容易导致主从不一致的SQL ,比如包含UUID函数的这种,转换为row。既然要革命,就搞的彻底一些。这种mix的中间状态最坑人了。
Q12: 读写分离,一般是在程序里做,还是用proxy ,用proxy的话一般用哪个?
这个还是独立写程序好一些,与程序解耦方便后期维护。proxy国内目前开源的比较多,选择也要慎重。
Q13: 我想问一下关于mysql线程池相关的问题,什么情况下适合使用线程池,相关的参数应该如何配置,老师有这方面的最佳实践没有?
线程池这个我也没测试过。从原理上来说,短链接更适合用线程池方式,减少建立连接的消耗。这个方面的最佳配置,我还没测试过,后面测试有进展可以再聊聊。
Q14: 误删数据这种,数据恢复流程是怎么样的(从库也被同步删除的情况)?
看你删除数据的情况,如果只是一张表,单表在几GB或几十GB。如果能有延时备份,对于数据恢复速度是很有好处的。恢复流程可以参考我刚才分享的部分。目前的MySQL数据恢复方案主要还是基于备份来恢复 ,可见备份的重要性。比如我今天下午15点删除了线上一张表,该如何恢复呢。首先确认删除语句,然后用备份扩容实例启动,假设备份时间点是凌晨3点。就还需要把凌晨3点到现在关于这个表的binlog导出来,然后应用到新扩容的实例上。确认好恢复的时间点,然后把删除表的数据导出来应用到线上。
Q15: 关于备份,binlog备份自然不用说了,物理备份有很多方式,有没有推荐的一种,逻辑备份在量大的时候恢复速度比较慢,一般用在什么场景?
物理备份采用xtrabackup热备方案比较好。逻辑备份一般用在单表恢复效果会非常好。比如你删了一个2G表,但你总数据量2T,用物理备份就会要慢了,逻辑备份就非常有用了。