实实在在讲啊,先从5.7跑到8.0,接着又到如今的9.x,能感受到MySQL历经这几年来着实挺艰难的。自从Oracle接手之后,社区版就如同被后妈抚养那般,没出现什么较大的动态了。偶尔在半夜瞅见那些疯狂的连接数,心里真的特别想为这老版本发出一声叹息。
并发上来后,最先疼的其实是内存
大家都以为数据库慢了就是该加索引,其实不是。
我碰到过最为离谱扯犊子一般的事儿,服务器有着256G内存,然而CPU的使用率居然不到10%,可就是卡顿到好似狗被诸多状况困扰那般。最终经过查找发现,连接的数量呈现出爆棚的态势。
MySQL 进行连接处理并非毫无代价,每一个连接都是一个线程,而每一个线程都需要占用一定内存。哪怕处于什么都不执行的状态,要是开启三千个连接并使其处于闲置,它自身也会很快因内部消耗而崩溃。
因而随后我将max_connections自默认的151予以提升,然而却也不敢提升得过于厉害。
更重要的是,wait_timeout以及interactive_timeout,这两个参数简直如同救命的稻草一般。以往并不知晓,众多处于睡眠状态的连接,就像僵尸一样占据着位置却不发挥作用。将超时的时间从28800秒(也就是8小时)缩短至300秒,世界顿时变得安静了下来。
锁!锁!锁!
MyISAM 这破引擎现在还有人用吗?
max_connections = 151 #同时处理最大连接数,推荐设置最大连接数是上限连接数的80%左右 sort_buffer_size = 2M #查询排序时缓冲区大小,只对order by和group by起作用,可增大此值为16M query_cache_limit = 1M #查询缓存限制,只有1M以下查询结果才会被缓存,以免结果数据较大把缓存池覆盖 query_cache_size = 16M #查看缓冲区大小,用于缓存SELECT查询结果,下一次有同样SELECT查询将直接从缓存池返回结果,可适当成倍增加此值 open_files_limit = 1024 #打开文件数限制,如果show global status like 'open_files'查看的值等于或者大于open_files_limit值时,程序会无法连接数据库或卡死
假设存在,那就赶快丢弃掉。并非讲它不妥,而是处于此高并发时期,它那种关于表级锁的操作方式太过粗暴。你打算读取?可以。你想要写入?统统都得被堵住。
换了 InnoDB 之后,你以为就万事大吉了?天真。
key_buffer_size = 16M #索引缓存区大小,一般设置物理内存的30-40% read_buffer_size = 128K #读操作缓冲区大小,推荐设置16M或32M
行锁也会死。
innodb_buffer_pool_size = 128M #索引和数据缓冲区大小,一般设置物理内存的60%-70%
innodb_buffer_pool_instances = 1 #缓冲池实例个数,推荐设置4个或8个
innodb_flush_log_at_trx_commit = 1 #关键参数,0代表大约每秒写入到日志并同步到磁盘,数据库故障会丢失1秒左右事务数据。1为每执行一条SQL后写入到日志并同步到磁盘,I/O开销大,执行完SQL要等待日志读写,效率低。2代表只把日志写入到系统缓存区,再每秒同步到磁盘,效率很高,如果服务器故障,才会丢失事务数据。对数据安全性要求不是很高的推荐设置2,性能高,修改后效果明显。 innodb_file_per_table = OFF #默认是共享表空间,共享表空间idbdata文件不断增大,影响一定的I/O性能。推荐开启独立表空间模式,每个表的索引和数据都存在自己独立的表空间中,可以实现单表在不同数据库中移动。 innodb_log_buffer_size = 8M #日志缓冲区大小,由于日志最长每秒钟刷新一次,所以一般不用超过16M
曾有一回我碰到个奇特需求,在一张高频更新的表上,先进行update操作,接着执行insert操作,最后又来一次update操作。结果并发情况一出现,死锁日志便接连不断地产生。直到那时才领悟到,事务粒度这个东西,越小越为合适。千万不要在事务当中进行外部调用或者开展复杂的业务逻辑,尽快完成提交,锁就能越早被释放。
关于那个坑爹的查询缓存
老版本的 DBA 都喜欢开查询缓存,觉得能提速。
血的教训告诉你,并发稍微高一点,查询缓存就是自杀利器。
因为那玩意儿是全局锁啊!你缓存失效的时候,所有核都得等着。
阿里云随后弄出了个Fast Query Cache,宣称是无锁设计。但实事求是讲,在如今这个时代,真正处于热度状态的数据,还是老老实实地放置到Redis里面去吧。不要再去折腾MySQL了,它仅仅是个用于存储数据的实体,而并非缓存服务器。
索引不是万能的,但没有索引是万万不能的
我最烦那些上来就给我整“把所有字段都建上索引”的伪专家。
你建那么多索引,写进去的时候不用花时间的吗?
关于一种经验方面的论调是这样一种情况:存在一种情况是写的情况多而读的情况少的那种表,索引在能够存在的数量方面尽量地减少;而另一种情况为读的情况多但写的情况少的那种表,索引在能够达到的精准程度方面尽可能地精细。
看慢查询日志的时候,别光盯着那些执行时间长的。
执行了十万次的查询,每次用时零点零二秒,合起来才是真正的性能杀手哦。此时稍微做些优化,增添个组合索引,那效果便会立刻显现出来啦。
分库分表这事,能晚点搞就晚点搞
分库分表听着高大上,做起来真要命。
改代码不说,跨库查询、分布式事务,哪个不是坑?
我现在的策略是:
单表不到 2000 万,能不分就不分。
mysql> show global status like 'Questions'; mysql> show global status like 'Uptime';
要是真到了要分开的地步,也千万别从一开始就弄上一千零二十四张表 ,得给自己留一条可以退路的路 ,采用一致性哈希 ,或者干脆就选用像TiDB这种NewSQL即可 的。
mysql> show global status like 'Com_commit'; mysql> show global status like 'Com_rollback'; mysql> show global status like 'Uptime'; TPS = (Com_commit + Com_rollback) / Uptime
备份?备份比你想的更重要
曾经有一回,我于测试环境玩耍时操作pt-query-digest,正当分析得极为投入起劲之时,手部突然一抖,结果在生产库之上执行了rm -rf这般的错误操作。
mysql>mysql> show global status where Variable_name in('com_select','com_insert','com_delete','com_update'); 等待1秒再执行,获取间隔差值,第二次每个变量值减去第一次对应的变量值,就是QPS
还好当时有增量备份。
千万不要相信那种所谓的主从同步就能够当作备份的说法。要是万一执行错误了一条 drop table,那么连从库也会跟着被删除掉,到时候想哭都已经来不及了。
mysql>mysql> show global status where Variable_name in('com_insert','com_delete','com_update'); 计算TPS,就不算查询操作了,计算出插入、删除、更新四个值即可。 经网友对这两个计算方式的测试得出,当数据库中myisam表比较多时,使用Questions计算比较准确。当数据库中innodb表比较多时,则以Com_*计算比较准确。
使用Xtrabackup来进行物理备份,那可真是非常不错的,它进行热备的时候不会对业务造成影响,而且恢复起来速度也是很快的。而像mysqldump那种逻辑备份方式,要是面对几百G的数据,那就别想着能行得通了,会慢到让你受不了的。
未来?谁说得准呢
经由近期对Percona博客的查阅所获悉,MySQL 9.5于性能方面再度呈现出稳固态势。
mysql> set global slow-query-log=on #开启慢查询功能 mysql> set global slow_query_log_file='
/var/log/mysql/mysql-slow.log'; #指定慢查询日志文件位置 mysql> set global
log_queries_not_using_indexes=on; #记录没有使用索引的查询 mysql> set global long_query_time=1; #只记录处理时间1s以上的慢查询
可是,所有人都在议论是否应当切换到PostgreSQL,还提及Pg的性能每一个年度都在呈现出增长的态势。
# mysqldumpslow -t 3
/var/log/mysql/mysql-slow.log #查看最慢的前三个查询
我同样进行了尝试,的确其功能十分强劲,然而要是真的实施迁移,那众多的存储过程修改起来会让人头发都掉完殆尽。
算了,先用着吧。
如同跟一位老相识一块儿凑合着过生活,尽管它时不时脾气较执拗,偶尔会出现卡顿状况,然而把它的脾气摸清楚之后,它依旧具备战斗力。
毕竟,哪有什么完美的数据库,只有合适的业务和不宕机的夜晚。

Comments NOTHING