赞
踩
一:死锁
在我们使用锁的时候,有一个问题是需要注意和避免的,我们知道,排它锁有互斥的特性。一个事务或者说一个线程持有锁的时候,会阻止其他的线程获取锁,这个时候 会造成阻塞等待,如果循环等待,会有可能造成死锁。
1.1、锁什么时候释放?
1.2、如果一个事务一直未释放锁,其他事务会被阻塞多久?
如果一直等下去,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占 用大量计算机资源,造成严重性能问题,甚至拖跨数据库。
MySQL有一个参数'innodb_lock_wait_timeout'
来控制获取锁的等待时间,默认是50秒。
1.3、死锁的发生
那么死锁需要满足什么条件?死锁的产生条件,因为锁本身是互斥的
表锁是不会发生死锁的原因,因为表锁的资源都是一次性获取的。
如果锁一直没有释放,就有可能造成大量阻塞或者发生死锁,造成系统吞吐量下降, 这时候就要查看是哪些事务持有了锁
1.4、查看锁信息(日志)
show status like 'innodb_row_lock_%';
InnoDB还提供了三张表来分析事务与锁的情况:
select * from information schema.INNODB_TRX;—当前运行的所有事务,还有具体的语句
select * from information schema.INNODB_LOCKS; 当前出现的锁
select * from information schema.INNODB_LOCK_WAITS;锁等待的对应关系
通过分析锁日志,找出持有锁的事务之后呢?
如果一个事务长时间持有锁不释放,可以kill事务对应的线程ID,也就是INNODB_TRX 表中的 trx_mysqI_thread_id,例如执行 kill 4, kill 7, kill 8.
当然,死锁的问题不能每次都靠kill线程来解决,这是治标不治本的行为。我们应该尽量在应用端也就是code层面避免。
1.5死锁的避免
1、程序中操作多张表,尽量相同的顺序访问,避免形成环路;
2、批量操作单表数据的时候,先对数据进行排序,避免形成环路;
3、申请足够级别的锁,如果要操作数据,就申请排它锁;
4、尽量为表添加合理的索引,使用索引访问数据,避免没有where条件的操作,避免锁表;
5、如果可以,大事务化成小事务,占有的资源锁越多,越容易出现死锁。;
6、使用等值査询而不是范围査询査询数据,命中记录,避免间隙锁对并发的影响;
7、降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁;
二:性能优化
我们说到性能调优,大部分时候想要实现的目标是让我们的査询更快。一个査询的流程又是由很多个环节组成的,每个环节都会消耗时间。
我们要减少查询所消耗的时间,就要从每一个环节入手。
2.1、连接—配置优化
第一个环节是客户端连接到服务端,连接这一块有可能是服务端连接数不够导致应用程序获取不到连接。
Mysql: error 1040: Too many connections的错误。这个是超过了服务端设置的最大并发连接数
2.1.1、解决连接数不够的问题:
从服务端来说:
show variables like 'max connections';#修改最大连接数,当有多个应用连接的时候
show global variables like '#及时释放不活动的连接,注意不要释放连接池还在使用的连接
从客户端来说:
连接池并不是越大越好,只要维护一定数量大小的连接池,其他的客户端排队等待 获取连接就可以了。有的时候连接池越大,效率反而越低。Druid的默认最大连接池大小是8。Hikari的默认最大连接池大小是10。建议是机器核数乘以2加1。也就是说,4核的机器,连接池维护9个连接就够了。
2.1.2、数据库的参数配置
说到了从数据库配置的层面去优化数据库。不管是数据库本身的配置,还是安装这个数据库服务的操作系统的配置,对于配置进行优化,最终的目标都是为了更 好地发挥硬件本身的性能,包括CPU、内存、磁盘、网络。在不同的硬件环境下,操作系统和MySQL的参数的配置是不同的,没有标准的配置。
Mysql大多数参数都提供了一个默认值,比如默认的页大小、连接数、缓冲区、日志大小等等,这些默认配置可以满足大部分情况的需求,除非有特殊的需求。
在清楚参数的含义的情况下再去修改它。修改配置的工作一般由专业的DBA完成。也有一些工具可以给出推荐值。
2.1.3、 缓存
除了合理设置服务端的连接数和客户端的连接池大小之外,我们还有哪些减少客户 端使用的连接数的方案呢?我们可以引入缓存。
在系统里面有一些很慢的查询,要么是数据量大,要么是关联的表多,要么是计算 逻辑非常复杂,这样的查询每次会占用连接很长的时间。所以为了减轻数据库的压力,和提升查询效率,我们可以把数据放到内存缓存起来, 比如使用redis,运行独立的缓存服务,属于架构层面的优化。
2.1.4、 主从集群
为了减少单台数据库服务器的读写压力,在架构层面我们还可以创建集群。
集群的话必然会面临一个问题,就是不同的节点之间数据一致性的问题。如果同时 读写多台数据库节点,怎么让所有的节点数据保持一致?
这个时候我们需要用到复制技术(replication),被复制的节点称为master,复制 的节点称为slave。slave本身也可以作为其他节点的数据来源,这个叫做级联复制。
MySQL所有更新语句都会记录到Server层的binlog,有了这个binlog,slave服务器会不断获取master服务器的binlog文件,然后解析里面的SQL语句,在slave服务器上面执行一遍,保持主从的数据一致。
这里面涉及到三个线程
做了主从复制配置案之后,我们只把数据写入master节点,而读的请求可以分担到slave节点,这种方案叫做读写分离
2.1.5、 分库分表
如果单张表存储的数据过大的时候,比如一张表有上亿的数据,每天以百万的量级增加,单表的查询性能还是会大 幅下降。这个时候我们应该怎么办呢?
这个时候就要用到分布式架构中的第二个重要的手段,叫做分片。把单个节点的数据分散到多个节点存储,减少存储和访问压力,这个就是限定数据范围、分库分表。
限定数据的范围 :
务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
库分表总体上可以分为两类:
但是尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度 ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。以上是架构层面的优化,可以用缓存,读写分离,分库分表。这些措施都可以减轻服务端的访问压力,提升客户端的响应效率。
2.2、优化器—SQL语句分析与优化
优化器的作用就是对我们的SQL语句进行优化分析,生成执行计划。
主要有两个切入点:
数据库慢SQL查询
EXPLAIN 执行计划分析
2.2.1、慢查询日志slow query log
show variables like 'slow_query%';
show variables like '%long_query';
参数的两种修改方式:
MySQL提供了 mysqldumpslow的工具,在MySQL的bin目录下。
mysqldumpslow -s t -t 10 -g 'select' /var/lib/mysql/localhost- slow.log
当然,有的时候查询慢,不一定是SQL语句的问题,也有可能是服务器状态的问题。 所以我们也要掌握一些查看服务器和存储引擎状态的命令。
#运行线程
show full processlist;
#显示用户运行线程。可以根据id号kill线程。
select * from infbrmation schema.processlist;
#查看MySQL服务器运行状态
SHOW GLOBAL STATUS;
#存储引擎的当前运行信息,包括事务持有的表锁、行锁信息;事务的锁等待情况;线程信号量等待;文件10请求;buffer pool统计信息。
show engine innodb status;
现在我们已经知道哪些SQL慢了,为什么慢呢?慢在哪里?
MySQL提供了一个执行计划的工具。通过EXPLAIN我们可以模拟服务端执行SQL 查询语句的过程。通过这种方式我们可以分析语句或者表的性能瓶颈。
2.2.2、EXPLAIN执行计划
参考: 官方文档
在Explain中可以看到很多的数据列,下面分别来说明一下每个数据列的含义
三:优化总结
3.1、服务端状态分析:
如果出现连接变慢,查询被阻塞,无法获取连接的情况
3.2、对于具体的慢SQL:
3.2.1、分析SQL语句基本情况
表的表结构
字段的索引情况
每张表的数据量
查询的业务含义
这个非常重要,因为有的时候你会发现SQL根本没必要这么写,或者表设计是有问题的
3.2.1、分析SQL找出慢的原因
找到原因:比如是没有走索引引起的,还是关联查询引起的,还是order by问题。
3.2.1、具体问题具体解决
如果SQL本身解决不了了,就要上升到表结构和架构
掌握正确的调优思路,才是解决数据库性能问题的根本。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。