分布式架构 Mysql优化及高可用

分布式架构 Mysql优化及高可用


特点介绍

  • Mysql是一个关系型数据库管理系统,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低
  • 源码开放,不需要支付额外的费用
  • 适用于中小型网站数据库
  • 为多种编程语言提供了 API,支持多个操作系统使用
  • 支持多线程,充分利用 CPU 资源
  • 提供用于管理、检查、优化数据库操作的管理工具
  • 支持多种存储引擎(MyISAM、查询/插入快,不支持事物,InnoDB 插入慢 支持ACID事务,支持行级锁定)

Mysql 优化思路

  • 表设计合理化
  • 索引优化(添加适当索引[四种: 普通索引、主键索引、唯一索引unique、全文索引])
  • Mysql配置优化 (配置最大并发数my.ini)
  • SQL查询优化
  • Mysql服务器硬件升级
  • 定时的去清除不需要的数据,定时进行碎片整理

Mysql 优化步骤

表设计合理化

  • 1.字符集的选择 如果确认全部是中文,不会使用多语言以及中文无法表示的字符,那么选GBK,只需要2个字节 UTF-8编码会占用3个字节

  • 2.表的存储引擎(查询/插入快,不需要事物支持,可用MyISAM、需要事物可用 InnoDB,不支持全文索引),MyISAM适合SELECT密集型的表,而InnoDB适合INSERT和UPDATE密集型的表

  • 3.如果一个表有许多的列,但平时参与查询和汇总的列却并不是很多,此时可以考虑将表格拆分成2个表,一个是常用的字段,另一个是很少用到的字段

  • 4.BLOB和CLOB 此类字段一般数据量很大,建议设计上数据库可以只保存其外部连接,而数据以其它方式保存,比如系统文件

  • 5.就是用空间换取时间。如果大表查询里经常要join某个基础表,且这个数据基本不变,比如人的姓名,城市的名字等。一旦基础表发生变动,
    则需要更新所有涉及到的冗余表

  • 6 合理构建分区表,分区策略(Range/List/Hash/Key)

  • 7 如果预期长度范围varchar就满足,就避免使用TEXT,表数据量越大,读取越慢,(Mysql 是行存储模式,所以会把整行读取出来,text 储存了大量的数据。读取时,占了大量的io开销)

  • 8.尽量使用TIMESTAMP而非DATETIME

索引优化( (mysql单表最大索引数量为16,建议4-8之间)

  • 1.尽可能使用长度短的主键,在主键上无需建单独的索引,因为系统内部为主键建立了聚簇索引,允许在其它索引上包含主键列
  • 2.外键会影响插入和更新性能,对于批量可靠数据的插入,尽可能用选用对应主表的主键作作为外键,外键是默认加上索引的
  • 3.优先创建复合索引,效果大于单索引
  • 4.经常需要检索查询、排序建议建立索引
  • 5.mysql强制使用指定索引查询 (select * from table_name force index (index_name) where conditions;)
  • 6.创建索引时,需要指定合适长度,其长度直接影响索引文件的大小,因此会影响增删改查的速度
    如 zachary_goods 商品表,title字段长度255,通过本地执行计划
    explain select id,title from zachary_goods where title=“测试商品”;

±—±------------±----------±-----±--------------±------------±--------±------±-----±-------------------------+

| id | select_type | table | type | possible_keys | key |
key_len | ref | rows | Extra |

±—±------------±----------±-----±--------------±------------±--------±------±-----±-------------------------+

| 1 | SIMPLE | zachary_goods | ref | index_title |
index_title | 150 | const | 1 | Using where; Using index |

±—±------------±----------±-----±--------------±------------±--------±------±-----±-------------------------+

其中key_len 为150过长这样当更新时是比较占内存的
设置区分度高的并且长度适合的索引
select count(distinct left(title,total))/count(*) from zachary_goods;
total是指截取的长度,实际上也可以发现设置该长度的查询度,比例越大说明越良好
通过测试发现索引长度30最佳
alter table zachary_goods add index index_title(title(30));

执行计划介绍

1.select_type: SIMPLE – 查询类型(简单查询、联合查询、子查询)
2.table: user – 显示这一行的数据是关于哪张表的
3.type: range – 区间索引(在小于1990/2/2区间的数据),这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL,const代表一次就命中,ALL代表扫描了全表才确定结果。一般来说,得保证查询至少达到range级别,最好能达到ref
4.possible_keys: birthday – 指出MySQL能使用哪个索引在该表中找到行。如果是空的,没有相关的索引。这时要提高性能,可通过检验WHERE子句,看是否引用某些字段,或者检查字段不是适合索引
5.key: birthday – 实际使用到的索引。如果为NULL,则没有使用索引。如果为primary的话,表示使用了主键
6.key_len: 4 – 最长的索引宽度。如果键是NULL,长度就是NULL。在不损失精确性的情况下,长度越短越好
7.ref: const – 显示哪个字段或常数与key一起被使用
8.rows: 1 – 这个数表示mysql要遍历多少数据才能找到
9.Extra: Using where; Using index – 执行状态说明,这里可以看到的坏的例子是Using temporary和Using

SQL查询优化

  • 1.可通过开启慢查询日志来找出较慢的SQL
  • 2.sql语句尽可能简单:一条sql只能在一个cpu运算;大语句拆小语句,减少锁时间;一条大sql可以堵死整个库
  • 3.不用SELECT *,罗列相关字段,减少资源开销
  • 4.OR改写成IN:OR的效率是n级别,IN的效率是log(n)级别,in的个数建议控制在200以内
  • 5.避免like %xxx式查询,全表扫描
  • 6.尽量避免在WHERE子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描
  • 7.对于连续数值,使用BETWEEN不用IN
  • 8.列表数据不要拿全表,要使用LIMIT来分页,每页数量也不要太大

Mysql配置优化

  • 1.修改MySQL客户端的数据库连接闲置最大时间值 wait_timeout参数值,由默认的8小时,修改为30分钟,wait_timeout=1800(单位秒)
    通过命令show variables like 'wait_timeout’查看结果值
  • 2.修改back_log参数值:由默认的50修改为500(每个连接256kb),back_log值指出在MySQL暂时停止回答新请求之前的短时间内多少个请求可以被存在堆栈中
  • 3.修改max_connections参数值,修改为3000;max_connections=3000,
    max_connections是指MySql的最大连接数,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量
  • 4.修改thread_concurrency值,thread_concurrency应设为CPU核数的2倍

Mysql常见问题分析及处理

  1. Mysql死锁(非主键索引更新引起的死锁)
    死锁一般会抛出MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
    主键更新,Mysql会锁住主键索引,非主键索引更新时;Mysql会先锁住非主键索引,再锁定主键索引
    如:update zachary_goods set status=‘CHECKED’ where title=“测试商品”,Mysql会执行以下过程
    1.由于用到了非主键索引,首先需要获取index_title上的行级锁
    2.获取锁成功后根据主键进行更新,所以需要获取主键上的行级锁
    3.更新完毕后,提交,并释放所有锁
    那么死锁如何产生呢?,如上SQL再执行1.2之间时,突然外界执行了 update zachary_goods set status=‘CHECKED’ where id=1 AND
    同样会先锁住主键索引,然后锁住非主键索引,此时此刻 上叙SQL等待主键锁,下叙SQL等待非主键索引,就产生了死锁
    处理方案
    1.默认更新时,先获取需要更新的记录的主键
    2.通过主键更新记录避免死锁

  2. Mysql 缺少索引的数据表更新引起的死锁
    相关异常Error: ER_LOCK_WAIT_TIMEOUT: Lock wait timeout exceeded; try restarting transaction
    分析思考:
    原因是锁等待超时,当前事务在等待其它事务释放锁资源造成的
    MySQL 默认的级别是 REPEATABLE READ(可重复读),这表示在 MySQL 的默认情况下,“脏读”、“不可重复读” 是不会发生的。这就需要在更新的时候进行必要的锁定(InnoDB 是采用行级锁的方式),从而保证一致性
    InnoDB 的行锁是通过给索引上的索引项加锁来实现的,意味着只有通过索引条件检索数据,其才使用行级锁,否则,其 将使用表锁
    执行SQL时候没有给相关字段加索引导致锁住了整个表,由于数据量大导致其它查询本表处于等待锁资源,而这个等待时间太久,导致超时了
    处理方案
    1.相关字段加索引
    2.text 字段做索引,所以必须选择字段前多少位做索引,或者使用全文索引,InnoDB不支持全文索引

  3. Mysql多线程update发生死锁
    相关异常Error updating database.
    Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
    分析思考: 因为行锁是对索引加锁,那么当where语句中包含多个条件时候,mysql在生成执行计划的时候实际上也只用到一个字段的索引(区分度最大的字段),所以即使where语句中包含多个字段,实际上也只使用了一个字段的索引,那么根据这个字段进行过滤出来的记录数可能就不止一条,这个可以通过explain查看到。
    当高并发的情况下,当两个事务同时需要对同一个检索的记录进行更新操作时,由于其中一个事务把同一个检索的所有记录都锁住了,
    那么必然会导致另外一个事务无法获取到锁
    处理方案
    1.建立复合索引,对where条件中所用到的所有的字段共同构建一个复合索引
    2.再次执行explain,发现这个时候确实只锁住了一条记录,问题解决

Mysql优化过程(千万级别数据)

读写分离:

04
主从复制过程:
02

一主多从:
1

级联复制:

2

  • 1.当传统单节点数据库由于负载过高,数据量大,查询缓慢,此时优化思路 可以做主从、读写分离
  • 2.所谓读写分离,1个主节点用于写数据,把读数据分流到1个从节点。从而提高节点利用率、缓解数据库压力
  • 3.以上方案可以撑一段时间,当数据量持续加大后,以上方案已经到达瓶颈后,这个时候分析写数据/读数据哪个有瓶颈?
  • 4.如果读数据有瓶颈后,可以优化成,1主多从,从节点做负载均衡。mysql的binlong同步5个节点以上会存在性能问题,建议3-5个节点
    如果由于业务系统需要,必须要大于5个节点以上,建议使用 从节点挂载同步到从节点,减少主节点同步到从节点的性能耗损
  • 5.如果写数据存在瓶颈,此时考虑表构造、索引优化
  • 6.当表构造、索引优化后并发已到瓶颈后,此时考虑分库,由于mysql单库存在最大并发限制(3000),提高并发、提高磁盘存储率
  • 7.分库后由于数据库持续增大,索引优化到瓶颈后效果不好。此时考虑分区。分区相当于单库的分表,
    Mysql支持多种分区算法,无嵌入程序。Mysql支持单库最大分区1024,意味着可以分1024个区块
  • 8.由于应用程序里面各种统计算法、业务模式加大,此时单台主节点数据库已经到达瓶颈(分区不支持数据库横向扩展),此时考虑分表,
    由于分表会有很多潜在问题,维护成本高额、统计数据繁琐、数据移植难度大等。笔者建议不到万不得已不要走此步骤
  • 9.分表有效将大表横向切分成小表,可分布在多台数据库上。性能非常高。常用分表如(shared-jdbc,my-cat,mysql-proxy官网插件)

注明:如是对公司业务发展非常了解、业务清晰明了、数据量预估到位、风险评估到位可提前设计一步到位、否则就是过度为了设计而设计
笔者建议,按照系统规模、业务场景逐渐优化改造,不要想着一步到位。

Mysql 高可用部署架构

  1. 由于Mysql的写入单台存在瓶颈,不管是主从复制、读写分离都不能完全有效利用服务器资源,并存在数据延迟的风险,数据不一致风险
    笔者推荐一款开源好用的插件 Galera Cluster
    04

    简单说明就是Mysql集群,和主从结构稍有不同,集群中都是主节点,都可以读写操作,当客户端写入到某台数据库后,
    实时自动同步新数据同步到其它节点上面,这种架构不共享任何数据,是一种高冗余架构。 它能解决Mysql如下问题
    1.多主架构:真正的多点读写的集群,在任何时候读写数据,都是最新的,充分利用服务器资源
    2.同步复制:集群不同节点之间数据同步,没有延迟,在数据库挂掉之后,数据不会丢失
    3.并发复制:从节点在APPLY数据时,支持并行执行,有更好的性能表现
    4.故障切换:在出现数据库故障时,因为支持多点写入,切的非常容易

总结

Mysql优化根据业务场景逐渐优化,不要盲目过度设计优化,根据系统业务情况采用适合数据库进行业务处理,传统数据库可以和Nosql数据库共存,分别使用它的优化,让系统业务更加稳健运行

作者简介:张程 技术研究

更多文章请关注微信公众号:zachary分解狮 (frankly0423)

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qaz7225277/article/details/89887794