MySQL 系列 常见优化策略

针对不同的瓶颈问题,提供优化策略

Posted by lichao modified on October 29, 2020

Linux操作系统优化

Linux 系统的一些参数配置,会影响到数据库的性能,例如tcp连接数、超时时间配置等

MySQL配置文件优化

MySQL 登录情况下可以通过show variables 命令查看,需要关注的MySQL配置参数。

MySQL 性能瓶颈在 IO 上,如何提升性能

针对这个问题,可以考虑以下三种方法:

  • 设置 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 参数,减少 binlog 的写盘次数。这个方法是基于“额外的故意等待”来实现的,因此可能会增加语句的响应时间,但没有丢失数据的风险。
  • 将 sync_binlog 设置为大于1的值(比较常见是100~1000)。这样做的风险是,主机掉电时会丢binlog日志。
  • 将 innodb_flush_log_at_trx_commit 设置为2。这样做的风险是,主机掉电的时候会丢数据。

不建议把 innodb_flush_log_at_trx_commit 设置成0。因为把这个参数设置成0,表示redo log只保存在内存中,这样的话MySQL本身异常重启也会丢数据,风险太大。而redo log写到文件系统的 page cache 的速度也是很快的,所以将这个参数设置成2跟设置成0其实性能差不多,但这样做MySQL异常重启时就不会丢数据了,相比之下风险会更小。

innodb_flush_log_at_trx_commit

用于设置 InnoDB 在事务提交后的日志写入频率:

  • innodb_flush_log_at_trx_commit = 0 : 表示log buffer 每秒都会写入到日志文件并刷新到磁盘。在事务提交的时候,不会主动触发写入磁盘的操作,也就是log buffer的刷新操作和事务没有关系。这种情况下MySQL的性能最好,但如果 mysqld 进程崩溃,通常会导致最后 1秒的日志丢失。
  • innodb_flush_log_at_trx_commit = 1 : 这是默认值,表示每次事务提交时,log buffer 会被写入到日志文件并刷新到磁盘。这种配置最安全,但由于每次事务都需要进行磁盘I/O,所以性能最差。
  • innodb_flush_log_at_trx_commit = 2 : 表示每次事务提交时log buffer都会写入到日志文件,但是每隔1秒才会将日志文件内容刷新到磁盘。该场景下,如果mysqld进程奔溃,不会造成日志的丢失,但如果操作系统奔溃,通常会导致最后 1秒的日志丢失。

对于一些数据一致性要求不高的场景,设置为2就行了;如果要求最高的性能则可以设置为0;像一些对数据一致性要求很严格的业务场景(如金融支付),即使性能最差,也最好设置为1保证数据没有丢失。

sync_binlog

用于控制 MySQL binlog 同步到磁盘的策略:

  • sync_binlog = 0 : 表示 MySQL 依赖操作系统不定期把 binlog 刷新到磁盘。
  • sync_binlog = n (n>0) : 表示 MySQL 每完成 n 次事务,就调用文件系统的刷新操作将缓存刷到磁盘。(如果启用了 autocommit,那么每个语句都会写一次binlog,否则每个事务写一次。)
  • sync_binlog 设置 0 可以保证最高的抗并发能力,但是数据库可能会出现阻塞(binlog 日志量太大,操作系统同步磁盘时占用过多资源导致业务出现阻塞). 如果业务要求数据库合适的抗并发能力,且不希望出现阻塞,sync_binlog 设置 n(n>1, 根据具体业务和压测结果设置); 对于金融支付这类场景,为保证安全性,还是推荐sync_binlog设置为1。

gorm 连接池优化

以下介绍几个常见的gorm连接池参数。

  • MaxOpenConns : 通过SetMaxOpenConns方法设置连接池的所有链接(包括长连接和短连接)的最大数目,默认值为0表示不限制。设置最大的连接数,可以避免高并发下mysql出现too many connections的错误。

  • MaxIdleConns : 通过SetMaxIdleConns方法设置连接池的空闲连接数,即长连接的最大数量。

  • ConnMaxLifetime : 通过SetConnMaxLifetime设置mysql长连接的最长使用时间,超过该时间该链接会自动关闭。 如果小于等于0,则永不过期(不设置默认为0)。

一般来说,MaxIdleConns * 机器数 需要大于 活动预估数据库请求QPS,保证活动高并发时无需频繁创建和销毁连接,降低调用耗时。 ConnMaxLifetime 根据具体业务情况设置,比如设置1h,可以在活动开始1h前进行预热,提前把连接数创建完毕,这样活动时无需新建连接,提高了数据库操作的性能。 根据设置结果计算的proxy单台代理连接数建议不超过5k,超过5k的话最好根据实际情况咨询DBA。

数据库表结构优化

数据库分表

  • 垂直分表
  • 水平分表

数据表字段类型选择

高并发场景下,数据表字段的选择优劣,对于数据库的性能有很大的影响,所以在数据表设计之初需要着重考虑字段类型的选择。以下介绍两个字段选型的建议。

  • 字符类型不要使用TEXT : 非必要情况下,不要使用TEXT类型,MySQL memory引擎的内部临时表不支持TEXT类型,如果查询中包含这样的数据,那么内部临时表会无法使用memory引擎,将会创建一张基于innodb引擎的内部临时表,使SQL的性能变得很差。
  • 字段尽量使用 NOT NULL : MySQL字段尽量都定义为NOT NULL,因为索引的NULL列需要额外的空间来保存,并且在进行比较和计算时要对NULL值做特别的处理。