==============================================
# 参数
==============================================
autocommit
事务操做中是否自动提交,若是为1则自动提交,为0则须要commit。
back_log
mysql服务在很短的时间内有不少的链接请求时该参数就会发挥做用。 若是短期内有很大链接数可考虑增长该值。不过限制于系统层面的链接数。 5.6.6以前默认50, 5.6.6以后基于50+(max_connections/5)公式,上限900
binlog_format
binlog的记录格式。
connect_timeout
这个超时使用在MySQL服务器和客户端交换受权包时。默认10秒。
key_buffer_size
只用于MyISAM存储引擎表,缓存MyISAM存储。
sort_buffer_size
主要用于SQL语句在内存中的临时排序
join_buffer_size
表链接时使用。
log_bin
打开或关闭binlog的参数。须要指定server-id。
innodb_buffer_pool_size
InnoDB缓存表和索引数据的内存区域。
innodb_fast_shutdown
innodb关闭的几种模式。动态参数,默认值为1,可选值为0,1,2
为0时,所有脏叶刷盘而且change buffer合并。关闭缓慢。
为1时,跳过以上操做。关闭迅速。
为2时,innodb只会刷新他的log,当mysql崩溃的时候,提交的事务不会丢失。可是恢复的时间会很长。
通常来讲,使用innodb_fast_shutdown在紧急状况下或者troubleshooting中。好比数据有在内存中有雪崩的危险。
sync_binlog
sync_binlog 的默认值是0,像操做系统刷其余文件的机制同样,MySQL不会同步到磁盘中去而是依赖操做系统来刷新binary log。
当sync_binlog =N (N>0) ,MySQL 在每写 N次 二进制日志binary log时,会使用fdatasync()函数将它的写二进制日志binary log同步到磁盘中去。
innodb_flush_log_at_trx_commit
0:log buffer将每秒一次地写入log file中,而且log file的flush(刷到磁盘)操做同时进行。该模式下在事务提交的时候,不会主动触发写入磁盘的操做。
1:每次事务提交时MySQL都会把log buffer的数据写入log file,而且flush(刷到磁盘)中去,该模式为系统默认。
2:每次事务提交时mysql都会把log buffer的数据写入log file,可是flush(刷到磁盘)操做并不会同时进行。该模式下,MySQL会每秒执行一次 flush(刷到磁盘)操做。
innodb_log_file_size
设置每一个log file的大小,默认48M。太小日志轮转(rotate)受影响,影响checkpoint,过大恢复缓慢。设置多大是一门技术,优化是一个调优的过程。
innodb_thread_concurrency
innodb可限制并发线程数。默认值为0,表示不受限制。若是参数设置大于0,则表示检查机制开启,容许进入的线程数就是参数的值。若是设置过大会由于增长消耗系统层面的链接和资源致使性能退化。 通常状况下,值得设定应小于CPU的核数。 根据系统的负载,硬件环境调整参数。
innodb_flush_method
有三个值:fdatasync(默认),O_DSYNC,O_DIRECT
默认是fdatasync,只要MYSQL线程进行了刷新动做,那么他的这些文件的数据必定会同步到磁盘
为O_DSYNC时,不绕过pape cache, 每次write的数据不只会在page cache里写入,还会写入存储设备,而且,O_SYNC保证每次write返回后,数据都已经写入page cache和存储设备。
为O_DIRECT时,该文件的读写操做将会绕过page cache,直接与存储设备打交道
建议设置为O_DIREC 避免双缓冲(double buffering)和下降swap的压力
max_connections
容许最大并发的链接数。若是由于max_connections而致使的链接错误,会致使状态参数Connection_errors_max_connections的增长。
max_user_connection
每一个数据库用户的最大链接
max_error_count
show warnings语句最多能显示的error,warnings。
wait_timeout
MySQL客户端的数据库链接闲置最大时间值。
thread_concurrency
应设为CPU核数的2倍
innodb_additional_mem_pool_size
设置了InnoDB存储引擎用来存放数据字典信息以及一些内部数据结构的内存空间大小,因此当咱们一个MySQL Instance中的数据库对象很是多的时候,是须要适当调整该参数的大小以确保全部数据都能存放在内存中提升访问效率的。
innodb_log_buffer_size
InnoDB存储引擎的事务日志所使用的缓冲区。
==============================================
# MySQL 规范
==============================================
必须使用InnoDB存储引擎
必须使用UTF8字符集
数据表、数据字段必须加入中文注释
禁止使用存储过程、视图、触发器、Event(解读:高并发大数据的互联网业务,架构设计思路是“解放数据库CPU,将计算转移到服务层”,并发量大的状况下,这些功能极可能将数据库拖死,业务逻辑放到服务层具有更好的扩展性,可以轻易实现“增机器就加性能”。数据库擅长存储与索引,CPU计算仍是让给应用服务器去作吧。)
禁止存储大文件或者大照片(解读:为什么要让数据库作它不擅长的事情?大文件和照片存储在文件系统,数据库里存URI多好)
只容许使用内网域名,而不是ip链接数据库
表必须有主键,例如自增主键
必须把字段定义为NOT NULL而且提供默认值(null的列使索引/索引统计/值比较都更加复杂,对MySQL来讲更难优化、null 这种类型MySQL内部须要进行特殊处理,增长数据库处理记录的复杂性;同等条件下,表中有较多空字段的时候,数据库的处理性能会下降不少、)
禁止使用TEXT、BLOB类型(会浪费更多的磁盘和内存空间,非必要的大量的大字段查询会淘汰掉热数据,致使内存命中率急剧下降,影响数据库性能)
禁止在更新十分频繁、区分度不高的属性上创建索引
禁止使用INSERT INTO t_xxx VALUES(xxx),必须显示指定插入的列属性
禁止在WHERE条件的属性上使用函数或者表达式(SELECT uid FROM t_user WHERE from_unixtime(day)>='2017-02-15' 会致使全表扫描,正确的写法是:SELECT uid FROM t_user WHERE day>= unix_timestamp('2017-02-15 00:00:00'))
==============================================
# MySQL新特性
==============================================
MySQL 5.5
1.InnoDB做为默认的数据库存储引擎。
2.用两个新的参数取代了 innodb_file_io_threads,那就是innodb_read_io_threads 和 innodb_write_io_threads,你就能够根据你的 CPU 核数来更改。
3.在 MySQL5.1.X 版本,因为代码写死,最多只会刷新 100 个脏页到磁盘,合并 20 个插入缓冲,即便磁盘有能力处理更多的请求,也只会处理这么多,这样在更新量较大(好比大批量 INSERT)的时候,脏页刷新可能会跟不上,致使性能降低。而在 MySQL5.5.X 版本里,innodb_io_capacity 参数能够动态调整刷新脏页的数量,在必定程度上解决了这一问题。
4.INNODB 同时支持多个 BufferPool 实例,经过 innodb_buffer_pool_instances 参数来增长InnoDB_Buffer_Pool 实例的个数。
5.增长了半同步复制,relay-log的自我修复,增长了 relay_log_recovery 参数,这个参数的做用是:当 slave 从库宕机后,假如 Relay-Log 损坏了,致使一部分中继日志没有处理,则自动放弃全部未执行的 relay-log,而且从新从 MASTER 上获取日志,这样保证 relay-log 的完整。默认状况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时,可在 slave 从库上开启该功能,建议开启。
MySQL 5.6
1.全文索引的支持。
2. undo log可独立出系统表空间,原来存在ibd系统表空间里。(innodb_undo_directory、innodb_undo_tablespaces)
3.支持多线程复制。slave_parallel_workers
4.支持延迟复制。CHANGE master TO MASTER_DELAY=600;
5.新增GTID复制。
6.ICP优化(Index Condition Pushdown):index_condition_pushdown=on。ICP的优化用于range, ref, eq_ref, and ref_or_null访问方法
Index Condition Pushdown (ICP)是MySQL用索引去表里取数据的一种优化。禁用ICP(MySQL5.6以前),引擎层会利用索引在基表中寻找数据行,而后返回给MySQL Server层,再去为这些数据行进行WHERE后的条件的过滤(回表)。启用ICP(MySQL5.6以后),若是部分WHERE条件能使用索引中的字段,MySQL会把这部分下推到引擎层。存储引擎经过使用索引把知足的行从表中读取出。ICP减小了引擎层访问基表的次数和MySQL Server 访问存储引擎的次数。总之是 ICP的优化在引擎层就可以过滤掉大量的数据,减小io次数,提升查询语句性能。
7.支持read-only事务。
MySQL 5.7
1.动态修改 Buffer Pool。
2.MySQL默认的部署策略发生了变化,变得更加安全。mysql_install_db 弃用了,改用 mysqld。
3.支持JSON数据类型
4.已经删除了test数据库,默认安装完后是没有test数据库。
5.能够为用户设置密码过时策略。
6.能够”锁”住用户,用以暂时禁用某个用户。
7.generated column,这一列由其余列计算而得。
8.sys schema。
9.在线开启GTID。
10.MySQL 5.7版本已经支持”真正”的并行复制功能。
MySQL 8.0
1.MySQL 8.0 的速度要比 MySQL 5.7 快 2 倍。
2.提供 NoSQL 存储功能。
3.新增了一个叫窗口函数的概念,它能够用来实现若干新的查询方式。窗口函数与 SUM()、COUNT() 这种集合函数相似,但它不会将多行查询结果合并为一行,而是将结果放回多行当中。即窗口函数不须要 GROUP BY。
4.隐藏索引。
5.降序索引。
6.utf8mb4 做为 MySQL 的默认字符集。
7.取消默认MyISAM系统表。
8.取消Query Cache。
==============================================
# InnoDB
==============================================
InnoDB体系结构
内存:
innodb_buffer_pool由包含数据、索引、insert buffer ,adaptive hash index,lock 信息及数据字典。
redo log buffer用来缓存重作日志。
additional memory pool:用来缓存LRU链表、等待、锁等数据结构。
线程
master thread负责刷新缓存数据到磁盘并协调调度其它后台进程。
IO thread 分为 insert buffer、log、read、write进程。分别用来处理insert buffer、重作日志、读写请求的IO回调。
purge thread用来回收undo 页
page cleaner thread用来刷新脏页。
关键特性之 insert buffer:
专门为维护非惟一辅助索引的更新设计的。由于innodb的记录是按主键的顺序存放的,因此主键的插入是顺序的,而汇集索引对应的辅助索引的更新则是离散的,为了不大量离散读写,先检查要更新的索引页是否已经缓存在了内存中,若是没有,先将辅助索引的更新都放入缓冲(inset buffer区),等待合适机会(master thread的定时操做,索引块须要被读取时,insert buffer bitmap检测到对应的索引页不够用时)进行insert buffer和索引页的合并。由于辅助索引缓存到insert buffer中时并不会读取磁盘上的索引页,以致于没法校验索引的惟一性,因此不适用惟一辅助索引。innodb中全部的非惟一辅助索引的insert buffer均由同一棵二叉树维护。二叉树的非叶子节点由space(表空间id)+marker(兼容老版本的insert buffer)+offset(在表空间中的位置)构成,叶子节点由space+marker+offset+metadata(进入顺序+类型+标志)+辅助索引构成,进行merge合并时,按顺序进行回放。mysql5.1以后,insert buffer支持change_buffer,还能够缓冲非惟一辅助索引的update\delete操做。insert buffer的二叉树结构是存放在共享表空间中的,因此经过独立表空间恢复表时,执行check table操做会失败,由于辅助索引的数据可能还在insert buffer中,须要经过repair table 重建表上所有的辅助索引。为了保证每次 merge insert buffer成功,表空间中每隔256个连续区就有一个insert buffer bitmap页用来记录索引页的可用空间。insert buffer bitmap页老是处于这个连续区间的第二页,每一个索引页在insert buffer bitmap中占4 bit。能够经过show engine innodb stauts\G;查看insert buffer and adaptive hash index 查看insert buffer的合并数量、空闲页数量、自己的大小、合并次数及索引操做次数。经过索引操做次数与合并次数的的比例能够判断出insert buffer所带来的性能提高。
关键特性之 double write:
由于脏页刷新到磁盘的写入单元小于单个页的大小,若是在写入过程当中数据库忽然宕机,可能会使数据页的写入不完成,形成数据页的损坏。而redo log中记录的是对页的物理操做,若是数据页损坏了,经过redo log也没法进行恢复。因此为了保证数据页的写入安全,引入了double write。double write的实现分两个部分,一个是缓冲池中2M的内存块大小,一个是共享表空间中连续的128个页,大小是2M。脏页从flush list刷新时,并非直接刷新到磁盘而是先调用函数(memcpy),将脏页拷贝到double write buffer中,而后再分两次,每次1M将double write buffer 刷新到磁盘double write 区,以后再调用fsync操做,同步到磁盘。若是应用在业务高峰期,innodb_dblwr_pages_written:innodb_dblwr_writes远小于64:1,则说明,系统写入压力不大。虽然,double write buffer刷新到磁盘的时候是顺序写,但仍是是有性能损耗的。若是系统自己支持页的安全性保障(部分写失效防范机制),如ZFS,那么就能够禁用掉该特性(skip_innodb_doublewrite)。
关键特性之 adaptive hash index:
innodb会对表上的索引页的查询进行监控,若是发现创建hash索引可以带来性能提高,就自动建立hash索引。hash索引的建立是有条件的,首先是一定可以带来性能提高。其次数据库以特定模式的连续访问超过了100次,经过该模式被访问的页的访问次数超过了1/16的记录行数。自适应hash根据B+树中的索引构造而来,只需为这个表的热点页构造hash索引而不是为整张表都构建。一样能够经过show engine innodb status\G中的 insert buffer and adaptive hash index(hash searches/s non-hash searches)查看hash index的使用状况。
MyISAM 和 InnoDB 的区别
1. InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,因此最好把多条SQL语言放在begin和commit之间,组成一个事务;
2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
3. InnoDB支持行级锁,而MyISAM只支持表级锁;
4. InnoDB是汇集索引,数据文件是和索引绑在一块儿的,必需要有主键,经过主键索引效率很高。可是辅助索引须要两次查询,先查询到主键,而后再经过主键查询到数据。所以,主键不该该过大,由于主键太大,其余索引也都会很大。而MyISAM是非汇集索引,数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
5. InnoDB不保存表的具体行数,执行select count(*) from table时须要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只须要读出该变量便可,速度很快;
6. Innodb不支持全文索引,而MyISAM支持全文索引,查询效率上MyISAM要高;
7. InnoDB 把数据和索引存放在一个数据文件里面,而MyISAM 表被存放在三个文件 frm:存放表格定义。 MYD:数据文件。MYI:索引文件。
为何InnoDB表最好要有自增列作主键?
1.InnoDB引擎表是基于B+树的索引组织表
2.使用自增列(INT/BIGINT类型)作主键,这时候写入顺序是自增的,和B+数叶子节点分裂顺序一致;
关于query cache
Query Cache(查询缓存,如下简称QC)存储SELECT语句及其产生的数据结果,特别适用于:频繁提交同一个语句,而且该表数据变化不是很频繁的场景,例如一些静态页面,或者页面中的某块不常常发生变化的信息。QC有可能会从InnoDB Buffer Pool或者MyISAM key buffer里读取结果。
因为QC须要缓存最新数据结果,所以表数据发生任何变化(INSERT、UPDATE、DELETE或其余可能产生数据变化的操做),都会致使QC被刷新。
QC严格要求2次SQL请求要彻底同样,包括SQL语句,链接的数据库、协议版本、字符集等因素都会影响。
关闭QC: query_cache_size = 0, query_cache_type = 0
==============================================
# 复制
==============================================
复制原理:
1. 主:binlog线程——记录下全部改变了数据库数据的语句,放进master上的binlog中;
2. 从:io线程——在使用start slave 以后,负责从master上拉取 binlog 内容,放进 本身的relay log中;
3. 从:sql执行线程——执行relay log中的语句;
MySQL复制格式小结
基于语句级的复制
binlog=statement
优势:
(1)binlog文件较小。
(2)日志是包含用户执行的原始SQL,方便统计和审计。
(3)出现最先可binlog、兼容较好。
(4)binlog方便阅读,方便故障修复。
缺点:
存在安全隐患,可能致使主从不一致。
对一些系统函数不能准确复制或是不能复制:load file()、uuid()、user()、found rows()、sysdate()。
基于行级的复制
binlog=row
优势:
(1)相比statement更加安全的复制格式。
(2)在某些状况下复制速度更快(SQL复杂、表有主键)。
(3)系统的特殊函数也能够复制。
(4)更少的锁。
缺点:
(1)binary log比较大(MySQL 5.6 支持binlog row image)。
(2)单语句更新/删除的表执行过多,会造成大量binlog。
(3)没法从binlog看见用户执行的SQL(MySQL5.6增长一个新的Event binlog_rw_query_log_event记录用户的query)。
基于混合级复制
1.混个使用ROW和statement格式,对于DDL记录会stement,对于TABLE里的行操做记录为ROW格式。
2.若是使用innodb表,事务级别使用了read commeitted or read uncommitted 日志级别只能使用row格式。
3.单在使用row格式中DDL语句仍是会记录成statement格式。
4.mixed格式,那么在如下几种状况会自动将binlog的模式由SBR模式改为RBR。
5.当DML语句更新一个NDB表时。
6.当函数中包含UUID()时。
7.2个及以上包含AUTO_INCREMENT字段的表被更新时。
8.行任何INSERT DELAYED语句时。
9.用UDF时。
10.视图中必需要求使用RBR时,例如建立视图是使用了UUID()函数。
异步复制
异步复制,主库将事务 Binlog 事件写入到 Binlog 文件中,此时主库只会通知一下 Dump 线程发送这些新的 Binlog,而后主库就会继续处理提交操做,而此时不会保证这些 Binlog 传到任何一个从库节点上。
全同步复制
全同步复制,当主库提交事务以后,全部的从库节点必须收到、APPLY而且提交这些事务,而后主库线程才能继续作后续操做。但缺点是,主库完成一个事务的时间会被拉长,性能下降。
半同步复制
半同步复制,是介于全同步复制与全异步复制之间的一种,主库只须要等待至少一个从库节点收到而且 Flush Binlog 到 Relay Log 文件便可,主库不须要等待全部从库给主库反馈。同时,这里只是一个收到的反馈,而不是已经彻底完成而且提交的反馈,如此,节省了不少时间
主从复制延时判断
当遇到从库延迟时,要怎么作?
首先输入 show slave status \G;看一下。
在生产环境中,主从复制经常会有复制延迟的现象,主要是master是并发的写,而slave是单线程的应用relay log,因此会出现复制延时,在MySQL 5.6版本中有了基于库的多线程复制。还有MariaDB的并行复制。可是咱们使用MySQL 5.5的版本也比较多。如何判断复制是否延时呢?工具如今可使用的有pt-heartbeat,可是若是咱们本身明白怎么样判断复制是否延时的话,本身写简单的shell脚本或者python脚本也能够完成。
复制是否延时的判断标准以下:
Master_Log_File: restoredb-bin.000013
Read_Master_Log_Pos: 2421074
Relay_Log_File: restoredb2-relay-bin.000010
Relay_Log_Pos: 2419771
Relay_Master_Log_File: restoredb-bin.000013
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 2421074
Relay_Log_Space: 2420428
不要经过Seconds_Behind_Master去判断,该值表示slave上SQL线程和IO线程之间的延迟
判断方法以下:
一、首先看 Relay_Master_Log_File 和 Master_Log_File 是否有差别
二、若是Relay_Master_Log_File 和 Master_Log_File 有差别的话,那说明延迟很大
三、若是Relay_Master_Log_File 和 Master_Log_File 没有差别,再来看Exec_Master_Log_Pos 和 Read_Master_Log_Pos 的差别,那么更加严谨的作法是同时在主库执行show master status和在从库上面执行show slave status 的输出进行比较。MHA就是这样保证数据一致性的。MMM都没有作到。这也算MHA比MMM更加优秀的地方。
GTID的限制
1.不支持非事务引擎(从库报错,stop slave;start slave;忽略)。
2.不支持create table ... select 语句复制(主库直接报错)。
3.不容许一个SQL同时更新一个事务引擎和非事务引擎的表。
4.在一个复制组中,必需要求统一开启GTID或者是关闭GTID。
5.开启GTID须要重启。
6.开启GTID后,就再也不使用原来的传统的复制方式。
7.对于create temporary table和drop temporary语句不支持。
8.不支持sql_slave_skip_counter。
==============================================
# MHA
==============================================
在MySQL故障切换过程当中,MHA能作到在0~30秒以内自动完成数据库的故障切换操做,而且在进行故障切换的过程当中,MHA能在最大程度上保证数据的一致性
该软件由两部分组成:MHA Manager(管理节点)和MHA Node(数据节点)。
要搭建MHA,要求一个复制集群中必须最少有三台数据库服务器。
为了尽量的减小主库硬件损坏宕机形成的数据丢失,所以在配置MHA的同时建议配置成MySQL 5.5的半同步复制。关于半同步复制原理各位本身进行查阅。(不是必须)。
MHA原理
1.从宕机崩溃的master保存二进制日志事件(binlog events);
2.识别含有最新更新的slave;
3.应用差别的中继日志(relay log)到其余的slave;
4.应用从master保存的二进制日志事件(binlog events);
5.提高一个slave为新的master;
6.使其余的slave链接新的master进行复制;
==============================================
# PXC
==============================================
特性以下:
1.同步复制,事务要么在全部节点提交或不提交。
2.多主复制,能够在任意节点进行写操做。
3.在从服务器上并行应用事件,真正意义上的并行复制。
4.节点自动配置。
5.数据一致性,再也不是异步复制。
优势以下:
1.当执行一个查询时,在本地节点上执行。由于全部数据都在本地,无需远程访问。
2.无需集中管理。能够在任什么时候间点失去任何节点,可是集群将照常工做,不受影响。
3.良好的读负载扩展,任意节点均可以查询。
缺点以下:
1.加入新节点,开销大。须要复制完整的数据。
2.不能有效的解决写缩放问题,全部的写操做都将发生在全部节点上。
3.有多少个节点就有多少重复的数据。
局限性
一、存储引擎:
基于PXC的复制仅适用于InnoDB存储引擎。
对其余存储引擎的表,包括mysql.*表之类的系统表,任何写入都不会被复制。
那建立用户那岂不是没法同步了?关于这个问题。对于基于DDL方式的语句仍是被支持的。
DDL语句使用基于语句级别的方式来实现(即不使用row模式)。
对mysql.*表的全部已DDL方式的更改都将以语句级别式进行复制。
如:CREATE USER… DDL被复制(语句级)
INSERT INTO mysql.user… myisam存储引擎,不会被复制,由于非DDL语句
固然也能够配置wsrep_replicate_myisam参数实现(不建议使用)
二、不支持的查询:
LOCK TABLES在多主模式中不支持UNLOCK TABLES以及LOCK TABLES
锁定功能,如GET_LOCK(),RELEASE_LOCK()等也不被支持
三、查询日志不能定向到表:
若是启用查询日志记录,则必须将日志转发到文件
使用general_log和general_log_file选择查询日志记录和日志文件名称
log_output = file # Author : Leshami # Blog : https://blog.csdn.net/leshami
四、最大事务大小:
容许的最大事务大小由wsrep_max_ws_rows和wsrep_max_ws_size变量定义
LOAD DATA INFILE方式处理每10000行提交一次。对于大的事务将被分解众多小型事务
五、集群乐观并发控制:
PXC集群使用乐观并发控制,事务发出COMMIT可能仍会在该阶段停止
能够有两个事务写入相同的行并在单独的Percona XtraDB集群节点中提交,而且只有其中一个能够成功提交。
失败的将被停止。对于集群级停止,Percona XtraDB集群返回死锁错误代码:
(Error: 1213 SQLSTATE: 40001 (ER_LOCK_DEADLOCK)).
六、因为可能的提交回滚,XA事务不受支持:
七、硬件配置短板限制:
整个群集的写吞吐量受最弱节点的限制。若是一个节点变慢,整个集群变慢。
若是您对稳定的高性能有要求,那么它应该由相应的硬件支持。
八、建议的最小群集大小是3个节点。第三个节点能够是仲裁者。
九、InnoDB虚假更改功能不受支持。
十、enforce_storage_engine=InnoDB与wsrep_replicate_myisam=OFF(默认)不兼容 。
十一、binlog_rows_query_log_events变量不受支持。
十二、高负载时避免ALTER TABLE … IMPORT / EXPORT
1三、若是DDL语句有问题将破坏集群。建议使用pt-online-schema-change操做DDL。
==============================================
# MGR(MySQL Group Replication)
==============================================
基于传统异步复制和半同步复制的缺陷——数据的一致性问题没法保证,MySQL官方在5.7.17版本正式推出组复制(MySQL Group Replication,简称MGR)。
由若干个节点共同组成一个复制组,一个事务的提交,必须通过组内大多数节点(N / 2 + 1)决议并经过,才能得以提交。
由3个节点组成一个复制组,Consensus层为一致性协议层,在事务提交过程当中,发生组间通信,由2个节点决议(certify)经过这个事务,事务才可以最终得以提交并响应。
引入组复制,主要是为了解决传统异步复制和半同步复制可能产生数据不一致的问题。组复制依靠分布式一致性协议(Paxos协议的变体),实现了分布式下数据的最终一致性
MySQL官方推出的高可用解决方案,基于原生复制技术,并以插件的方式提供。
复制的管理操做变得更为自动化
经过Paxos协议提供数据库集群节点数据强一致保证
集群间全部节点可写入
解决网络分区致使的脑裂问题,提高复制数据的可靠性。
MGR是Share Nothing,Oracle RAC是Share Everything。
高容错性,只要不是大多数节点坏掉就能够继续工做,有自动检测机制,当不一样节点产生资源争用冲突时,不会出现错误,按照先到者优先原则进行处理,而且内置了自动化脑裂防御机制
MGR优点:
1.不会出现脑裂现象;
2.冗余能力好,可以保证binlog event至少被复制到超过一半的成员上,主要同时宕机的成员不超过半数便不会致使数据丢失;
3.宕机的服务器重启后,再也不须要特殊的处理就能够从新加入组;
4.多节点写入支持:多写模式下支持集群中的全部节点均可以写入
MGR的限制:
存储引擎必须为innodb
每一个表必须提供主键
只支持ipv4,网络需求较高
不支持Savepoints
必须打开GTID特性,二进制日志格式必须设置为ROW
二进制日志不支持binlog event checksum
MGR搭建步骤:
1.安装搭建MySQL数据。
2.在原有参数文件的基础上,确认加入如下参数:
binlog-format = ROW
gtid-mode = ON
enforce-gtid-consistency = ON
log-slave-updates = ON
master-info-repository = TABLE
relay-log-info-repository = TABLE
binlog-checksum = NONE
transaction_write_set_extraction =XXHASH64 ###开启主键信息采集功能
loose-group_replication_group_name ="aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" ###设置组名
loose-group_replication_start_on_boot =off
loose-group_replication_local_address ="192.168.56.101:33061" ###设置成员的本地地址
loose-group_replication_group_seeds ="192.168.56.101:33061,192.168.56.102:33061,192.168.56.103:33061" ###设置种子成员的地址
loose-group_replication_bootstrap_group =off
loose-group_replication_single_primary_mode=FALSE ###搭建多主模式
loose-group_replication_enforce_update_everywhere_checks= TRUE ###避免未检测到的外键冲突
3.建立受权用户。
4.安装插件,启动复制组
CHANGE MASTER TO MASTER_USER='repl', MASTER_PASSWORD='abc_Test123' FOR CHANNEL 'group_replication_recovery';
INSTALL PLUGIN group_replication SONAME 'group_replication.so';
set global group_replication_single_primary_mode=off;
START GROUP_REPLICATION;
5.db二、db3上启动group_replication:
Db2上mysql命令行上执行启动:
set global group_replication_allow_local_disjoint_gtids_join=ON;
start group_replication;
select * from performance_schema.replication_group_members;
Db3上启动group_replication:
set global group_replication_allow_local_disjoint_gtids_join=ON;
start group_replication;
6.查看现有组成员
mysql> SELECT * FROM performance_schema.`replication_group_members`;
平常维护步骤:
一、若是从库某一节点关闭
stop group_replication;
二、若是全部的库都关闭后,第一个库做为主库首先执行
set global group_replication_bootstrap_group=ON;
start group_replication;
剩下的库直接执行便可!
start group_replication;
三、若是主库故障,会自动从两个从库选出一个主库,主库启动后再次执行以下命令后会变成从库
start group_replication;
==============================================
# 执行计划
==============================================
select_type
示查询中每一个select子句的类型(简单OR复杂)
a. SIMPLE:查询中不包含子查询或者UNION
b. 查询中若包含任何复杂的子部分,最外层查询则被标记为:PRIMARY
c. 在SELECT或WHERE列表中包含了子查询,该子查询被标记为:SUBQUERY
d. 在FROM列表中包含的子查询被标记为:DERIVED(衍生)用来表示包含在from子句中的子查询的select,mysql会递归执行并将结果放到一个临时表中。服务器内部称为"派生表",由于该临时表是从子查询中派生出来的
e. 若第二个SELECT出如今UNION以后,则被标记为UNION;若UNION包含在FROM子句的子查询中,外层SELECT将被标记为:DERIVED
f. 从UNION表获取结果的SELECT被标记为:UNION RESULT
SUBQUERY和UNION还能够被标记为DEPENDENT和UNCACHEABLE。
DEPENDENT意味着select依赖于外层查询中发现的数据。
UNCACHEABLE意味着select中的某些 特性阻止结果被缓存于一个item_cache中。
type
表示MySQL在表中找到所需行的方式,又称“访问类型”,常见类型以下:
ALL 执行full table scan,这事最差的一种方式
index 执行full index scan,而且能够经过索引完成结果扫描而且直接从索引中取的想要的结果数据,也就是能够避免回表,比ALL略好,由于索引文件一般比所有数据要来的小
range 利用索引进行范围查询,比index略好
index_subquery 子查询中能够用到索引
unique_subquery 子查询中能够用到惟一索引,效率比 index_subquery 更高些
index_merge 能够利用index merge特性用到多个索引,提升查询效率
ref_or_null 表链接类型是ref,但进行扫描的索引列中可能包含NULL值
fulltext 全文检索
ref 基于索引的等值查询,或者表间等值链接
eq_ref 表链接时基于主键或非NULL的惟一索引完成扫描,比ref略好
const 基于主键或惟一索引惟一值查询,最多返回一条结果,比eq_ref略好
system 查询对象表只有一行数据,这是最好的状况
possible_keys
指出MySQL能使用哪一个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不必定被查询使用
key
显示MySQL在查询中实际使用的索引,若没有使用索引,显示为NULL
key_len
表示索引中使用的字节数,可经过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并不是实际使用长度,即key_len是根据表定义计算而得,不是经过表内检索出的)
ref
表示上述表的链接匹配条件,即哪些列或常量被用于查找索引列上的值
rows
表示MySQL根据表统计信息及索引选用状况,估算的找到所需的记录所须要读取的行数
Extra
包含不适合在其余列中显示但十分重要的额外信息
Using filesort 将用外部排序而不是按照索引顺序排列结果,数据较少时从内存排序,不然须要在磁盘完成排序,代价很是高,须要添加合适的索引
Using temporary 须要建立一个临时表来存储结果,这一般发生在对没有索引的列进行GROUP BY时,或者ORDER BY里的列不都在索引里,须要添加合适的索引
Using index 表示MySQL使用覆盖索引避免全表扫描,不须要再到表中进行二次查找数据,这是比较好的结果之一。注意不要和type中的index类型混淆
Using where 一般是进行了全表/全索引扫描后再用WHERE子句完成结果过滤,须要添加合适的索引
Impossible WHERE 对Where子句判断的结果老是false而不能选择任何数据,例如where 1=0,无需过多关注
Select tables optimized away 使用某些聚合函数来访问存在索引的某个字段时,优化器会经过索引直接一次定位到所须要的数据行完成整个查询,例如MIN()\MAX(),这种也是比较好的结果之一
==============================================
# 事务、锁
==============================================
脏读:一个事务按相同的查询条件从新读取之前检索过的数据,却发现其余事务更新后达到了知足其查询条件的旧数据(此时它还未被提交),这种现象就称为“脏读”。
不可重复读:一个事务按相同的查询条件从新读取之前检索过的数据,却发现其余事务更新后达到了知足其查询条件的旧数据(此时它已被提交),这种现象就称为“不可重复读”。
幻读:一个事务按相同的查询条件从新读取之前检索过的数据,却发现其余事务插入了知足其查询条件的新数据(此时它已被提交),这种现象就被称为“幻读”。
事务隔离级别
Read Uncommitted(读未提交)隔离级别最低
容许脏读,容许事务查看其它事务所进行的未提交更改,可能读取到其余会话中未提交事务修改的数据。
Read Commited(读已提交)
容许幻读,容许事务查看其它事务所进行的已提交更改,只能读取到已经提交的数据。
Repeatable Read(可重复读)
消除了脏读、不可重复读、幻读,保证事务一致性。
在同一个事务内的查询都是事务开始时刻一致的,确保每一个事务的读取结果都是同样的,默认隔离级别。
Serializable(串行)隔离级别最高
串行化读,每次读都须要得到表级共享锁,读写间相互都会阻塞。
一般的锁范围:
1.全局锁(global lock)。
2.表锁(table lock)。
3.行锁(row lock)。
InnoDB行锁范围(粒度):
1.record lock. 单个记录上的锁
2.gap lock. 间隙锁,锁定一个范围,但不包含记录自己
3.next-key lock = record lock + gap lock. 锁定一个范围,而且锁定记录自己
Record Lock 老是会去锁住索引记录,若是innodb存储引擎表在创建的时候没有设置任何一个索引,并且查询的时候没有使用到索引,那么这时就会致使表锁。
Next-Key Lock是结合了Gap Lock和Record Lock的一种锁定算法,在Next-Key Lock算法下,innodb对于行的查询都是采用这种锁定算法。例如一个索引有10,11,13,20这4个值,那么该索引可能被Next-Key Locking的范围为:
(- &,10]
(10,11]
(13,20]
(20,+ &)
采用Next-Key Lock的锁定技术称为Next-Key Locking。这种设计的目的是为了解决幻读(Phantom Problem)。利用这种锁定技术,锁定的不是单个值,而是一个范围。
注:当查询的索引含有惟一属性时,innodb存储引擎会对Next-Key Lock进行优化,将其降级为Record Lock,即锁住索引记录自己,而再也不是范围。
注意:
对于惟一索引,其加上的是Record Lock,仅锁住记录自己。但也有特别状况,那就是惟一索引由多个列组成,而查询仅是查找多个惟一索引列中的其中一个,那么加锁的状况依然是Next-key lock。
对于辅助索引,其加上的是Next-Key Lock,锁定的是范围,包含记录自己。
另外若是使用相等的条件给一个不存在的记录加锁,innodb也会使用Next-key lock
特别注意:
innodb存储引擎是经过给索引上的索引项加锁来实现,这意味着:只有经过索引条件检索数据,innodb才会使用行锁,不然,innodb将使用表锁。固然这种说法是在表没有主键或者没有任何索引的状况下。若是一个表有主键,没有其余的索引,检索条件又不是主键,SQL会走聚簇索引的全扫描进行过滤,因为过滤是由MySQL Server层面进行的。所以每条记录,不管是否知足条件,都会被加上X锁。可是,为了效率考量,MySQL作了优化,对于不知足条件的记录,会在判断后放锁,最终持有的,是知足条件的记录上的锁,可是不知足条件的记录上的加锁/放锁动做不会省略。同时,优化也违背了2PL的约束。
RC级别下,只有record lock,没有next key lock。
RR级别下,除非primary key或unique key是record lock,其他都是next key lock。
==============================================
# pt工具
==============================================
pt-heartbeat 监控mysql复制延迟
pt-online-schema-change 在线修改表结构
pt-table-checksum 校验主从复制一致性
pt-table-sync 同步表数据
pt-online-schema-change工具的使用限制:
1)若是修改表有外键,除非使用 --alter-foreign-keys-method 指定特定的值,不然工具不予执行
2)被修改表必需要有主键,不然报错:Cannot chunk the original table `houyi`.`ga`: There is no good index and the table is oversized. at ./pt-online-schema-change line 5353.
3)被修改表上不能有针对after delete|insert|update三个触发器,不然修改表结构操做失败
online ddl的原理以下:
一、建立一个和原来表结构同样的临时表并ddl
二、锁住原表,全部数据都没法写入(insert,update,delete)
三、将原表数据写入到临时表中(经过insert ...select方式)
四、写入完后,重命名临时表和原表名称
五、删除原表,释放锁
pt-online-schema-change在线ddl原理以下:
一、建立一个和原来表结构同样的临时表并ddl
二、将原表数据写入到临时表中(经过insert ...select方式),而且在原表上建立触发器,若是原表有数据写入,经过触发器方式将新增的数据写入临时表中(前提该表以前没有触发器)
三、写入完后,重命名临时表和原表名称
四、删除原表
==============================================
# 备份恢复
==============================================
mysqldump实现原理
1.修改session级别的sql_mode为空,避免可能有些些sql_mode值会对备份产生影响
2.强制刷新表缓存到磁盘,并关闭表。若是另外一个会话已经加上表锁,那么该语句会被阻塞
3.调用 flush tables with read lock 对整个实例加全局读锁
4.开启快照读,在session级别将隔离级别设置成RR,由于开启一个一致性快照事务,须要在RR隔离级别,获取此时的快照(仅对innodb表起做用)
5.备份非innodb表数据(*.frm,*.myi,*.myd等)
6.非innodb表备份完毕后,释放FTWRL锁
7.逐一备份innodb表数据
8.表备份结束,回滚到保存点sp,以释放select *语句产生的MDL锁,若是不回滚,后续整个备份过程当中没法对该表执行DDL操做
9.备份完成后,释放该保存点
Xtrabackup实现原理
1.innobackupex 在启动后,会先 fork 一个进程,启动 xtrabackup进程,而后就等待 xtrabackup 备份完 ibd 数据文件;
2.xtrabackup 在备份 InnoDB 相关数据时,是有2种线程的,1种是 redo 拷贝线程,负责拷贝 redo 文件,1种是 ibd 拷贝线程,负责拷贝 ibd 文件;redo 拷贝线程只有一个,在 ibd 拷贝线程以前启动,在 ibd 线程结束后结束。xtrabackup 进程开始执行后,先启动 redo 拷贝线程,从最新的 checkpoint 点开始顺序拷贝 redo 日志;而后再启动 ibd 数据拷贝线程,在 xtrabackup 拷贝 ibd 过程当中,innobackupex 进程一直处于等待状态(等待文件被建立)。
3.xtrabackup 拷贝完成idb后,通知 innobackupex(经过建立文件),同时本身进入等待(redo 线程仍然继续拷贝);
4.innobackupex 收到 xtrabackup 通知后,执行FLUSH TABLES WITH READ LOCK (FTWRL),取得一致性位点,而后开始备份非 InnoDB 文件(包括 frm、MYD、MYI、CSV、opt、par等)。拷贝非 InnoDB 文件过程当中,由于数据库处于全局只读状态,若是在业务的主库备份的话,要特别当心,非 InnoDB 表(主要是MyISAM)比较多的话整库只读时间就会比较长,这个影响必定要评估到。
5.当 innobackupex 拷贝完全部非 InnoDB 表文件后,通知 xtrabackup(经过删文件) ,同时本身进入等待(等待另外一个文件被建立);
6.xtrabackup 收到 innobackupex 备份完非 InnoDB 通知后,就中止 redo 拷贝线程,而后通知 innobackupexredo log 拷贝完成(经过建立文件);
7.innobackupex 收到 redo 备份完成通知后,就开始解锁,执行 UNLOCK TABLES;
8.最后 innobackupex 和 xtrabackup 进程各自完成收尾工做,如资源的释放、写备份元数据信息等,innobackupex 等待 xtrabackup 子进程结束后退出。
==============================================
# 常见问题
==============================================
某人曰,在数据检索的条件中使用!=操做符时,存储引擎会放弃使用索引。
理由:由于检索的范围不能肯定,因此使用索引效率不高,会被引擎自动改成全表扫描。你承认他的说法吗?
答:一般状况下,这个说法是正确的。固然,也有特殊状况,话不能说绝对了。
有一个测试表共80万条数据,其中type列只有一、2两个值,分别占比97%和3%。
这种状况下,查询条件 WHERE type != 1,是有可能也能够走索引的。
下面是两个SQL的执行计划:
mysql> desc select * from t1 where type = 1\G
**************** 1. row ****************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: type
key: type
key_len: 4
ref: const
rows: 399731
filtered: 100.00
Extra: NULL
mysql> desc select * from t1 where type != 1\G
**************** 1. row ****************
id: 1
select_type: SIMPLE
table: t1
partitions: NULL
type: ref
possible_keys: type
key: type
key_len: 4
ref: const
rows: 10182
filtered: 100.00
Extra: NULL
type数据分布
mysql> select type, count(*) as cnt from t1 group by type order by cnt;
+------+--------+
| type | cnt |
+------+--------+
| 2 | 38304 |
| 1 | 761690 |
+------+--------+
MySQL在高并发时有什么过载保护的方法?
一、在前端Nginx层/中间件中限流,控制对MySQL的请求数。
二、控制MySQL的参数max_connections/max_user_connections,防止太高并发。
三、利用pt-kill等工具,及时杀掉引起性能问题的SQL。
四、根据服务器的压力状况,适当调整MySQL的innodb_thread_concurrency参数。
五、快速构建从库,缓解主库读压力。
六、适当调整max_execution_time=N。当SQL语句超过N秒,不予执行。
七、尽快优化慢SQL。
在大表执行ddl的过程当中,若临时中断,会发生什么情况,须要特别处理吗 ?
前提说明:MySQL5.7.2三、innodb表、“双1”
一、添加/删除列,采用copy的方式
1.一、ctrl+c。在当前session中,手动执行ctrl+c。无影响,而且会自动删除产生的临时文件。
1.二、kill -9。在执行ddl的时候,服务器发生意外宕机或者手动执行kill -9。待MySQL启动后,则会自动执行InnoDB Recovered流程。而且不会删除产生的临时文件,须要手工处理。
二、添加/删除索引,采用INPLACE方式
2.一、ctrl+c。同1.1
2.二、kill -9。不会删除临时文件,也不会执行InnoDB Recovered流程而且报错 Operating system error number 2 in a file operation ....OS error: 71
在开始执行alter table的过程当中,在没有结束的时候,并不会写入到binglog文件中。
如何优化一条慢SQL
1.表设计、数据类型是否合理。
2.SQL写法是否正确。
3.表的统计信息是否正确。
4.看执行计划,判断上面有没有合适的索引。
MySQL数据库cpu飙升到500%的话该怎么处理?
当 cpu 飙升到 500%时,先用操做系统命令 top 命令观察是否是 mysqld 占用致使的,若是不是,找出占用高的进程,并进行相关处理。若是是 mysqld 形成的, show processlist,看看里面跑的 session 状况,是否是有消耗资源的 sql 在运行。找出消耗高的 sql,
看看执行计划是否准确, index 是否缺失,或者实在是数据量太大形成。通常来讲,确定要 kill 掉这些线程(同时观察 cpu 使用率是否降低),等进行相应的调整(好比说加索引、改 sql、改内存参数)以后,再从新跑这些 SQL。也有多是每一个 sql 消耗资源并很少,可是忽然之间,
有大量的 session 连进来致使 cpu 飙升,这种状况就须要跟应用一块儿来分析为什么链接数会激增,再作出相应的调整,好比说限制链接数等前端