1、硬件优化: 建议物理机(io大)
a.CPU: 64位Cpu,每台机器8-16核。
在服务器的BIOS设置中,可调整下面的几个配置,目的是发挥CPU最大性能,或者避免经典的NUMA问题:
1)选择Performance Per Watt Optimized(DAPC)模式,发挥CPU最大性能,跑DB这种通常需要高运算量的服务就不要考虑节电了;
2)关闭C1E和C States等选项,目的也是为了提升CPU效率;
3)Memory Frequency(内存频率)选择Maximum Performance(最佳性能);
4)内存设置菜单中,启用Node Interleaving,避免NUMA问题;
b.mem: 96-128G 3-4个实例,32-64G跑两个实例
c.disk:数量越多越好。 性能: ssd(高并发)>sas(普通业务线上)>sata(线下)
raid: raid0>raid10>raid5>raid1
1) 使用SSD或者PCIe SSD设备,至少获得数百倍甚至万倍的IOPS提升;
2) 购置阵列卡同时配备CACHE及BBU模块,可明显提升IOPS(主要是指机械盘,SSD或PCIe SSD除外。同时需要定期检查CACHE及BBU模块的健康状况,确保意外时不至于丢失数据);
3) 有阵列卡时,设置阵列写策略为WB,甚至FORCE WB(若有双电保护,或对数据安全性要求不是特别高的话),严禁使用WT策略。并且闭阵列预读策略,基本上是鸡肋,用处不大;
4) 尽可能选用RAID-10,而非RAID-5;
5) 使用机械盘的话,尽可能选择高转速的,例如选用15KRPM,而不是7.2KRPM的盘,不差几个钱的;
d.网卡: 多块网卡bond,以及buffer,tcp的优化
2、 软件优化
操作系统:x86_64系统
a、文件系统层优化
在文件系统层,下面几个措施可明显提升IOPS性能:
1)使用deadline/noop这两种I/O调度器,千万别用cfq(它不适合跑DB类服务);
2)使用xfs文件系统,千万别用ext3;ext4勉强可用,但业务量很大的话,则一定要用xfs;
3)文件系统mount参数中增加:noatime, nodiratime, nobarrier几个选项(nobarrier是xfs文件系统特有的);
b)其他内核参数优化
针对关键内核参数设定合适的值,目的是为了减少swap的倾向,并且让内存和磁盘I/O不会出现大幅波动,导致瞬间波峰负载:
1)将vm.swappiness设置为5-10左右即可,甚至设置为0(RHEL 7以上则慎重设置为0,除非你允许OOM kill发生),以降低使用SWAP的机会;
2)将vm.dirty_background_ratio设置为5-10,将vm.dirty_ratio设置为它的两倍左右,以确保能持续将脏数据刷新到磁盘,避免瞬间I/O写,产生严重等待(和MySQL中的innodb_max_dirty_pages_pct类似);
3)将net.ipv4.tcp_tw_recycle、net.ipv4.tcp_tw_reuse都设置为1,减少TIME_WAIT,提高TCP效率;
4)至于网传的read_ahead_kb、nr_requests这两个参数,我经过测试后,发现对读写混合为主的OLTP环境影响并不大(应该是对读敏感的场景更有效果),不过没准是我测试方法有问题,可自行斟酌是否调整;
软件:mysql编译优化
3.my.cnf参数的优化
a.注意:my.cnf菜蔬优化的幅度很小。大部分架构以及sql语句的优化
建议调整下面几个关键参数以获得较好的性能(可使用本站提供的my.cnf生成器生成配置文件模板):
1)选择Percona或MariaDB版本的话,强烈建议启用thread pool特性,可使得在高并发的情况下,性能不会发生大幅下降。此外,还有extra_port功能,非常实用, 关键时刻能救命的。还有另外一个重要特色是 QUERY_RESPONSE_TIME 功能,也能使我们对整体的SQL响应时间分布有直观感受;
2)设置default-storage-engine=InnoDB,也就是默认采用InnoDB引擎,强烈建议不要再使用MyISAM引擎了,InnoDB引擎绝对可以满足99%以上的业务场景;
3)调整innodb_buffer_pool_size大小,如果是单实例且绝大多数是InnoDB引擎表的话,可考虑设置为物理内存的50% ~ 70%左右;
4)根据实际需要设置innodb_flush_log_at_trx_commit、sync_binlog的值。如果要求数据不能丢失,那么两个都设为1。如果允许丢失一点数据,则可分别设为2和10。而如果完全不用care数据是否丢失的话(例如在slave上,反正大不了重做一次),则可都设为0。这三种设置值导致数据库的性能受到影响程度分别是:高、中、低,也就是第一个会另数据库最慢,最后一个则相反;
5)设置innodb_file_per_table = 1,使用独立表空间,我实在是想不出来用共享表空间有什么好处了;
6)设置innodb_data_file_path = ibdata1:1G:autoextend,千万不要用默认的10M,否则在有高并发事务时,会受到不小的影响;
7)设置innodb_log_file_size=256M,设置innodb_log_files_in_group=2,基本可满足90%以上的场景;
8)设置long_query_time = 1,而在5.5版本以上,已经可以设置为小于1了,建议设置为0.05(50毫秒),记录那些执行较慢的SQL,用于后续的分析排查;
9)根据业务实际需要,适当调整max_connection(最大连接数)、max_connection_error(最大错误数,建议设置为10万以上,而open_files_limit、innodb_open_files、table_open_cache、table_definition_cache这几个参数则可设为约10倍于max_connection的大小;
10)常见的误区是把tmp_table_size和max_heap_table_size设置的比较大,曾经见过设置为1G的,这2个选项是每个连接会话都会分配的,因此不要设置过大,否则容易导致OOM发生;其他的一些连接会话级选项例如:sort_buffer_size、join_buffer_size、read_buffer_size、read_rnd_buffer_size等,也需要注意不能设置过大;
11)由于已经建议不再使用MyISAM引擎了,因此可以把key_buffer_size设置为32M左右,并且强烈建议关闭query cache功能;
b. 监控:生产参数使一般情况下的参数
命令监控:show global status\G;
调优工具: mysqlreport
C.my.cnf配置生成工具
http://imysql.com/my-cnf-wizard.html
4.sql语句的优化
a.索引优化
1)白名单之际-百度,项目开发,dba参与,较少上线后的慢sql数量
抓出慢sql,配置my.cnf参数的优化
long_query_time =2
log-slow-quries=/data/slow-log.log
按天轮询slow-log.log
2)慢查询日志分析工具--mysqlsla(推荐)
mysqldumpslow,mysqlsla,myprofi,mysql-explian-slow-log,mysqllogfilter
b.大的复杂的sql语句拆分成多个晓得sql语句
子查询,join连表查询
c.数据库使数据存储的覅放,不是计算数据的地方
对数据计算,应用类处理,都要拿到前端应用解决,禁止在数据库上处理
d.搜索功能,like ‘%old%’,不要用mysql数据库,用搜索工具
e.下面列举了几个常见有助于提升MySQL效率的Schema设计规范及SQL使用建议:
1)所有的InnoDB表都设计一个无业务用途的自增列做主键,对于绝大多数场景都是如此,真正纯只读用InnoDB表的并不多,真如此的话还不如用TokuDB来得划算;
2)字段长度满足需求前提下,尽可能选择长度小的。此外,字段属性尽量都加上NOT NULL约束,可一定程度提高性能;
3)尽可能不使用TEXT/BLOB类型,确实需要的话,建议拆分到子表中,不要和主表放在一起,避免SELECT * 的时候读性能太差。
4)读取数据时,只选取所需要的列,不要每次都SELECT *,避免产生严重的随机读问题,尤其是读到一些TEXT/BLOB列;
5)对一个VARCHAR(N)列创建索引时,通常取其50%(甚至更小)左右长度创建前缀索引就足以满足80%以上的查询需求了,没必要创建整列的全长度索引;
6)通常情况下,子查询的性能比较差,建议改造成JOIN写法;
7)多表联接查询时,关联字段类型尽量一致,并且都要有索引;
8)多表连接查询时,把结果集小的表(注意,这里是指过滤后的结果集,不一定是全表数据量小的)作为驱动表;
9)多表联接并且有排序时,排序字段必须是驱动表里的,否则排序列无法用到索引;
10)多用复合索引,少用多个独立索引,尤其是一些基数(Cardinality)太小(比如说,该列的唯一值总数少于255)的列就不要创建独立索引了;
11)类似分页功能的SQL,建议先用主键关联,然后返回结果集,效率会高很多;
5.架构优化
a.业务拆分:搜索功能,like ‘%old%’,不要用mysql数据库
b.业务拆分:某些业务应用使用nosql持久化存储,例如:MEMCACHEDB REDIS ttserver (粉丝关注,好友关系等)
c.数据库前端必须要加cache。例如:memcache,用户登陆,商品查询
d.动态数据的静态化。整个文件静态化,页面片段静态化
e.数据库集群与读写分离。一主多从。通过程序或者dbproxy进行集群读写分离
f.单表数据超过2000万,拆库拆表(登陆、商品、订单)
6.流程,制度,安全优化
任何一个认为数据库记录的更新都要有一个流程
a.人的流程:开发-->核心开发-->运维或dba
b.测试流程:内网测试-->idc测试-->线上执行
c.客户端管理,phpmyadmin
7.其他建议
关于MySQL的管理维护的其他建议有:
1)通常地,单表物理大小不超过10GB,单表行数不超过1亿条,行平均长度不超过8KB,如果机器性能足够,这些数据量MySQL是完全能处理的过来的,不用担心性能问题,这么建议主要是考虑ONLINE DDL的代价较高;
2)不用太担心mysqld进程占用太多内存,只要不发生OOM kill和用到大量的SWAP都还好;
3)在以往,单机上跑多实例的目的是能最大化利用计算资源,如果单实例已经能耗尽大部分计算资源的话,就没必要再跑多实例了;
4)定期使用pt-duplicate-key-checker检查并删除重复的索引。定期使用pt-index-usage工具检查并删除使用频率很低的索引;
5)定期采集slow query log,用pt-query-digest工具进行分析,可结合Anemometer系统进行slow query管理以便分析slow query并进行后续优化工作;
6)可使用pt-kill杀掉超长时间的SQL请求,Percona版本中有个选项 innodb_kill_idle_transaction 也可实现该功能;
7)使用pt-online-schema-change来完成大表的ONLINE DDL需求;
8)定期使用pt-table-checksum、pt-table-sync来检查并修复mysql主从复制的数据差异;
写在最后:这次的优化参考,大部分情况下我都介绍了适用的场景,如果你的应用场景和本文描述的不太一样,那么建议根据实际情况进行调整,而不是生搬硬套。欢迎质疑拍砖,但拒绝不经过大脑的习惯性抵制。